2 * BIRD -- BGP Attributes
4 * (c) 2000 Martin Mares <mj@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
13 #include "nest/bird.h"
14 #include "nest/iface.h"
15 #include "nest/protocol.h"
16 #include "nest/route.h"
17 #include "nest/attrs.h"
18 #include "conf/conf.h"
19 #include "lib/resource.h"
20 #include "lib/string.h"
21 #include "lib/unaligned.h"
25 static byte bgp_mandatory_attrs
[] = { BA_ORIGIN
, BA_AS_PATH
37 int (*validate
)(struct bgp_proto
*p
, byte
*attr
, int len
);
38 void (*format
)(eattr
*ea
, byte
*buf
);
42 bgp_check_origin(struct bgp_proto
*p UNUSED
, byte
*a UNUSED
, int len
)
50 bgp_format_origin(eattr
*a
, byte
*buf
)
52 static char *bgp_origin_names
[] = { "IGP", "EGP", "Incomplete" };
54 bsprintf(buf
, bgp_origin_names
[a
->u
.data
]);
58 bgp_check_path(struct bgp_proto
*p UNUSED
, byte
*a
, int len
)
62 DBG("Path segment %02x %02x\n", a
[0], a
[1]);
64 a
[0] != AS_PATH_SET
&& a
[0] != AS_PATH_SEQUENCE
||
74 bgp_check_next_hop(struct bgp_proto
*p UNUSED
, byte
*a
, int len
)
81 memcpy(&addr
, a
, len
);
83 if (ipa_classify(addr
) & IADDR_HOST
)
91 bgp_check_reach_nlri(struct bgp_proto
*p UNUSED
, byte
*a UNUSED
, int len UNUSED
)
94 p
->mp_reach_start
= a
;
95 p
->mp_reach_len
= len
;
101 bgp_check_unreach_nlri(struct bgp_proto
*p UNUSED
, byte
*a UNUSED
, int len UNUSED
)
104 p
->mp_unreach_start
= a
;
105 p
->mp_unreach_len
= len
;
110 static struct attr_desc bgp_attr_table
[] = {
111 { NULL
, -1, 0, 0, 0, /* Undefined */
113 { "origin", 1, BAF_TRANSITIVE
, EAF_TYPE_INT
, 1, /* BA_ORIGIN */
114 bgp_check_origin
, bgp_format_origin
},
115 { "as_path", -1, BAF_TRANSITIVE
, EAF_TYPE_AS_PATH
, 1, /* BA_AS_PATH */
116 bgp_check_path
, NULL
},
117 { "next_hop", 4, BAF_TRANSITIVE
, EAF_TYPE_IP_ADDRESS
, 1, /* BA_NEXT_HOP */
118 bgp_check_next_hop
, NULL
},
119 { "med", 4, BAF_OPTIONAL
, EAF_TYPE_INT
, 0, /* BA_MULTI_EXIT_DISC */
121 { "local_pref", 4, BAF_TRANSITIVE
, EAF_TYPE_INT
, 0, /* BA_LOCAL_PREF */
123 { "atomic_aggr", 0, BAF_TRANSITIVE
, EAF_TYPE_OPAQUE
, 1, /* BA_ATOMIC_AGGR */
125 { "aggregator", 6, BAF_OPTIONAL
| BAF_TRANSITIVE
, EAF_TYPE_OPAQUE
, 1, /* BA_AGGREGATOR */
127 { "community", -1, BAF_OPTIONAL
| BAF_TRANSITIVE
, EAF_TYPE_INT_SET
, 1, /* BA_COMMUNITY */
129 { NULL
, }, /* BA_ORIGINATOR_ID */
130 { NULL
, }, /* BA_CLUSTER_LIST */
131 { NULL
, }, /* BA_DPA */
132 { NULL
, }, /* BA_ADVERTISER */
133 { NULL
, }, /* BA_RCID_PATH */
134 { "mp_reach_nlri", -1, BAF_OPTIONAL
, EAF_TYPE_OPAQUE
, 1, /* BA_MP_REACH_NLRI */
135 bgp_check_reach_nlri
, NULL
},
136 { "mp_unreach_nlri", -1, BAF_OPTIONAL
, EAF_TYPE_OPAQUE
, 1, /* BA_MP_UNREACH_NLRI */
137 bgp_check_unreach_nlri
, NULL
},
140 #define ATTR_KNOWN(code) ((code) < ARRAY_SIZE(bgp_attr_table) && bgp_attr_table[code].name)
143 bgp_set_attr(eattr
*e
, struct linpool
*pool
, unsigned attr
, unsigned val
)
145 ASSERT(ATTR_KNOWN(attr
));
146 e
->id
= EA_CODE(EAP_BGP
, attr
);
147 e
->type
= bgp_attr_table
[attr
].type
;
148 e
->flags
= bgp_attr_table
[attr
].expected_flags
;
149 if (e
->type
& EAF_EMBEDDED
)
156 e
->u
.ptr
= lp_alloc(pool
, sizeof(struct adata
) + val
);
157 e
->u
.ptr
->length
= val
;
158 return e
->u
.ptr
->data
;
163 bgp_attach_attr(ea_list
**to
, struct linpool
*pool
, unsigned attr
, unsigned val
)
165 ea_list
*a
= lp_alloc(pool
, sizeof(ea_list
) + sizeof(eattr
));
168 a
->flags
= EALF_SORTED
;
170 return bgp_set_attr(a
->attrs
, pool
, attr
, val
);
174 * bgp_encode_attrs - encode BGP attributes
176 * @attrs: a list of extended attributes
177 * @remains: remaining space in the buffer
179 * The bgp_encode_attrs() function takes a list of extended attributes
180 * and converts it to its BGP representation (a part of an Update message).
182 * Result: Length of the attribute block generated.
185 bgp_encode_attrs(byte
*w
, ea_list
*attrs
, int remains
)
187 unsigned int i
, code
, flags
;
191 for(i
=0; i
<attrs
->count
; i
++)
193 eattr
*a
= &attrs
->attrs
[i
];
194 ASSERT(EA_PROTO(a
->id
) == EAP_BGP
);
197 /* When talking multiprotocol BGP, the NEXT_HOP attributes are used only temporarily. */
198 if (code
== BA_NEXT_HOP
)
201 flags
= a
->flags
& (BAF_OPTIONAL
| BAF_TRANSITIVE
| BAF_PARTIAL
);
202 if (ATTR_KNOWN(code
))
204 struct attr_desc
*desc
= &bgp_attr_table
[code
];
205 len
= desc
->expected_length
;
208 ASSERT(!(a
->type
& EAF_EMBEDDED
));
209 len
= a
->u
.ptr
->length
;
214 ASSERT((a
->type
& EAF_TYPE_MASK
) == EAF_TYPE_OPAQUE
);
215 len
= a
->u
.ptr
->length
;
217 DBG("\tAttribute %02x (type %02x, %d bytes, flags %02x)\n", code
, a
->type
, len
, flags
);
218 if (remains
< len
+ 4)
220 log(L_ERR
"BGP: attribute list too long, ignoring the remaining attributes");
232 *w
++ = flags
| BAF_EXT_LEN
;
238 switch (a
->type
& EAF_TYPE_MASK
)
241 case EAF_TYPE_ROUTER_ID
:
243 put_u32(w
, a
->u
.data
);
247 case EAF_TYPE_IP_ADDRESS
:
249 ip_addr ip
= *(ip_addr
*)a
->u
.ptr
->data
;
254 case EAF_TYPE_INT_SET
:
256 u32
*z
= (u32
*)a
->u
.ptr
->data
;
258 for(i
=0; i
<len
; i
+=4)
262 case EAF_TYPE_OPAQUE
:
263 case EAF_TYPE_AS_PATH
:
264 memcpy(w
, a
->u
.ptr
->data
, len
);
267 bug("bgp_encode_attrs: unknown attribute type %02x", a
->type
);
276 bgp_init_prefix(struct fib_node
*N
)
278 struct bgp_prefix
*p
= (struct bgp_prefix
*) N
;
279 p
->bucket_node
.next
= NULL
;
283 bgp_compare_u32(const u32
*x
, const u32
*y
)
285 return (*x
< *y
) ? -1 : (*x
> *y
) ? 1 : 0;
289 bgp_normalize_set(u32
*dest
, u32
*src
, unsigned cnt
)
291 memcpy(dest
, src
, sizeof(u32
) * cnt
);
292 qsort(dest
, cnt
, sizeof(u32
), (int(*)(const void *, const void *)) bgp_compare_u32
);
296 bgp_rehash_buckets(struct bgp_proto
*p
)
298 struct bgp_bucket
**old
= p
->bucket_hash
;
299 struct bgp_bucket
**new;
300 unsigned oldn
= p
->hash_size
;
302 struct bgp_bucket
*b
;
304 p
->hash_size
= p
->hash_limit
;
305 DBG("BGP: Rehashing bucket table from %d to %d\n", oldn
, p
->hash_size
);
307 if (p
->hash_limit
>= 65536)
309 new = p
->bucket_hash
= mb_allocz(p
->p
.pool
, p
->hash_size
* sizeof(struct bgp_bucket
*));
310 mask
= p
->hash_size
- 1;
311 for (i
=0; i
<oldn
; i
++)
314 old
[i
] = b
->hash_next
;
316 b
->hash_next
= new[e
];
318 b
->hash_next
->hash_prev
= b
;
325 static struct bgp_bucket
*
326 bgp_new_bucket(struct bgp_proto
*p
, ea_list
*new, unsigned hash
)
328 struct bgp_bucket
*b
;
329 unsigned ea_size
= sizeof(ea_list
) + new->count
* sizeof(eattr
);
330 unsigned ea_size_aligned
= BIRD_ALIGN(ea_size
, CPU_STRUCT_ALIGN
);
331 unsigned size
= sizeof(struct bgp_bucket
) + ea_size
;
334 unsigned index
= hash
& (p
->hash_size
- 1);
336 /* Gather total size of non-inline attributes */
337 for (i
=0; i
<new->count
; i
++)
339 eattr
*a
= &new->attrs
[i
];
340 if (!(a
->type
& EAF_EMBEDDED
))
341 size
+= BIRD_ALIGN(sizeof(struct adata
) + a
->u
.ptr
->length
, CPU_STRUCT_ALIGN
);
344 /* Create the bucket and hash it */
345 b
= mb_alloc(p
->p
.pool
, size
);
346 b
->hash_next
= p
->bucket_hash
[index
];
348 b
->hash_next
->hash_prev
= b
;
349 p
->bucket_hash
[index
] = b
;
352 add_tail(&p
->bucket_queue
, &b
->send_node
);
353 init_list(&b
->prefixes
);
354 memcpy(b
->eattrs
, new, ea_size
);
355 dest
= ((byte
*)b
->eattrs
) + ea_size_aligned
;
357 /* Copy values of non-inline attributes */
358 for (i
=0; i
<new->count
; i
++)
360 eattr
*a
= &b
->eattrs
->attrs
[i
];
361 if (!(a
->type
& EAF_EMBEDDED
))
363 struct adata
*oa
= a
->u
.ptr
;
364 struct adata
*na
= (struct adata
*) dest
;
365 memcpy(na
, oa
, sizeof(struct adata
) + oa
->length
);
367 dest
+= BIRD_ALIGN(sizeof(struct adata
) + na
->length
, CPU_STRUCT_ALIGN
);
371 /* If needed, rehash */
373 if (p
->hash_count
> p
->hash_limit
)
374 bgp_rehash_buckets(p
);
380 bgp_export_check(struct bgp_proto
*p
, ea_list
*new)
385 /* Check if next hop is valid */
386 a
= ea_find(new, EA_CODE(EAP_BGP
, BA_NEXT_HOP
));
387 if (!a
|| ipa_equal(p
->next_hop
, *(ip_addr
*)a
->u
.ptr
))
389 DBG("\tInvalid NEXT_HOP\n");
393 /* Check if we aren't forbidden to export the route by communities */
394 a
= ea_find(new, EA_CODE(EAP_BGP
, BA_COMMUNITY
));
398 if (int_set_contains(d
, BGP_COMM_NO_ADVERTISE
))
400 DBG("\tNO_ADVERTISE\n");
403 if (!p
->is_internal
&&
404 (int_set_contains(d
, BGP_COMM_NO_EXPORT
) ||
405 int_set_contains(d
, BGP_COMM_NO_EXPORT_SUBCONFED
)))
407 DBG("\tNO_EXPORT\n");
415 static struct bgp_bucket
*
416 bgp_get_bucket(struct bgp_proto
*p
, ea_list
*attrs
, int originate
)
419 unsigned i
, cnt
, hash
, code
;
422 struct bgp_bucket
*b
;
424 /* Merge the attribute list */
425 new = alloca(ea_scan(attrs
));
426 ea_merge(attrs
, new);
429 /* Normalize attributes */
438 byte buf
[EA_FORMAT_BUF_SIZE
];
443 if (EA_PROTO(a
->id
) != EAP_BGP
)
446 if (ATTR_KNOWN(code
))
448 if (!bgp_attr_table
[code
].allow_in_ebgp
&& !p
->is_internal
)
450 /* The flags might have been zero if the attr was added by filters */
451 a
->flags
= (a
->flags
& BAF_PARTIAL
) | bgp_attr_table
[code
].expected_flags
;
457 /* Don't re-export unknown non-transitive attributes */
458 if (!(a
->flags
& BAF_TRANSITIVE
))
462 if ((d
->type
& EAF_ORIGINATED
) && !originate
&& (d
->flags
& BAF_TRANSITIVE
) && (d
->flags
& BAF_OPTIONAL
))
463 d
->flags
|= BAF_PARTIAL
;
464 switch (d
->type
& EAF_TYPE_MASK
)
466 case EAF_TYPE_INT_SET
:
468 struct adata
*z
= alloca(sizeof(struct adata
) + d
->u
.ptr
->length
);
469 z
->length
= d
->u
.ptr
->length
;
470 bgp_normalize_set((u32
*) z
->data
, (u32
*) d
->u
.ptr
->data
, z
->length
/ 4);
482 for(b
=p
->bucket_hash
[hash
& (p
->hash_size
- 1)]; b
; b
=b
->hash_next
)
483 if (b
->hash
== hash
&& ea_same(b
->eattrs
, new))
485 DBG("Found bucket.\n");
489 /* Ensure that there are all mandatory attributes */
490 for(i
=0; i
<ARRAY_SIZE(bgp_mandatory_attrs
); i
++)
491 if (!(seen
& (1 << bgp_mandatory_attrs
[i
])))
493 log(L_ERR
"%s: Mandatory attribute %s missing", p
->p
.name
, bgp_attr_table
[bgp_mandatory_attrs
[i
]].name
);
497 if (!bgp_export_check(p
, new))
500 /* Create new bucket */
501 DBG("Creating bucket.\n");
502 return bgp_new_bucket(p
, new, hash
);
506 bgp_free_bucket(struct bgp_proto
*p
, struct bgp_bucket
*buck
)
509 buck
->hash_next
->hash_prev
= buck
->hash_prev
;
511 buck
->hash_prev
->hash_next
= buck
->hash_next
;
513 p
->bucket_hash
[buck
->hash
& (p
->hash_size
-1)] = buck
->hash_next
;
518 bgp_rt_notify(struct proto
*P
, net
*n
, rte
*new, rte
*old UNUSED
, ea_list
*attrs
)
520 struct bgp_proto
*p
= (struct bgp_proto
*) P
;
521 struct bgp_bucket
*buck
;
522 struct bgp_prefix
*px
;
524 DBG("BGP: Got route %I/%d %s\n", n
->n
.prefix
, n
->n
.pxlen
, new ? "up" : "down");
528 buck
= bgp_get_bucket(p
, attrs
, new->attrs
->source
!= RTS_BGP
);
529 if (!buck
) /* Inconsistent attribute list */
534 if (!(buck
= p
->withdraw_bucket
))
536 buck
= p
->withdraw_bucket
= mb_alloc(P
->pool
, sizeof(struct bgp_bucket
));
537 init_list(&buck
->prefixes
);
540 px
= fib_get(&p
->prefix_fib
, &n
->n
.prefix
, n
->n
.pxlen
);
541 if (px
->bucket_node
.next
)
543 DBG("\tRemoving old entry.\n");
544 rem_node(&px
->bucket_node
);
546 add_tail(&buck
->prefixes
, &px
->bucket_node
);
547 bgp_schedule_packet(p
->conn
, PKT_UPDATE
);
551 bgp_create_attrs(struct bgp_proto
*p
, rte
*e
, ea_list
**attrs
, struct linpool
*pool
)
553 ea_list
*ea
= lp_alloc(pool
, sizeof(ea_list
) + 4*sizeof(eattr
));
559 ea
->flags
= EALF_SORTED
;
562 bgp_set_attr(ea
->attrs
, pool
, BA_ORIGIN
,
563 ((rta
->source
== RTS_OSPF_EXT1
) || (rta
->source
== RTS_OSPF_EXT2
)) ? ORIGIN_INCOMPLETE
: ORIGIN_IGP
);
566 bgp_set_attr(ea
->attrs
+1, pool
, BA_AS_PATH
, 0);
569 z
= bgp_set_attr(ea
->attrs
+1, pool
, BA_AS_PATH
, 4);
570 z
[0] = AS_PATH_SEQUENCE
;
572 put_u16(z
+2, p
->local_as
);
575 z
= bgp_set_attr(ea
->attrs
+2, pool
, BA_NEXT_HOP
, sizeof(ip_addr
));
576 if (p
->cf
->next_hop_self
||
578 rta
->dest
!= RTD_ROUTER
)
580 if (ipa_nonzero(p
->cf
->source_addr
))
581 *(ip_addr
*)z
= p
->cf
->source_addr
;
583 *(ip_addr
*)z
= p
->local_addr
;
586 *(ip_addr
*)z
= e
->attrs
->gw
;
588 bgp_set_attr(ea
->attrs
+3, pool
, BA_LOCAL_PREF
, 0);
590 return 0; /* Leave decision to the filters */
594 bgp_path_prepend(struct linpool
*pool
, eattr
*a
, ea_list
*old
, int as
)
596 struct ea_list
*e
= lp_alloc(pool
, sizeof(ea_list
) + sizeof(eattr
));
597 struct adata
*olda
= a
->u
.ptr
;
600 e
->flags
= EALF_SORTED
;
602 e
->attrs
[0].id
= EA_CODE(EAP_BGP
, BA_AS_PATH
);
603 e
->attrs
[0].flags
= BAF_TRANSITIVE
;
604 e
->attrs
[0].type
= EAF_TYPE_AS_PATH
;
605 e
->attrs
[0].u
.ptr
= as_path_prepend(pool
, olda
, as
);
610 bgp_update_attrs(struct bgp_proto
*p
, rte
*e
, ea_list
**attrs
, struct linpool
*pool
)
614 if (!p
->is_internal
&& (a
= ea_find(e
->attrs
->eattrs
, EA_CODE(EAP_BGP
, BA_AS_PATH
))))
615 *attrs
= bgp_path_prepend(pool
, a
, *attrs
, p
->local_as
);
617 a
= ea_find(e
->attrs
->eattrs
, EA_CODE(EAP_BGP
, BA_NEXT_HOP
));
618 if (a
&& (p
->is_internal
|| (!p
->is_internal
&& e
->attrs
->iface
== p
->neigh
->iface
)))
620 /* Leave the original next hop attribute, will check later where does it point */
624 /* Need to create new one */
625 *(ip_addr
*) bgp_attach_attr(attrs
, pool
, BA_NEXT_HOP
, sizeof(ip_addr
)) = p
->local_addr
;
628 return 0; /* Leave decision to the filters */
632 bgp_import_control(struct proto
*P
, rte
**new, ea_list
**attrs
, struct linpool
*pool
)
635 struct bgp_proto
*p
= (struct bgp_proto
*) P
;
636 struct bgp_proto
*new_bgp
= (e
->attrs
->proto
->proto
== &proto_bgp
) ? (struct bgp_proto
*) e
->attrs
->proto
: NULL
;
638 if (p
== new_bgp
) /* Poison reverse updates */
642 if (p
->local_as
== new_bgp
->local_as
&& p
->is_internal
&& new_bgp
->is_internal
)
643 return -1; /* Don't redistribute internal routes with IBGP */
644 return bgp_update_attrs(p
, e
, attrs
, pool
);
647 return bgp_create_attrs(p
, e
, attrs
, pool
);
651 bgp_rte_better(rte
*new, rte
*old
)
653 struct bgp_proto
*new_bgp
= (struct bgp_proto
*) new->attrs
->proto
;
654 struct bgp_proto
*old_bgp
= (struct bgp_proto
*) old
->attrs
->proto
;
658 /* Start with local preferences */
659 x
= ea_find(new->attrs
->eattrs
, EA_CODE(EAP_BGP
, BA_LOCAL_PREF
));
660 y
= ea_find(old
->attrs
->eattrs
, EA_CODE(EAP_BGP
, BA_LOCAL_PREF
));
661 n
= x
? x
->u
.data
: new_bgp
->cf
->default_local_pref
;
662 o
= y
? y
->u
.data
: old_bgp
->cf
->default_local_pref
;
668 /* Use AS path lengths */
669 if (new_bgp
->cf
->compare_path_lengths
|| old_bgp
->cf
->compare_path_lengths
)
671 x
= ea_find(new->attrs
->eattrs
, EA_CODE(EAP_BGP
, BA_AS_PATH
));
672 y
= ea_find(old
->attrs
->eattrs
, EA_CODE(EAP_BGP
, BA_AS_PATH
));
673 n
= x
? as_path_getlen(x
->u
.ptr
) : 100000;
674 o
= y
? as_path_getlen(y
->u
.ptr
) : 100000;
682 x
= ea_find(new->attrs
->eattrs
, EA_CODE(EAP_BGP
, BA_ORIGIN
));
683 y
= ea_find(old
->attrs
->eattrs
, EA_CODE(EAP_BGP
, BA_ORIGIN
));
684 n
= x
? x
->u
.data
: ORIGIN_INCOMPLETE
;
685 o
= y
? y
->u
.data
: ORIGIN_INCOMPLETE
;
692 x
= ea_find(new->attrs
->eattrs
, EA_CODE(EAP_BGP
, BA_MULTI_EXIT_DISC
));
693 y
= ea_find(old
->attrs
->eattrs
, EA_CODE(EAP_BGP
, BA_MULTI_EXIT_DISC
));
694 n
= x
? x
->u
.data
: new_bgp
->cf
->default_med
;
695 o
= y
? y
->u
.data
: old_bgp
->cf
->default_med
;
701 /* A tie breaking procedure according to RFC 1771, section 9.1.2.1 */
702 /* We don't have interior distances */
703 /* We prefer external peers */
704 if (new_bgp
->is_internal
> old_bgp
->is_internal
)
706 if (new_bgp
->is_internal
< old_bgp
->is_internal
)
708 /* Finally we compare BGP identifiers */
709 return (new_bgp
->remote_id
< old_bgp
->remote_id
);
713 bgp_path_loopy(struct bgp_proto
*p
, eattr
*a
)
715 byte
*path
= a
->u
.ptr
->data
;
716 int len
= a
->u
.ptr
->length
;
726 if (get_u16(path
) == p
->local_as
)
735 * bgp_decode_attrs - check and decode BGP attributes
737 * @attr: start of attribute block
738 * @len: length of attribute block
739 * @pool: linear pool to make all the allocations in
740 * @mandatory: 1 iff presence of mandatory attributes has to be checked
742 * This function takes a BGP attribute block (a part of an Update message), checks
743 * its consistency and converts it to a list of BIRD route attributes represented
747 bgp_decode_attrs(struct bgp_conn
*conn
, byte
*attr
, unsigned int len
, struct linpool
*pool
, int mandatory
)
749 struct bgp_proto
*bgp
= conn
->bgp
;
750 rta
*a
= lp_alloc(pool
, sizeof(struct rta
));
751 unsigned int flags
, code
, l
, i
, type
;
753 byte
*z
, *attr_start
;
761 a
->scope
= SCOPE_UNIVERSE
;
762 a
->cast
= RTC_UNICAST
;
763 a
->dest
= RTD_ROUTER
;
766 a
->from
= bgp
->cf
->remote_ip
;
769 /* Parse the attributes */
770 bzero(seen
, sizeof(seen
));
771 DBG("BGP: Parsing attributes\n");
780 if (flags
& BAF_EXT_LEN
)
800 DBG("Attr %02x %02x %d\n", code
, flags
, l
);
801 if (seen
[code
/8] & (1 << (code
%8)))
803 if (ATTR_KNOWN(code
))
805 struct attr_desc
*desc
= &bgp_attr_table
[code
];
806 if (desc
->expected_length
>= 0 && desc
->expected_length
!= (int) l
)
807 { errcode
= 5; goto err
; }
808 if ((desc
->expected_flags
^ flags
) & (BAF_OPTIONAL
| BAF_TRANSITIVE
))
809 { errcode
= 4; goto err
; }
810 if (!desc
->allow_in_ebgp
&& !bgp
->is_internal
)
814 errcode
= desc
->validate(bgp
, z
, l
);
822 else /* Unknown attribute */
824 if (!(flags
& BAF_OPTIONAL
))
825 { errcode
= 2; goto err
; }
826 type
= EAF_TYPE_OPAQUE
;
828 seen
[code
/8] |= (1 << (code
%8));
829 ea
= lp_alloc(pool
, sizeof(ea_list
) + sizeof(eattr
));
830 ea
->next
= a
->eattrs
;
834 ea
->attrs
[0].id
= EA_CODE(EAP_BGP
, code
);
835 ea
->attrs
[0].flags
= flags
;
836 ea
->attrs
[0].type
= type
;
837 if (type
& EAF_EMBEDDED
)
841 ad
= lp_alloc(pool
, sizeof(struct adata
) + l
);
842 ea
->attrs
[0].u
.ptr
= ad
;
844 memcpy(ad
->data
, z
, l
);
848 case EAF_TYPE_ROUTER_ID
:
851 ea
->attrs
[0].u
.data
= *z
;
853 ea
->attrs
[0].u
.data
= get_u32(z
);
855 case EAF_TYPE_IP_ADDRESS
:
856 ipa_ntoh(*(ip_addr
*)ad
->data
);
858 case EAF_TYPE_INT_SET
:
860 u32
*z
= (u32
*) ad
->data
;
861 for(i
=0; i
<ad
->length
/4; i
++)
869 if (seen
[BA_MP_REACH_NLRI
/ 8] & (1 << (BA_MP_REACH_NLRI
% 8)))
873 /* Check if all mandatory attributes are present */
876 for(i
=0; i
< ARRAY_SIZE(bgp_mandatory_attrs
); i
++)
878 code
= bgp_mandatory_attrs
[i
];
879 if (!(seen
[code
/8] & (1 << (code
%8))))
881 bgp_error(conn
, 3, 3, &bgp_mandatory_attrs
[i
], 1);
887 /* If the AS path attribute contains our AS, reject the routes */
888 e
= ea_find(a
->eattrs
, EA_CODE(EAP_BGP
, BA_AS_PATH
));
889 if (e
&& bgp_path_loopy(bgp
, e
))
891 DBG("BGP: Path loop!\n");
895 /* If there's no local preference, define one */
896 if (!(seen
[0] && (1 << BA_LOCAL_PREF
)))
897 bgp_attach_attr(&a
->eattrs
, pool
, BA_LOCAL_PREF
, 0);
901 bgp_error(conn
, 3, 1, NULL
, 0);
905 bgp_error(conn
, 3, errcode
, attr_start
, z
+l
-attr_start
);
910 bgp_get_attr(eattr
*a
, byte
*buf
)
912 unsigned int i
= EA_ID(a
->id
);
917 d
= &bgp_attr_table
[i
];
918 buf
+= bsprintf(buf
, "%s", d
->name
);
928 bsprintf(buf
, "%02x%s", i
, (a
->flags
& BAF_TRANSITIVE
) ? " [t]" : "");
933 bgp_attr_init(struct bgp_proto
*p
)
936 p
->hash_limit
= p
->hash_size
* 4;
937 p
->bucket_hash
= mb_allocz(p
->p
.pool
, p
->hash_size
* sizeof(struct bgp_bucket
*));
938 init_list(&p
->bucket_queue
);
939 p
->withdraw_bucket
= NULL
;
940 fib_init(&p
->prefix_fib
, p
->p
.pool
, sizeof(struct bgp_prefix
), 0, bgp_init_prefix
);
944 bgp_get_route_info(rte
*e
, byte
*buf
, ea_list
*attrs
)
946 eattr
*p
= ea_find(attrs
, EA_CODE(EAP_BGP
, BA_AS_PATH
));
947 eattr
*o
= ea_find(attrs
, EA_CODE(EAP_BGP
, BA_ORIGIN
));
950 buf
+= bsprintf(buf
, " (%d) [", e
->pref
);
951 if (p
&& (origas
= as_path_get_first(p
->u
.ptr
)) >= 0)
952 buf
+= bsprintf(buf
, "AS%d", origas
);
954 buf
+= bsprintf(buf
, "%c", "ie?"[o
->u
.data
]);