]>
git.ipfire.org Git - thirdparty/bird.git/blob - proto/bgp/attrs.c
5c1e70db6e08afb02ab027b973ca18e053d613b4
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.
11 #include "nest/bird.h"
12 #include "nest/iface.h"
13 #include "nest/protocol.h"
14 #include "nest/route.h"
15 #include "conf/conf.h"
16 #include "lib/resource.h"
17 #include "lib/string.h"
18 #include "lib/unaligned.h"
22 static int bgp_mandatory_attrs
[] = { BA_ORIGIN
, BA_AS_PATH
, BA_NEXT_HOP
};
25 struct bgp_bucket
*next
;
31 char *name
; /* FIXME: Use the same names as in filters */
35 int (*validate
)(struct bgp_proto
*p
, byte
*attr
, int len
);
36 void (*format
)(eattr
*ea
, byte
*buf
);
39 extern struct attr_desc bgp_attr_table
[];
42 bgp_normalize_set(u32
*dest
, u32
*src
, unsigned cnt
)
44 memcpy(dest
, src
, sizeof(u32
) * cnt
);
49 bgp_rehash_buckets(struct bgp_proto
*p
)
51 struct bgp_bucket
**old
= p
->bucket_table
;
52 struct bgp_bucket
**new;
53 unsigned oldn
= p
->hash_size
;
57 p
->hash_size
= p
->hash_limit
;
58 DBG("BGP: Rehashing bucket table from %d to %d\n", oldn
, p
->hash_size
);
60 if (p
->hash_limit
>= 65536)
62 new = p
->bucket_table
= mb_allocz(p
->p
.pool
, p
->hash_size
* sizeof(struct bgp_bucket
*));
63 mask
= p
->hash_size
- 1;
64 for (i
=0; i
<oldn
; i
++)
75 static struct bgp_bucket
*
76 bgp_new_bucket(struct bgp_proto
*p
, ea_list
*new, unsigned hash
)
79 unsigned ea_size
= sizeof(ea_list
) + new->count
* sizeof(eattr
);
80 unsigned ea_size_aligned
= ALIGN(ea_size
, CPU_STRUCT_ALIGN
);
81 unsigned size
= sizeof(struct bgp_bucket
) + ea_size
;
84 unsigned index
= hash
& (p
->hash_size
- 1);
86 /* Gather total size of non-inline attributes */
87 for (i
=0; i
<new->count
; i
++)
89 eattr
*a
= &new->attrs
[i
];
90 if (!(a
->type
& EAF_EMBEDDED
))
91 size
+= ALIGN(sizeof(struct adata
) + a
->u
.ptr
->length
, CPU_STRUCT_ALIGN
);
94 /* Create the bucket and hash it */
95 b
= mb_alloc(p
->p
.pool
, size
);
96 b
->next
= p
->bucket_table
[index
];
97 p
->bucket_table
[index
] = b
;
99 memcpy(b
->eattrs
, new, ea_size
);
100 dest
= ((byte
*)b
->eattrs
) + ea_size_aligned
;
102 /* Copy values of non-inline attributes */
103 for (i
=0; i
<new->count
; i
++)
105 eattr
*a
= &new->attrs
[i
];
106 if (!(a
->type
& EAF_EMBEDDED
))
108 struct adata
*oa
= a
->u
.ptr
;
109 struct adata
*na
= (struct adata
*) dest
;
110 memcpy(na
, oa
, sizeof(struct adata
) + oa
->length
);
112 dest
+= ALIGN(na
->length
, CPU_STRUCT_ALIGN
);
116 /* If needed, rehash */
118 if (p
->hash_count
> p
->hash_limit
)
119 bgp_rehash_buckets(p
);
124 static struct bgp_bucket
*
125 bgp_get_bucket(struct bgp_proto
*p
, ea_list
*old
, ea_list
*tmp
)
132 struct bgp_bucket
*b
;
134 /* Merge the attribute lists */
135 for(t
=tmp
; t
->next
; t
=t
->next
)
138 new = alloca(ea_scan(tmp
));
143 /* Normalize attributes */
157 if (EA_PROTO(a
->id
) != EAP_BGP
)
159 if (EA_ID(a
->id
) < 32)
160 seen
|= 1 << EA_ID(a
->id
);
162 switch (d
->type
& EAF_TYPE_MASK
)
164 case EAF_TYPE_INT_SET
:
166 struct adata
*z
= alloca(sizeof(struct adata
) + d
->u
.ptr
->length
);
167 z
->length
= d
->u
.ptr
->length
;
168 bgp_normalize_set((u32
*) z
->data
, (u32
*) d
->u
.ptr
->data
, z
->length
/ 4);
180 for(b
=p
->bucket_table
[hash
& (p
->hash_size
- 1)]; b
; b
=b
->next
)
181 if (b
->hash
== hash
&& ea_same(b
->eattrs
, new))
183 DBG("Found bucket.\n");
187 /* Ensure that there are all mandatory attributes */
188 /* FIXME: Introduce array size macro */
189 for(i
=0; i
<sizeof(bgp_mandatory_attrs
)/sizeof(bgp_mandatory_attrs
[0]); i
++)
190 if (!(seen
& (1 << bgp_mandatory_attrs
[i
])))
192 log(L_ERR
"%s: Mandatory attribute %s missing", p
->p
.name
, bgp_attr_table
[bgp_mandatory_attrs
[i
]].name
);
196 /* Create new bucket */
197 DBG("Creating bucket.\n");
198 return bgp_new_bucket(p
, new, hash
);
202 bgp_rt_notify(struct proto
*P
, net
*n
, rte
*new, rte
*old
, ea_list
*tmpa
)
204 struct bgp_proto
*p
= (struct bgp_proto
*) P
;
206 DBG("BGP: Got route %I/%d\n", n
->n
.prefix
, n
->n
.pxlen
);
210 struct bgp_bucket
*buck
= bgp_get_bucket(p
, new->attrs
->eattrs
, tmpa
);
211 if (!buck
) /* Inconsistent attribute list */
215 /* FIXME: Normalize attributes */
216 /* FIXME: Check next hop */
220 bgp_create_attrs(struct bgp_proto
*p
, rte
*e
, ea_list
**attrs
, struct linpool
*pool
)
222 ea_list
*ea
= lp_alloc(pool
, sizeof(ea_list
) + 3*sizeof(eattr
));
223 eattr
*a
= ea
->attrs
;
228 ea
->flags
= EALF_SORTED
;
231 a
->id
= EA_CODE(EAP_BGP
, BA_ORIGIN
);
232 a
->flags
= BAF_TRANSITIVE
;
233 a
->type
= EAF_TYPE_INT
;
234 if (rta
->source
== RTS_RIP_EXT
|| rta
->source
== RTS_OSPF_EXT
)
235 a
->u
.data
= 2; /* Incomplete */
237 a
->u
.data
= 0; /* IGP */
240 a
->id
= EA_CODE(EAP_BGP
, BA_AS_PATH
);
241 a
->flags
= BAF_TRANSITIVE
;
242 a
->type
= EAF_TYPE_AS_PATH
;
245 a
->u
.ptr
= lp_alloc(pool
, sizeof(struct adata
));
246 a
->u
.ptr
->length
= 0;
251 a
->u
.ptr
= lp_alloc(pool
, sizeof(struct adata
) + 4);
252 a
->u
.ptr
->length
= 4;
254 z
[0] = 2; /* AS_SEQUENCE */
256 put_u16(z
+2, p
->local_as
);
260 a
->id
= EA_CODE(EAP_BGP
, BA_NEXT_HOP
);
261 a
->flags
= BAF_TRANSITIVE
;
262 a
->type
= EAF_TYPE_IP_ADDRESS
;
263 a
->u
.ptr
= lp_alloc(pool
, sizeof(struct adata
) + sizeof(ip_addr
));
264 a
->u
.ptr
->length
= sizeof(ip_addr
);
265 if (p
->cf
->next_hop_self
||
267 rta
->dest
!= RTD_ROUTER
)
268 *(ip_addr
*)a
->u
.ptr
->data
= p
->local_addr
;
270 *(ip_addr
*)a
->u
.ptr
->data
= e
->attrs
->gw
;
272 return 0; /* Leave decision to the filters */
276 bgp_path_prepend(struct linpool
*pool
, eattr
*a
, ea_list
*old
, int as
)
278 struct ea_list
*e
= lp_alloc(pool
, sizeof(ea_list
) + sizeof(eattr
));
279 struct adata
*olda
= a
->u
.ptr
;
283 e
->flags
= EALF_SORTED
;
285 e
->attrs
[0].id
= EA_CODE(EAP_BGP
, BA_AS_PATH
);
286 e
->attrs
[0].flags
= BAF_TRANSITIVE
;
287 e
->attrs
[0].type
= EAF_TYPE_AS_PATH
;
288 if (olda
->length
&& olda
->data
[0] == 2 && olda
->data
[1] < 255) /* Starting with sequence => just prepend the AS number */
290 newa
= lp_alloc(pool
, sizeof(struct adata
) + olda
->length
+ 2);
291 newa
->length
= olda
->length
+ 2;
293 newa
->data
[1] = olda
->data
[1] + 1;
294 memcpy(newa
->data
+4, olda
->data
+2, olda
->length
-2);
296 else /* Create new path segment */
298 newa
= lp_alloc(pool
, sizeof(struct adata
) + olda
->length
+ 4);
299 newa
->length
= olda
->length
+ 4;
302 memcpy(newa
->data
+4, olda
->data
, olda
->length
);
304 put_u16(newa
->data
+2, as
);
305 e
->attrs
[0].u
.ptr
= newa
;
310 bgp_update_attrs(struct bgp_proto
*p
, rte
*e
, ea_list
**attrs
, struct linpool
*pool
)
315 *attrs
= bgp_path_prepend(pool
, ea_find(e
->attrs
->eattrs
, EA_CODE(EAP_BGP
, BA_AS_PATH
)), *attrs
, p
->local_as
);
317 a
= ea_find(e
->attrs
->eattrs
, EA_CODE(EAP_BGP
, BA_NEXT_HOP
));
318 if (a
&& (p
->is_internal
|| (!p
->is_internal
&& e
->attrs
->iface
== p
->neigh
->iface
)))
320 /* Leave the original next hop attribute, will check later where does it point */
324 /* Need to create new one */
325 ea_list
*ea
= lp_alloc(pool
, sizeof(ea_list
) + sizeof(eattr
));
328 ea
->flags
= EALF_SORTED
;
331 a
->id
= EA_CODE(EAP_BGP
, BA_NEXT_HOP
);
332 a
->flags
= BAF_TRANSITIVE
;
333 a
->type
= EAF_TYPE_IP_ADDRESS
;
334 a
->u
.ptr
= lp_alloc(pool
, sizeof(struct adata
) + sizeof(ip_addr
));
335 a
->u
.ptr
->length
= sizeof(ip_addr
);
336 *(ip_addr
*)a
->u
.ptr
->data
= p
->local_addr
;
339 return 0; /* Leave decision to the filters */
343 bgp_import_control(struct proto
*P
, rte
**new, ea_list
**attrs
, struct linpool
*pool
)
346 struct bgp_proto
*p
= (struct bgp_proto
*) P
;
347 struct bgp_proto
*new_bgp
= (e
->attrs
->proto
->proto
== &proto_bgp
) ? (struct bgp_proto
*) e
->attrs
->proto
: NULL
;
349 if (p
== new_bgp
) /* Poison reverse updates */
353 if (p
->local_as
== new_bgp
->local_as
&& p
->is_internal
&& new_bgp
->is_internal
)
354 return -1; /* Don't redistribute internal routes with IBGP */
355 return bgp_update_attrs(p
, e
, attrs
, pool
);
358 return bgp_create_attrs(p
, e
, attrs
, pool
);
362 bgp_rte_better(rte
*new, rte
*old
)
364 struct bgp_proto
*new_bgp
= (struct bgp_proto
*) new->attrs
->proto
;
365 struct bgp_proto
*old_bgp
= (struct bgp_proto
*) old
->attrs
->proto
;
366 eattr
*new_lpref
= ea_find(new->attrs
->eattrs
, EA_CODE(EAP_BGP
, BA_LOCAL_PREF
));
367 eattr
*old_lpref
= ea_find(old
->attrs
->eattrs
, EA_CODE(EAP_BGP
, BA_LOCAL_PREF
));
369 /* Start with local preferences */
370 if (new_lpref
&& old_lpref
) /* Somebody might have undefined them */
372 if (new_lpref
->u
.data
> old_lpref
->u
.data
)
374 if (new_lpref
->u
.data
< old_lpref
->u
.data
)
378 /* A tie breaking procedure according to RFC 1771, section 9.1.2.1 */
379 /* FIXME: Look at MULTI_EXIT_DISC, take the lowest */
380 /* We don't have interior distances */
381 /* We prefer external peers */
382 if (new_bgp
->is_internal
> old_bgp
->is_internal
)
384 if (new_bgp
->is_internal
< old_bgp
->is_internal
)
386 /* Finally we compare BGP identifiers */
387 return (new_bgp
->remote_id
< old_bgp
->remote_id
);
391 bgp_local_pref(struct bgp_proto
*p
, rta
*a
)
393 return 0; /* FIXME (should be compatible with Cisco defaults?) */
397 bgp_path_loopy(struct bgp_proto
*p
, eattr
*a
)
399 byte
*path
= a
->u
.ptr
->data
;
400 int len
= a
->u
.ptr
->length
;
410 if (get_u16(path
) == p
->local_as
)
419 bgp_check_origin(struct bgp_proto
*p
, byte
*a
, int len
)
427 bgp_format_origin(eattr
*a
, byte
*buf
)
429 static char *bgp_origin_names
[] = { "IGP", "EGP", "Incomplete" };
431 bsprintf(buf
, bgp_origin_names
[a
->u
.data
]);
435 bgp_check_path(struct bgp_proto
*p
, byte
*a
, int len
)
439 DBG("Path segment %02x %02x\n", a
[0], a
[1]);
441 a
[0] != BGP_PATH_AS_SET
&& a
[0] != BGP_PATH_AS_SEQUENCE
||
451 bgp_check_next_hop(struct bgp_proto
*p
, byte
*a
, int len
)
455 memcpy(&addr
, a
, len
);
456 if (ipa_classify(ipa_ntoh(addr
)) & IADDR_HOST
)
463 bgp_check_local_pref(struct bgp_proto
*p
, byte
*a
, int len
)
465 if (!p
->is_internal
) /* Ignore local preference from EBGP connections */
470 static struct attr_desc bgp_attr_table
[] = {
471 { NULL
, -1, 0, 0, /* Undefined */
473 { "origin", 1, BAF_TRANSITIVE
, EAF_TYPE_INT
, /* BA_ORIGIN */
474 bgp_check_origin
, bgp_format_origin
},
475 { "as_path", -1, BAF_TRANSITIVE
, EAF_TYPE_AS_PATH
, /* BA_AS_PATH */
476 bgp_check_path
, NULL
},
477 { "next_hop", 4, BAF_TRANSITIVE
, EAF_TYPE_IP_ADDRESS
, /* BA_NEXT_HOP */
478 bgp_check_next_hop
, NULL
},
479 { "MED", 4, BAF_OPTIONAL
, EAF_TYPE_INT
, /* BA_MULTI_EXIT_DISC */
481 { "local_pref", 4, BAF_OPTIONAL
, EAF_TYPE_INT
, /* BA_LOCAL_PREF */
482 bgp_check_local_pref
, NULL
},
483 { "atomic_aggr", 0, BAF_OPTIONAL
, EAF_TYPE_OPAQUE
, /* BA_ATOMIC_AGGR */
485 { "aggregator", 6, BAF_OPTIONAL
, EAF_TYPE_OPAQUE
, /* BA_AGGREGATOR */
488 /* FIXME: Handle community lists and remember to convert their endianity and normalize them */
489 { 0, 0 }, /* BA_COMMUNITY */
490 { 0, 0 }, /* BA_ORIGINATOR_ID */
491 { 0, 0 }, /* BA_CLUSTER_LIST */
496 bgp_decode_attrs(struct bgp_conn
*conn
, byte
*attr
, unsigned int len
, struct linpool
*pool
)
498 struct bgp_proto
*bgp
= conn
->bgp
;
499 rta
*a
= lp_alloc(pool
, sizeof(struct rta
));
500 unsigned int flags
, code
, l
, i
, type
;
502 byte
*z
, *attr_start
;
512 a
->scope
= SCOPE_UNIVERSE
;
513 a
->cast
= RTC_UNICAST
;
514 a
->dest
= RTD_ROUTER
;
517 a
->from
= bgp
->cf
->remote_ip
;
520 /* Parse the attributes */
521 bzero(seen
, sizeof(seen
));
522 DBG("BGP: Parsing attributes\n");
531 if (flags
& BAF_EXT_LEN
)
551 DBG("Attr %02x %02x %d\n", code
, flags
, l
);
552 if (seen
[code
/8] & (1 << (code
%8)))
554 if (code
&& code
< sizeof(bgp_attr_table
)/sizeof(bgp_attr_table
[0]))
556 struct attr_desc
*desc
= &bgp_attr_table
[code
];
557 if (desc
->expected_length
>= 0 && desc
->expected_length
!= (int) l
)
558 { errcode
= 5; goto err
; }
559 if ((desc
->expected_flags
^ flags
) & (BAF_OPTIONAL
| BAF_TRANSITIVE
))
560 { errcode
= 4; goto err
; }
563 errcode
= desc
->validate(bgp
, z
, l
);
571 else /* Unknown attribute */
572 { /* FIXME: Send partial bit when forwarding */
573 if (!(flags
& BAF_OPTIONAL
))
574 { errcode
= 2; goto err
; }
575 type
= EAF_TYPE_OPAQUE
;
577 seen
[code
/8] |= (1 << (code
%8));
578 ea
= lp_alloc(pool
, sizeof(ea_list
) + sizeof(eattr
));
579 ea
->next
= a
->eattrs
;
583 ea
->attrs
[0].id
= EA_CODE(EAP_BGP
, code
);
584 ea
->attrs
[0].flags
= flags
;
585 ea
->attrs
[0].type
= type
;
586 if (type
& EAF_EMBEDDED
)
590 ad
= lp_alloc(pool
, sizeof(struct adata
) + l
);
591 ea
->attrs
[0].u
.ptr
= ad
;
593 memcpy(ad
->data
, z
, l
);
597 case EAF_TYPE_ROUTER_ID
:
600 ea
->attrs
[0].u
.data
= *z
;
602 ea
->attrs
[0].u
.data
= get_u32(z
);
604 case EAF_TYPE_IP_ADDRESS
:
605 *(ip_addr
*)ad
->data
= ipa_ntoh(*(ip_addr
*)ad
->data
);
610 /* Check if all mandatory attributes are present */
611 for(i
=0; i
< sizeof(bgp_mandatory_attrs
)/sizeof(bgp_mandatory_attrs
[0]); i
++)
613 code
= bgp_mandatory_attrs
[i
];
614 if (!(seen
[code
/8] & (1 << (code
%8))))
616 bgp_error(conn
, 3, 3, code
, 1);
621 /* Assign local preference if none defined */
622 if (!(seen
[BA_LOCAL_PREF
/8] & (1 << (BA_LOCAL_PREF
%8))))
624 ea
= lp_alloc(pool
, sizeof(ea_list
) + sizeof(eattr
));
625 ea
->next
= a
->eattrs
;
629 ea
->attrs
[0].id
= EA_CODE(EAP_BGP
, BA_LOCAL_PREF
);
630 ea
->attrs
[0].flags
= BAF_OPTIONAL
;
631 ea
->attrs
[0].type
= EAF_TYPE_INT
;
632 ea
->attrs
[0].u
.data
= bgp_local_pref(bgp
, a
);
635 /* If the AS path attribute contains our AS, reject the routes */
636 e
= ea_find(a
->eattrs
, EA_CODE(EAP_BGP
, BA_AS_PATH
));
638 if (bgp_path_loopy(bgp
, e
))
641 /* Fill in the remaining rta fields */
642 e
= ea_find(a
->eattrs
, EA_CODE(EAP_BGP
, BA_NEXT_HOP
));
644 nexthop
= *(ip_addr
*) e
->u
.ptr
->data
;
645 if (ipa_equal(nexthop
, bgp
->local_addr
))
647 DBG("BGP: Loop!\n"); /* FIXME */
650 neigh
= neigh_find(&bgp
->p
, &nexthop
, 0) ? : bgp
->neigh
;
652 a
->iface
= neigh
->iface
;
653 return rta_lookup(a
);
656 bgp_error(conn
, 3, 1, len
, 0);
660 bgp_error(conn
, 3, errcode
, code
, 0); /* FIXME: Return attribute data! */
665 bgp_get_attr(eattr
*a
, byte
*buf
)
667 unsigned int i
= EA_ID(a
->id
);
670 if (i
&& i
< sizeof(bgp_attr_table
)/sizeof(bgp_attr_table
[0]))
672 d
= &bgp_attr_table
[i
];
673 buf
+= bsprintf(buf
, "%s", d
->name
);
683 bsprintf(buf
, "%02x%s", i
, (a
->flags
& BAF_TRANSITIVE
) ? "[t]" : "");
688 bgp_attr_init(struct bgp_proto
*p
)
691 p
->hash_limit
= p
->hash_size
* 4;
692 p
->bucket_table
= mb_allocz(p
->p
.pool
, p
->hash_size
* sizeof(struct bgp_bucket
*));