]> git.ipfire.org Git - thirdparty/bird.git/blame - proto/bgp/attrs.c
BGP: Fix handling of transitive extended communities
[thirdparty/bird.git] / proto / bgp / attrs.c
CommitLineData
c01e3741
MM
1/*
2 * BIRD -- BGP Attributes
3 *
4 * (c) 2000 Martin Mares <mj@ucw.cz>
d15b0b0a
OZ
5 * (c) 2008--2016 Ondrej Zajicek <santiago@crfreenet.org>
6 * (c) 2008--2016 CZ.NIC z.s.p.o.
c01e3741
MM
7 *
8 * Can be freely distributed and used under the terms of the GNU GPL.
9 */
10
85368cd4 11#undef LOCAL_DEBUG
c00d31be 12
e3558ab1
MM
13#include <stdlib.h>
14
c01e3741
MM
15#include "nest/bird.h"
16#include "nest/iface.h"
17#include "nest/protocol.h"
18#include "nest/route.h"
c0668f36 19#include "nest/attrs.h"
c01e3741 20#include "conf/conf.h"
c00d31be
MM
21#include "lib/resource.h"
22#include "lib/string.h"
23#include "lib/unaligned.h"
c01e3741
MM
24
25#include "bgp.h"
c00d31be 26
06fb60c4
OZ
27/*
28 * UPDATE message error handling
29 *
30 * All checks from RFC 4271 6.3 are done as specified with these exceptions:
31 * - The semantic check of an IP address from NEXT_HOP attribute is missing.
32 * - Checks of some optional attribute values are missing.
33 * - Syntactic and semantic checks of NLRIs (done in DECODE_PREFIX())
34 * are probably inadequate.
35 *
36 * Loop detection based on AS_PATH causes updates to be withdrawn. RFC
09ee846d 37 * 4271 does not explicitly specify the behavior in that case.
06fb60c4
OZ
38 *
39 * Loop detection related to route reflection (based on ORIGINATOR_ID
40 * and CLUSTER_LIST) causes updates to be withdrawn. RFC 4456 8
41 * specifies that such updates should be ignored, but that is generally
42 * a bad idea.
43 *
d15b0b0a
OZ
44 * BGP attribute table has several hooks:
45 *
46 * export - Hook that validates and normalizes attribute during export phase.
47 * Receives eattr, may modify it (e.g., sort community lists for canonical
48 * representation), UNSET() it (e.g., skip empty lists), or WITHDRAW() it if
49 * necessary. May assume that eattr has value valid w.r.t. its type, but may be
50 * invalid w.r.t. BGP constraints. Optional.
51 *
52 * encode - Hook that converts internal representation to external one during
53 * packet writing. Receives eattr and puts it in the buffer (including attribute
54 * header). Returns number of bytes, or -1 if not enough space. May assume that
55 * eattr has value valid w.r.t. its type and validated by export hook. Mandatory
56 * for all known attributes that exist internally after export phase (i.e., all
57 * except pseudoattributes MP_(UN)REACH_NLRI).
58 *
59 * decode - Hook that converts external representation to internal one during
60 * packet parsing. Receives attribute data in buffer, validates it and adds
61 * attribute to ea_list. If data are invalid, steps DISCARD(), WITHDRAW() or
62 * bgp_parse_error() may be used to escape. Mandatory for all known attributes.
63 *
64 * format - Optional hook that converts eattr to textual representation.
06fb60c4
OZ
65 */
66
ae8f5584 67
d15b0b0a
OZ
68struct bgp_attr_desc {
69 const char *name;
70 uint type;
71 uint flags;
72 void (*export)(struct bgp_export_state *s, eattr *a);
73 int (*encode)(struct bgp_write_state *s, eattr *a, byte *buf, uint size);
74 void (*decode)(struct bgp_parse_state *s, uint code, uint flags, byte *data, uint len, ea_list **to);
75 void (*format)(eattr *ea, byte *buf, uint size);
ae8f5584
MM
76};
77
d15b0b0a
OZ
78static const struct bgp_attr_desc bgp_attr_table[];
79
80static inline int bgp_attr_known(uint code);
81
82eattr *
83bgp_set_attr(ea_list **attrs, struct linpool *pool, uint code, uint flags, uintptr_t val)
84{
85 ASSERT(bgp_attr_known(code));
86
daf113ac
MJM
87 return ea_set_attr(
88 attrs,
89 pool,
90 EA_CODE(PROTOCOL_BGP, code),
91 flags,
92 bgp_attr_table[code].type,
93 val
94 );
d15b0b0a
OZ
95}
96
97
98
99#define REPORT(msg, args...) \
100 ({ log(L_REMOTE "%s: " msg, s->proto->p.name, ## args); })
101
102#define DISCARD(msg, args...) \
103 ({ REPORT(msg, ## args); return; })
104
105#define WITHDRAW(msg, args...) \
106 ({ REPORT(msg, ## args); s->err_withdraw = 1; return; })
107
108#define UNSET(a) \
109 ({ a->type = EAF_TYPE_UNDEF; return; })
110
111#define NEW_BGP "Discarding %s attribute received from AS4-aware neighbor"
112#define BAD_EBGP "Discarding %s attribute received from EBGP neighbor"
113#define BAD_LENGTH "Malformed %s attribute - invalid length (%u)"
114#define BAD_VALUE "Malformed %s attribute - invalid value (%u)"
115#define NO_MANDATORY "Missing mandatory %s attribute"
116
117
118static inline int
119bgp_put_attr_hdr3(byte *buf, uint code, uint flags, uint len)
120{
121 *buf++ = flags;
122 *buf++ = code;
123 *buf++ = len;
124 return 3;
125}
126
127static inline int
128bgp_put_attr_hdr4(byte *buf, uint code, uint flags, uint len)
129{
130 *buf++ = flags | BAF_EXT_LEN;
131 *buf++ = code;
132 put_u16(buf, len);
133 return 4;
134}
135
136static inline int
137bgp_put_attr_hdr(byte *buf, uint code, uint flags, uint len)
138{
139 if (len < 256)
140 return bgp_put_attr_hdr3(buf, code, flags, len);
141 else
142 return bgp_put_attr_hdr4(buf, code, flags, len);
143}
06fb60c4 144
f421cfdd 145static int
d15b0b0a 146bgp_encode_u8(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size)
f421cfdd 147{
d15b0b0a
OZ
148 if (size < (3+1))
149 return -1;
150
151 bgp_put_attr_hdr3(buf, EA_ID(a->id), a->flags, 1);
152 buf[3] = a->u.data;
153
154 return 3+1;
f421cfdd
MM
155}
156
d15b0b0a
OZ
157static int
158bgp_encode_u32(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size)
f421cfdd 159{
d15b0b0a
OZ
160 if (size < (3+4))
161 return -1;
162
163 bgp_put_attr_hdr3(buf, EA_ID(a->id), a->flags, 4);
164 put_u32(buf+3, a->u.data);
f421cfdd 165
d15b0b0a 166 return 3+4;
f421cfdd
MM
167}
168
169static int
d15b0b0a 170bgp_encode_u32s(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size)
f421cfdd 171{
d15b0b0a 172 uint len = a->u.ptr->length;
29c430f8 173
d15b0b0a
OZ
174 if (size < (4+len))
175 return -1;
29c430f8 176
d15b0b0a
OZ
177 uint hdr = bgp_put_attr_hdr(buf, EA_ID(a->id), a->flags, len);
178 put_u32s(buf + hdr, (u32 *) a->u.ptr->data, len / 4);
179
180 return hdr + len;
f421cfdd
MM
181}
182
11cb6202 183static int
4c553c5a 184bgp_put_attr(byte *buf, uint size, uint code, uint flags, const byte *data, uint len)
29c430f8 185{
d15b0b0a
OZ
186 if (size < (4+len))
187 return -1;
29c430f8 188
d15b0b0a
OZ
189 uint hdr = bgp_put_attr_hdr(buf, code, flags, len);
190 memcpy(buf + hdr, data, len);
29c430f8 191
d15b0b0a
OZ
192 return hdr + len;
193}
194
195static int
196bgp_encode_raw(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size)
197{
198 return bgp_put_attr(buf, size, EA_ID(a->id), a->flags, a->u.ptr->data, a->u.ptr->length);
199}
200
201
09ee846d
OZ
202/*
203 * AIGP handling
204 */
205
206static int
207bgp_aigp_valid(byte *data, uint len, char *err, uint elen)
208{
209 byte *pos = data;
210 char *err_dsc = NULL;
211 uint err_val = 0;
212
213#define BAD(DSC,VAL) ({ err_dsc = DSC; err_val = VAL; goto bad; })
214 while (len)
215 {
216 if (len < 3)
217 BAD("TLV framing error", len);
218
219 /* Process one TLV */
220 uint ptype = pos[0];
221 uint plen = get_u16(pos + 1);
222
223 if (len < plen)
224 BAD("TLV framing error", plen);
225
226 if (plen < 3)
227 BAD("Bad TLV length", plen);
228
229 if ((ptype == BGP_AIGP_METRIC) && (plen != 11))
230 BAD("Bad AIGP TLV length", plen);
231
232 ADVANCE(pos, len, plen);
233 }
234#undef BAD
235
236 return 1;
237
238bad:
239 if (err)
240 if (bsnprintf(err, elen, "%s (%u) at %d", err_dsc, err_val, (int) (pos - data)) < 0)
241 err[0] = 0;
242
243 return 0;
244}
245
246static const byte *
247bgp_aigp_get_tlv(const struct adata *ad, uint type)
248{
249 if (!ad)
250 return NULL;
251
252 uint len = ad->length;
253 const byte *pos = ad->data;
254
255 while (len)
256 {
257 uint ptype = pos[0];
258 uint plen = get_u16(pos + 1);
259
260 if (ptype == type)
261 return pos;
262
263 ADVANCE(pos, len, plen);
264 }
265
266 return NULL;
267}
268
269static const struct adata *
270bgp_aigp_set_tlv(struct linpool *pool, const struct adata *ad, uint type, byte *data, uint dlen)
271{
272 uint len = ad ? ad->length : 0;
273 const byte *pos = ad ? ad->data : NULL;
274 struct adata *res = lp_alloc_adata(pool, len + 3 + dlen);
275 byte *dst = res->data;
276 byte *tlv = NULL;
277 int del = 0;
278
279 while (len)
280 {
281 uint ptype = pos[0];
282 uint plen = get_u16(pos + 1);
283
284 /* Find position for new TLV */
285 if ((ptype >= type) && !tlv)
286 {
287 tlv = dst;
288 dst += 3 + dlen;
289 }
290
291 /* Skip first matching TLV, copy others */
292 if ((ptype == type) && !del)
293 del = 1;
294 else
295 {
296 memcpy(dst, pos, plen);
297 dst += plen;
298 }
299
300 ADVANCE(pos, len, plen);
301 }
302
303 if (!tlv)
304 {
305 tlv = dst;
306 dst += 3 + dlen;
307 }
308
309 /* Store the TLD */
310 put_u8(tlv + 0, type);
311 put_u16(tlv + 1, 3 + dlen);
312 memcpy(tlv + 3, data, dlen);
313
314 /* Update length */
315 res->length = dst - res->data;
316
317 return res;
318}
319
320static u64 UNUSED
321bgp_aigp_get_metric(const struct adata *ad, u64 def)
322{
323 const byte *b = bgp_aigp_get_tlv(ad, BGP_AIGP_METRIC);
324 return b ? get_u64(b + 3) : def;
325}
326
327static const struct adata *
328bgp_aigp_set_metric(struct linpool *pool, const struct adata *ad, u64 metric)
329{
330 byte data[8];
331 put_u64(data, metric);
332 return bgp_aigp_set_tlv(pool, ad, BGP_AIGP_METRIC, data, 8);
333}
334
335int
336bgp_total_aigp_metric_(rte *e, u64 *metric, const struct adata **ad)
337{
338 eattr *a = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AIGP));
339 if (!a)
340 return 0;
341
342 const byte *b = bgp_aigp_get_tlv(a->u.ptr, BGP_AIGP_METRIC);
343 if (!b)
344 return 0;
345
346 u64 aigp = get_u64(b + 3);
347 u64 step = e->attrs->igp_metric;
348
349 if (!rte_resolvable(e) || (step >= IGP_METRIC_UNKNOWN))
350 step = BGP_AIGP_MAX;
351
352 if (!step)
353 step = 1;
354
355 *ad = a->u.ptr;
356 *metric = aigp + step;
357 if (*metric < aigp)
358 *metric = BGP_AIGP_MAX;
359
360 return 1;
361}
362
363static inline int
364bgp_init_aigp_metric(rte *e, u64 *metric, const struct adata **ad)
365{
366 if (e->attrs->source == RTS_BGP)
367 return 0;
368
369 *metric = rt_get_igp_metric(e);
370 *ad = NULL;
371 return *metric < IGP_METRIC_UNKNOWN;
372}
373
374
d15b0b0a
OZ
375/*
376 * Attribute hooks
377 */
29c430f8 378
d15b0b0a
OZ
379static void
380bgp_export_origin(struct bgp_export_state *s, eattr *a)
381{
382 if (a->u.data > 2)
383 WITHDRAW(BAD_VALUE, "ORIGIN", a->u.data);
29c430f8
OZ
384}
385
d15b0b0a
OZ
386static void
387bgp_decode_origin(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
11cb6202 388{
d15b0b0a
OZ
389 if (len != 1)
390 WITHDRAW(BAD_LENGTH, "ORIGIN", len);
391
392 if (data[0] > 2)
393 WITHDRAW(BAD_VALUE, "ORIGIN", data[0]);
394
395 bgp_set_attr_u32(to, s->pool, BA_ORIGIN, flags, data[0]);
29c430f8
OZ
396}
397
d15b0b0a
OZ
398static void
399bgp_format_origin(eattr *a, byte *buf, uint size UNUSED)
29c430f8 400{
d15b0b0a
OZ
401 static const char *bgp_origin_names[] = { "IGP", "EGP", "Incomplete" };
402
403 bsprintf(buf, (a->u.data <= 2) ? bgp_origin_names[a->u.data] : "?");
11cb6202
OZ
404}
405
d15b0b0a 406
f421cfdd 407static int
d15b0b0a 408bgp_encode_as_path(struct bgp_write_state *s, eattr *a, byte *buf, uint size)
f421cfdd 409{
4c553c5a 410 const byte *data = a->u.ptr->data;
d15b0b0a 411 uint len = a->u.ptr->length;
f421cfdd 412
d15b0b0a
OZ
413 if (!s->as4_session)
414 {
415 /* Prepare 16-bit AS_PATH (from 32-bit one) in a temporary buffer */
4c553c5a
MM
416 byte *dst = alloca(len);
417 len = as_path_32to16(dst, data, len);
418 data = dst;
d15b0b0a
OZ
419 }
420
421 return bgp_put_attr(buf, size, BA_AS_PATH, a->flags, data, len);
422}
423
424static void
425bgp_decode_as_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
426{
5509e17d
OZ
427 struct bgp_proto *p = s->proto;
428 int as_length = s->as4_session ? 4 : 2;
429 int as_confed = p->cf->confederation && p->is_interior;
d15b0b0a
OZ
430 char err[128];
431
5509e17d 432 if (!as_path_valid(data, len, as_length, as_confed, err, sizeof(err)))
d15b0b0a
OZ
433 WITHDRAW("Malformed AS_PATH attribute - %s", err);
434
5509e17d
OZ
435 /* In some circumstances check for initial AS_CONFED_SEQUENCE; RFC 5065 5.0 */
436 if (p->is_interior && !p->is_internal &&
437 ((len < 2) || (data[0] != AS_PATH_CONFED_SEQUENCE)))
438 WITHDRAW("Malformed AS_PATH attribute - %s", "missing initial AS_CONFED_SEQUENCE");
439
d15b0b0a
OZ
440 if (!s->as4_session)
441 {
442 /* Prepare 32-bit AS_PATH (from 16-bit one) in a temporary buffer */
443 byte *src = data;
444 data = alloca(2*len);
445 len = as_path_16to32(data, src, len);
446 }
447
448 bgp_set_attr_data(to, s->pool, BA_AS_PATH, flags, data, len);
449}
450
451
452static int
453bgp_encode_next_hop(struct bgp_write_state *s, eattr *a, byte *buf, uint size)
454{
455 /*
456 * The NEXT_HOP attribute is used only in traditional (IPv4) BGP. In MP-BGP,
457 * the next hop is encoded as a part of the MP_REACH_NLRI attribute, so we
458 * store it and encode it later by AFI-specific hooks.
459 */
460
863ecfc7 461 if (!s->mp_reach)
d15b0b0a 462 {
863ecfc7
OZ
463 // ASSERT(a->u.ptr->length == sizeof(ip_addr));
464
465 /* FIXME: skip IPv6 next hops for IPv4 routes during MRT dump */
466 ip_addr *addr = (void *) a->u.ptr->data;
467 if ((a->u.ptr->length != sizeof(ip_addr)) || !ipa_is_ip4(*addr))
468 return 0;
d15b0b0a
OZ
469
470 if (size < (3+4))
471 return -1;
472
473 bgp_put_attr_hdr3(buf, BA_NEXT_HOP, a->flags, 4);
863ecfc7 474 put_ip4(buf+3, ipa_to_ip4(*addr));
d15b0b0a
OZ
475
476 return 3+4;
477 }
478 else
479 {
480 s->mp_next_hop = a;
f421cfdd 481 return 0;
d15b0b0a
OZ
482 }
483}
484
485static void
486bgp_decode_next_hop(struct bgp_parse_state *s, uint code UNUSED, uint flags UNUSED, byte *data, uint len, ea_list **to UNUSED)
487{
488 if (len != 4)
489 WITHDRAW(BAD_LENGTH, "NEXT_HOP", len);
490
491 /* Semantic checks are done later */
492 s->ip_next_hop_len = len;
493 s->ip_next_hop_data = data;
494}
495
496/* TODO: This function should use AF-specific hook */
497static void
498bgp_format_next_hop(eattr *a, byte *buf, uint size UNUSED)
499{
500 ip_addr *nh = (void *) a->u.ptr->data;
501 uint len = a->u.ptr->length;
502
503 ASSERT((len == 16) || (len == 32));
504
505 /* in IPv6, we may have two addresses in NEXT HOP */
506 if ((len == 16) || ipa_zero(nh[1]))
507 bsprintf(buf, "%I", nh[0]);
f421cfdd 508 else
d15b0b0a 509 bsprintf(buf, "%I %I", nh[0], nh[1]);
1c1da87b
MM
510}
511
d15b0b0a 512
d0e2d6d1 513static void
d15b0b0a 514bgp_decode_med(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
d0e2d6d1 515{
d15b0b0a
OZ
516 if (len != 4)
517 WITHDRAW(BAD_LENGTH, "MULTI_EXIT_DISC", len);
d0e2d6d1 518
d15b0b0a
OZ
519 u32 val = get_u32(data);
520 bgp_set_attr_u32(to, s->pool, BA_MULTI_EXIT_DISC, flags, val);
d0e2d6d1
OZ
521}
522
d15b0b0a
OZ
523
524static void
525bgp_export_local_pref(struct bgp_export_state *s, eattr *a)
11cb6202 526{
e919601a 527 if (!s->proto->is_interior && !s->proto->cf->allow_local_pref)
d15b0b0a 528 UNSET(a);
11cb6202
OZ
529}
530
cd17c651 531static void
d15b0b0a 532bgp_decode_local_pref(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
cd17c651 533{
e919601a 534 if (!s->proto->is_interior && !s->proto->cf->allow_local_pref)
d15b0b0a 535 DISCARD(BAD_EBGP, "LOCAL_PREF");
cd17c651 536
d15b0b0a
OZ
537 if (len != 4)
538 WITHDRAW(BAD_LENGTH, "LOCAL_PREF", len);
cd17c651 539
d15b0b0a
OZ
540 u32 val = get_u32(data);
541 bgp_set_attr_u32(to, s->pool, BA_LOCAL_PREF, flags, val);
cd17c651
OZ
542}
543
d15b0b0a
OZ
544
545static void
546bgp_decode_atomic_aggr(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data UNUSED, uint len, ea_list **to)
06fb60c4 547{
d15b0b0a
OZ
548 if (len != 0)
549 DISCARD(BAD_LENGTH, "ATOMIC_AGGR", len);
550
551 bgp_set_attr_data(to, s->pool, BA_ATOMIC_AGGR, flags, NULL, 0);
06fb60c4
OZ
552}
553
4847a894 554static int
d15b0b0a
OZ
555bgp_encode_aggregator(struct bgp_write_state *s, eattr *a, byte *buf, uint size)
556{
4c553c5a 557 const byte *data = a->u.ptr->data;
d15b0b0a
OZ
558 uint len = a->u.ptr->length;
559
560 if (!s->as4_session)
561 {
562 /* Prepare 16-bit AGGREGATOR (from 32-bit one) in a temporary buffer */
4c553c5a
MM
563 byte *dst = alloca(6);
564 len = aggregator_32to16(dst, data);
d15b0b0a
OZ
565 }
566
567 return bgp_put_attr(buf, size, BA_AGGREGATOR, a->flags, data, len);
568}
569
570static void
571bgp_decode_aggregator(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
572{
573 if (len != (s->as4_session ? 8 : 6))
574 DISCARD(BAD_LENGTH, "AGGREGATOR", len);
575
576 if (!s->as4_session)
577 {
578 /* Prepare 32-bit AGGREGATOR (from 16-bit one) in a temporary buffer */
579 byte *src = data;
580 data = alloca(8);
581 len = aggregator_16to32(data, src);
582 }
583
584 bgp_set_attr_data(to, s->pool, BA_AGGREGATOR, flags, data, len);
585}
586
587static void
588bgp_format_aggregator(eattr *a, byte *buf, uint size UNUSED)
589{
4c553c5a 590 const byte *data = a->u.ptr->data;
d15b0b0a
OZ
591
592 bsprintf(buf, "%I4 AS%u", get_ip4(data+4), get_u32(data+0));
593}
594
595
596static void
597bgp_export_community(struct bgp_export_state *s, eattr *a)
598{
599 if (a->u.ptr->length == 0)
600 UNSET(a);
601
602 a->u.ptr = int_set_sort(s->pool, a->u.ptr);
603}
604
605static void
606bgp_decode_community(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
607{
608 if (!len || (len % 4))
609 WITHDRAW(BAD_LENGTH, "COMMUNITY", len);
610
611 struct adata *ad = lp_alloc_adata(s->pool, len);
612 get_u32s(data, (u32 *) ad->data, len / 4);
613 bgp_set_attr_ptr(to, s->pool, BA_COMMUNITY, flags, ad);
614}
615
616
617static void
618bgp_export_originator_id(struct bgp_export_state *s, eattr *a)
4847a894 619{
d15b0b0a
OZ
620 if (!s->proto->is_internal)
621 UNSET(a);
4847a894
OZ
622}
623
aebe06b4 624static void
d15b0b0a
OZ
625bgp_decode_originator_id(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
626{
627 if (!s->proto->is_internal)
628 DISCARD(BAD_EBGP, "ORIGINATOR_ID");
629
630 if (len != 4)
631 WITHDRAW(BAD_LENGTH, "ORIGINATOR_ID", len);
632
633 u32 val = get_u32(data);
634 bgp_set_attr_u32(to, s->pool, BA_ORIGINATOR_ID, flags, val);
635}
636
637
638static void
639bgp_export_cluster_list(struct bgp_export_state *s UNUSED, eattr *a)
640{
641 if (!s->proto->is_internal)
642 UNSET(a);
643
644 if (a->u.ptr->length == 0)
645 UNSET(a);
646}
647
648static void
649bgp_decode_cluster_list(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
650{
651 if (!s->proto->is_internal)
652 DISCARD(BAD_EBGP, "CLUSTER_LIST");
653
654 if (!len || (len % 4))
655 WITHDRAW(BAD_LENGTH, "CLUSTER_LIST", len);
656
657 struct adata *ad = lp_alloc_adata(s->pool, len);
658 get_u32s(data, (u32 *) ad->data, len / 4);
659 bgp_set_attr_ptr(to, s->pool, BA_CLUSTER_LIST, flags, ad);
660}
661
662static void
663bgp_format_cluster_list(eattr *a, byte *buf, uint size)
aebe06b4 664{
fdf16eb6 665 /* Truncates cluster lists larger than buflen, probably not a problem */
d15b0b0a 666 int_set_format(a->u.ptr, 0, -1, buf, size);
aebe06b4
OZ
667}
668
d15b0b0a
OZ
669
670static inline u32
671get_af3(byte *buf)
1c1da87b 672{
d15b0b0a 673 return (get_u16(buf) << 16) | buf[2];
1c1da87b
MM
674}
675
d15b0b0a
OZ
676static void
677bgp_decode_mp_reach_nlri(struct bgp_parse_state *s, uint code UNUSED, uint flags UNUSED, byte *data, uint len, ea_list **to UNUSED)
1c1da87b 678{
d15b0b0a
OZ
679 /*
680 * 2 B MP_REACH_NLRI data - Address Family Identifier
681 * 1 B MP_REACH_NLRI data - Subsequent Address Family Identifier
682 * 1 B MP_REACH_NLRI data - Length of Next Hop Network Address
683 * var MP_REACH_NLRI data - Network Address of Next Hop
684 * 1 B MP_REACH_NLRI data - Reserved (zero)
685 * var MP_REACH_NLRI data - Network Layer Reachability Information
686 */
687
688 if ((len < 5) || (len < (5 + (uint) data[3])))
689 bgp_parse_error(s, 9);
690
691 s->mp_reach_af = get_af3(data);
692 s->mp_next_hop_len = data[3];
693 s->mp_next_hop_data = data + 4;
694 s->mp_reach_len = len - 5 - s->mp_next_hop_len;
695 s->mp_reach_nlri = data + 5 + s->mp_next_hop_len;
f421cfdd
MM
696}
697
d15b0b0a
OZ
698
699static void
700bgp_decode_mp_unreach_nlri(struct bgp_parse_state *s, uint code UNUSED, uint flags UNUSED, byte *data, uint len, ea_list **to UNUSED)
42a0c054 701{
d15b0b0a
OZ
702 /*
703 * 2 B MP_UNREACH_NLRI data - Address Family Identifier
704 * 1 B MP_UNREACH_NLRI data - Subsequent Address Family Identifier
705 * var MP_UNREACH_NLRI data - Network Layer Reachability Information
706 */
707
708 if (len < 3)
709 bgp_parse_error(s, 9);
710
711 s->mp_unreach_af = get_af3(data);
712 s->mp_unreach_len = len - 3;
713 s->mp_unreach_nlri = data + 3;
42a0c054
OZ
714}
715
d15b0b0a
OZ
716
717static void
718bgp_export_ext_community(struct bgp_export_state *s, eattr *a)
719{
ec331acf
OZ
720 if (!s->proto->is_interior)
721 {
722 struct adata *ad = ec_set_del_nontrans(s->pool, a->u.ptr);
d807ea08 723
ec331acf
OZ
724 if (ad->length == 0)
725 UNSET(a);
d15b0b0a 726
ec331acf
OZ
727 ec_set_sort_x(ad);
728 a->u.ptr = ad;
729 }
730 else
731 {
732 if (a->u.ptr->length == 0)
733 UNSET(a);
734
735 a->u.ptr = ec_set_sort(s->pool, a->u.ptr);
736 }
d15b0b0a
OZ
737}
738
739static void
740bgp_decode_ext_community(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
741{
742 if (!len || (len % 8))
743 WITHDRAW(BAD_LENGTH, "EXT_COMMUNITY", len);
744
745 struct adata *ad = lp_alloc_adata(s->pool, len);
746 get_u32s(data, (u32 *) ad->data, len / 4);
747 bgp_set_attr_ptr(to, s->pool, BA_EXT_COMMUNITY, flags, ad);
748}
749
750
751static void
752bgp_decode_as4_aggregator(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
753{
754 if (s->as4_session)
755 DISCARD(NEW_BGP, "AS4_AGGREGATOR");
756
757 if (len != 8)
758 DISCARD(BAD_LENGTH, "AS4_AGGREGATOR", len);
759
760 bgp_set_attr_data(to, s->pool, BA_AS4_AGGREGATOR, flags, data, len);
761}
762
763static void
764bgp_decode_as4_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
765{
766 char err[128];
767
768 if (s->as4_session)
769 DISCARD(NEW_BGP, "AS4_PATH");
770
771 if (len < 6)
772 DISCARD(BAD_LENGTH, "AS4_PATH", len);
773
5509e17d 774 if (!as_path_valid(data, len, 4, 1, err, sizeof(err)))
d15b0b0a
OZ
775 DISCARD("Malformed AS4_PATH attribute - %s", err);
776
5509e17d
OZ
777 struct adata *a = lp_alloc_adata(s->pool, len);
778 memcpy(a->data, data, len);
779
780 /* AS_CONFED* segments are invalid in AS4_PATH; RFC 6793 6 */
781 if (as_path_contains_confed(a))
782 {
783 REPORT("Discarding AS_CONFED* segment from AS4_PATH attribute");
784 a = as_path_strip_confed(s->pool, a);
785 }
786
787 bgp_set_attr_ptr(to, s->pool, BA_AS4_PATH, flags, a);
d15b0b0a
OZ
788}
789
09ee846d
OZ
790
791static void
792bgp_export_aigp(struct bgp_export_state *s, eattr *a)
793{
794 if (!s->channel->cf->aigp)
795 UNSET(a);
796}
797
798static void
799bgp_decode_aigp(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
800{
801 char err[128];
802
803 /* Acceptability test postponed to bgp_finish_attrs() */
804
805 if ((flags ^ bgp_attr_table[BA_AIGP].flags) & (BAF_OPTIONAL | BAF_TRANSITIVE))
806 DISCARD("Malformed AIGP attribute - conflicting flags (%02x)", flags);
807
808 if (!bgp_aigp_valid(data, len, err, sizeof(err)))
809 DISCARD("Malformed AIGP attribute - %s", err);
810
811 bgp_set_attr_data(to, s->pool, BA_AIGP, flags, data, len);
812}
813
814static void
815bgp_format_aigp(eattr *a, byte *buf, uint size UNUSED)
816{
817 const byte *b = bgp_aigp_get_tlv(a->u.ptr, BGP_AIGP_METRIC);
818
819 if (!b)
820 bsprintf(buf, "?");
821 else
822 bsprintf(buf, "%lu", get_u64(b + 3));
823}
824
825
d15b0b0a
OZ
826static void
827bgp_export_large_community(struct bgp_export_state *s, eattr *a)
828{
829 if (a->u.ptr->length == 0)
830 UNSET(a);
831
832 a->u.ptr = lc_set_sort(s->pool, a->u.ptr);
833}
834
835static void
836bgp_decode_large_community(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
837{
838 if (!len || (len % 12))
839 WITHDRAW(BAD_LENGTH, "LARGE_COMMUNITY", len);
840
841 struct adata *ad = lp_alloc_adata(s->pool, len);
842 get_u32s(data, (u32 *) ad->data, len / 4);
843 bgp_set_attr_ptr(to, s->pool, BA_LARGE_COMMUNITY, flags, ad);
844}
845
1e37e35c
OZ
846static void
847bgp_export_mpls_label_stack(struct bgp_export_state *s, eattr *a)
848{
849 net_addr *n = s->route->net->n.addr;
850 u32 *labels = (u32 *) a->u.ptr->data;
851 uint lnum = a->u.ptr->length / 4;
852
853 /* Perhaps we should just ignore it? */
854 if (!s->mpls)
855 WITHDRAW("Unexpected MPLS stack");
856
857 /* Empty MPLS stack is not allowed */
858 if (!lnum)
859 WITHDRAW("Malformed MPLS stack - empty");
860
861 /* This is ugly, but we must ensure that labels fit into NLRI field */
862 if ((24*lnum + (net_is_vpn(n) ? 64 : 0) + net_pxlen(n)) > 255)
863 WITHDRAW("Malformed MPLS stack - too many labels (%u)", lnum);
864
865 for (uint i = 0; i < lnum; i++)
866 {
867 if (labels[i] > 0xfffff)
868 WITHDRAW("Malformed MPLS stack - invalid label (%u)", labels[i]);
869
870 /* TODO: Check for special-purpose label values? */
871 }
872}
873
874static int
875bgp_encode_mpls_label_stack(struct bgp_write_state *s, eattr *a, byte *buf UNUSED, uint size UNUSED)
876{
877 /*
878 * MPLS labels are encoded as a part of the NLRI in MP_REACH_NLRI attribute,
879 * so we store MPLS_LABEL_STACK and encode it later by AFI-specific hooks.
880 */
881
882 s->mpls_labels = a->u.ptr;
883 return 0;
884}
885
886static void
887bgp_decode_mpls_label_stack(struct bgp_parse_state *s, uint code UNUSED, uint flags UNUSED, byte *data UNUSED, uint len UNUSED, ea_list **to UNUSED)
888{
889 DISCARD("Discarding received attribute #0");
890}
891
892static void
893bgp_format_mpls_label_stack(eattr *a, byte *buf, uint size)
894{
895 u32 *labels = (u32 *) a->u.ptr->data;
896 uint lnum = a->u.ptr->length / 4;
897 char *pos = buf;
898
899 for (uint i = 0; i < lnum; i++)
900 {
901 if (size < 20)
902 {
903 bsprintf(pos, "...");
904 return;
905 }
906
907 uint l = bsprintf(pos, "%d/", labels[i]);
908 ADVANCE(pos, size, l);
909 }
910
911 /* Clear last slash or terminate empty string */
912 pos[lnum ? -1 : 0] = 0;
913}
914
d15b0b0a
OZ
915static inline void
916bgp_decode_unknown(struct bgp_parse_state *s, uint code, uint flags, byte *data, uint len, ea_list **to)
917{
d493d0f1 918 /* Cannot use bgp_set_attr_data() as it works on known attributes only */
ee7e2ffd 919 ea_set_attr_data(to, s->pool, EA_CODE(PROTOCOL_BGP, code), flags, EAF_TYPE_OPAQUE, data, len);
d15b0b0a
OZ
920}
921
922
923/*
924 * Attribute table
925 */
926
927static const struct bgp_attr_desc bgp_attr_table[] = {
928 [BA_ORIGIN] = {
929 .name = "origin",
930 .type = EAF_TYPE_INT,
931 .flags = BAF_TRANSITIVE,
932 .export = bgp_export_origin,
933 .encode = bgp_encode_u8,
934 .decode = bgp_decode_origin,
935 .format = bgp_format_origin,
936 },
937 [BA_AS_PATH] = {
938 .name = "as_path",
939 .type = EAF_TYPE_AS_PATH,
940 .flags = BAF_TRANSITIVE,
941 .encode = bgp_encode_as_path,
942 .decode = bgp_decode_as_path,
943 },
944 [BA_NEXT_HOP] = {
945 .name = "next_hop",
946 .type = EAF_TYPE_IP_ADDRESS,
947 .flags = BAF_TRANSITIVE,
948 .encode = bgp_encode_next_hop,
949 .decode = bgp_decode_next_hop,
950 .format = bgp_format_next_hop,
951 },
952 [BA_MULTI_EXIT_DISC] = {
953 .name = "med",
954 .type = EAF_TYPE_INT,
955 .flags = BAF_OPTIONAL,
956 .encode = bgp_encode_u32,
957 .decode = bgp_decode_med,
958 },
959 [BA_LOCAL_PREF] = {
960 .name = "local_pref",
961 .type = EAF_TYPE_INT,
962 .flags = BAF_TRANSITIVE,
963 .export = bgp_export_local_pref,
964 .encode = bgp_encode_u32,
965 .decode = bgp_decode_local_pref,
966 },
967 [BA_ATOMIC_AGGR] = {
968 .name = "atomic_aggr",
969 .type = EAF_TYPE_OPAQUE,
970 .flags = BAF_TRANSITIVE,
971 .encode = bgp_encode_raw,
972 .decode = bgp_decode_atomic_aggr,
973 },
974 [BA_AGGREGATOR] = {
975 .name = "aggregator",
976 .type = EAF_TYPE_OPAQUE,
977 .flags = BAF_OPTIONAL | BAF_TRANSITIVE,
978 .encode = bgp_encode_aggregator,
979 .decode = bgp_decode_aggregator,
980 .format = bgp_format_aggregator,
981 },
982 [BA_COMMUNITY] = {
983 .name = "community",
984 .type = EAF_TYPE_INT_SET,
985 .flags = BAF_OPTIONAL | BAF_TRANSITIVE,
986 .export = bgp_export_community,
987 .encode = bgp_encode_u32s,
988 .decode = bgp_decode_community,
989 },
990 [BA_ORIGINATOR_ID] = {
991 .name = "originator_id",
992 .type = EAF_TYPE_ROUTER_ID,
993 .flags = BAF_OPTIONAL,
994 .export = bgp_export_originator_id,
995 .encode = bgp_encode_u32,
996 .decode = bgp_decode_originator_id,
997 },
998 [BA_CLUSTER_LIST] = {
999 .name = "cluster_list",
1000 .type = EAF_TYPE_INT_SET,
1001 .flags = BAF_OPTIONAL,
1002 .export = bgp_export_cluster_list,
1003 .encode = bgp_encode_u32s,
1004 .decode = bgp_decode_cluster_list,
1005 .format = bgp_format_cluster_list,
1006 },
1007 [BA_MP_REACH_NLRI] = {
1008 .name = "mp_reach_nlri",
1009 .type = EAF_TYPE_OPAQUE,
1010 .flags = BAF_OPTIONAL,
1011 .decode = bgp_decode_mp_reach_nlri,
1012 },
1013 [BA_MP_UNREACH_NLRI] = {
1014 .name = "mp_unreach_nlri",
1015 .type = EAF_TYPE_OPAQUE,
1016 .flags = BAF_OPTIONAL,
1017 .decode = bgp_decode_mp_unreach_nlri,
1018 },
1019 [BA_EXT_COMMUNITY] = {
1020 .name = "ext_community",
1021 .type = EAF_TYPE_EC_SET,
1022 .flags = BAF_OPTIONAL | BAF_TRANSITIVE,
1023 .export = bgp_export_ext_community,
1024 .encode = bgp_encode_u32s,
1025 .decode = bgp_decode_ext_community,
1026 },
1027 [BA_AS4_PATH] = {
1028 .name = "as4_path",
1029 .type = EAF_TYPE_AS_PATH,
1030 .flags = BAF_OPTIONAL | BAF_TRANSITIVE,
1031 .encode = bgp_encode_raw,
1032 .decode = bgp_decode_as4_path,
1033 },
1034 [BA_AS4_AGGREGATOR] = {
1035 .name = "as4_aggregator",
1036 .type = EAF_TYPE_OPAQUE,
1037 .flags = BAF_OPTIONAL | BAF_TRANSITIVE,
1038 .encode = bgp_encode_raw,
1039 .decode = bgp_decode_as4_aggregator,
1040 .format = bgp_format_aggregator,
1041 },
09ee846d
OZ
1042 [BA_AIGP] = {
1043 .name = "aigp",
1044 .type = EAF_TYPE_OPAQUE,
1045 .flags = BAF_OPTIONAL | BAF_DECODE_FLAGS,
1046 .export = bgp_export_aigp,
1047 .encode = bgp_encode_raw,
1048 .decode = bgp_decode_aigp,
1049 .format = bgp_format_aigp,
1050 },
d15b0b0a
OZ
1051 [BA_LARGE_COMMUNITY] = {
1052 .name = "large_community",
1053 .type = EAF_TYPE_LC_SET,
1054 .flags = BAF_OPTIONAL | BAF_TRANSITIVE,
1055 .export = bgp_export_large_community,
1056 .encode = bgp_encode_u32s,
1057 .decode = bgp_decode_large_community,
1058 },
1e37e35c
OZ
1059 [BA_MPLS_LABEL_STACK] = {
1060 .name = "mpls_label_stack",
1061 .type = EAF_TYPE_INT_SET,
1062 .export = bgp_export_mpls_label_stack,
1063 .encode = bgp_encode_mpls_label_stack,
1064 .decode = bgp_decode_mpls_label_stack,
1065 .format = bgp_format_mpls_label_stack,
1066 },
f421cfdd
MM
1067};
1068
d15b0b0a
OZ
1069static inline int
1070bgp_attr_known(uint code)
1071{
1072 return (code < ARRAY_SIZE(bgp_attr_table)) && bgp_attr_table[code].name;
1073}
1074
1075
1076/*
1077 * Attribute export
11cb6202
OZ
1078 */
1079
d15b0b0a
OZ
1080static inline void
1081bgp_export_attr(struct bgp_export_state *s, eattr *a, ea_list *to)
1082{
ee7e2ffd 1083 if (EA_PROTO(a->id) != PROTOCOL_BGP)
d15b0b0a
OZ
1084 return;
1085
1086 uint code = EA_ID(a->id);
1087
1088 if (bgp_attr_known(code))
1089 {
1090 const struct bgp_attr_desc *desc = &bgp_attr_table[code];
1091
1092 /* The flags might have been zero if the attr was added by filters */
1093 a->flags = (a->flags & BAF_PARTIAL) | desc->flags;
1094
1095 /* Set partial bit if new opt-trans attribute is attached to non-local route */
1096 if ((s->src != NULL) && (a->type & EAF_ORIGINATED) &&
1097 (a->flags & BAF_OPTIONAL) && (a->flags & BAF_TRANSITIVE))
1098 a->flags |= BAF_PARTIAL;
d1a74339 1099
d15b0b0a
OZ
1100 /* Call specific hook */
1101 CALL(desc->export, s, a);
1102
1103 /* Attribute might become undefined in hook */
1104 if ((a->type & EAF_TYPE_MASK) == EAF_TYPE_UNDEF)
1105 return;
1106 }
1107 else
1108 {
1109 /* Don't re-export unknown non-transitive attributes */
1110 if (!(a->flags & BAF_TRANSITIVE))
1111 return;
1112
1113 a->flags |= BAF_PARTIAL;
1114 }
1115
1116 /* Append updated attribute */
1117 to->attrs[to->count++] = *a;
1118}
1119
1120/**
1121 * bgp_export_attrs - export BGP attributes
1122 * @s: BGP export state
1123 * @attrs: a list of extended attributes
1124 *
1125 * The bgp_export_attrs() function takes a list of attributes and merges it to
1126 * one newly allocated and sorted segment. Attributes are validated and
1127 * normalized by type-specific export hooks and attribute flags are updated.
1128 * Some attributes may be eliminated (e.g. unknown non-tranitive attributes, or
1129 * empty community sets).
1130 *
1131 * Result: one sorted attribute list segment, or NULL if attributes are unsuitable.
1132 */
1133static inline ea_list *
1134bgp_export_attrs(struct bgp_export_state *s, ea_list *attrs)
4847a894 1135{
d15b0b0a
OZ
1136 /* Merge the attribute list */
1137 ea_list *new = lp_alloc(s->pool, ea_scan(attrs));
1138 ea_merge(attrs, new);
1139 ea_sort(new);
1140
1141 uint i, count;
1142 count = new->count;
1143 new->count = 0;
1144
1145 /* Export each attribute */
1146 for (i = 0; i < count; i++)
1147 bgp_export_attr(s, &new->attrs[i], new);
1148
1149 if (s->err_withdraw)
1150 return NULL;
1151
1152 return new;
4847a894
OZ
1153}
1154
d15b0b0a
OZ
1155
1156/*
1157 * Attribute encoding
1158 */
1159
1160static inline int
1161bgp_encode_attr(struct bgp_write_state *s, eattr *a, byte *buf, uint size)
cf3d6470 1162{
ee7e2ffd 1163 ASSERT(EA_PROTO(a->id) == PROTOCOL_BGP);
d15b0b0a
OZ
1164
1165 uint code = EA_ID(a->id);
1166
1167 if (bgp_attr_known(code))
1168 return bgp_attr_table[code].encode(s, a, buf, size);
cf3d6470 1169 else
d15b0b0a 1170 return bgp_encode_raw(s, a, buf, size);
cf3d6470
MM
1171}
1172
d15b0b0a
OZ
1173/**
1174 * bgp_encode_attrs - encode BGP attributes
1175 * @s: BGP write state
1176 * @attrs: a list of extended attributes
1177 * @buf: buffer
1178 * @end: buffer end
1179 *
1180 * The bgp_encode_attrs() function takes a list of extended attributes
1181 * and converts it to its BGP representation (a part of an Update message).
863ecfc7 1182 * BGP write state may be fake when called from MRT protocol.
d15b0b0a
OZ
1183 *
1184 * Result: Length of the attribute block generated or -1 if not enough space.
1185 */
1186int
1187bgp_encode_attrs(struct bgp_write_state *s, ea_list *attrs, byte *buf, byte *end)
4847a894 1188{
d15b0b0a
OZ
1189 byte *pos = buf;
1190 int i, len;
1191
1192 for (i = 0; i < attrs->count; i++)
1193 {
1194 len = bgp_encode_attr(s, &attrs->attrs[i], pos, end - pos);
1195
1196 if (len < 0)
1197 return -1;
1198
1199 pos += len;
1200 }
1201
1202 return pos - buf;
4847a894
OZ
1203}
1204
d15b0b0a
OZ
1205
1206/*
1207 * Attribute decoding
1208 */
1209
1210static void bgp_process_as4_attrs(ea_list **attrs, struct linpool *pool);
1211
1212static inline int
1213bgp_as_path_loopy(struct bgp_proto *p, ea_list *attrs, u32 asn)
cf3d6470 1214{
d15b0b0a
OZ
1215 eattr *e = bgp_find_attr(attrs, BA_AS_PATH);
1216 int num = p->cf->allow_local_as + 1;
1217 return (e && (num > 0) && as_path_contains(e->u.ptr, asn, num));
4847a894
OZ
1218}
1219
d15b0b0a
OZ
1220static inline int
1221bgp_originator_id_loopy(struct bgp_proto *p, ea_list *attrs)
4847a894 1222{
d15b0b0a
OZ
1223 eattr *e = bgp_find_attr(attrs, BA_ORIGINATOR_ID);
1224 return (e && (e->u.data == p->local_id));
cf3d6470
MM
1225}
1226
d15b0b0a
OZ
1227static inline int
1228bgp_cluster_list_loopy(struct bgp_proto *p, ea_list *attrs)
11cb6202 1229{
d15b0b0a
OZ
1230 eattr *e = bgp_find_attr(attrs, BA_CLUSTER_LIST);
1231 return (e && int_set_contains(e->u.ptr, p->rr_cluster_id));
1232}
11cb6202 1233
d15b0b0a
OZ
1234static inline void
1235bgp_decode_attr(struct bgp_parse_state *s, uint code, uint flags, byte *data, uint len, ea_list **to)
1236{
1237 /* Handle duplicate attributes; RFC 7606 3 (g) */
1238 if (BIT32_TEST(s->attrs_seen, code))
1239 {
1240 if ((code == BA_MP_REACH_NLRI) || (code == BA_MP_UNREACH_NLRI))
1241 bgp_parse_error(s, 1);
1242 else
1243 DISCARD("Discarding duplicate attribute (code %u)", code);
1244 }
1245 BIT32_SET(s->attrs_seen, code);
11cb6202 1246
d15b0b0a
OZ
1247 if (bgp_attr_known(code))
1248 {
1249 const struct bgp_attr_desc *desc = &bgp_attr_table[code];
1250
1251 /* Handle conflicting flags; RFC 7606 3 (c) */
09ee846d
OZ
1252 if (((flags ^ desc->flags) & (BAF_OPTIONAL | BAF_TRANSITIVE)) &&
1253 !(desc->flags & BAF_DECODE_FLAGS))
d15b0b0a 1254 WITHDRAW("Malformed %s attribute - conflicting flags (%02x)", desc->name, flags);
11cb6202 1255
d15b0b0a
OZ
1256 desc->decode(s, code, flags, data, len, to);
1257 }
1258 else /* Unknown attribute */
1259 {
1260 if (!(flags & BAF_OPTIONAL))
1261 WITHDRAW("Unknown attribute (code %u) - conflicting flags (%02x)", code, flags);
1262
1263 bgp_decode_unknown(s, code, flags, data, len, to);
1264 }
11cb6202
OZ
1265}
1266
d15b0b0a
OZ
1267/**
1268 * bgp_decode_attrs - check and decode BGP attributes
1269 * @s: BGP parse state
1270 * @data: start of attribute block
1271 * @len: length of attribute block
1272 *
1273 * This function takes a BGP attribute block (a part of an Update message), checks
1274 * its consistency and converts it to a list of BIRD route attributes represented
1275 * by an (uncached) &rta.
1276 */
1277ea_list *
1278bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len)
11cb6202 1279{
d15b0b0a
OZ
1280 struct bgp_proto *p = s->proto;
1281 ea_list *attrs = NULL;
1282 uint code, flags, alen;
1283 byte *pos = data;
11cb6202 1284
d15b0b0a
OZ
1285 /* Parse the attributes */
1286 while (len)
1287 {
1288 alen = 0;
1289
1290 /* Read attribute type */
1291 if (len < 2)
1292 goto framing_error;
1293 flags = pos[0];
1294 code = pos[1];
1295 ADVANCE(pos, len, 2);
1296
1297 /* Read attribute length */
1298 if (flags & BAF_EXT_LEN)
11cb6202 1299 {
d15b0b0a
OZ
1300 if (len < 2)
1301 goto framing_error;
1302 alen = get_u16(pos);
1303 ADVANCE(pos, len, 2);
11cb6202 1304 }
d15b0b0a
OZ
1305 else
1306 {
1307 if (len < 1)
1308 goto framing_error;
1309 alen = *pos;
1310 ADVANCE(pos, len, 1);
1311 }
1312
1313 if (alen > len)
1314 goto framing_error;
1315
1316 DBG("Attr %02x %02x %u\n", code, flags, alen);
1317
1318 bgp_decode_attr(s, code, flags, pos, alen, &attrs);
1319 ADVANCE(pos, len, alen);
1320 }
1321
1322 if (s->err_withdraw)
1323 goto withdraw;
1324
1325 /* If there is no reachability NLRI, we are finished */
1326 if (!s->ip_reach_len && !s->mp_reach_len)
1327 return NULL;
1328
1329
1330 /* Handle missing mandatory attributes; RFC 7606 3 (d) */
1331 if (!BIT32_TEST(s->attrs_seen, BA_ORIGIN))
1332 { REPORT(NO_MANDATORY, "ORIGIN"); goto withdraw; }
1333
1334 if (!BIT32_TEST(s->attrs_seen, BA_AS_PATH))
1335 { REPORT(NO_MANDATORY, "AS_PATH"); goto withdraw; }
11cb6202 1336
9c9050ff
OZ
1337 if (s->ip_reach_len && !BIT32_TEST(s->attrs_seen, BA_NEXT_HOP))
1338 { REPORT(NO_MANDATORY, "NEXT_HOP"); goto withdraw; }
1339
d15b0b0a
OZ
1340 /* When receiving attributes from non-AS4-aware BGP speaker, we have to
1341 reconstruct AS_PATH and AGGREGATOR attributes; RFC 6793 4.2.3 */
1342 if (!p->as4_session)
1343 bgp_process_as4_attrs(&attrs, s->pool);
11cb6202 1344
d15b0b0a
OZ
1345 /* Reject routes with our ASN in AS_PATH attribute */
1346 if (bgp_as_path_loopy(p, attrs, p->local_as))
1347 goto withdraw;
11cb6202 1348
5509e17d 1349 /* Reject routes with our Confederation ID in AS_PATH attribute; RFC 5065 4.0 */
d15b0b0a
OZ
1350 if ((p->public_as != p->local_as) && bgp_as_path_loopy(p, attrs, p->public_as))
1351 goto withdraw;
11cb6202 1352
d15b0b0a
OZ
1353 /* Reject routes with our Router ID in ORIGINATOR_ID attribute; RFC 4456 8 */
1354 if (p->is_internal && bgp_originator_id_loopy(p, attrs))
1355 goto withdraw;
11cb6202 1356
d15b0b0a
OZ
1357 /* Reject routes with our Cluster ID in CLUSTER_LIST attribute; RFC 4456 8 */
1358 if (p->rr_client && bgp_cluster_list_loopy(p, attrs))
1359 goto withdraw;
11cb6202 1360
d15b0b0a
OZ
1361 /* If there is no local preference, define one */
1362 if (!BIT32_TEST(s->attrs_seen, BA_LOCAL_PREF))
1363 bgp_set_attr_u32(&attrs, s->pool, BA_LOCAL_PREF, 0, p->cf->default_local_pref);
11cb6202 1364
d15b0b0a 1365 return attrs;
f421cfdd 1366
11cb6202 1367
d15b0b0a
OZ
1368framing_error:
1369 /* RFC 7606 4 - handle attribute framing errors */
1370 REPORT("Malformed attribute list - framing error (%u/%u) at %d",
1371 alen, len, (int) (pos - s->attrs));
ae8f5584 1372
d15b0b0a
OZ
1373withdraw:
1374 /* RFC 7606 5.2 - handle missing NLRI during errors */
1375 if (!s->ip_reach_len && !s->mp_reach_len)
1376 bgp_parse_error(s, 1);
c2b28c99 1377
d15b0b0a
OZ
1378 s->err_withdraw = 1;
1379 return NULL;
e3558ab1
MM
1380}
1381
09ee846d
OZ
1382void
1383bgp_finish_attrs(struct bgp_parse_state *s, rta *a)
1384{
1385 /* AIGP test here instead of in bgp_decode_aigp() - we need to know channel */
1386 if (BIT32_TEST(s->attrs_seen, BA_AIGP) && !s->channel->cf->aigp)
1387 {
1388 REPORT("Discarding AIGP attribute received on non-AIGP session");
1389 bgp_unset_attr(&a->eattrs, s->pool, BA_AIGP);
1390 }
1391}
1392
ae8f5584 1393
d15b0b0a
OZ
1394/*
1395 * Route bucket hash table
1396 */
42a0c054 1397
d15b0b0a
OZ
1398#define RBH_KEY(b) b->eattrs, b->hash
1399#define RBH_NEXT(b) b->next
1400#define RBH_EQ(a1,h1,a2,h2) h1 == h2 && ea_same(a1, a2)
1401#define RBH_FN(a,h) h
42a0c054 1402
d15b0b0a
OZ
1403#define RBH_REHASH bgp_rbh_rehash
1404#define RBH_PARAMS /8, *2, 2, 2, 8, 20
42a0c054 1405
42a0c054 1406
d15b0b0a 1407HASH_DEFINE_REHASH_FN(RBH, struct bgp_bucket)
66dbdbd9 1408
d15b0b0a
OZ
1409void
1410bgp_init_bucket_table(struct bgp_channel *c)
66dbdbd9 1411{
d15b0b0a 1412 HASH_INIT(c->bucket_hash, c->pool, 8);
66dbdbd9 1413
d15b0b0a
OZ
1414 init_list(&c->bucket_queue);
1415 c->withdraw_bucket = NULL;
ae8f5584
MM
1416}
1417
7fc55925
OZ
1418void
1419bgp_free_bucket_table(struct bgp_channel *c)
1420{
1421 HASH_FREE(c->bucket_hash);
1422
1423 struct bgp_bucket *b;
1424 WALK_LIST_FIRST(b, c->bucket_queue)
1425 {
1426 rem_node(&b->send_node);
1427 mb_free(b);
1428 }
1429
1430 mb_free(c->withdraw_bucket);
1431 c->withdraw_bucket = NULL;
1432}
1433
ae8f5584 1434static struct bgp_bucket *
d15b0b0a 1435bgp_get_bucket(struct bgp_channel *c, ea_list *new)
ae8f5584 1436{
d15b0b0a
OZ
1437 /* Hash and lookup */
1438 u32 hash = ea_hash(new);
1439 struct bgp_bucket *b = HASH_FIND(c->bucket_hash, RBH, new, hash);
1440
1441 if (b)
1442 return b;
1443
1444 uint ea_size = sizeof(ea_list) + new->count * sizeof(eattr);
1445 uint ea_size_aligned = BIRD_ALIGN(ea_size, CPU_STRUCT_ALIGN);
1446 uint size = sizeof(struct bgp_bucket) + ea_size_aligned;
1447 uint i;
ae8f5584 1448 byte *dest;
ae8f5584
MM
1449
1450 /* Gather total size of non-inline attributes */
d15b0b0a
OZ
1451 for (i = 0; i < new->count; i++)
1452 {
1453 eattr *a = &new->attrs[i];
ae8f5584 1454
d15b0b0a
OZ
1455 if (!(a->type & EAF_EMBEDDED))
1456 size += BIRD_ALIGN(sizeof(struct adata) + a->u.ptr->length, CPU_STRUCT_ALIGN);
1457 }
1458
1459 /* Create the bucket */
1460 b = mb_alloc(c->pool, size);
f421cfdd 1461 init_list(&b->prefixes);
d15b0b0a
OZ
1462 b->hash = hash;
1463
1464 /* Copy list of extended attributes */
ae8f5584 1465 memcpy(b->eattrs, new, ea_size);
d15b0b0a 1466 dest = ((byte *) b->eattrs) + ea_size_aligned;
ae8f5584
MM
1467
1468 /* Copy values of non-inline attributes */
d15b0b0a
OZ
1469 for (i = 0; i < new->count; i++)
1470 {
1471 eattr *a = &b->eattrs->attrs[i];
1472
1473 if (!(a->type & EAF_EMBEDDED))
ae8f5584 1474 {
4c553c5a 1475 const struct adata *oa = a->u.ptr;
d15b0b0a
OZ
1476 struct adata *na = (struct adata *) dest;
1477 memcpy(na, oa, sizeof(struct adata) + oa->length);
1478 a->u.ptr = na;
1479 dest += BIRD_ALIGN(sizeof(struct adata) + na->length, CPU_STRUCT_ALIGN);
ae8f5584 1480 }
d15b0b0a 1481 }
ae8f5584 1482
d15b0b0a
OZ
1483 /* Insert the bucket to send queue and bucket hash */
1484 add_tail(&c->bucket_queue, &b->send_node);
1485 HASH_INSERT2(c->bucket_hash, RBH, c->pool, b);
ae8f5584
MM
1486
1487 return b;
1488}
1489
1490static struct bgp_bucket *
d15b0b0a 1491bgp_get_withdraw_bucket(struct bgp_channel *c)
ae8f5584 1492{
d15b0b0a
OZ
1493 if (!c->withdraw_bucket)
1494 {
1495 c->withdraw_bucket = mb_allocz(c->pool, sizeof(struct bgp_bucket));
1496 init_list(&c->withdraw_bucket->prefixes);
1497 }
ae8f5584 1498
d15b0b0a
OZ
1499 return c->withdraw_bucket;
1500}
ae8f5584 1501
d15b0b0a
OZ
1502void
1503bgp_free_bucket(struct bgp_channel *c, struct bgp_bucket *b)
1504{
1505 rem_node(&b->send_node);
1506 HASH_REMOVE2(c->bucket_hash, RBH, c->pool, b);
1507 mb_free(b);
1508}
f421cfdd 1509
d15b0b0a
OZ
1510void
1511bgp_defer_bucket(struct bgp_channel *c, struct bgp_bucket *b)
1512{
1513 rem_node(&b->send_node);
1514 add_tail(&c->bucket_queue, &b->send_node);
ae8f5584
MM
1515}
1516
f421cfdd 1517void
d15b0b0a 1518bgp_withdraw_bucket(struct bgp_channel *c, struct bgp_bucket *b)
f421cfdd 1519{
d15b0b0a
OZ
1520 struct bgp_proto *p = (void *) c->c.proto;
1521 struct bgp_bucket *wb = bgp_get_withdraw_bucket(c);
1522
1523 log(L_ERR "%s: Attribute list too long", p->p.name);
1524 while (!EMPTY_LIST(b->prefixes))
1525 {
1526 struct bgp_prefix *px = HEAD(b->prefixes);
1527
1528 log(L_ERR "%s: - withdrawing %N", p->p.name, &px->net);
1529 rem_node(&px->buck_node);
1530 add_tail(&wb->prefixes, &px->buck_node);
1531 }
f421cfdd
MM
1532}
1533
094d2bdb 1534
d15b0b0a
OZ
1535/*
1536 * Prefix hash table
1537 */
094d2bdb 1538
d15b0b0a
OZ
1539#define PXH_KEY(px) px->net, px->path_id, px->hash
1540#define PXH_NEXT(px) px->next
1541#define PXH_EQ(n1,i1,h1,n2,i2,h2) h1 == h2 && i1 == i2 && net_equal(n1, n2)
1542#define PXH_FN(n,i,h) h
e7d2ac44
OZ
1543
1544#define PXH_REHASH bgp_pxh_rehash
026bfedb 1545#define PXH_PARAMS /8, *2, 2, 2, 8, 24
e7d2ac44 1546
094d2bdb 1547
e7d2ac44 1548HASH_DEFINE_REHASH_FN(PXH, struct bgp_prefix)
094d2bdb
OZ
1549
1550void
d15b0b0a 1551bgp_init_prefix_table(struct bgp_channel *c)
094d2bdb 1552{
d15b0b0a 1553 HASH_INIT(c->prefix_hash, c->pool, 8);
094d2bdb 1554
ac3ad139
OZ
1555 uint alen = net_addr_length[c->c.net_type];
1556 c->prefix_slab = alen ? sl_new(c->pool, sizeof(struct bgp_prefix) + alen) : NULL;
094d2bdb
OZ
1557}
1558
ed1a908e 1559void
c259669f 1560bgp_free_prefix_table(struct bgp_channel *c)
ed1a908e 1561{
c259669f 1562 HASH_FREE(c->prefix_hash);
ed1a908e 1563
c259669f
OZ
1564 rfree(c->prefix_slab);
1565 c->prefix_slab = NULL;
094d2bdb
OZ
1566}
1567
1568static struct bgp_prefix *
d15b0b0a 1569bgp_get_prefix(struct bgp_channel *c, net_addr *net, u32 path_id)
094d2bdb 1570{
d15b0b0a
OZ
1571 u32 hash = net_hash(net) ^ u32_hash(path_id);
1572 struct bgp_prefix *px = HASH_FIND(c->prefix_hash, PXH, net, path_id, hash);
094d2bdb 1573
d15b0b0a
OZ
1574 if (px)
1575 {
1576 rem_node(&px->buck_node);
1577 return px;
1578 }
094d2bdb 1579
ac3ad139
OZ
1580 if (c->prefix_slab)
1581 px = sl_alloc(c->prefix_slab);
1582 else
1583 px = mb_alloc(c->pool, sizeof(struct bgp_prefix) + net->length);
1584
d15b0b0a
OZ
1585 px->buck_node.next = NULL;
1586 px->buck_node.prev = NULL;
1587 px->hash = hash;
1588 px->path_id = path_id;
1589 net_copy(px->net, net);
094d2bdb 1590
d15b0b0a 1591 HASH_INSERT2(c->prefix_hash, PXH, c->pool, px);
094d2bdb 1592
d15b0b0a 1593 return px;
094d2bdb
OZ
1594}
1595
1596void
d15b0b0a 1597bgp_free_prefix(struct bgp_channel *c, struct bgp_prefix *px)
094d2bdb 1598{
d15b0b0a
OZ
1599 rem_node(&px->buck_node);
1600 HASH_REMOVE2(c->prefix_hash, PXH, c->pool, px);
ac3ad139
OZ
1601
1602 if (c->prefix_slab)
1603 sl_free(c->prefix_slab, px);
1604 else
1605 mb_free(px);
094d2bdb
OZ
1606}
1607
1608
d15b0b0a
OZ
1609/*
1610 * BGP protocol glue
1611 */
ef2c708d 1612
d15b0b0a 1613int
14375237 1614bgp_preexport(struct proto *P, rte **new, struct linpool *pool UNUSED)
ef2c708d 1615{
d15b0b0a
OZ
1616 rte *e = *new;
1617 struct proto *SRC = e->attrs->src->proto;
1618 struct bgp_proto *p = (struct bgp_proto *) P;
1619 struct bgp_proto *src = (SRC->proto == &proto_bgp) ? (struct bgp_proto *) SRC : NULL;
ef2c708d 1620
d15b0b0a
OZ
1621 /* Reject our routes */
1622 if (src == p)
1623 return -1;
4847a894 1624
d15b0b0a
OZ
1625 /* Accept non-BGP routes */
1626 if (src == NULL)
1627 return 0;
4847a894 1628
d15b0b0a
OZ
1629 /* IBGP route reflection, RFC 4456 */
1630 if (p->is_internal && src->is_internal && (p->local_as == src->local_as))
1631 {
1632 /* Rejected unless configured as route reflector */
1633 if (!p->rr_client && !src->rr_client)
1634 return -1;
1635
1636 /* Generally, this should be handled when path is received, but we check it
1637 also here as rr_cluster_id may be undefined or different in src. */
1638 if (p->rr_cluster_id && bgp_cluster_list_loopy(p, e->attrs->eattrs))
1639 return -1;
1640 }
1641
1642 /* Handle well-known communities, RFC 1997 */
1643 struct eattr *c;
1644 if (p->cf->interpret_communities &&
ee7e2ffd 1645 (c = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY))))
d15b0b0a 1646 {
4c553c5a 1647 const struct adata *d = c->u.ptr;
d15b0b0a
OZ
1648
1649 /* Do not export anywhere */
1650 if (int_set_contains(d, BGP_COMM_NO_ADVERTISE))
1651 return -1;
1652
1653 /* Do not export outside of AS (or member-AS) */
1654 if (!p->is_internal && int_set_contains(d, BGP_COMM_NO_EXPORT_SUBCONFED))
1655 return -1;
1656
1657 /* Do not export outside of AS (or confederation) */
1658 if (!p->is_interior && int_set_contains(d, BGP_COMM_NO_EXPORT))
1659 return -1;
5bd73431
OZ
1660
1661 /* Do not export LLGR_STALE routes to LLGR-ignorant peers */
1662 if (!p->conn->remote_caps->llgr_aware && int_set_contains(d, BGP_COMM_LLGR_STALE))
1663 return -1;
d15b0b0a 1664 }
4847a894 1665
d15b0b0a 1666 return 0;
4847a894
OZ
1667}
1668
d15b0b0a 1669static ea_list *
82f42ea0 1670bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *attrs0, struct linpool *pool)
ef2c708d 1671{
d15b0b0a
OZ
1672 struct proto *SRC = e->attrs->src->proto;
1673 struct bgp_proto *src = (SRC->proto == &proto_bgp) ? (void *) SRC : NULL;
1e37e35c 1674 struct bgp_export_state s = { .proto = p, .channel = c, .pool = pool, .src = src, .route = e, .mpls = c->desc->mpls };
82f42ea0 1675 ea_list *attrs = attrs0;
48e842cc 1676 eattr *a;
4c553c5a 1677 const adata *ad;
48e842cc 1678
d15b0b0a 1679 /* ORIGIN attribute - mandatory, attach if missing */
82f42ea0 1680 if (! bgp_find_attr(attrs0, BA_ORIGIN))
d15b0b0a
OZ
1681 bgp_set_attr_u32(&attrs, pool, BA_ORIGIN, 0, src ? ORIGIN_INCOMPLETE : ORIGIN_IGP);
1682
82f42ea0
OZ
1683 /* AS_PATH attribute - mandatory */
1684 a = bgp_find_attr(attrs0, BA_AS_PATH);
1685 ad = a ? a->u.ptr : &null_adata;
5509e17d
OZ
1686
1687 /* AS_PATH attribute - strip AS_CONFED* segments outside confederation */
1688 if ((!p->cf->confederation || !p->is_interior) && as_path_contains_confed(ad))
1689 ad = as_path_strip_confed(pool, ad);
1690
d15b0b0a 1691 /* AS_PATH attribute - keep or prepend ASN */
532116e7 1692 if (p->is_internal || p->rs_client)
d15b0b0a
OZ
1693 {
1694 /* IBGP or route server -> just ensure there is one */
5509e17d
OZ
1695 if (!a)
1696 bgp_set_attr_ptr(&attrs, pool, BA_AS_PATH, 0, &null_adata);
d15b0b0a
OZ
1697 }
1698 else if (p->is_interior)
1699 {
5509e17d
OZ
1700 /* Confederation -> prepend ASN as AS_CONFED_SEQUENCE */
1701 ad = as_path_prepend2(pool, ad, AS_PATH_CONFED_SEQUENCE, p->public_as);
1702 bgp_set_attr_ptr(&attrs, pool, BA_AS_PATH, 0, ad);
d15b0b0a
OZ
1703 }
1704 else /* Regular EBGP (no RS, no confederation) */
1705 {
5509e17d
OZ
1706 /* Regular EBGP -> prepend ASN as regular sequence */
1707 ad = as_path_prepend2(pool, ad, AS_PATH_SEQUENCE, p->public_as);
1708 bgp_set_attr_ptr(&attrs, pool, BA_AS_PATH, 0, ad);
d15b0b0a
OZ
1709
1710 /* MULTI_EXIT_DESC attribute - accept only if set in export filter */
82f42ea0 1711 a = bgp_find_attr(attrs0, BA_MULTI_EXIT_DISC);
d15b0b0a
OZ
1712 if (a && !(a->type & EAF_FRESH))
1713 bgp_unset_attr(&attrs, pool, BA_MULTI_EXIT_DISC);
1714 }
1715
1716 /* NEXT_HOP attribute - delegated to AF-specific hook */
82f42ea0 1717 a = bgp_find_attr(attrs0, BA_NEXT_HOP);
d15b0b0a
OZ
1718 bgp_update_next_hop(&s, a, &attrs);
1719
1720 /* LOCAL_PREF attribute - required for IBGP, attach if missing */
82f42ea0 1721 if (p->is_interior && ! bgp_find_attr(attrs0, BA_LOCAL_PREF))
d15b0b0a
OZ
1722 bgp_set_attr_u32(&attrs, pool, BA_LOCAL_PREF, 0, p->cf->default_local_pref);
1723
09ee846d
OZ
1724 /* AIGP attribute - accumulate local metric or originate new one */
1725 u64 metric;
1726 if (s.local_next_hop &&
1727 (bgp_total_aigp_metric_(e, &metric, &ad) ||
1728 (c->cf->aigp_originate && bgp_init_aigp_metric(e, &metric, &ad))))
1729 {
1730 ad = bgp_aigp_set_metric(pool, ad, metric);
1731 bgp_set_attr_ptr(&attrs, pool, BA_AIGP, 0, ad);
1732 }
1733
d15b0b0a
OZ
1734 /* IBGP route reflection, RFC 4456 */
1735 if (src && src->is_internal && p->is_internal && (src->local_as == p->local_as))
1736 {
1737 /* ORIGINATOR_ID attribute - attach if not already set */
82f42ea0 1738 if (! bgp_find_attr(attrs0, BA_ORIGINATOR_ID))
d15b0b0a
OZ
1739 bgp_set_attr_u32(&attrs, pool, BA_ORIGINATOR_ID, 0, src->remote_id);
1740
1741 /* CLUSTER_LIST attribute - prepend cluster ID */
82f42ea0
OZ
1742 a = bgp_find_attr(attrs0, BA_CLUSTER_LIST);
1743 ad = a ? a->u.ptr : NULL;
1744
1745 /* Prepend src cluster ID */
d15b0b0a 1746 if (src->rr_cluster_id)
c259669f 1747 ad = int_set_prepend(pool, ad, src->rr_cluster_id);
d15b0b0a 1748
82f42ea0 1749 /* Prepend dst cluster ID if src and dst clusters are different */
d15b0b0a 1750 if (p->rr_cluster_id && (src->rr_cluster_id != p->rr_cluster_id))
c259669f 1751 ad = int_set_prepend(pool, ad, p->rr_cluster_id);
82f42ea0
OZ
1752
1753 /* Should be at least one prepended cluster ID */
1754 bgp_set_attr_ptr(&attrs, pool, BA_CLUSTER_LIST, 0, ad);
d15b0b0a
OZ
1755 }
1756
1757 /* AS4_* transition attributes, RFC 6793 4.2.2 */
1758 if (! p->as4_session)
1759 {
1760 a = bgp_find_attr(attrs, BA_AS_PATH);
1761 if (a && as_path_contains_as4(a->u.ptr))
48e842cc 1762 {
d15b0b0a
OZ
1763 bgp_set_attr_ptr(&attrs, pool, BA_AS_PATH, 0, as_path_to_old(pool, a->u.ptr));
1764 bgp_set_attr_ptr(&attrs, pool, BA_AS4_PATH, 0, as_path_strip_confed(pool, a->u.ptr));
4847a894
OZ
1765 }
1766
d15b0b0a
OZ
1767 a = bgp_find_attr(attrs, BA_AGGREGATOR);
1768 if (a && aggregator_contains_as4(a->u.ptr))
4847a894 1769 {
d15b0b0a
OZ
1770 bgp_set_attr_ptr(&attrs, pool, BA_AGGREGATOR, 0, aggregator_to_old(pool, a->u.ptr));
1771 bgp_set_attr_ptr(&attrs, pool, BA_AS4_AGGREGATOR, 0, a->u.ptr);
48e842cc 1772 }
d15b0b0a 1773 }
ef2c708d 1774
82f42ea0
OZ
1775 /*
1776 * Presence of mandatory attributes ORIGIN and AS_PATH is ensured by above
1777 * conditions. Presence and validity of quasi-mandatory NEXT_HOP attribute
1778 * should be checked in AF-specific hooks.
1779 */
1780
d15b0b0a
OZ
1781 /* Apply per-attribute export hooks for validatation and normalization */
1782 return bgp_export_attrs(&s, attrs);
ef2c708d
MM
1783}
1784
d15b0b0a 1785void
13c0be19 1786bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old)
6cb8f742 1787{
d15b0b0a
OZ
1788 struct bgp_proto *p = (void *) P;
1789 struct bgp_channel *c = (void *) C;
1790 struct bgp_bucket *buck;
1791 struct bgp_prefix *px;
1792 u32 path;
6cb8f742 1793
d15b0b0a
OZ
1794 if (new)
1795 {
13c0be19 1796 struct ea_list *attrs = bgp_update_attrs(p, c, new, new->attrs->eattrs, bgp_linpool2);
6cb8f742 1797
d15b0b0a
OZ
1798 /* If attributes are invalid, we fail back to withdraw */
1799 buck = attrs ? bgp_get_bucket(c, attrs) : bgp_get_withdraw_bucket(c);
1800 path = new->attrs->src->global_id;
ef2c708d 1801
1e37e35c 1802 lp_flush(bgp_linpool2);
d15b0b0a 1803 }
ef2c708d 1804 else
d15b0b0a
OZ
1805 {
1806 buck = bgp_get_withdraw_bucket(c);
1807 path = old->attrs->src->global_id;
1808 }
1809
1810 px = bgp_get_prefix(c, n->n.addr, c->add_path_tx ? path : 0);
1811 add_tail(&buck->prefixes, &px->buck_node);
1812
1813 bgp_schedule_packet(p->conn, c, PKT_UPDATE);
ef2c708d
MM
1814}
1815
d15b0b0a 1816
b6bf284a
OZ
1817static inline u32
1818bgp_get_neighbor(rte *r)
1819{
ee7e2ffd 1820 eattr *e = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
b6bf284a
OZ
1821 u32 as;
1822
5509e17d 1823 if (e && as_path_get_first_regular(e->u.ptr, &as))
b6bf284a 1824 return as;
5509e17d
OZ
1825
1826 /* If AS_PATH is not defined, we treat rte as locally originated */
1827 struct bgp_proto *p = (void *) r->attrs->src->proto;
1828 return p->cf->confederation ?: p->local_as;
b6bf284a
OZ
1829}
1830
5bd73431
OZ
1831static inline int
1832rte_stale(rte *r)
1833{
1834 if (r->u.bgp.stale < 0)
1835 {
1836 /* If staleness is unknown, compute and cache it */
1837 eattr *a = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY));
1838 r->u.bgp.stale = a && int_set_contains(a->u.ptr, BGP_COMM_LLGR_STALE);
1839 }
1840
1841 return r->u.bgp.stale;
1842}
1843
ef2c708d
MM
1844int
1845bgp_rte_better(rte *new, rte *old)
1846{
094d2bdb
OZ
1847 struct bgp_proto *new_bgp = (struct bgp_proto *) new->attrs->src->proto;
1848 struct bgp_proto *old_bgp = (struct bgp_proto *) old->attrs->src->proto;
56a2bed4
MM
1849 eattr *x, *y;
1850 u32 n, o;
ef2c708d 1851
be4cd99a
OZ
1852 /* Skip suppressed routes (see bgp_rte_recalculate()) */
1853 n = new->u.bgp.suppressed;
1854 o = old->u.bgp.suppressed;
1855 if (n > o)
1856 return 0;
1857 if (n < o)
1858 return 1;
1859
ac3ac49a 1860 /* RFC 4271 9.1.2.1. Route resolvability test */
7e95c05d
OZ
1861 n = rte_resolvable(new);
1862 o = rte_resolvable(old);
ac3ac49a
OZ
1863 if (n > o)
1864 return 1;
1865 if (n < o)
1866 return 0;
1867
5bd73431
OZ
1868 /* LLGR draft - depreference stale routes */
1869 n = rte_stale(new);
1870 o = rte_stale(old);
1871 if (n > o)
1872 return 0;
1873 if (n < o)
1874 return 1;
1875
1876 /* Start with local preferences */
ee7e2ffd
JMM
1877 x = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF));
1878 y = ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF));
56a2bed4
MM
1879 n = x ? x->u.data : new_bgp->cf->default_local_pref;
1880 o = y ? y->u.data : old_bgp->cf->default_local_pref;
1881 if (n > o)
1882 return 1;
1883 if (n < o)
1884 return 0;
1885
09ee846d
OZ
1886 /* RFC 7311 4.1 - Apply AIGP metric */
1887 u64 n2 = bgp_total_aigp_metric(new);
1888 u64 o2 = bgp_total_aigp_metric(old);
1889 if (n2 < o2)
1890 return 1;
1891 if (n2 > o2)
1892 return 0;
1893
4847a894 1894 /* RFC 4271 9.1.2.2. a) Use AS path lengths */
56a2bed4 1895 if (new_bgp->cf->compare_path_lengths || old_bgp->cf->compare_path_lengths)
d15b0b0a 1896 {
ee7e2ffd
JMM
1897 x = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
1898 y = ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
d15b0b0a
OZ
1899 n = x ? as_path_getlen(x->u.ptr) : AS_PATH_MAXLEN;
1900 o = y ? as_path_getlen(y->u.ptr) : AS_PATH_MAXLEN;
1901 if (n < o)
1902 return 1;
1903 if (n > o)
1904 return 0;
1905 }
ef2c708d 1906
4847a894 1907 /* RFC 4271 9.1.2.2. b) Use origins */
ee7e2ffd
JMM
1908 x = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGIN));
1909 y = ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGIN));
cea63664
MM
1910 n = x ? x->u.data : ORIGIN_INCOMPLETE;
1911 o = y ? y->u.data : ORIGIN_INCOMPLETE;
56a2bed4
MM
1912 if (n < o)
1913 return 1;
1914 if (n > o)
1915 return 0;
1916
4847a894 1917 /* RFC 4271 9.1.2.2. c) Compare MED's */
be4cd99a
OZ
1918 /* Proper RFC 4271 path selection cannot be interpreted as finding
1919 * the best path in some ordering. It is implemented partially in
1920 * bgp_rte_recalculate() when deterministic_med option is
1921 * active. Without that option, the behavior is just an
1922 * approximation, which in specific situations may lead to
1923 * persistent routing loops, because it is nondeterministic - it
1924 * depends on the order in which routes appeared. But it is also the
1925 * same behavior as used by default in Cisco routers, so it is
1926 * probably not a big issue.
73272f04
OZ
1927 */
1928 if (new_bgp->cf->med_metric || old_bgp->cf->med_metric ||
1929 (bgp_get_neighbor(new) == bgp_get_neighbor(old)))
d15b0b0a 1930 {
ee7e2ffd
JMM
1931 x = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC));
1932 y = ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC));
d15b0b0a
OZ
1933 n = x ? x->u.data : new_bgp->cf->default_med;
1934 o = y ? y->u.data : old_bgp->cf->default_med;
1935 if (n < o)
1936 return 1;
1937 if (n > o)
1938 return 0;
1939 }
56a2bed4 1940
4847a894 1941 /* RFC 4271 9.1.2.2. d) Prefer external peers */
d15b0b0a 1942 if (new_bgp->is_interior > old_bgp->is_interior)
ef2c708d 1943 return 0;
d15b0b0a 1944 if (new_bgp->is_interior < old_bgp->is_interior)
ef2c708d 1945 return 1;
ef2c708d 1946
d1e146f2
OZ
1947 /* RFC 4271 9.1.2.2. e) Compare IGP metrics */
1948 n = new_bgp->cf->igp_metric ? new->attrs->igp_metric : 0;
1949 o = old_bgp->cf->igp_metric ? old->attrs->igp_metric : 0;
1950 if (n < o)
1951 return 1;
1952 if (n > o)
1953 return 0;
4847a894 1954
4847a894 1955 /* RFC 4271 9.1.2.2. f) Compare BGP identifiers */
d15b0b0a 1956 /* RFC 4456 9. a) Use ORIGINATOR_ID instead of local neighbor ID */
ee7e2ffd
JMM
1957 x = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID));
1958 y = ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID));
4847a894
OZ
1959 n = x ? x->u.data : new_bgp->remote_id;
1960 o = y ? y->u.data : old_bgp->remote_id;
3228c72c
OZ
1961
1962 /* RFC 5004 - prefer older routes */
1963 /* (if both are external and from different peer) */
1964 if ((new_bgp->cf->prefer_older || old_bgp->cf->prefer_older) &&
1965 !new_bgp->is_internal && n != o)
1966 return 0;
1967
1968 /* rest of RFC 4271 9.1.2.2. f) */
4847a894
OZ
1969 if (n < o)
1970 return 1;
1971 if (n > o)
1972 return 0;
11cb6202 1973
3075824d 1974 /* RFC 4456 9. b) Compare cluster list lengths */
ee7e2ffd
JMM
1975 x = ea_find(new->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_CLUSTER_LIST));
1976 y = ea_find(old->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_CLUSTER_LIST));
3075824d
OZ
1977 n = x ? int_set_get_size(x->u.ptr) : 0;
1978 o = y ? int_set_get_size(y->u.ptr) : 0;
1979 if (n < o)
1980 return 1;
1981 if (n > o)
1982 return 0;
1983
4847a894 1984 /* RFC 4271 9.1.2.2. g) Compare peer IP adresses */
a22c3e59 1985 return ipa_compare(new_bgp->remote_ip, old_bgp->remote_ip) < 0;
4847a894
OZ
1986}
1987
be4cd99a 1988
8d9eef17
OZ
1989int
1990bgp_rte_mergable(rte *pri, rte *sec)
1991{
1992 struct bgp_proto *pri_bgp = (struct bgp_proto *) pri->attrs->src->proto;
1993 struct bgp_proto *sec_bgp = (struct bgp_proto *) sec->attrs->src->proto;
1994 eattr *x, *y;
1995 u32 p, s;
1996
1997 /* Skip suppressed routes (see bgp_rte_recalculate()) */
1998 if (pri->u.bgp.suppressed != sec->u.bgp.suppressed)
1999 return 0;
2000
2001 /* RFC 4271 9.1.2.1. Route resolvability test */
f6a6a776 2002 if (rte_resolvable(pri) != rte_resolvable(sec))
8d9eef17
OZ
2003 return 0;
2004
5bd73431
OZ
2005 /* LLGR draft - depreference stale routes */
2006 if (rte_stale(pri) != rte_stale(sec))
2007 return 0;
2008
8d9eef17 2009 /* Start with local preferences */
ee7e2ffd
JMM
2010 x = ea_find(pri->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF));
2011 y = ea_find(sec->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_LOCAL_PREF));
8d9eef17
OZ
2012 p = x ? x->u.data : pri_bgp->cf->default_local_pref;
2013 s = y ? y->u.data : sec_bgp->cf->default_local_pref;
2014 if (p != s)
2015 return 0;
2016
2017 /* RFC 4271 9.1.2.2. a) Use AS path lengths */
2018 if (pri_bgp->cf->compare_path_lengths || sec_bgp->cf->compare_path_lengths)
d15b0b0a 2019 {
ee7e2ffd
JMM
2020 x = ea_find(pri->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
2021 y = ea_find(sec->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
d15b0b0a
OZ
2022 p = x ? as_path_getlen(x->u.ptr) : AS_PATH_MAXLEN;
2023 s = y ? as_path_getlen(y->u.ptr) : AS_PATH_MAXLEN;
8d9eef17 2024
d15b0b0a
OZ
2025 if (p != s)
2026 return 0;
8d9eef17 2027
d15b0b0a
OZ
2028// if (DELTA(p, s) > pri_bgp->cf->relax_multipath)
2029// return 0;
2030 }
8d9eef17
OZ
2031
2032 /* RFC 4271 9.1.2.2. b) Use origins */
ee7e2ffd
JMM
2033 x = ea_find(pri->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGIN));
2034 y = ea_find(sec->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGIN));
8d9eef17
OZ
2035 p = x ? x->u.data : ORIGIN_INCOMPLETE;
2036 s = y ? y->u.data : ORIGIN_INCOMPLETE;
2037 if (p != s)
2038 return 0;
2039
2040 /* RFC 4271 9.1.2.2. c) Compare MED's */
2041 if (pri_bgp->cf->med_metric || sec_bgp->cf->med_metric ||
2042 (bgp_get_neighbor(pri) == bgp_get_neighbor(sec)))
d15b0b0a 2043 {
ee7e2ffd
JMM
2044 x = ea_find(pri->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC));
2045 y = ea_find(sec->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_MULTI_EXIT_DISC));
d15b0b0a
OZ
2046 p = x ? x->u.data : pri_bgp->cf->default_med;
2047 s = y ? y->u.data : sec_bgp->cf->default_med;
2048 if (p != s)
2049 return 0;
2050 }
8d9eef17
OZ
2051
2052 /* RFC 4271 9.1.2.2. d) Prefer external peers */
5509e17d 2053 if (pri_bgp->is_interior != sec_bgp->is_interior)
8d9eef17
OZ
2054 return 0;
2055
2056 /* RFC 4271 9.1.2.2. e) Compare IGP metrics */
2057 p = pri_bgp->cf->igp_metric ? pri->attrs->igp_metric : 0;
2058 s = sec_bgp->cf->igp_metric ? sec->attrs->igp_metric : 0;
2059 if (p != s)
2060 return 0;
2061
2062 /* Remaining criteria are ignored */
2063
2064 return 1;
2065}
2066
2067
be4cd99a
OZ
2068static inline int
2069same_group(rte *r, u32 lpref, u32 lasn)
2070{
2071 return (r->pref == lpref) && (bgp_get_neighbor(r) == lasn);
2072}
2073
2074static inline int
2075use_deterministic_med(rte *r)
2076{
094d2bdb 2077 struct proto *P = r->attrs->src->proto;
26822d8f 2078 return (P->proto == &proto_bgp) && ((struct bgp_proto *) P)->cf->deterministic_med;
be4cd99a
OZ
2079}
2080
2081int
2082bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
2083{
2084 rte *r, *s;
2085 rte *key = new ? new : old;
2086 u32 lpref = key->pref;
2087 u32 lasn = bgp_get_neighbor(key);
f6a6a776 2088 int old_suppressed = old ? old->u.bgp.suppressed : 0;
be4cd99a
OZ
2089
2090 /*
2091 * Proper RFC 4271 path selection is a bit complicated, it cannot be
2092 * implemented just by rte_better(), because it is not a linear
2093 * ordering. But it can be splitted to two levels, where the lower
2094 * level chooses the best routes in each group of routes from the
2095 * same neighboring AS and higher level chooses the best route (with
2096 * a slightly different ordering) between the best-in-group routes.
2097 *
2098 * When deterministic_med is disabled, we just ignore this issue and
2099 * choose the best route by bgp_rte_better() alone. If enabled, the
2100 * lower level of the route selection is done here (for the group
2101 * to which the changed route belongs), all routes in group are
2102 * marked as suppressed, just chosen best-in-group is not.
2103 *
2104 * Global best route selection then implements higher level by
2105 * choosing between non-suppressed routes (as they are always
2106 * preferred over suppressed routes). Routes from BGP protocols
2107 * that do not set deterministic_med are just never suppressed. As
2108 * they do not participate in the lower level selection, it is OK
2109 * that this fn is not called for them.
2110 *
2111 * The idea is simple, the implementation is more problematic,
d15b0b0a 2112 * mostly because of optimizations in rte_recalculate() that
be4cd99a
OZ
2113 * avoids full recalculation in most cases.
2114 *
2115 * We can assume that at least one of new, old is non-NULL and both
2116 * are from the same protocol with enabled deterministic_med. We
2117 * group routes by both neighbor AS (lasn) and preference (lpref),
2118 * because bgp_rte_better() does not handle preference itself.
2119 */
2120
2121 /* If new and old are from different groups, we just process that
2122 as two independent events */
2123 if (new && old && !same_group(old, lpref, lasn))
d15b0b0a
OZ
2124 {
2125 int i1, i2;
2126 i1 = bgp_rte_recalculate(table, net, NULL, old, old_best);
2127 i2 = bgp_rte_recalculate(table, net, new, NULL, old_best);
2128 return i1 || i2;
2129 }
be4cd99a 2130
d15b0b0a 2131 /*
be4cd99a
OZ
2132 * We could find the best-in-group and then make some shortcuts like
2133 * in rte_recalculate, but as we would have to walk through all
2134 * net->routes just to find it, it is probably not worth. So we
f6a6a776 2135 * just have one simple fast case that use just the old route.
be4cd99a
OZ
2136 * We also set suppressed flag to avoid using it in bgp_rte_better().
2137 */
2138
2139 if (new)
2140 new->u.bgp.suppressed = 1;
2141
2142 if (old)
d15b0b0a 2143 {
d15b0b0a 2144 old->u.bgp.suppressed = 1;
d15b0b0a 2145
f6a6a776
OZ
2146 /* The fast case - replace not best with worse (or remove not best) */
2147 if (old_suppressed && !(new && bgp_rte_better(new, old)))
d15b0b0a 2148 return 0;
d15b0b0a 2149 }
be4cd99a
OZ
2150
2151 /* The default case - find a new best-in-group route */
2152 r = new; /* new may not be in the list */
cf98be7b 2153 for (s=net->routes; rte_is_valid(s); s=s->next)
be4cd99a 2154 if (use_deterministic_med(s) && same_group(s, lpref, lasn))
d15b0b0a
OZ
2155 {
2156 s->u.bgp.suppressed = 1;
2157 if (!r || bgp_rte_better(s, r))
2158 r = s;
2159 }
be4cd99a
OZ
2160
2161 /* Simple case - the last route in group disappears */
2162 if (!r)
2163 return 0;
2164
f6a6a776
OZ
2165 /* Found if new is mergable with best-in-group */
2166 if (new && (new != r) && bgp_rte_mergable(r, new))
2167 new->u.bgp.suppressed = 0;
2168
2169 /* Found all existing routes mergable with best-in-group */
2170 for (s=net->routes; rte_is_valid(s); s=s->next)
2171 if (use_deterministic_med(s) && same_group(s, lpref, lasn))
2172 if ((s != r) && bgp_rte_mergable(r, s))
2173 s->u.bgp.suppressed = 0;
2174
be4cd99a
OZ
2175 /* Found best-in-group */
2176 r->u.bgp.suppressed = 0;
2177
2178 /*
2179 * There are generally two reasons why we have to force
2180 * recalculation (return 1): First, the new route may be wrongfully
2181 * chosen to be the best in the first case check in
2182 * rte_recalculate(), this may happen only if old_best is from the
2183 * same group. Second, another (different than new route)
2184 * best-in-group is chosen and that may be the proper best (although
2185 * rte_recalculate() without ignore that possibility).
2186 *
2187 * There are three possible cases according to whether the old route
f6a6a776
OZ
2188 * was the best in group (OBG, i.e. !old_suppressed) and whether the
2189 * new route is the best in group (NBG, tested by r == new). These
2190 * cases work even if old or new is NULL.
be4cd99a
OZ
2191 *
2192 * NBG -> new is a possible candidate for the best route, so we just
2193 * check for the first reason using same_group().
2194 *
2195 * !NBG && OBG -> Second reason applies, return 1
2196 *
2197 * !NBG && !OBG -> Best in group does not change, old != old_best,
2198 * rte_better(new, old_best) is false and therefore
2199 * the first reason does not apply, return 0
2200 */
2201
2202 if (r == new)
2203 return old_best && same_group(old_best, lpref, lasn);
2204 else
f6a6a776 2205 return !old_suppressed;
be4cd99a
OZ
2206}
2207
5bd73431
OZ
2208struct rte *
2209bgp_rte_modify_stale(struct rte *r, struct linpool *pool)
2210{
2211 eattr *a = ea_find(r->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY));
4c553c5a 2212 const struct adata *ad = a ? a->u.ptr : NULL;
5bd73431
OZ
2213 uint flags = a ? a->flags : BAF_PARTIAL;
2214
2215 if (ad && int_set_contains(ad, BGP_COMM_NO_LLGR))
2216 return NULL;
2217
2218 if (ad && int_set_contains(ad, BGP_COMM_LLGR_STALE))
2219 return r;
2220
2221 r = rte_cow_rta(r, pool);
2222 bgp_set_attr_ptr(&(r->attrs->eattrs), pool, BA_COMMUNITY, flags,
2223 int_set_add(pool, ad, BGP_COMM_LLGR_STALE));
2224 r->u.bgp.stale = 1;
2225
2226 return r;
2227}
2228
11cb6202 2229
d15b0b0a
OZ
2230/*
2231 * Reconstruct AS_PATH and AGGREGATOR according to RFC 6793 4.2.3
11cb6202 2232 */
11cb6202 2233static void
d15b0b0a 2234bgp_process_as4_attrs(ea_list **attrs, struct linpool *pool)
11cb6202 2235{
d15b0b0a
OZ
2236 eattr *p2 = bgp_find_attr(*attrs, BA_AS_PATH);
2237 eattr *p4 = bgp_find_attr(*attrs, BA_AS4_PATH);
2238 eattr *a2 = bgp_find_attr(*attrs, BA_AGGREGATOR);
2239 eattr *a4 = bgp_find_attr(*attrs, BA_AS4_AGGREGATOR);
11cb6202 2240
d15b0b0a
OZ
2241 /* First, unset AS4_* attributes */
2242 if (p4) bgp_unset_attr(attrs, pool, BA_AS4_PATH);
2243 if (a4) bgp_unset_attr(attrs, pool, BA_AS4_AGGREGATOR);
c00d31be 2244
d15b0b0a
OZ
2245 /* Handle AGGREGATOR attribute */
2246 if (a2 && a4)
2247 {
2248 u32 a2_asn = get_u32(a2->u.ptr->data);
ef2c708d 2249
d15b0b0a
OZ
2250 /* If routes were aggregated by an old router, then AS4_PATH and
2251 AS4_AGGREGATOR are invalid. In that case we give up. */
2252 if (a2_asn != AS_TRANS)
2253 return;
f307842a 2254
d15b0b0a
OZ
2255 /* Use AS4_AGGREGATOR instead of AGGREGATOR */
2256 a2->u.ptr = a4->u.ptr;
2257 }
c00d31be 2258
d15b0b0a
OZ
2259 /* Handle AS_PATH attribute */
2260 if (p2 && p4)
2261 {
5509e17d 2262 /* Both as_path_getlen() and as_path_cut() take AS_CONFED* as zero length */
d15b0b0a
OZ
2263 int p2_len = as_path_getlen(p2->u.ptr);
2264 int p4_len = as_path_getlen(p4->u.ptr);
4847a894 2265
d15b0b0a
OZ
2266 /* AS_PATH is too short, give up */
2267 if (p2_len < p4_len)
2268 return;
c00d31be 2269
d15b0b0a 2270 /* Merge AS_PATH and AS4_PATH */
4c553c5a
MM
2271 struct adata *apc = as_path_cut(pool, p2->u.ptr, p2_len - p4_len);
2272 p2->u.ptr = as_path_merge(pool, apc, p4->u.ptr);
d15b0b0a 2273 }
c00d31be 2274}
10be74da
MM
2275
2276int
aebe06b4 2277bgp_get_attr(eattr *a, byte *buf, int buflen)
10be74da 2278{
ae80a2de 2279 uint i = EA_ID(a->id);
d15b0b0a 2280 const struct bgp_attr_desc *d;
6c4df703 2281 int len;
10be74da 2282
d15b0b0a
OZ
2283 if (bgp_attr_known(i))
2284 {
2285 d = &bgp_attr_table[i];
2286 len = bsprintf(buf, "%s", d->name);
2287 buf += len;
2288 if (d->format)
10be74da 2289 {
d15b0b0a
OZ
2290 *buf++ = ':';
2291 *buf++ = ' ';
2292 d->format(a, buf, buflen - len - 2);
2293 return GA_FULL;
10be74da 2294 }
d15b0b0a
OZ
2295 return GA_NAME;
2296 }
2297
d1a74339 2298 bsprintf(buf, "%02x%s", i, (a->flags & BAF_TRANSITIVE) ? " [t]" : "");
10be74da
MM
2299 return GA_NAME;
2300}
ae8f5584 2301
5e88d730 2302void
13c0be19 2303bgp_get_route_info(rte *e, byte *buf)
5e88d730 2304{
13c0be19
JMM
2305 eattr *p = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
2306 eattr *o = ea_find(e->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGIN));
11cb6202 2307 u32 origas;
5e88d730 2308
3ce17142
OZ
2309 buf += bsprintf(buf, " (%d", e->pref);
2310
be4cd99a 2311 if (e->u.bgp.suppressed)
3ce17142 2312 buf += bsprintf(buf, "-");
be4cd99a 2313
5bd73431
OZ
2314 if (rte_stale(e))
2315 buf += bsprintf(buf, "s");
2316
09ee846d
OZ
2317 u64 metric = bgp_total_aigp_metric(e);
2318 if (metric < BGP_AIGP_MAX)
2319 {
2320 buf += bsprintf(buf, "/%lu", metric);
2321 }
2322 else if (e->attrs->igp_metric)
d15b0b0a
OZ
2323 {
2324 if (!rte_resolvable(e))
2325 buf += bsprintf(buf, "/-");
2326 else if (e->attrs->igp_metric >= IGP_METRIC_UNKNOWN)
2327 buf += bsprintf(buf, "/?");
2328 else
2329 buf += bsprintf(buf, "/%d", e->attrs->igp_metric);
2330 }
d1e146f2
OZ
2331 buf += bsprintf(buf, ") [");
2332
52b9b2a1 2333 if (p && as_path_get_last(p->u.ptr, &origas))
11cb6202 2334 buf += bsprintf(buf, "AS%u", origas);
5e88d730
MM
2335 if (o)
2336 buf += bsprintf(buf, "%c", "ie?"[o->u.data]);
2337 strcpy(buf, "]");
2338}