]> git.ipfire.org Git - thirdparty/bird.git/blame - proto/bgp/attrs.c
The top-level Makefile is a generated file, so remove it from the repo.
[thirdparty/bird.git] / proto / bgp / attrs.c
CommitLineData
c01e3741
MM
1/*
2 * BIRD -- BGP Attributes
3 *
4 * (c) 2000 Martin Mares <mj@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
85368cd4 9#undef LOCAL_DEBUG
c00d31be 10
e3558ab1
MM
11#include <stdlib.h>
12
c01e3741
MM
13#include "nest/bird.h"
14#include "nest/iface.h"
15#include "nest/protocol.h"
16#include "nest/route.h"
c0668f36 17#include "nest/attrs.h"
c01e3741 18#include "conf/conf.h"
c00d31be
MM
19#include "lib/resource.h"
20#include "lib/string.h"
21#include "lib/unaligned.h"
c01e3741
MM
22
23#include "bgp.h"
c00d31be 24
1c1da87b
MM
25static byte bgp_mandatory_attrs[] = { BA_ORIGIN, BA_AS_PATH
26#ifndef IPV6
27,BA_NEXT_HOP
28#endif
29};
ae8f5584 30
ae8f5584 31struct attr_desc {
99f70c78 32 char *name;
ae8f5584
MM
33 int expected_length;
34 int expected_flags;
35 int type;
56a2bed4 36 int allow_in_ebgp;
ae8f5584
MM
37 int (*validate)(struct bgp_proto *p, byte *attr, int len);
38 void (*format)(eattr *ea, byte *buf);
39};
40
f421cfdd 41static int
e21423ba 42bgp_check_origin(struct bgp_proto *p UNUSED, byte *a UNUSED, int len)
f421cfdd
MM
43{
44 if (len > 2)
45 return 6;
46 return 0;
47}
48
49static void
50bgp_format_origin(eattr *a, byte *buf)
51{
52 static char *bgp_origin_names[] = { "IGP", "EGP", "Incomplete" };
53
54 bsprintf(buf, bgp_origin_names[a->u.data]);
55}
56
57static int
e21423ba 58bgp_check_path(struct bgp_proto *p UNUSED, byte *a, int len)
f421cfdd
MM
59{
60 while (len)
61 {
62 DBG("Path segment %02x %02x\n", a[0], a[1]);
63 if (len < 2 ||
1ed2fe96 64 a[0] != AS_PATH_SET && a[0] != AS_PATH_SEQUENCE ||
f421cfdd
MM
65 2*a[1] + 2 > len)
66 return 11;
67 len -= 2*a[1] + 2;
68 a += 2*a[1] + 2;
69 }
70 return 0;
71}
72
73static int
e21423ba 74bgp_check_next_hop(struct bgp_proto *p UNUSED, byte *a, int len)
f421cfdd 75{
1c1da87b
MM
76#ifdef IPV6
77 return -1;
78#else
f421cfdd
MM
79 ip_addr addr;
80
81 memcpy(&addr, a, len);
82 ipa_ntoh(addr);
83 if (ipa_classify(addr) & IADDR_HOST)
84 return 0;
85 else
86 return 8;
1c1da87b
MM
87#endif
88}
89
90static int
e21423ba 91bgp_check_reach_nlri(struct bgp_proto *p UNUSED, byte *a UNUSED, int len UNUSED)
1c1da87b
MM
92{
93#ifdef IPV6
94 p->mp_reach_start = a;
95 p->mp_reach_len = len;
1c1da87b 96#endif
cf3d6470 97 return -1;
1c1da87b
MM
98}
99
100static int
e21423ba 101bgp_check_unreach_nlri(struct bgp_proto *p UNUSED, byte *a UNUSED, int len UNUSED)
1c1da87b
MM
102{
103#ifdef IPV6
104 p->mp_unreach_start = a;
105 p->mp_unreach_len = len;
1c1da87b 106#endif
cf3d6470 107 return -1;
f421cfdd
MM
108}
109
f421cfdd 110static struct attr_desc bgp_attr_table[] = {
1c1da87b 111 { NULL, -1, 0, 0, 0, /* Undefined */
f421cfdd 112 NULL, NULL },
1c1da87b 113 { "origin", 1, BAF_TRANSITIVE, EAF_TYPE_INT, 1, /* BA_ORIGIN */
f421cfdd 114 bgp_check_origin, bgp_format_origin },
1c1da87b 115 { "as_path", -1, BAF_TRANSITIVE, EAF_TYPE_AS_PATH, 1, /* BA_AS_PATH */
f421cfdd 116 bgp_check_path, NULL },
1c1da87b 117 { "next_hop", 4, BAF_TRANSITIVE, EAF_TYPE_IP_ADDRESS, 1, /* BA_NEXT_HOP */
f421cfdd 118 bgp_check_next_hop, NULL },
1c1da87b 119 { "med", 4, BAF_OPTIONAL, EAF_TYPE_INT, 0, /* BA_MULTI_EXIT_DISC */
f421cfdd 120 NULL, NULL },
2138d3b4 121 { "local_pref", 4, BAF_TRANSITIVE, EAF_TYPE_INT, 0, /* BA_LOCAL_PREF */
f421cfdd 122 NULL, NULL },
1c1da87b 123 { "atomic_aggr", 0, BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1, /* BA_ATOMIC_AGGR */
f421cfdd 124 NULL, NULL },
f381cdce 125 { "aggregator", 6, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1, /* BA_AGGREGATOR */
56a2bed4 126 NULL, NULL },
1c1da87b 127 { "community", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_INT_SET, 1, /* BA_COMMUNITY */
1ed2fe96 128 NULL, NULL },
1c1da87b
MM
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 },
f421cfdd
MM
138};
139
d1a74339
MM
140#define ATTR_KNOWN(code) ((code) < ARRAY_SIZE(bgp_attr_table) && bgp_attr_table[code].name)
141
cf3d6470
MM
142static byte *
143bgp_set_attr(eattr *e, struct linpool *pool, unsigned attr, unsigned val)
144{
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)
150 {
151 e->u.data = val;
152 return NULL;
153 }
154 else
155 {
156 e->u.ptr = lp_alloc(pool, sizeof(struct adata) + val);
157 e->u.ptr->length = val;
158 return e->u.ptr->data;
159 }
160}
161
f421cfdd 162byte *
cf3d6470
MM
163bgp_attach_attr(ea_list **to, struct linpool *pool, unsigned attr, unsigned val)
164{
165 ea_list *a = lp_alloc(pool, sizeof(ea_list) + sizeof(eattr));
166 a->next = *to;
167 *to = a;
168 a->flags = EALF_SORTED;
169 a->count = 1;
170 return bgp_set_attr(a->attrs, pool, attr, val);
171}
172
54e55169
MM
173/**
174 * bgp_encode_attrs - encode BGP attributes
175 * @w: buffer
176 * @attrs: a list of extended attributes
177 * @remains: remaining space in the buffer
178 *
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).
181 *
182 * Result: Length of the attribute block generated.
183 */
cf3d6470
MM
184unsigned int
185bgp_encode_attrs(byte *w, ea_list *attrs, int remains)
f421cfdd 186{
f421cfdd
MM
187 unsigned int i, code, flags;
188 byte *start = w;
189 int len;
190
cf3d6470 191 for(i=0; i<attrs->count; i++)
f421cfdd 192 {
cf3d6470 193 eattr *a = &attrs->attrs[i];
f421cfdd
MM
194 ASSERT(EA_PROTO(a->id) == EAP_BGP);
195 code = EA_ID(a->id);
cf3d6470
MM
196#ifdef IPV6
197 /* When talking multiprotocol BGP, the NEXT_HOP attributes are used only temporarily. */
198 if (code == BA_NEXT_HOP)
199 continue;
200#endif
e3558ab1 201 flags = a->flags & (BAF_OPTIONAL | BAF_TRANSITIVE | BAF_PARTIAL);
d1a74339 202 if (ATTR_KNOWN(code))
f421cfdd
MM
203 {
204 struct attr_desc *desc = &bgp_attr_table[code];
205 len = desc->expected_length;
206 if (len < 0)
207 {
208 ASSERT(!(a->type & EAF_EMBEDDED));
209 len = a->u.ptr->length;
210 }
211 }
212 else
213 {
214 ASSERT((a->type & EAF_TYPE_MASK) == EAF_TYPE_OPAQUE);
215 len = a->u.ptr->length;
216 }
e3558ab1 217 DBG("\tAttribute %02x (type %02x, %d bytes, flags %02x)\n", code, a->type, len, flags);
f421cfdd
MM
218 if (remains < len + 4)
219 {
220 log(L_ERR "BGP: attribute list too long, ignoring the remaining attributes");
221 break;
222 }
f421cfdd
MM
223 if (len < 256)
224 {
225 *w++ = flags;
226 *w++ = code;
227 *w++ = len;
228 remains -= 3;
229 }
230 else
231 {
232 *w++ = flags | BAF_EXT_LEN;
233 *w++ = code;
234 put_u16(w, len);
235 w += 2;
236 remains -= 4;
237 }
238 switch (a->type & EAF_TYPE_MASK)
239 {
240 case EAF_TYPE_INT:
241 case EAF_TYPE_ROUTER_ID:
242 if (len == 4)
243 put_u32(w, a->u.data);
244 else
245 *w = a->u.data;
246 break;
247 case EAF_TYPE_IP_ADDRESS:
248 {
249 ip_addr ip = *(ip_addr *)a->u.ptr->data;
250 ipa_hton(ip);
251 memcpy(w, &ip, len);
252 break;
253 }
1ed2fe96
MM
254 case EAF_TYPE_INT_SET:
255 {
256 u32 *z = (u32 *)a->u.ptr->data;
257 int i;
258 for(i=0; i<len; i+=4)
259 put_u32(w+i, *z++);
260 break;
261 }
f421cfdd
MM
262 case EAF_TYPE_OPAQUE:
263 case EAF_TYPE_AS_PATH:
f421cfdd
MM
264 memcpy(w, a->u.ptr->data, len);
265 break;
266 default:
267 bug("bgp_encode_attrs: unknown attribute type %02x", a->type);
268 }
269 remains -= len;
270 w += len;
271 }
cf3d6470 272 return w - start;
f421cfdd 273}
ae8f5584 274
c2b28c99
MM
275static void
276bgp_init_prefix(struct fib_node *N)
277{
278 struct bgp_prefix *p = (struct bgp_prefix *) N;
f421cfdd 279 p->bucket_node.next = NULL;
c2b28c99
MM
280}
281
e3558ab1
MM
282static int
283bgp_compare_u32(const u32 *x, const u32 *y)
284{
285 return (*x < *y) ? -1 : (*x > *y) ? 1 : 0;
286}
287
ae8f5584
MM
288static void
289bgp_normalize_set(u32 *dest, u32 *src, unsigned cnt)
290{
291 memcpy(dest, src, sizeof(u32) * cnt);
e3558ab1 292 qsort(dest, cnt, sizeof(u32), (int(*)(const void *, const void *)) bgp_compare_u32);
ae8f5584
MM
293}
294
295static void
296bgp_rehash_buckets(struct bgp_proto *p)
297{
c2b28c99 298 struct bgp_bucket **old = p->bucket_hash;
ae8f5584
MM
299 struct bgp_bucket **new;
300 unsigned oldn = p->hash_size;
301 unsigned i, e, mask;
302 struct bgp_bucket *b;
303
304 p->hash_size = p->hash_limit;
305 DBG("BGP: Rehashing bucket table from %d to %d\n", oldn, p->hash_size);
306 p->hash_limit *= 4;
307 if (p->hash_limit >= 65536)
308 p->hash_limit = ~0;
c2b28c99 309 new = p->bucket_hash = mb_allocz(p->p.pool, p->hash_size * sizeof(struct bgp_bucket *));
ae8f5584
MM
310 mask = p->hash_size - 1;
311 for (i=0; i<oldn; i++)
312 while (b = old[i])
313 {
c2b28c99 314 old[i] = b->hash_next;
ae8f5584 315 e = b->hash & mask;
c2b28c99
MM
316 b->hash_next = new[e];
317 if (b->hash_next)
318 b->hash_next->hash_prev = b;
319 b->hash_prev = NULL;
ae8f5584
MM
320 new[e] = b;
321 }
322 mb_free(old);
323}
324
325static struct bgp_bucket *
326bgp_new_bucket(struct bgp_proto *p, ea_list *new, unsigned hash)
327{
328 struct bgp_bucket *b;
329 unsigned ea_size = sizeof(ea_list) + new->count * sizeof(eattr);
7fdd338c 330 unsigned ea_size_aligned = BIRD_ALIGN(ea_size, CPU_STRUCT_ALIGN);
ae8f5584
MM
331 unsigned size = sizeof(struct bgp_bucket) + ea_size;
332 unsigned i;
333 byte *dest;
334 unsigned index = hash & (p->hash_size - 1);
335
336 /* Gather total size of non-inline attributes */
337 for (i=0; i<new->count; i++)
338 {
339 eattr *a = &new->attrs[i];
340 if (!(a->type & EAF_EMBEDDED))
7fdd338c 341 size += BIRD_ALIGN(sizeof(struct adata) + a->u.ptr->length, CPU_STRUCT_ALIGN);
ae8f5584
MM
342 }
343
344 /* Create the bucket and hash it */
345 b = mb_alloc(p->p.pool, size);
c2b28c99
MM
346 b->hash_next = p->bucket_hash[index];
347 if (b->hash_next)
348 b->hash_next->hash_prev = b;
349 p->bucket_hash[index] = b;
350 b->hash_prev = NULL;
ae8f5584 351 b->hash = hash;
f421cfdd
MM
352 add_tail(&p->bucket_queue, &b->send_node);
353 init_list(&b->prefixes);
ae8f5584
MM
354 memcpy(b->eattrs, new, ea_size);
355 dest = ((byte *)b->eattrs) + ea_size_aligned;
356
357 /* Copy values of non-inline attributes */
358 for (i=0; i<new->count; i++)
359 {
85368cd4 360 eattr *a = &b->eattrs->attrs[i];
ae8f5584
MM
361 if (!(a->type & EAF_EMBEDDED))
362 {
363 struct adata *oa = a->u.ptr;
364 struct adata *na = (struct adata *) dest;
365 memcpy(na, oa, sizeof(struct adata) + oa->length);
366 a->u.ptr = na;
7fdd338c 367 dest += BIRD_ALIGN(sizeof(struct adata) + na->length, CPU_STRUCT_ALIGN);
ae8f5584
MM
368 }
369 }
370
371 /* If needed, rehash */
372 p->hash_count++;
373 if (p->hash_count > p->hash_limit)
374 bgp_rehash_buckets(p);
375
376 return b;
377}
378
bd2d8190
MM
379static int
380bgp_export_check(struct bgp_proto *p, ea_list *new)
381{
382 eattr *a;
383 struct adata *d;
384
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))
388 {
389 DBG("\tInvalid NEXT_HOP\n");
390 return 0;
391 }
392
393 /* Check if we aren't forbidden to export the route by communities */
394 a = ea_find(new, EA_CODE(EAP_BGP, BA_COMMUNITY));
395 if (a)
396 {
397 d = a->u.ptr;
398 if (int_set_contains(d, BGP_COMM_NO_ADVERTISE))
399 {
400 DBG("\tNO_ADVERTISE\n");
401 return 0;
402 }
403 if (!p->is_internal &&
404 (int_set_contains(d, BGP_COMM_NO_EXPORT) ||
405 int_set_contains(d, BGP_COMM_NO_EXPORT_SUBCONFED)))
406 {
407 DBG("\tNO_EXPORT\n");
408 return 0;
409 }
410 }
411
412 return 1;
413}
414
ae8f5584 415static struct bgp_bucket *
02bd064a 416bgp_get_bucket(struct bgp_proto *p, ea_list *attrs, int originate)
ae8f5584 417{
e21423ba 418 ea_list *new;
56a2bed4 419 unsigned i, cnt, hash, code;
ae8f5584
MM
420 eattr *a, *d;
421 u32 seen = 0;
ae8f5584
MM
422 struct bgp_bucket *b;
423
02bd064a
MM
424 /* Merge the attribute list */
425 new = alloca(ea_scan(attrs));
426 ea_merge(attrs, new);
8b258e4e 427 ea_sort(new);
ae8f5584
MM
428
429 /* Normalize attributes */
430 d = new->attrs;
431 cnt = new->count;
432 new->count = 0;
433 for(i=0; i<cnt; i++)
434 {
435 a = &new->attrs[i];
436#ifdef LOCAL_DEBUG
437 {
1ed2fe96 438 byte buf[EA_FORMAT_BUF_SIZE];
ae8f5584
MM
439 ea_format(a, buf);
440 DBG("\t%s\n", buf);
441 }
442#endif
443 if (EA_PROTO(a->id) != EAP_BGP)
444 continue;
56a2bed4 445 code = EA_ID(a->id);
d1a74339 446 if (ATTR_KNOWN(code))
56a2bed4
MM
447 {
448 if (!bgp_attr_table[code].allow_in_ebgp && !p->is_internal)
449 continue;
684c25d9
MM
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;
d1a74339
MM
452 if (code < 32)
453 seen |= 1 << code;
454 }
455 else
456 {
457 /* Don't re-export unknown non-transitive attributes */
458 if (!(a->flags & BAF_TRANSITIVE))
459 continue;
56a2bed4 460 }
ae8f5584 461 *d = *a;
e3558ab1
MM
462 if ((d->type & EAF_ORIGINATED) && !originate && (d->flags & BAF_TRANSITIVE) && (d->flags & BAF_OPTIONAL))
463 d->flags |= BAF_PARTIAL;
ae8f5584
MM
464 switch (d->type & EAF_TYPE_MASK)
465 {
e3558ab1 466 case EAF_TYPE_INT_SET:
ae8f5584
MM
467 {
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);
471 d->u.ptr = z;
472 break;
473 }
de10a974 474 default: ;
ae8f5584
MM
475 }
476 d++;
477 new->count++;
478 }
479
480 /* Hash */
481 hash = ea_hash(new);
c2b28c99 482 for(b=p->bucket_hash[hash & (p->hash_size - 1)]; b; b=b->hash_next)
ae8f5584
MM
483 if (b->hash == hash && ea_same(b->eattrs, new))
484 {
485 DBG("Found bucket.\n");
486 return b;
487 }
488
489 /* Ensure that there are all mandatory attributes */
77506349 490 for(i=0; i<ARRAY_SIZE(bgp_mandatory_attrs); i++)
ae8f5584
MM
491 if (!(seen & (1 << bgp_mandatory_attrs[i])))
492 {
493 log(L_ERR "%s: Mandatory attribute %s missing", p->p.name, bgp_attr_table[bgp_mandatory_attrs[i]].name);
494 return NULL;
495 }
496
bd2d8190 497 if (!bgp_export_check(p, new))
f421cfdd
MM
498 return NULL;
499
ae8f5584
MM
500 /* Create new bucket */
501 DBG("Creating bucket.\n");
502 return bgp_new_bucket(p, new, hash);
503}
504
f421cfdd
MM
505void
506bgp_free_bucket(struct bgp_proto *p, struct bgp_bucket *buck)
507{
508 if (buck->hash_next)
509 buck->hash_next->hash_prev = buck->hash_prev;
510 if (buck->hash_prev)
511 buck->hash_prev->hash_next = buck->hash_next;
512 else
513 p->bucket_hash[buck->hash & (p->hash_size-1)] = buck->hash_next;
514 mb_free(buck);
515}
516
ef2c708d 517void
e21423ba 518bgp_rt_notify(struct proto *P, net *n, rte *new, rte *old UNUSED, ea_list *attrs)
ef2c708d 519{
ae8f5584 520 struct bgp_proto *p = (struct bgp_proto *) P;
f421cfdd
MM
521 struct bgp_bucket *buck;
522 struct bgp_prefix *px;
ae8f5584 523
f421cfdd 524 DBG("BGP: Got route %I/%d %s\n", n->n.prefix, n->n.pxlen, new ? "up" : "down");
ae8f5584
MM
525
526 if (new)
527 {
02bd064a 528 buck = bgp_get_bucket(p, attrs, new->attrs->source != RTS_BGP);
ae8f5584
MM
529 if (!buck) /* Inconsistent attribute list */
530 return;
531 }
f421cfdd
MM
532 else
533 {
534 if (!(buck = p->withdraw_bucket))
535 {
536 buck = p->withdraw_bucket = mb_alloc(P->pool, sizeof(struct bgp_bucket));
537 init_list(&buck->prefixes);
538 }
539 }
540 px = fib_get(&p->prefix_fib, &n->n.prefix, n->n.pxlen);
541 if (px->bucket_node.next)
542 {
543 DBG("\tRemoving old entry.\n");
544 rem_node(&px->bucket_node);
545 }
546 add_tail(&buck->prefixes, &px->bucket_node);
547 bgp_schedule_packet(p->conn, PKT_UPDATE);
ef2c708d
MM
548}
549
48e842cc
MM
550static int
551bgp_create_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *pool)
ef2c708d 552{
8b258e4e 553 ea_list *ea = lp_alloc(pool, sizeof(ea_list) + 4*sizeof(eattr));
ef2c708d 554 rta *rta = e->attrs;
cf3d6470 555 byte *z;
ef2c708d 556
48e842cc
MM
557 ea->next = *attrs;
558 *attrs = ea;
ef2c708d 559 ea->flags = EALF_SORTED;
8b258e4e 560 ea->count = 4;
ef2c708d 561
cf3d6470 562 bgp_set_attr(ea->attrs, pool, BA_ORIGIN,
98ac6176 563 ((rta->source == RTS_OSPF_EXT1) || (rta->source == RTS_OSPF_EXT2)) ? ORIGIN_INCOMPLETE : ORIGIN_IGP);
ef2c708d 564
ef2c708d 565 if (p->is_internal)
cf3d6470 566 bgp_set_attr(ea->attrs+1, pool, BA_AS_PATH, 0);
ef2c708d
MM
567 else
568 {
cf3d6470 569 z = bgp_set_attr(ea->attrs+1, pool, BA_AS_PATH, 4);
8b258e4e 570 z[0] = AS_PATH_SEQUENCE;
ef2c708d
MM
571 z[1] = 1; /* 1 AS */
572 put_u16(z+2, p->local_as);
573 }
574
cf3d6470 575 z = bgp_set_attr(ea->attrs+2, pool, BA_NEXT_HOP, sizeof(ip_addr));
48e842cc
MM
576 if (p->cf->next_hop_self ||
577 !p->is_internal ||
578 rta->dest != RTD_ROUTER)
85ae398a
OF
579 {
580 if (ipa_nonzero(p->cf->source_addr))
581 *(ip_addr *)z = p->cf->source_addr;
582 else
583 *(ip_addr *)z = p->local_addr;
584 }
ef2c708d 585 else
cf3d6470 586 *(ip_addr *)z = e->attrs->gw;
8b258e4e 587
cf3d6470 588 bgp_set_attr(ea->attrs+3, pool, BA_LOCAL_PREF, 0);
ef2c708d 589
48e842cc 590 return 0; /* Leave decision to the filters */
ef2c708d
MM
591}
592
0a40e973
PM
593static ea_list *
594bgp_path_prepend(struct linpool *pool, eattr *a, ea_list *old, int as)
595{
596 struct ea_list *e = lp_alloc(pool, sizeof(ea_list) + sizeof(eattr));
597 struct adata *olda = a->u.ptr;
598
599 e->next = old;
600 e->flags = EALF_SORTED;
601 e->count = 1;
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;
c8f685cb 605 e->attrs[0].u.ptr = as_path_prepend(pool, olda, as);
ef2c708d
MM
606 return e;
607}
608
48e842cc
MM
609static int
610bgp_update_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *pool)
ef2c708d 611{
48e842cc
MM
612 eattr *a;
613
cf3d6470
MM
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);
ef2c708d 616
48e842cc
MM
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)))
619 {
620 /* Leave the original next hop attribute, will check later where does it point */
621 }
622 else
623 {
624 /* Need to create new one */
cf3d6470 625 *(ip_addr *) bgp_attach_attr(attrs, pool, BA_NEXT_HOP, sizeof(ip_addr)) = p->local_addr;
48e842cc 626 }
ef2c708d 627
48e842cc 628 return 0; /* Leave decision to the filters */
ef2c708d
MM
629}
630
631int
632bgp_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool)
633{
634 rte *e = *new;
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;
637
48e842cc 638 if (p == new_bgp) /* Poison reverse updates */
ef2c708d
MM
639 return -1;
640 if (new_bgp)
641 {
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 */
48e842cc 644 return bgp_update_attrs(p, e, attrs, pool);
ef2c708d
MM
645 }
646 else
48e842cc 647 return bgp_create_attrs(p, e, attrs, pool);
ef2c708d
MM
648}
649
650int
651bgp_rte_better(rte *new, rte *old)
652{
653 struct bgp_proto *new_bgp = (struct bgp_proto *) new->attrs->proto;
654 struct bgp_proto *old_bgp = (struct bgp_proto *) old->attrs->proto;
56a2bed4
MM
655 eattr *x, *y;
656 u32 n, o;
ef2c708d
MM
657
658 /* Start with local preferences */
56a2bed4
MM
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;
663 if (n > o)
664 return 1;
665 if (n < o)
666 return 0;
667
668 /* Use AS path lengths */
669 if (new_bgp->cf->compare_path_lengths || old_bgp->cf->compare_path_lengths)
ef2c708d 670 {
56a2bed4
MM
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;
675 if (n < o)
ef2c708d 676 return 1;
56a2bed4 677 if (n > o)
ef2c708d
MM
678 return 0;
679 }
680
56a2bed4
MM
681 /* Use origins */
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));
cea63664
MM
684 n = x ? x->u.data : ORIGIN_INCOMPLETE;
685 o = y ? y->u.data : ORIGIN_INCOMPLETE;
56a2bed4
MM
686 if (n < o)
687 return 1;
688 if (n > o)
689 return 0;
690
691 /* Compare MED's */
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;
696 if (n < o)
697 return 1;
698 if (n > o)
699 return 0;
700
ef2c708d 701 /* A tie breaking procedure according to RFC 1771, section 9.1.2.1 */
ef2c708d
MM
702 /* We don't have interior distances */
703 /* We prefer external peers */
704 if (new_bgp->is_internal > old_bgp->is_internal)
705 return 0;
706 if (new_bgp->is_internal < old_bgp->is_internal)
707 return 1;
708 /* Finally we compare BGP identifiers */
709 return (new_bgp->remote_id < old_bgp->remote_id);
710}
711
ef2c708d
MM
712static int
713bgp_path_loopy(struct bgp_proto *p, eattr *a)
714{
715 byte *path = a->u.ptr->data;
716 int len = a->u.ptr->length;
717 int i, n;
718
719 while (len > 0)
720 {
721 n = path[1];
5db9bae2 722 len -= 2 + 2*n;
ef2c708d
MM
723 path += 2;
724 for(i=0; i<n; i++)
725 {
726 if (get_u16(path) == p->local_as)
727 return 1;
728 path += 2;
729 }
730 }
731 return 0;
732}
733
54e55169
MM
734/**
735 * bgp_decode_attrs - check and decode BGP attributes
736 * @conn: connection
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
741 *
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
744 * by a &rta.
745 */
c00d31be 746struct rta *
2a9e064d 747bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct linpool *pool, int mandatory)
c00d31be
MM
748{
749 struct bgp_proto *bgp = conn->bgp;
750 rta *a = lp_alloc(pool, sizeof(struct rta));
ef2c708d
MM
751 unsigned int flags, code, l, i, type;
752 int errcode;
c00d31be
MM
753 byte *z, *attr_start;
754 byte seen[256/8];
755 eattr *e;
756 ea_list *ea;
757 struct adata *ad;
c00d31be
MM
758
759 a->proto = &bgp->p;
760 a->source = RTS_BGP;
761 a->scope = SCOPE_UNIVERSE;
762 a->cast = RTC_UNICAST;
763 a->dest = RTD_ROUTER;
764 a->flags = 0;
765 a->aflags = 0;
766 a->from = bgp->cf->remote_ip;
767 a->eattrs = NULL;
768
769 /* Parse the attributes */
770 bzero(seen, sizeof(seen));
771 DBG("BGP: Parsing attributes\n");
772 while (len)
773 {
774 if (len < 2)
775 goto malformed;
776 attr_start = attr;
777 flags = *attr++;
778 code = *attr++;
779 len -= 2;
780 if (flags & BAF_EXT_LEN)
781 {
782 if (len < 2)
783 goto malformed;
784 l = get_u16(attr);
785 attr += 2;
786 len -= 2;
787 }
788 else
789 {
790 if (len < 1)
791 goto malformed;
792 l = *attr++;
793 len--;
794 }
795 if (l > len)
796 goto malformed;
797 len -= l;
798 z = attr;
799 attr += l;
800 DBG("Attr %02x %02x %d\n", code, flags, l);
801 if (seen[code/8] & (1 << (code%8)))
802 goto malformed;
d1a74339 803 if (ATTR_KNOWN(code))
c00d31be
MM
804 {
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; }
56a2bed4
MM
810 if (!desc->allow_in_ebgp && !bgp->is_internal)
811 continue;
ef2c708d
MM
812 if (desc->validate)
813 {
814 errcode = desc->validate(bgp, z, l);
815 if (errcode > 0)
816 goto err;
817 if (errcode < 0)
818 continue;
819 }
c00d31be
MM
820 type = desc->type;
821 }
822 else /* Unknown attribute */
e3558ab1 823 {
c00d31be
MM
824 if (!(flags & BAF_OPTIONAL))
825 { errcode = 2; goto err; }
826 type = EAF_TYPE_OPAQUE;
827 }
ef2c708d
MM
828 seen[code/8] |= (1 << (code%8));
829 ea = lp_alloc(pool, sizeof(ea_list) + sizeof(eattr));
c00d31be
MM
830 ea->next = a->eattrs;
831 a->eattrs = ea;
832 ea->flags = 0;
833 ea->count = 1;
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)
838 ad = NULL;
839 else
840 {
841 ad = lp_alloc(pool, sizeof(struct adata) + l);
842 ea->attrs[0].u.ptr = ad;
843 ad->length = l;
844 memcpy(ad->data, z, l);
845 }
846 switch (type)
847 {
848 case EAF_TYPE_ROUTER_ID:
849 case EAF_TYPE_INT:
10be74da
MM
850 if (l == 1)
851 ea->attrs[0].u.data = *z;
852 else
853 ea->attrs[0].u.data = get_u32(z);
c00d31be
MM
854 break;
855 case EAF_TYPE_IP_ADDRESS:
f421cfdd 856 ipa_ntoh(*(ip_addr *)ad->data);
c00d31be 857 break;
1ed2fe96
MM
858 case EAF_TYPE_INT_SET:
859 {
860 u32 *z = (u32 *) ad->data;
861 for(i=0; i<ad->length/4; i++)
862 z[i] = ntohl(z[i]);
863 break;
864 }
c00d31be
MM
865 }
866 }
867
1c1da87b
MM
868#ifdef IPV6
869 if (seen[BA_MP_REACH_NLRI / 8] & (1 << (BA_MP_REACH_NLRI % 8)))
870 mandatory = 1;
871#endif
872
c00d31be 873 /* Check if all mandatory attributes are present */
2a9e064d 874 if (mandatory)
c00d31be 875 {
efcece2d 876 for(i=0; i < ARRAY_SIZE(bgp_mandatory_attrs); i++)
c00d31be 877 {
2a9e064d
MM
878 code = bgp_mandatory_attrs[i];
879 if (!(seen[code/8] & (1 << (code%8))))
880 {
efcece2d 881 bgp_error(conn, 3, 3, &bgp_mandatory_attrs[i], 1);
2a9e064d
MM
882 return NULL;
883 }
c00d31be
MM
884 }
885 }
886
ef2c708d
MM
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));
54896cbd 889 if (e && bgp_path_loopy(bgp, e))
e3558ab1
MM
890 {
891 DBG("BGP: Path loop!\n");
892 return NULL;
893 }
ef2c708d 894
8b258e4e
MM
895 /* If there's no local preference, define one */
896 if (!(seen[0] && (1 << BA_LOCAL_PREF)))
cf3d6470 897 bgp_attach_attr(&a->eattrs, pool, BA_LOCAL_PREF, 0);
2a9e064d 898 return a;
c00d31be
MM
899
900malformed:
efcece2d 901 bgp_error(conn, 3, 1, NULL, 0);
c00d31be
MM
902 return NULL;
903
904err:
2138d3b4 905 bgp_error(conn, 3, errcode, attr_start, z+l-attr_start);
c00d31be
MM
906 return NULL;
907}
10be74da
MM
908
909int
910bgp_get_attr(eattr *a, byte *buf)
911{
912 unsigned int i = EA_ID(a->id);
913 struct attr_desc *d;
914
d1a74339 915 if (ATTR_KNOWN(i))
10be74da
MM
916 {
917 d = &bgp_attr_table[i];
918 buf += bsprintf(buf, "%s", d->name);
919 if (d->format)
920 {
921 *buf++ = ':';
922 *buf++ = ' ';
923 d->format(a, buf);
924 return GA_FULL;
925 }
926 return GA_NAME;
927 }
d1a74339 928 bsprintf(buf, "%02x%s", i, (a->flags & BAF_TRANSITIVE) ? " [t]" : "");
10be74da
MM
929 return GA_NAME;
930}
ae8f5584
MM
931
932void
933bgp_attr_init(struct bgp_proto *p)
934{
935 p->hash_size = 256;
936 p->hash_limit = p->hash_size * 4;
c2b28c99
MM
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);
ae8f5584 941}
5e88d730
MM
942
943void
944bgp_get_route_info(rte *e, byte *buf, ea_list *attrs)
945{
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));
948 int origas;
949
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);
953 if (o)
954 buf += bsprintf(buf, "%c", "ie?"[o->u.data]);
955 strcpy(buf, "]");
956}