Line data Source code
1 : /* BGP attributes management routines.
2 : * Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
3 : *
4 : * This file is part of GNU Zebra.
5 : *
6 : * GNU Zebra is free software; you can redistribute it and/or modify it
7 : * under the terms of the GNU General Public License as published by the
8 : * Free Software Foundation; either version 2, or (at your option) any
9 : * later version.
10 : *
11 : * GNU Zebra is distributed in the hope that it will be useful, but
12 : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License along
17 : * with this program; see the file COPYING; if not, write to the Free Software
18 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 : */
20 :
21 : #include <zebra.h>
22 :
23 : #include "linklist.h"
24 : #include "prefix.h"
25 : #include "memory.h"
26 : #include "vector.h"
27 : #include "stream.h"
28 : #include "log.h"
29 : #include "hash.h"
30 : #include "jhash.h"
31 : #include "queue.h"
32 : #include "table.h"
33 : #include "filter.h"
34 : #include "command.h"
35 : #include "srv6.h"
36 : #include "frrstr.h"
37 :
38 : #include "bgpd/bgpd.h"
39 : #include "bgpd/bgp_attr.h"
40 : #include "bgpd/bgp_route.h"
41 : #include "bgpd/bgp_aspath.h"
42 : #include "bgpd/bgp_community.h"
43 : #include "bgpd/bgp_debug.h"
44 : #include "bgpd/bgp_errors.h"
45 : #include "bgpd/bgp_label.h"
46 : #include "bgpd/bgp_packet.h"
47 : #include "bgpd/bgp_ecommunity.h"
48 : #include "bgpd/bgp_lcommunity.h"
49 : #include "bgpd/bgp_updgrp.h"
50 : #include "bgpd/bgp_encap_types.h"
51 : #ifdef ENABLE_BGP_VNC
52 : #include "bgpd/rfapi/bgp_rfapi_cfg.h"
53 : #include "bgp_encap_types.h"
54 : #include "bgp_vnc_types.h"
55 : #endif
56 : #include "bgp_evpn.h"
57 : #include "bgp_flowspec_private.h"
58 : #include "bgp_mac.h"
59 :
60 : /* Attribute strings for logging. */
61 : static const struct message attr_str[] = {
62 : {BGP_ATTR_ORIGIN, "ORIGIN"},
63 : {BGP_ATTR_AS_PATH, "AS_PATH"},
64 : {BGP_ATTR_NEXT_HOP, "NEXT_HOP"},
65 : {BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC"},
66 : {BGP_ATTR_LOCAL_PREF, "LOCAL_PREF"},
67 : {BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE"},
68 : {BGP_ATTR_AGGREGATOR, "AGGREGATOR"},
69 : {BGP_ATTR_COMMUNITIES, "COMMUNITY"},
70 : {BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID"},
71 : {BGP_ATTR_CLUSTER_LIST, "CLUSTER_LIST"},
72 : {BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI"},
73 : {BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI"},
74 : {BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES"},
75 : {BGP_ATTR_AS4_PATH, "AS4_PATH"},
76 : {BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR"},
77 : {BGP_ATTR_PMSI_TUNNEL, "PMSI_TUNNEL_ATTRIBUTE"},
78 : {BGP_ATTR_ENCAP, "ENCAP"},
79 : {BGP_ATTR_OTC, "OTC"},
80 : #ifdef ENABLE_BGP_VNC_ATTR
81 : {BGP_ATTR_VNC, "VNC"},
82 : #endif
83 : {BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY"},
84 : {BGP_ATTR_PREFIX_SID, "PREFIX_SID"},
85 : {BGP_ATTR_IPV6_EXT_COMMUNITIES, "IPV6_EXT_COMMUNITIES"},
86 : {BGP_ATTR_AIGP, "AIGP"},
87 : {0}};
88 :
89 : static const struct message attr_flag_str[] = {
90 : {BGP_ATTR_FLAG_OPTIONAL, "Optional"},
91 : {BGP_ATTR_FLAG_TRANS, "Transitive"},
92 : {BGP_ATTR_FLAG_PARTIAL, "Partial"},
93 : /* bgp_attr_flags_diagnose() relies on this bit being last in
94 : this list */
95 : {BGP_ATTR_FLAG_EXTLEN, "Extended Length"},
96 : {0}};
97 :
98 : static struct hash *cluster_hash;
99 :
100 0 : static void *cluster_hash_alloc(void *p)
101 : {
102 0 : const struct cluster_list *val = (const struct cluster_list *)p;
103 0 : struct cluster_list *cluster;
104 :
105 0 : cluster = XMALLOC(MTYPE_CLUSTER, sizeof(struct cluster_list));
106 0 : cluster->length = val->length;
107 :
108 0 : if (cluster->length) {
109 0 : cluster->list = XMALLOC(MTYPE_CLUSTER_VAL, val->length);
110 0 : memcpy(cluster->list, val->list, val->length);
111 : } else
112 0 : cluster->list = NULL;
113 :
114 0 : cluster->refcnt = 0;
115 :
116 0 : return cluster;
117 : }
118 :
119 : /* Cluster list related functions. */
120 0 : static struct cluster_list *cluster_parse(struct in_addr *pnt, int length)
121 : {
122 0 : struct cluster_list tmp = {};
123 0 : struct cluster_list *cluster;
124 :
125 0 : tmp.length = length;
126 0 : tmp.list = length == 0 ? NULL : pnt;
127 :
128 0 : cluster = hash_get(cluster_hash, &tmp, cluster_hash_alloc);
129 0 : cluster->refcnt++;
130 0 : return cluster;
131 : }
132 :
133 0 : bool cluster_loop_check(struct cluster_list *cluster, struct in_addr originator)
134 : {
135 0 : int i;
136 :
137 0 : for (i = 0; i < cluster->length / 4; i++)
138 0 : if (cluster->list[i].s_addr == originator.s_addr)
139 : return true;
140 : return false;
141 : }
142 :
143 0 : static unsigned int cluster_hash_key_make(const void *p)
144 : {
145 0 : const struct cluster_list *cluster = p;
146 :
147 0 : return jhash(cluster->list, cluster->length, 0);
148 : }
149 :
150 0 : static bool cluster_hash_cmp(const void *p1, const void *p2)
151 : {
152 0 : const struct cluster_list *cluster1 = p1;
153 0 : const struct cluster_list *cluster2 = p2;
154 :
155 0 : if (cluster1->list == cluster2->list)
156 : return true;
157 :
158 0 : if (!cluster1->list || !cluster2->list)
159 : return false;
160 :
161 0 : if (cluster1->length != cluster2->length)
162 : return false;
163 :
164 0 : return (memcmp(cluster1->list, cluster2->list, cluster1->length) == 0);
165 : }
166 :
167 0 : static void cluster_free(struct cluster_list *cluster)
168 : {
169 0 : XFREE(MTYPE_CLUSTER_VAL, cluster->list);
170 0 : XFREE(MTYPE_CLUSTER, cluster);
171 0 : }
172 :
173 0 : static struct cluster_list *cluster_intern(struct cluster_list *cluster)
174 : {
175 0 : struct cluster_list *find;
176 :
177 0 : find = hash_get(cluster_hash, cluster, cluster_hash_alloc);
178 0 : find->refcnt++;
179 :
180 0 : return find;
181 : }
182 :
183 0 : static void cluster_unintern(struct cluster_list **cluster)
184 : {
185 0 : if ((*cluster)->refcnt)
186 0 : (*cluster)->refcnt--;
187 :
188 0 : if ((*cluster)->refcnt == 0) {
189 0 : void *p = hash_release(cluster_hash, *cluster);
190 0 : assert(p == *cluster);
191 0 : cluster_free(*cluster);
192 0 : *cluster = NULL;
193 : }
194 0 : }
195 :
196 2 : static void cluster_init(void)
197 : {
198 2 : cluster_hash = hash_create(cluster_hash_key_make, cluster_hash_cmp,
199 : "BGP Cluster");
200 2 : }
201 :
202 2 : static void cluster_finish(void)
203 : {
204 2 : hash_clean(cluster_hash, (void (*)(void *))cluster_free);
205 2 : hash_free(cluster_hash);
206 2 : cluster_hash = NULL;
207 2 : }
208 :
209 : static struct hash *encap_hash = NULL;
210 : #ifdef ENABLE_BGP_VNC
211 : static struct hash *vnc_hash = NULL;
212 : #endif
213 : static struct hash *srv6_l3vpn_hash;
214 : static struct hash *srv6_vpn_hash;
215 :
216 0 : struct bgp_attr_encap_subtlv *encap_tlv_dup(struct bgp_attr_encap_subtlv *orig)
217 : {
218 0 : struct bgp_attr_encap_subtlv *new;
219 0 : struct bgp_attr_encap_subtlv *tail;
220 0 : struct bgp_attr_encap_subtlv *p;
221 :
222 0 : for (p = orig, tail = new = NULL; p; p = p->next) {
223 0 : int size = sizeof(struct bgp_attr_encap_subtlv) + p->length;
224 0 : if (tail) {
225 0 : tail->next = XCALLOC(MTYPE_ENCAP_TLV, size);
226 0 : tail = tail->next;
227 : } else {
228 0 : tail = new = XCALLOC(MTYPE_ENCAP_TLV, size);
229 : }
230 0 : assert(tail);
231 0 : memcpy(tail, p, size);
232 0 : tail->next = NULL;
233 : }
234 :
235 0 : return new;
236 : }
237 :
238 0 : static void encap_free(struct bgp_attr_encap_subtlv *p)
239 : {
240 0 : struct bgp_attr_encap_subtlv *next;
241 0 : while (p) {
242 0 : next = p->next;
243 0 : p->next = NULL;
244 0 : XFREE(MTYPE_ENCAP_TLV, p);
245 0 : p = next;
246 : }
247 0 : }
248 :
249 0 : void bgp_attr_flush_encap(struct attr *attr)
250 : {
251 0 : if (!attr)
252 : return;
253 :
254 0 : if (attr->encap_subtlvs) {
255 0 : encap_free(attr->encap_subtlvs);
256 0 : attr->encap_subtlvs = NULL;
257 : }
258 : #ifdef ENABLE_BGP_VNC
259 0 : struct bgp_attr_encap_subtlv *vnc_subtlvs =
260 0 : bgp_attr_get_vnc_subtlvs(attr);
261 :
262 0 : if (vnc_subtlvs) {
263 0 : encap_free(vnc_subtlvs);
264 0 : bgp_attr_set_vnc_subtlvs(attr, NULL);
265 : }
266 : #endif
267 : }
268 :
269 : /*
270 : * Compare encap sub-tlv chains
271 : *
272 : * 1 = equivalent
273 : * 0 = not equivalent
274 : *
275 : * This algorithm could be made faster if needed
276 : */
277 36 : static bool encap_same(const struct bgp_attr_encap_subtlv *h1,
278 : const struct bgp_attr_encap_subtlv *h2)
279 : {
280 36 : const struct bgp_attr_encap_subtlv *p;
281 36 : const struct bgp_attr_encap_subtlv *q;
282 :
283 36 : if (h1 == h2)
284 : return true;
285 0 : if (h1 == NULL || h2 == NULL)
286 : return false;
287 :
288 0 : for (p = h1; p; p = p->next) {
289 0 : for (q = h2; q; q = q->next) {
290 0 : if ((p->type == q->type) && (p->length == q->length)
291 0 : && !memcmp(p->value, q->value, p->length)) {
292 :
293 : break;
294 : }
295 : }
296 0 : if (!q)
297 : return false;
298 : }
299 :
300 0 : for (p = h2; p; p = p->next) {
301 0 : for (q = h1; q; q = q->next) {
302 0 : if ((p->type == q->type) && (p->length == q->length)
303 0 : && !memcmp(p->value, q->value, p->length)) {
304 :
305 : break;
306 : }
307 : }
308 0 : if (!q)
309 : return false;
310 : }
311 :
312 : return true;
313 : }
314 :
315 0 : static void *encap_hash_alloc(void *p)
316 : {
317 : /* Encap structure is already allocated. */
318 0 : return p;
319 : }
320 :
321 : typedef enum {
322 : ENCAP_SUBTLV_TYPE,
323 : #ifdef ENABLE_BGP_VNC
324 : VNC_SUBTLV_TYPE
325 : #endif
326 : } encap_subtlv_type;
327 :
328 : static struct bgp_attr_encap_subtlv *
329 0 : encap_intern(struct bgp_attr_encap_subtlv *encap, encap_subtlv_type type)
330 : {
331 0 : struct bgp_attr_encap_subtlv *find;
332 0 : struct hash *hash = encap_hash;
333 : #ifdef ENABLE_BGP_VNC
334 0 : if (type == VNC_SUBTLV_TYPE)
335 0 : hash = vnc_hash;
336 : #endif
337 :
338 0 : find = hash_get(hash, encap, encap_hash_alloc);
339 0 : if (find != encap)
340 0 : encap_free(encap);
341 0 : find->refcnt++;
342 :
343 0 : return find;
344 : }
345 :
346 0 : static void encap_unintern(struct bgp_attr_encap_subtlv **encapp,
347 : encap_subtlv_type type)
348 : {
349 0 : struct bgp_attr_encap_subtlv *encap = *encapp;
350 0 : if (encap->refcnt)
351 0 : encap->refcnt--;
352 :
353 0 : if (encap->refcnt == 0) {
354 0 : struct hash *hash = encap_hash;
355 : #ifdef ENABLE_BGP_VNC
356 0 : if (type == VNC_SUBTLV_TYPE)
357 0 : hash = vnc_hash;
358 : #endif
359 0 : hash_release(hash, encap);
360 0 : encap_free(encap);
361 0 : *encapp = NULL;
362 : }
363 0 : }
364 :
365 0 : static unsigned int encap_hash_key_make(const void *p)
366 : {
367 0 : const struct bgp_attr_encap_subtlv *encap = p;
368 :
369 0 : return jhash(encap->value, encap->length, 0);
370 : }
371 :
372 0 : static bool encap_hash_cmp(const void *p1, const void *p2)
373 : {
374 0 : return encap_same((const struct bgp_attr_encap_subtlv *)p1,
375 : (const struct bgp_attr_encap_subtlv *)p2);
376 : }
377 :
378 2 : static void encap_init(void)
379 : {
380 2 : encap_hash = hash_create(encap_hash_key_make, encap_hash_cmp,
381 : "BGP Encap Hash");
382 : #ifdef ENABLE_BGP_VNC
383 2 : vnc_hash = hash_create(encap_hash_key_make, encap_hash_cmp,
384 : "BGP VNC Hash");
385 : #endif
386 2 : }
387 :
388 2 : static void encap_finish(void)
389 : {
390 2 : hash_clean(encap_hash, (void (*)(void *))encap_free);
391 2 : hash_free(encap_hash);
392 2 : encap_hash = NULL;
393 : #ifdef ENABLE_BGP_VNC
394 2 : hash_clean(vnc_hash, (void (*)(void *))encap_free);
395 2 : hash_free(vnc_hash);
396 2 : vnc_hash = NULL;
397 : #endif
398 2 : }
399 :
400 18 : static bool overlay_index_same(const struct attr *a1, const struct attr *a2)
401 : {
402 18 : if (!a1 && a2)
403 : return false;
404 18 : if (!a2 && a1)
405 : return false;
406 18 : if (!a1 && !a2)
407 : return true;
408 :
409 18 : return bgp_route_evpn_same(bgp_attr_get_evpn_overlay(a1),
410 : bgp_attr_get_evpn_overlay(a2));
411 : }
412 :
413 : /* Unknown transit attribute. */
414 : static struct hash *transit_hash;
415 :
416 0 : static void transit_free(struct transit *transit)
417 : {
418 0 : XFREE(MTYPE_TRANSIT_VAL, transit->val);
419 0 : XFREE(MTYPE_TRANSIT, transit);
420 0 : }
421 :
422 0 : static void *transit_hash_alloc(void *p)
423 : {
424 : /* Transit structure is already allocated. */
425 0 : return p;
426 : }
427 :
428 0 : static struct transit *transit_intern(struct transit *transit)
429 : {
430 0 : struct transit *find;
431 :
432 0 : find = hash_get(transit_hash, transit, transit_hash_alloc);
433 0 : if (find != transit)
434 0 : transit_free(transit);
435 0 : find->refcnt++;
436 :
437 0 : return find;
438 : }
439 :
440 0 : static void transit_unintern(struct transit **transit)
441 : {
442 0 : if ((*transit)->refcnt)
443 0 : (*transit)->refcnt--;
444 :
445 0 : if ((*transit)->refcnt == 0) {
446 0 : hash_release(transit_hash, *transit);
447 0 : transit_free(*transit);
448 0 : *transit = NULL;
449 : }
450 0 : }
451 :
452 0 : static bool bgp_attr_aigp_get_tlv_metric(uint8_t *pnt, int length,
453 : uint64_t *aigp)
454 : {
455 0 : uint8_t *data = pnt;
456 0 : uint8_t tlv_type;
457 0 : uint16_t tlv_length;
458 :
459 0 : while (length) {
460 0 : tlv_type = *data;
461 0 : ptr_get_be16(data + 1, &tlv_length);
462 0 : (void)data;
463 :
464 : /* The value field of the AIGP TLV is always 8 octets
465 : * long and its value is interpreted as an unsigned 64-bit
466 : * integer.
467 : */
468 0 : if (tlv_type == BGP_AIGP_TLV_METRIC) {
469 0 : (void)ptr_get_be64(data + 3, aigp);
470 :
471 : /* If an AIGP attribute is received and its first AIGP
472 : * TLV contains the maximum value 0xffffffffffffffff,
473 : * the attribute SHOULD be considered to be malformed
474 : * and SHOULD be discarded as specified in this section.
475 : */
476 0 : if (*aigp == BGP_AIGP_TLV_METRIC_MAX) {
477 0 : zlog_err("Bad AIGP TLV (%s) length: %llu",
478 : BGP_AIGP_TLV_METRIC_DESC,
479 : BGP_AIGP_TLV_METRIC_MAX);
480 0 : return false;
481 : }
482 :
483 : return true;
484 : }
485 :
486 0 : data += tlv_length;
487 0 : length -= tlv_length;
488 : }
489 :
490 : return false;
491 : }
492 :
493 0 : static uint64_t bgp_aigp_metric_total(struct bgp_path_info *bpi)
494 : {
495 0 : uint64_t aigp = bgp_attr_get_aigp_metric(bpi->attr);
496 :
497 0 : if (bpi->nexthop)
498 0 : return aigp + bpi->nexthop->metric;
499 : else
500 : return aigp;
501 : }
502 :
503 0 : static void stream_put_bgp_aigp_tlv_metric(struct stream *s,
504 : struct bgp_path_info *bpi)
505 : {
506 0 : stream_putc(s, BGP_AIGP_TLV_METRIC);
507 0 : stream_putw(s, BGP_AIGP_TLV_METRIC_LEN);
508 0 : stream_putq(s, bgp_aigp_metric_total(bpi));
509 0 : }
510 :
511 0 : static bool bgp_attr_aigp_valid(uint8_t *pnt, int length)
512 : {
513 0 : uint8_t *data = pnt;
514 0 : uint8_t tlv_type;
515 0 : uint16_t tlv_length;
516 :
517 0 : if (length < 3) {
518 0 : zlog_err("Bad AIGP attribute length (MUST be minimum 3): %u",
519 : length);
520 0 : return false;
521 : }
522 :
523 0 : while (length) {
524 0 : tlv_type = *data;
525 0 : ptr_get_be16(data + 1, &tlv_length);
526 0 : (void)data;
527 :
528 0 : if (length < tlv_length) {
529 0 : zlog_err(
530 : "Bad AIGP attribute length: %u, but TLV length: %u",
531 : length, tlv_length);
532 0 : return false;
533 : }
534 :
535 0 : if (tlv_length < 3) {
536 0 : zlog_err("Bad AIGP TLV length (MUST be minimum 3): %u",
537 : tlv_length);
538 0 : return false;
539 : }
540 :
541 : /* AIGP TLV, Length: 11 */
542 0 : if (tlv_type == BGP_AIGP_TLV_METRIC &&
543 : tlv_length != BGP_AIGP_TLV_METRIC_LEN) {
544 0 : zlog_err("Bad AIGP TLV (%s) length: %u",
545 : BGP_AIGP_TLV_METRIC_DESC, tlv_length);
546 0 : return false;
547 : }
548 :
549 0 : data += tlv_length;
550 0 : length -= tlv_length;
551 : }
552 :
553 : return true;
554 : }
555 :
556 0 : static void *srv6_l3vpn_hash_alloc(void *p)
557 : {
558 0 : return p;
559 : }
560 :
561 0 : static void srv6_l3vpn_free(struct bgp_attr_srv6_l3vpn *l3vpn)
562 : {
563 0 : XFREE(MTYPE_BGP_SRV6_L3VPN, l3vpn);
564 0 : }
565 :
566 : static struct bgp_attr_srv6_l3vpn *
567 0 : srv6_l3vpn_intern(struct bgp_attr_srv6_l3vpn *l3vpn)
568 : {
569 0 : struct bgp_attr_srv6_l3vpn *find;
570 :
571 0 : find = hash_get(srv6_l3vpn_hash, l3vpn, srv6_l3vpn_hash_alloc);
572 0 : if (find != l3vpn)
573 0 : srv6_l3vpn_free(l3vpn);
574 0 : find->refcnt++;
575 0 : return find;
576 : }
577 :
578 0 : static void srv6_l3vpn_unintern(struct bgp_attr_srv6_l3vpn **l3vpnp)
579 : {
580 0 : struct bgp_attr_srv6_l3vpn *l3vpn = *l3vpnp;
581 :
582 0 : if (l3vpn->refcnt)
583 0 : l3vpn->refcnt--;
584 :
585 0 : if (l3vpn->refcnt == 0) {
586 0 : hash_release(srv6_l3vpn_hash, l3vpn);
587 0 : srv6_l3vpn_free(l3vpn);
588 0 : *l3vpnp = NULL;
589 : }
590 0 : }
591 :
592 0 : static void *srv6_vpn_hash_alloc(void *p)
593 : {
594 0 : return p;
595 : }
596 :
597 0 : static void srv6_vpn_free(struct bgp_attr_srv6_vpn *vpn)
598 : {
599 0 : XFREE(MTYPE_BGP_SRV6_VPN, vpn);
600 0 : }
601 :
602 0 : static struct bgp_attr_srv6_vpn *srv6_vpn_intern(struct bgp_attr_srv6_vpn *vpn)
603 : {
604 0 : struct bgp_attr_srv6_vpn *find;
605 :
606 0 : find = hash_get(srv6_vpn_hash, vpn, srv6_vpn_hash_alloc);
607 0 : if (find != vpn)
608 0 : srv6_vpn_free(vpn);
609 0 : find->refcnt++;
610 0 : return find;
611 : }
612 :
613 0 : static void srv6_vpn_unintern(struct bgp_attr_srv6_vpn **vpnp)
614 : {
615 0 : struct bgp_attr_srv6_vpn *vpn = *vpnp;
616 :
617 0 : if (vpn->refcnt)
618 0 : vpn->refcnt--;
619 :
620 0 : if (vpn->refcnt == 0) {
621 0 : hash_release(srv6_vpn_hash, vpn);
622 0 : srv6_vpn_free(vpn);
623 0 : *vpnp = NULL;
624 : }
625 0 : }
626 :
627 0 : static uint32_t srv6_l3vpn_hash_key_make(const void *p)
628 : {
629 0 : const struct bgp_attr_srv6_l3vpn *l3vpn = p;
630 0 : uint32_t key = 0;
631 :
632 0 : key = jhash(&l3vpn->sid, 16, key);
633 0 : key = jhash_1word(l3vpn->sid_flags, key);
634 0 : key = jhash_1word(l3vpn->endpoint_behavior, key);
635 0 : key = jhash_1word(l3vpn->loc_block_len, key);
636 0 : key = jhash_1word(l3vpn->loc_node_len, key);
637 0 : key = jhash_1word(l3vpn->func_len, key);
638 0 : key = jhash_1word(l3vpn->arg_len, key);
639 0 : key = jhash_1word(l3vpn->transposition_len, key);
640 0 : key = jhash_1word(l3vpn->transposition_offset, key);
641 0 : return key;
642 : }
643 :
644 0 : static bool srv6_l3vpn_hash_cmp(const void *p1, const void *p2)
645 : {
646 0 : const struct bgp_attr_srv6_l3vpn *l3vpn1 = p1;
647 0 : const struct bgp_attr_srv6_l3vpn *l3vpn2 = p2;
648 :
649 0 : return sid_same(&l3vpn1->sid, &l3vpn2->sid)
650 : && l3vpn1->sid_flags == l3vpn2->sid_flags
651 0 : && l3vpn1->endpoint_behavior == l3vpn2->endpoint_behavior
652 : && l3vpn1->loc_block_len == l3vpn2->loc_block_len
653 : && l3vpn1->loc_node_len == l3vpn2->loc_node_len
654 : && l3vpn1->func_len == l3vpn2->func_len
655 0 : && l3vpn1->arg_len == l3vpn2->arg_len
656 : && l3vpn1->transposition_len == l3vpn2->transposition_len
657 0 : && l3vpn1->transposition_offset == l3vpn2->transposition_offset;
658 : }
659 :
660 18 : static bool srv6_l3vpn_same(const struct bgp_attr_srv6_l3vpn *h1,
661 : const struct bgp_attr_srv6_l3vpn *h2)
662 : {
663 18 : if (h1 == h2)
664 : return true;
665 0 : else if (h1 == NULL || h2 == NULL)
666 : return false;
667 : else
668 0 : return srv6_l3vpn_hash_cmp((const void *)h1, (const void *)h2);
669 : }
670 :
671 0 : static unsigned int srv6_vpn_hash_key_make(const void *p)
672 : {
673 0 : const struct bgp_attr_srv6_vpn *vpn = p;
674 0 : uint32_t key = 0;
675 :
676 0 : key = jhash(&vpn->sid, 16, key);
677 0 : key = jhash_1word(vpn->sid_flags, key);
678 0 : return key;
679 : }
680 :
681 0 : static bool srv6_vpn_hash_cmp(const void *p1, const void *p2)
682 : {
683 0 : const struct bgp_attr_srv6_vpn *vpn1 = p1;
684 0 : const struct bgp_attr_srv6_vpn *vpn2 = p2;
685 :
686 0 : return sid_same(&vpn1->sid, &vpn2->sid)
687 0 : && vpn1->sid_flags == vpn2->sid_flags;
688 : }
689 :
690 18 : static bool srv6_vpn_same(const struct bgp_attr_srv6_vpn *h1,
691 : const struct bgp_attr_srv6_vpn *h2)
692 : {
693 18 : if (h1 == h2)
694 : return true;
695 0 : else if (h1 == NULL || h2 == NULL)
696 : return false;
697 : else
698 0 : return srv6_vpn_hash_cmp((const void *)h1, (const void *)h2);
699 : }
700 :
701 2 : static void srv6_init(void)
702 : {
703 4 : srv6_l3vpn_hash =
704 2 : hash_create(srv6_l3vpn_hash_key_make, srv6_l3vpn_hash_cmp,
705 : "BGP Prefix-SID SRv6-L3VPN-Service-TLV");
706 2 : srv6_vpn_hash = hash_create(srv6_vpn_hash_key_make, srv6_vpn_hash_cmp,
707 : "BGP Prefix-SID SRv6-VPN-Service-TLV");
708 2 : }
709 :
710 2 : static void srv6_finish(void)
711 : {
712 2 : hash_clean(srv6_l3vpn_hash, (void (*)(void *))srv6_l3vpn_free);
713 2 : hash_free(srv6_l3vpn_hash);
714 2 : srv6_l3vpn_hash = NULL;
715 2 : hash_clean(srv6_vpn_hash, (void (*)(void *))srv6_vpn_free);
716 2 : hash_free(srv6_vpn_hash);
717 2 : srv6_vpn_hash = NULL;
718 2 : }
719 :
720 0 : static unsigned int transit_hash_key_make(const void *p)
721 : {
722 0 : const struct transit *transit = p;
723 :
724 0 : return jhash(transit->val, transit->length, 0);
725 : }
726 :
727 0 : static bool transit_hash_cmp(const void *p1, const void *p2)
728 : {
729 0 : const struct transit *transit1 = p1;
730 0 : const struct transit *transit2 = p2;
731 :
732 0 : return (transit1->length == transit2->length
733 0 : && memcmp(transit1->val, transit2->val, transit1->length) == 0);
734 : }
735 :
736 2 : static void transit_init(void)
737 : {
738 2 : transit_hash = hash_create(transit_hash_key_make, transit_hash_cmp,
739 : "BGP Transit Hash");
740 2 : }
741 :
742 2 : static void transit_finish(void)
743 : {
744 2 : hash_clean(transit_hash, (void (*)(void *))transit_free);
745 2 : hash_free(transit_hash);
746 2 : transit_hash = NULL;
747 2 : }
748 :
749 : /* Attribute hash routines. */
750 : static struct hash *attrhash;
751 :
752 0 : unsigned long int attr_count(void)
753 : {
754 0 : return attrhash->count;
755 : }
756 :
757 0 : unsigned long int attr_unknown_count(void)
758 : {
759 0 : return transit_hash->count;
760 : }
761 :
762 28 : unsigned int attrhash_key_make(const void *p)
763 : {
764 28 : const struct attr *attr = (struct attr *)p;
765 28 : uint32_t key = 0;
766 : #define MIX(val) key = jhash_1word(val, key)
767 : #define MIX3(a, b, c) key = jhash_3words((a), (b), (c), key)
768 :
769 28 : MIX3(attr->origin, attr->nexthop.s_addr, attr->med);
770 28 : MIX3(attr->local_pref, attr->aggregator_as,
771 : attr->aggregator_addr.s_addr);
772 28 : MIX3(attr->weight, attr->mp_nexthop_global_in.s_addr,
773 : attr->originator_id.s_addr);
774 28 : MIX3(attr->tag, attr->label, attr->label_index);
775 :
776 28 : if (attr->aspath)
777 28 : MIX(aspath_key_make(attr->aspath));
778 28 : if (bgp_attr_get_community(attr))
779 0 : MIX(community_hash_make(bgp_attr_get_community(attr)));
780 28 : if (bgp_attr_get_lcommunity(attr))
781 0 : MIX(lcommunity_hash_make(bgp_attr_get_lcommunity(attr)));
782 28 : if (bgp_attr_get_ecommunity(attr))
783 0 : MIX(ecommunity_hash_make(bgp_attr_get_ecommunity(attr)));
784 28 : if (bgp_attr_get_ipv6_ecommunity(attr))
785 0 : MIX(ecommunity_hash_make(bgp_attr_get_ipv6_ecommunity(attr)));
786 28 : if (bgp_attr_get_cluster(attr))
787 0 : MIX(cluster_hash_key_make(bgp_attr_get_cluster(attr)));
788 28 : if (bgp_attr_get_transit(attr))
789 0 : MIX(transit_hash_key_make(bgp_attr_get_transit(attr)));
790 28 : if (attr->encap_subtlvs)
791 0 : MIX(encap_hash_key_make(attr->encap_subtlvs));
792 28 : if (attr->srv6_l3vpn)
793 0 : MIX(srv6_l3vpn_hash_key_make(attr->srv6_l3vpn));
794 28 : if (attr->srv6_vpn)
795 0 : MIX(srv6_vpn_hash_key_make(attr->srv6_vpn));
796 : #ifdef ENABLE_BGP_VNC
797 28 : struct bgp_attr_encap_subtlv *vnc_subtlvs =
798 28 : bgp_attr_get_vnc_subtlvs(attr);
799 28 : if (vnc_subtlvs)
800 0 : MIX(encap_hash_key_make(vnc_subtlvs));
801 : #endif
802 28 : MIX(attr->mp_nexthop_len);
803 28 : key = jhash(attr->mp_nexthop_global.s6_addr, IPV6_MAX_BYTELEN, key);
804 28 : key = jhash(attr->mp_nexthop_local.s6_addr, IPV6_MAX_BYTELEN, key);
805 28 : MIX3(attr->nh_ifindex, attr->nh_lla_ifindex, attr->distance);
806 28 : MIX(attr->rmap_table_id);
807 28 : MIX(attr->nh_type);
808 28 : MIX(attr->bh_type);
809 28 : MIX(attr->otc);
810 28 : MIX(bgp_attr_get_aigp_metric(attr));
811 :
812 28 : return key;
813 : }
814 :
815 18 : bool attrhash_cmp(const void *p1, const void *p2)
816 : {
817 18 : const struct attr *attr1 = p1;
818 18 : const struct attr *attr2 = p2;
819 :
820 18 : if (attr1->flag == attr2->flag && attr1->origin == attr2->origin
821 18 : && attr1->nexthop.s_addr == attr2->nexthop.s_addr
822 18 : && attr1->aspath == attr2->aspath
823 18 : && bgp_attr_get_community(attr1)
824 18 : == bgp_attr_get_community(attr2)
825 18 : && attr1->med == attr2->med
826 18 : && attr1->local_pref == attr2->local_pref
827 18 : && attr1->rmap_change_flags == attr2->rmap_change_flags) {
828 18 : if (attr1->aggregator_as == attr2->aggregator_as
829 18 : && attr1->aggregator_addr.s_addr
830 18 : == attr2->aggregator_addr.s_addr
831 18 : && attr1->weight == attr2->weight
832 18 : && attr1->tag == attr2->tag
833 18 : && attr1->label_index == attr2->label_index
834 18 : && attr1->mp_nexthop_len == attr2->mp_nexthop_len
835 18 : && bgp_attr_get_ecommunity(attr1)
836 18 : == bgp_attr_get_ecommunity(attr2)
837 18 : && bgp_attr_get_ipv6_ecommunity(attr1)
838 18 : == bgp_attr_get_ipv6_ecommunity(attr2)
839 18 : && bgp_attr_get_lcommunity(attr1)
840 18 : == bgp_attr_get_lcommunity(attr2)
841 18 : && bgp_attr_get_cluster(attr1)
842 18 : == bgp_attr_get_cluster(attr2)
843 18 : && bgp_attr_get_transit(attr1)
844 18 : == bgp_attr_get_transit(attr2)
845 18 : && bgp_attr_get_aigp_metric(attr1)
846 18 : == bgp_attr_get_aigp_metric(attr2)
847 18 : && attr1->rmap_table_id == attr2->rmap_table_id
848 18 : && (attr1->encap_tunneltype == attr2->encap_tunneltype)
849 18 : && encap_same(attr1->encap_subtlvs, attr2->encap_subtlvs)
850 : #ifdef ENABLE_BGP_VNC
851 18 : && encap_same(bgp_attr_get_vnc_subtlvs(attr1),
852 18 : bgp_attr_get_vnc_subtlvs(attr2))
853 : #endif
854 18 : && IPV6_ADDR_SAME(&attr1->mp_nexthop_global,
855 : &attr2->mp_nexthop_global)
856 18 : && IPV6_ADDR_SAME(&attr1->mp_nexthop_local,
857 : &attr2->mp_nexthop_local)
858 18 : && IPV4_ADDR_SAME(&attr1->mp_nexthop_global_in,
859 : &attr2->mp_nexthop_global_in)
860 18 : && IPV4_ADDR_SAME(&attr1->originator_id,
861 : &attr2->originator_id)
862 18 : && overlay_index_same(attr1, attr2)
863 18 : && !memcmp(&attr1->esi, &attr2->esi, sizeof(esi_t))
864 18 : && attr1->es_flags == attr2->es_flags
865 18 : && attr1->mm_sync_seqnum == attr2->mm_sync_seqnum
866 : && attr1->df_pref == attr2->df_pref
867 18 : && attr1->df_alg == attr2->df_alg
868 18 : && attr1->nh_ifindex == attr2->nh_ifindex
869 18 : && attr1->nh_lla_ifindex == attr2->nh_lla_ifindex
870 18 : && attr1->distance == attr2->distance
871 18 : && srv6_l3vpn_same(attr1->srv6_l3vpn, attr2->srv6_l3vpn)
872 18 : && srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn)
873 18 : && attr1->srte_color == attr2->srte_color
874 : && attr1->nh_type == attr2->nh_type
875 18 : && attr1->bh_type == attr2->bh_type
876 18 : && attr1->otc == attr2->otc)
877 : return true;
878 : }
879 :
880 : return false;
881 : }
882 :
883 2 : static void attrhash_init(void)
884 : {
885 4 : attrhash =
886 2 : hash_create(attrhash_key_make, attrhash_cmp, "BGP Attributes");
887 2 : }
888 :
889 : /*
890 : * special for hash_clean below
891 : */
892 0 : static void attr_vfree(void *attr)
893 : {
894 0 : XFREE(MTYPE_ATTR, attr);
895 0 : }
896 :
897 2 : static void attrhash_finish(void)
898 : {
899 2 : hash_clean(attrhash, attr_vfree);
900 2 : hash_free(attrhash);
901 2 : attrhash = NULL;
902 2 : }
903 :
904 0 : static void attr_show_all_iterator(struct hash_bucket *bucket, struct vty *vty)
905 : {
906 0 : struct attr *attr = bucket->data;
907 0 : struct in6_addr *sid = NULL;
908 :
909 0 : if (attr->srv6_l3vpn)
910 0 : sid = &attr->srv6_l3vpn->sid;
911 0 : else if (attr->srv6_vpn)
912 0 : sid = &attr->srv6_vpn->sid;
913 :
914 0 : vty_out(vty, "attr[%ld] nexthop %pI4\n", attr->refcnt, &attr->nexthop);
915 :
916 0 : vty_out(vty,
917 : "\tflags: %" PRIu64
918 : " distance: %u med: %u local_pref: %u origin: %u weight: %u label: %u sid: %pI6\n",
919 0 : attr->flag, attr->distance, attr->med, attr->local_pref,
920 0 : attr->origin, attr->weight, attr->label, sid);
921 0 : }
922 :
923 0 : void attr_show_all(struct vty *vty)
924 : {
925 0 : hash_iterate(attrhash, (void (*)(struct hash_bucket *,
926 : void *))attr_show_all_iterator,
927 : vty);
928 0 : }
929 :
930 4 : static void *bgp_attr_hash_alloc(void *p)
931 : {
932 4 : struct attr *val = (struct attr *)p;
933 4 : struct attr *attr;
934 :
935 4 : attr = XMALLOC(MTYPE_ATTR, sizeof(struct attr));
936 4 : *attr = *val;
937 4 : if (val->encap_subtlvs) {
938 0 : val->encap_subtlvs = NULL;
939 : }
940 : #ifdef ENABLE_BGP_VNC
941 4 : struct bgp_attr_encap_subtlv *vnc_subtlvs =
942 4 : bgp_attr_get_vnc_subtlvs(val);
943 :
944 4 : if (vnc_subtlvs)
945 0 : bgp_attr_set_vnc_subtlvs(val, NULL);
946 : #endif
947 :
948 4 : attr->refcnt = 0;
949 4 : return attr;
950 : }
951 :
952 : /* Internet argument attribute. */
953 13 : struct attr *bgp_attr_intern(struct attr *attr)
954 : {
955 13 : struct attr *find;
956 13 : struct ecommunity *ecomm = NULL;
957 13 : struct ecommunity *ipv6_ecomm = NULL;
958 13 : struct lcommunity *lcomm = NULL;
959 13 : struct community *comm = NULL;
960 :
961 : /* Intern referenced structure. */
962 13 : if (attr->aspath) {
963 13 : if (!attr->aspath->refcnt)
964 0 : attr->aspath = aspath_intern(attr->aspath);
965 : else
966 13 : attr->aspath->refcnt++;
967 : }
968 :
969 13 : comm = bgp_attr_get_community(attr);
970 13 : if (comm) {
971 0 : if (!comm->refcnt)
972 0 : bgp_attr_set_community(attr, community_intern(comm));
973 : else
974 0 : comm->refcnt++;
975 : }
976 :
977 13 : ecomm = bgp_attr_get_ecommunity(attr);
978 13 : if (ecomm) {
979 0 : if (!ecomm->refcnt)
980 0 : bgp_attr_set_ecommunity(attr, ecommunity_intern(ecomm));
981 : else
982 0 : ecomm->refcnt++;
983 : }
984 :
985 13 : ipv6_ecomm = bgp_attr_get_ipv6_ecommunity(attr);
986 13 : if (ipv6_ecomm) {
987 0 : if (!ipv6_ecomm->refcnt)
988 0 : bgp_attr_set_ipv6_ecommunity(
989 : attr, ecommunity_intern(ipv6_ecomm));
990 : else
991 0 : ipv6_ecomm->refcnt++;
992 : }
993 :
994 13 : lcomm = bgp_attr_get_lcommunity(attr);
995 13 : if (lcomm) {
996 0 : if (!lcomm->refcnt)
997 0 : bgp_attr_set_lcommunity(attr, lcommunity_intern(lcomm));
998 : else
999 0 : lcomm->refcnt++;
1000 : }
1001 :
1002 13 : struct cluster_list *cluster = bgp_attr_get_cluster(attr);
1003 :
1004 13 : if (cluster) {
1005 0 : if (!cluster->refcnt)
1006 0 : bgp_attr_set_cluster(attr, cluster_intern(cluster));
1007 : else
1008 0 : cluster->refcnt++;
1009 : }
1010 :
1011 13 : struct transit *transit = bgp_attr_get_transit(attr);
1012 :
1013 13 : if (transit) {
1014 0 : if (!transit->refcnt)
1015 0 : bgp_attr_set_transit(attr, transit_intern(transit));
1016 : else
1017 0 : transit->refcnt++;
1018 : }
1019 13 : if (attr->encap_subtlvs) {
1020 0 : if (!attr->encap_subtlvs->refcnt)
1021 0 : attr->encap_subtlvs = encap_intern(attr->encap_subtlvs,
1022 : ENCAP_SUBTLV_TYPE);
1023 : else
1024 0 : attr->encap_subtlvs->refcnt++;
1025 : }
1026 13 : if (attr->srv6_l3vpn) {
1027 0 : if (!attr->srv6_l3vpn->refcnt)
1028 0 : attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn);
1029 : else
1030 0 : attr->srv6_l3vpn->refcnt++;
1031 : }
1032 13 : if (attr->srv6_vpn) {
1033 0 : if (!attr->srv6_vpn->refcnt)
1034 0 : attr->srv6_vpn = srv6_vpn_intern(attr->srv6_vpn);
1035 : else
1036 0 : attr->srv6_vpn->refcnt++;
1037 : }
1038 : #ifdef ENABLE_BGP_VNC
1039 13 : struct bgp_attr_encap_subtlv *vnc_subtlvs =
1040 13 : bgp_attr_get_vnc_subtlvs(attr);
1041 :
1042 13 : if (vnc_subtlvs) {
1043 0 : if (!vnc_subtlvs->refcnt)
1044 0 : bgp_attr_set_vnc_subtlvs(
1045 : attr,
1046 : encap_intern(vnc_subtlvs, VNC_SUBTLV_TYPE));
1047 : else
1048 0 : vnc_subtlvs->refcnt++;
1049 : }
1050 : #endif
1051 :
1052 : /* At this point, attr only contains intern'd pointers. that means
1053 : * if we find it in attrhash, it has all the same pointers and we
1054 : * correctly updated the refcounts on these.
1055 : * If we don't find it, we need to allocate a one because in all
1056 : * cases this returns a new reference to a hashed attr, but the input
1057 : * wasn't on hash. */
1058 13 : find = (struct attr *)hash_get(attrhash, attr, bgp_attr_hash_alloc);
1059 13 : find->refcnt++;
1060 :
1061 13 : return find;
1062 : }
1063 :
1064 : /* Make network statement's attribute. */
1065 3 : struct attr *bgp_attr_default_set(struct attr *attr, struct bgp *bgp,
1066 : uint8_t origin)
1067 : {
1068 3 : memset(attr, 0, sizeof(struct attr));
1069 :
1070 3 : attr->origin = origin;
1071 3 : attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN);
1072 3 : attr->aspath = aspath_empty();
1073 3 : attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
1074 3 : attr->weight = BGP_ATTR_DEFAULT_WEIGHT;
1075 3 : attr->tag = 0;
1076 3 : attr->label_index = BGP_INVALID_LABEL_INDEX;
1077 3 : attr->label = MPLS_INVALID_LABEL;
1078 3 : attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
1079 3 : attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
1080 3 : attr->local_pref = bgp->default_local_pref;
1081 :
1082 3 : return attr;
1083 : }
1084 :
1085 : /* Create the attributes for an aggregate */
1086 0 : struct attr *bgp_attr_aggregate_intern(
1087 : struct bgp *bgp, uint8_t origin, struct aspath *aspath,
1088 : struct community *community, struct ecommunity *ecommunity,
1089 : struct lcommunity *lcommunity, struct bgp_aggregate *aggregate,
1090 : uint8_t atomic_aggregate, const struct prefix *p)
1091 : {
1092 0 : struct attr attr;
1093 0 : struct attr *new;
1094 0 : route_map_result_t ret;
1095 :
1096 0 : memset(&attr, 0, sizeof(attr));
1097 :
1098 : /* Origin attribute. */
1099 0 : attr.origin = origin;
1100 0 : attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN);
1101 :
1102 : /* MED */
1103 0 : attr.med = 0;
1104 0 : attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
1105 :
1106 : /* AS path attribute. */
1107 0 : if (aspath)
1108 0 : attr.aspath = aspath_intern(aspath);
1109 : else
1110 0 : attr.aspath = aspath_empty();
1111 0 : attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
1112 :
1113 : /* Next hop attribute. */
1114 0 : attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
1115 :
1116 0 : if (community) {
1117 0 : uint32_t gshut = COMMUNITY_GSHUT;
1118 :
1119 : /* If we are not shutting down ourselves and we are
1120 : * aggregating a route that contains the GSHUT community we
1121 : * need to remove that community when creating the aggregate */
1122 0 : if (!bgp_in_graceful_shutdown(bgp)
1123 0 : && community_include(community, gshut)) {
1124 0 : community_del_val(community, &gshut);
1125 : }
1126 :
1127 0 : bgp_attr_set_community(&attr, community);
1128 : }
1129 :
1130 0 : if (ecommunity)
1131 0 : bgp_attr_set_ecommunity(&attr, ecommunity);
1132 :
1133 0 : if (lcommunity)
1134 0 : bgp_attr_set_lcommunity(&attr, lcommunity);
1135 :
1136 0 : if (bgp_in_graceful_shutdown(bgp))
1137 0 : bgp_attr_add_gshut_community(&attr);
1138 :
1139 0 : attr.label_index = BGP_INVALID_LABEL_INDEX;
1140 0 : attr.label = MPLS_INVALID_LABEL;
1141 0 : attr.weight = BGP_ATTR_DEFAULT_WEIGHT;
1142 0 : attr.mp_nexthop_len = IPV6_MAX_BYTELEN;
1143 0 : if (!aggregate->as_set || atomic_aggregate)
1144 0 : attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE);
1145 0 : attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR);
1146 0 : if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1147 0 : attr.aggregator_as = bgp->confed_id;
1148 : else
1149 0 : attr.aggregator_as = bgp->as;
1150 0 : attr.aggregator_addr = bgp->router_id;
1151 :
1152 : /* Apply route-map */
1153 0 : if (aggregate->rmap.name) {
1154 0 : struct attr attr_tmp = attr;
1155 0 : struct bgp_path_info rmap_path;
1156 :
1157 0 : memset(&rmap_path, 0, sizeof(rmap_path));
1158 0 : rmap_path.peer = bgp->peer_self;
1159 0 : rmap_path.attr = &attr_tmp;
1160 :
1161 0 : SET_FLAG(bgp->peer_self->rmap_type, PEER_RMAP_TYPE_AGGREGATE);
1162 :
1163 0 : ret = route_map_apply(aggregate->rmap.map, p, &rmap_path);
1164 :
1165 0 : bgp->peer_self->rmap_type = 0;
1166 :
1167 0 : if (ret == RMAP_DENYMATCH) {
1168 : /* Free uninterned attribute. */
1169 0 : bgp_attr_flush(&attr_tmp);
1170 :
1171 : /* Unintern original. */
1172 0 : aspath_unintern(&attr.aspath);
1173 0 : return NULL;
1174 : }
1175 :
1176 0 : if (bgp_in_graceful_shutdown(bgp))
1177 0 : bgp_attr_add_gshut_community(&attr_tmp);
1178 :
1179 0 : new = bgp_attr_intern(&attr_tmp);
1180 : } else {
1181 :
1182 0 : if (bgp_in_graceful_shutdown(bgp))
1183 0 : bgp_attr_add_gshut_community(&attr);
1184 :
1185 0 : new = bgp_attr_intern(&attr);
1186 : }
1187 :
1188 : /* Always release the 'intern()'ed AS Path. */
1189 0 : aspath_unintern(&attr.aspath);
1190 :
1191 0 : return new;
1192 : }
1193 :
1194 : /* Unintern just the sub-components of the attr, but not the attr */
1195 17 : void bgp_attr_unintern_sub(struct attr *attr)
1196 : {
1197 17 : struct ecommunity *ecomm = NULL;
1198 17 : struct ecommunity *ipv6_ecomm = NULL;
1199 17 : struct cluster_list *cluster;
1200 17 : struct lcommunity *lcomm = NULL;
1201 17 : struct community *comm = NULL;
1202 :
1203 : /* aspath refcount shoud be decrement. */
1204 17 : aspath_unintern(&attr->aspath);
1205 17 : UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH));
1206 :
1207 17 : comm = bgp_attr_get_community(attr);
1208 17 : community_unintern(&comm);
1209 17 : bgp_attr_set_community(attr, NULL);
1210 :
1211 17 : ecomm = bgp_attr_get_ecommunity(attr);
1212 17 : ecommunity_unintern(&ecomm);
1213 17 : bgp_attr_set_ecommunity(attr, NULL);
1214 :
1215 17 : ipv6_ecomm = bgp_attr_get_ipv6_ecommunity(attr);
1216 17 : ecommunity_unintern(&ipv6_ecomm);
1217 17 : bgp_attr_set_ipv6_ecommunity(attr, NULL);
1218 :
1219 17 : lcomm = bgp_attr_get_lcommunity(attr);
1220 17 : lcommunity_unintern(&lcomm);
1221 17 : bgp_attr_set_lcommunity(attr, NULL);
1222 :
1223 17 : cluster = bgp_attr_get_cluster(attr);
1224 17 : if (cluster) {
1225 0 : cluster_unintern(&cluster);
1226 0 : bgp_attr_set_cluster(attr, cluster);
1227 : }
1228 17 : UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST));
1229 :
1230 17 : struct transit *transit = bgp_attr_get_transit(attr);
1231 :
1232 17 : if (transit) {
1233 0 : transit_unintern(&transit);
1234 0 : bgp_attr_set_transit(attr, transit);
1235 : }
1236 :
1237 17 : if (attr->encap_subtlvs)
1238 0 : encap_unintern(&attr->encap_subtlvs, ENCAP_SUBTLV_TYPE);
1239 :
1240 : #ifdef ENABLE_BGP_VNC
1241 17 : struct bgp_attr_encap_subtlv *vnc_subtlvs =
1242 17 : bgp_attr_get_vnc_subtlvs(attr);
1243 :
1244 17 : if (vnc_subtlvs) {
1245 0 : encap_unintern(&vnc_subtlvs, VNC_SUBTLV_TYPE);
1246 0 : bgp_attr_set_vnc_subtlvs(attr, vnc_subtlvs);
1247 : }
1248 : #endif
1249 :
1250 17 : if (attr->srv6_l3vpn)
1251 0 : srv6_l3vpn_unintern(&attr->srv6_l3vpn);
1252 :
1253 17 : if (attr->srv6_vpn)
1254 0 : srv6_vpn_unintern(&attr->srv6_vpn);
1255 17 : }
1256 :
1257 : /* Free bgp attribute and aspath. */
1258 13 : void bgp_attr_unintern(struct attr **pattr)
1259 : {
1260 13 : struct attr *attr = *pattr;
1261 13 : struct attr *ret;
1262 13 : struct attr tmp;
1263 :
1264 : /* Decrement attribute reference. */
1265 13 : attr->refcnt--;
1266 :
1267 13 : tmp = *attr;
1268 :
1269 : /* If reference becomes zero then free attribute object. */
1270 13 : if (attr->refcnt == 0) {
1271 4 : ret = hash_release(attrhash, attr);
1272 4 : assert(ret != NULL);
1273 4 : XFREE(MTYPE_ATTR, attr);
1274 4 : *pattr = NULL;
1275 : }
1276 :
1277 13 : bgp_attr_unintern_sub(&tmp);
1278 13 : }
1279 :
1280 0 : void bgp_attr_flush(struct attr *attr)
1281 : {
1282 0 : struct ecommunity *ecomm;
1283 0 : struct ecommunity *ipv6_ecomm;
1284 0 : struct cluster_list *cluster;
1285 0 : struct lcommunity *lcomm;
1286 0 : struct community *comm;
1287 :
1288 0 : if (attr->aspath && !attr->aspath->refcnt) {
1289 0 : aspath_free(attr->aspath);
1290 0 : attr->aspath = NULL;
1291 : }
1292 0 : comm = bgp_attr_get_community(attr);
1293 0 : if (comm && !comm->refcnt)
1294 0 : community_free(&comm);
1295 0 : bgp_attr_set_community(attr, NULL);
1296 :
1297 0 : ecomm = bgp_attr_get_ecommunity(attr);
1298 0 : if (ecomm && !ecomm->refcnt)
1299 0 : ecommunity_free(&ecomm);
1300 0 : bgp_attr_set_ecommunity(attr, NULL);
1301 :
1302 0 : ipv6_ecomm = bgp_attr_get_ipv6_ecommunity(attr);
1303 0 : if (ipv6_ecomm && !ipv6_ecomm->refcnt)
1304 0 : ecommunity_free(&ipv6_ecomm);
1305 0 : bgp_attr_set_ipv6_ecommunity(attr, NULL);
1306 :
1307 0 : lcomm = bgp_attr_get_lcommunity(attr);
1308 0 : if (lcomm && !lcomm->refcnt)
1309 0 : lcommunity_free(&lcomm);
1310 0 : bgp_attr_set_lcommunity(attr, NULL);
1311 :
1312 0 : cluster = bgp_attr_get_cluster(attr);
1313 0 : if (cluster && !cluster->refcnt) {
1314 0 : cluster_free(cluster);
1315 0 : bgp_attr_set_cluster(attr, NULL);
1316 : }
1317 :
1318 0 : struct transit *transit = bgp_attr_get_transit(attr);
1319 :
1320 0 : if (transit && !transit->refcnt) {
1321 0 : transit_free(transit);
1322 0 : bgp_attr_set_transit(attr, NULL);
1323 : }
1324 0 : if (attr->encap_subtlvs && !attr->encap_subtlvs->refcnt) {
1325 0 : encap_free(attr->encap_subtlvs);
1326 0 : attr->encap_subtlvs = NULL;
1327 : }
1328 0 : if (attr->srv6_l3vpn && !attr->srv6_l3vpn->refcnt) {
1329 0 : srv6_l3vpn_free(attr->srv6_l3vpn);
1330 0 : attr->srv6_l3vpn = NULL;
1331 : }
1332 0 : if (attr->srv6_vpn && !attr->srv6_vpn->refcnt) {
1333 0 : srv6_vpn_free(attr->srv6_vpn);
1334 0 : attr->srv6_vpn = NULL;
1335 : }
1336 : #ifdef ENABLE_BGP_VNC
1337 0 : struct bgp_attr_encap_subtlv *vnc_subtlvs =
1338 0 : bgp_attr_get_vnc_subtlvs(attr);
1339 :
1340 0 : if (vnc_subtlvs && !vnc_subtlvs->refcnt) {
1341 0 : encap_free(vnc_subtlvs);
1342 0 : bgp_attr_set_vnc_subtlvs(attr, NULL);
1343 : }
1344 : #endif
1345 0 : }
1346 :
1347 : /* Implement draft-scudder-idr-optional-transitive behaviour and
1348 : * avoid resetting sessions for malformed attributes which are
1349 : * are partial/optional and hence where the error likely was not
1350 : * introduced by the sending neighbour.
1351 : */
1352 : static enum bgp_attr_parse_ret
1353 0 : bgp_attr_malformed(struct bgp_attr_parser_args *args, uint8_t subcode,
1354 : bgp_size_t length)
1355 : {
1356 0 : struct peer *const peer = args->peer;
1357 0 : struct attr *const attr = args->attr;
1358 0 : const uint8_t flags = args->flags;
1359 : /* startp and length must be special-cased, as whether or not to
1360 : * send the attribute data with the NOTIFY depends on the error,
1361 : * the caller therefore signals this with the seperate length argument
1362 : */
1363 0 : uint8_t *notify_datap = (length > 0 ? args->startp : NULL);
1364 :
1365 0 : if (bgp_debug_update(peer, NULL, NULL, 1)) {
1366 0 : char attr_str[BUFSIZ] = {0};
1367 :
1368 0 : bgp_dump_attr(attr, attr_str, sizeof(attr_str));
1369 :
1370 0 : zlog_debug("%s: attributes: %s", __func__, attr_str);
1371 : }
1372 :
1373 : /* Only relax error handling for eBGP peers */
1374 0 : if (peer->sort != BGP_PEER_EBGP) {
1375 0 : bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR, subcode,
1376 : notify_datap, length);
1377 0 : return BGP_ATTR_PARSE_ERROR;
1378 : }
1379 :
1380 : /* Adjust the stream getp to the end of the attribute, in case we can
1381 : * still proceed but the caller hasn't read all the attribute.
1382 : */
1383 0 : stream_set_getp(BGP_INPUT(peer),
1384 0 : (args->startp - STREAM_DATA(BGP_INPUT(peer)))
1385 0 : + args->total);
1386 :
1387 0 : switch (args->type) {
1388 : /* where an attribute is relatively inconsequential, e.g. it does not
1389 : * affect route selection, and can be safely ignored, then any such
1390 : * attributes which are malformed should just be ignored and the route
1391 : * processed as normal.
1392 : */
1393 : case BGP_ATTR_AS4_AGGREGATOR:
1394 : case BGP_ATTR_AGGREGATOR:
1395 : case BGP_ATTR_ATOMIC_AGGREGATE:
1396 : return BGP_ATTR_PARSE_PROCEED;
1397 :
1398 : /* Core attributes, particularly ones which may influence route
1399 : * selection, should be treat-as-withdraw.
1400 : */
1401 : case BGP_ATTR_ORIGIN:
1402 : case BGP_ATTR_AS_PATH:
1403 : case BGP_ATTR_NEXT_HOP:
1404 : case BGP_ATTR_MULTI_EXIT_DISC:
1405 : case BGP_ATTR_LOCAL_PREF:
1406 : case BGP_ATTR_COMMUNITIES:
1407 : case BGP_ATTR_EXT_COMMUNITIES:
1408 : case BGP_ATTR_IPV6_EXT_COMMUNITIES:
1409 : case BGP_ATTR_LARGE_COMMUNITIES:
1410 : case BGP_ATTR_ORIGINATOR_ID:
1411 : case BGP_ATTR_CLUSTER_LIST:
1412 : case BGP_ATTR_OTC:
1413 : return BGP_ATTR_PARSE_WITHDRAW;
1414 0 : case BGP_ATTR_MP_REACH_NLRI:
1415 : case BGP_ATTR_MP_UNREACH_NLRI:
1416 0 : bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR, subcode,
1417 : notify_datap, length);
1418 0 : return BGP_ATTR_PARSE_ERROR;
1419 : }
1420 :
1421 : /* Partial optional attributes that are malformed should not cause
1422 : * the whole session to be reset. Instead treat it as a withdrawal
1423 : * of the routes, if possible.
1424 : */
1425 0 : if (CHECK_FLAG(flags, BGP_ATTR_FLAG_TRANS)
1426 0 : && CHECK_FLAG(flags, BGP_ATTR_FLAG_OPTIONAL)
1427 0 : && CHECK_FLAG(flags, BGP_ATTR_FLAG_PARTIAL))
1428 : return BGP_ATTR_PARSE_WITHDRAW;
1429 :
1430 : /* default to reset */
1431 : return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
1432 : }
1433 :
1434 : /* Find out what is wrong with the path attribute flag bits and log the error.
1435 : "Flag bits" here stand for Optional, Transitive and Partial, but not for
1436 : Extended Length. Checking O/T/P bits at once implies, that the attribute
1437 : being diagnosed is defined by RFC as either a "well-known" or an "optional,
1438 : non-transitive" attribute. */
1439 : static void
1440 0 : bgp_attr_flags_diagnose(struct bgp_attr_parser_args *args,
1441 : uint8_t desired_flags /* how RFC says it must be */
1442 : )
1443 : {
1444 0 : uint8_t seen = 0, i;
1445 0 : uint8_t real_flags = args->flags;
1446 0 : const uint8_t attr_code = args->type;
1447 :
1448 0 : desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
1449 0 : real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
1450 0 : for (i = 0; i <= 2; i++) /* O,T,P, but not E */
1451 0 : if (CHECK_FLAG(desired_flags, attr_flag_str[i].key)
1452 0 : != CHECK_FLAG(real_flags, attr_flag_str[i].key)) {
1453 0 : flog_err(EC_BGP_ATTR_FLAG,
1454 : "%s attribute must%s be flagged as \"%s\"",
1455 : lookup_msg(attr_str, attr_code, NULL),
1456 : CHECK_FLAG(desired_flags, attr_flag_str[i].key)
1457 : ? ""
1458 : : " not",
1459 : attr_flag_str[i].str);
1460 0 : seen = 1;
1461 : }
1462 0 : if (!seen) {
1463 0 : zlog_debug(
1464 : "Strange, %s called for attr %s, but no problem found with flags (real flags 0x%x, desired 0x%x)",
1465 : __func__, lookup_msg(attr_str, attr_code, NULL),
1466 : real_flags, desired_flags);
1467 : }
1468 0 : }
1469 :
1470 : /* Required flags for attributes. EXTLEN will be masked off when testing,
1471 : * as will PARTIAL for optional+transitive attributes.
1472 : */
1473 : const uint8_t attr_flags_values[] = {
1474 : [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS,
1475 : [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS,
1476 : [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS,
1477 : [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL,
1478 : [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS,
1479 : [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
1480 : [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
1481 : [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
1482 : [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL,
1483 : [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL,
1484 : [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
1485 : [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
1486 : [BGP_ATTR_EXT_COMMUNITIES] =
1487 : BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
1488 : [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
1489 : [BGP_ATTR_AS4_AGGREGATOR] =
1490 : BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
1491 : [BGP_ATTR_PMSI_TUNNEL] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
1492 : [BGP_ATTR_LARGE_COMMUNITIES] =
1493 : BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
1494 : [BGP_ATTR_OTC] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
1495 : [BGP_ATTR_PREFIX_SID] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
1496 : [BGP_ATTR_IPV6_EXT_COMMUNITIES] =
1497 : BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
1498 : [BGP_ATTR_AIGP] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
1499 : };
1500 : static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1;
1501 :
1502 11 : static bool bgp_attr_flag_invalid(struct bgp_attr_parser_args *args)
1503 : {
1504 11 : uint8_t mask = BGP_ATTR_FLAG_EXTLEN;
1505 11 : const uint8_t flags = args->flags;
1506 11 : const uint8_t attr_code = args->type;
1507 :
1508 : /* there may be attributes we don't know about */
1509 11 : if (attr_code > attr_flags_values_max)
1510 : return false;
1511 11 : if (attr_flags_values[attr_code] == 0)
1512 : return false;
1513 :
1514 : /* RFC4271, "For well-known attributes, the Transitive bit MUST be set
1515 : * to
1516 : * 1."
1517 : */
1518 11 : if (!CHECK_FLAG(BGP_ATTR_FLAG_OPTIONAL, flags)
1519 9 : && !CHECK_FLAG(BGP_ATTR_FLAG_TRANS, flags)) {
1520 0 : flog_err(
1521 : EC_BGP_ATTR_FLAG,
1522 : "%s well-known attributes must have transitive flag set (%x)",
1523 : lookup_msg(attr_str, attr_code, NULL), flags);
1524 0 : return true;
1525 : }
1526 :
1527 : /* "For well-known attributes and for optional non-transitive
1528 : * attributes,
1529 : * the Partial bit MUST be set to 0."
1530 : */
1531 11 : if (CHECK_FLAG(flags, BGP_ATTR_FLAG_PARTIAL)) {
1532 0 : if (!CHECK_FLAG(flags, BGP_ATTR_FLAG_OPTIONAL)) {
1533 0 : flog_err(EC_BGP_ATTR_FLAG,
1534 : "%s well-known attribute must NOT have the partial flag set (%x)",
1535 : lookup_msg(attr_str, attr_code, NULL), flags);
1536 0 : return true;
1537 : }
1538 0 : if (CHECK_FLAG(flags, BGP_ATTR_FLAG_OPTIONAL)
1539 0 : && !CHECK_FLAG(flags, BGP_ATTR_FLAG_TRANS)) {
1540 0 : flog_err(EC_BGP_ATTR_FLAG,
1541 : "%s optional + transitive attribute must NOT have the partial flag set (%x)",
1542 : lookup_msg(attr_str, attr_code, NULL), flags);
1543 0 : return true;
1544 : }
1545 : }
1546 :
1547 : /* Optional transitive attributes may go through speakers that don't
1548 : * reocgnise them and set the Partial bit.
1549 : */
1550 11 : if (CHECK_FLAG(flags, BGP_ATTR_FLAG_OPTIONAL)
1551 2 : && CHECK_FLAG(flags, BGP_ATTR_FLAG_TRANS))
1552 11 : SET_FLAG(mask, BGP_ATTR_FLAG_PARTIAL);
1553 :
1554 11 : if ((flags & ~mask) == attr_flags_values[attr_code])
1555 : return false;
1556 :
1557 0 : bgp_attr_flags_diagnose(args, attr_flags_values[attr_code]);
1558 0 : return true;
1559 : }
1560 :
1561 : /* Get origin attribute of the update message. */
1562 : static enum bgp_attr_parse_ret
1563 3 : bgp_attr_origin(struct bgp_attr_parser_args *args)
1564 : {
1565 3 : struct peer *const peer = args->peer;
1566 3 : struct attr *const attr = args->attr;
1567 3 : const bgp_size_t length = args->length;
1568 :
1569 : /* If any recognized attribute has Attribute Length that conflicts
1570 : with the expected length (based on the attribute type code), then
1571 : the Error Subcode is set to Attribute Length Error. The Data
1572 : field contains the erroneous attribute (type, length and
1573 : value). */
1574 3 : if (length != 1) {
1575 0 : flog_err(EC_BGP_ATTR_LEN,
1576 : "Origin attribute length is not one %d", length);
1577 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1578 0 : args->total);
1579 : }
1580 :
1581 : /* Fetch origin attribute. */
1582 3 : attr->origin = stream_getc(BGP_INPUT(peer));
1583 :
1584 : /* If the ORIGIN attribute has an undefined value, then the Error
1585 : Subcode is set to Invalid Origin Attribute. The Data field
1586 : contains the unrecognized attribute (type, length and value). */
1587 3 : if ((attr->origin != BGP_ORIGIN_IGP) && (attr->origin != BGP_ORIGIN_EGP)
1588 : && (attr->origin != BGP_ORIGIN_INCOMPLETE)) {
1589 0 : flog_err(EC_BGP_ATTR_ORIGIN,
1590 : "Origin attribute value is invalid %d", attr->origin);
1591 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
1592 0 : args->total);
1593 : }
1594 :
1595 : /* Set oring attribute flag. */
1596 3 : attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN);
1597 :
1598 3 : return 0;
1599 : }
1600 :
1601 : /* Parse AS path information. This function is wrapper of
1602 : aspath_parse. */
1603 3 : static int bgp_attr_aspath(struct bgp_attr_parser_args *args)
1604 : {
1605 3 : struct attr *const attr = args->attr;
1606 3 : struct peer *const peer = args->peer;
1607 3 : const bgp_size_t length = args->length;
1608 :
1609 : /*
1610 : * peer with AS4 => will get 4Byte ASnums
1611 : * otherwise, will get 16 Bit
1612 : */
1613 6 : attr->aspath = aspath_parse(
1614 : peer->curr, length,
1615 : CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)
1616 3 : && CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV));
1617 :
1618 : /* In case of IBGP, length will be zero. */
1619 3 : if (!attr->aspath) {
1620 0 : flog_err(EC_BGP_ATTR_MAL_AS_PATH,
1621 : "Malformed AS path from %s, length is %d", peer->host,
1622 : length);
1623 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
1624 : 0);
1625 : }
1626 :
1627 : /* Conformant BGP speakers SHOULD NOT send BGP
1628 : * UPDATE messages containing AS_SET or AS_CONFED_SET. Upon receipt of
1629 : * such messages, conformant BGP speakers SHOULD use the "Treat-as-
1630 : * withdraw" error handling behavior as per [RFC7606].
1631 : */
1632 3 : if (peer->bgp->reject_as_sets && aspath_check_as_sets(attr->aspath)) {
1633 0 : flog_err(EC_BGP_ATTR_MAL_AS_PATH,
1634 : "AS_SET and AS_CONFED_SET are deprecated from %pBP",
1635 : peer);
1636 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
1637 : 0);
1638 : }
1639 :
1640 : /* Set aspath attribute flag. */
1641 3 : attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
1642 :
1643 3 : return BGP_ATTR_PARSE_PROCEED;
1644 : }
1645 :
1646 3 : static enum bgp_attr_parse_ret bgp_attr_aspath_check(struct peer *const peer,
1647 : struct attr *const attr)
1648 : {
1649 : /* These checks were part of bgp_attr_aspath, but with
1650 : * as4 we should to check aspath things when
1651 : * aspath synthesizing with as4_path has already taken place.
1652 : * Otherwise we check ASPATH and use the synthesized thing, and that is
1653 : * not right.
1654 : * So do the checks later, i.e. here
1655 : */
1656 3 : struct aspath *aspath;
1657 :
1658 : /* Confederation sanity check. */
1659 3 : if ((peer->sort == BGP_PEER_CONFED
1660 0 : && !aspath_left_confed_check(attr->aspath))
1661 3 : || (peer->sort == BGP_PEER_EBGP
1662 3 : && aspath_confed_check(attr->aspath))) {
1663 0 : flog_err(EC_BGP_ATTR_MAL_AS_PATH, "Malformed AS path from %s",
1664 : peer->host);
1665 0 : return BGP_ATTR_PARSE_WITHDRAW;
1666 : }
1667 :
1668 : /* First AS check for EBGP. */
1669 3 : if (CHECK_FLAG(peer->flags, PEER_FLAG_ENFORCE_FIRST_AS)) {
1670 0 : if (peer->sort == BGP_PEER_EBGP
1671 0 : && !aspath_firstas_check(attr->aspath, peer->as)) {
1672 0 : flog_err(EC_BGP_ATTR_FIRST_AS,
1673 : "%s incorrect first AS (must be %u)",
1674 : peer->host, peer->as);
1675 0 : return BGP_ATTR_PARSE_WITHDRAW;
1676 : }
1677 : }
1678 :
1679 : /* Codification of AS 0 Processing */
1680 3 : if (peer->sort == BGP_PEER_EBGP && aspath_check_as_zero(attr->aspath)) {
1681 0 : flog_err(
1682 : EC_BGP_ATTR_MAL_AS_PATH,
1683 : "Malformed AS path, AS number is 0 in the path from %s",
1684 : peer->host);
1685 0 : return BGP_ATTR_PARSE_WITHDRAW;
1686 : }
1687 :
1688 : /* local-as prepend */
1689 3 : if (peer->change_local_as
1690 0 : && !CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)) {
1691 0 : aspath = aspath_dup(attr->aspath);
1692 0 : aspath = aspath_add_seq(aspath, peer->change_local_as);
1693 0 : aspath_unintern(&attr->aspath);
1694 0 : attr->aspath = aspath_intern(aspath);
1695 : }
1696 :
1697 : return BGP_ATTR_PARSE_PROCEED;
1698 : }
1699 :
1700 : /* Parse AS4 path information. This function is another wrapper of
1701 : aspath_parse. */
1702 0 : static int bgp_attr_as4_path(struct bgp_attr_parser_args *args,
1703 : struct aspath **as4_path)
1704 : {
1705 0 : struct peer *const peer = args->peer;
1706 0 : struct attr *const attr = args->attr;
1707 0 : const bgp_size_t length = args->length;
1708 :
1709 0 : *as4_path = aspath_parse(peer->curr, length, 1);
1710 :
1711 : /* In case of IBGP, length will be zero. */
1712 0 : if (!*as4_path) {
1713 0 : flog_err(EC_BGP_ATTR_MAL_AS_PATH,
1714 : "Malformed AS4 path from %s, length is %d", peer->host,
1715 : length);
1716 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
1717 : 0);
1718 : }
1719 :
1720 : /* Conformant BGP speakers SHOULD NOT send BGP
1721 : * UPDATE messages containing AS_SET or AS_CONFED_SET. Upon receipt of
1722 : * such messages, conformant BGP speakers SHOULD use the "Treat-as-
1723 : * withdraw" error handling behavior as per [RFC7606].
1724 : */
1725 0 : if (peer->bgp->reject_as_sets && aspath_check_as_sets(attr->aspath)) {
1726 0 : flog_err(EC_BGP_ATTR_MAL_AS_PATH,
1727 : "AS_SET and AS_CONFED_SET are deprecated from %pBP",
1728 : peer);
1729 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
1730 : 0);
1731 : }
1732 :
1733 : /* Set aspath attribute flag. */
1734 0 : attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH);
1735 :
1736 0 : return BGP_ATTR_PARSE_PROCEED;
1737 : }
1738 :
1739 : /*
1740 : * Check that the nexthop attribute is valid.
1741 : */
1742 3 : enum bgp_attr_parse_ret bgp_attr_nexthop_valid(struct peer *peer,
1743 : struct attr *attr)
1744 : {
1745 3 : struct bgp *bgp = peer->bgp;
1746 :
1747 3 : if (ipv4_martian(&attr->nexthop) && !bgp->allow_martian) {
1748 0 : uint8_t data[7]; /* type(2) + length(1) + nhop(4) */
1749 :
1750 0 : flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %pI4",
1751 : &attr->nexthop);
1752 0 : data[0] = BGP_ATTR_FLAG_TRANS;
1753 0 : data[1] = BGP_ATTR_NEXT_HOP;
1754 0 : data[2] = BGP_ATTR_NHLEN_IPV4;
1755 0 : memcpy(&data[3], &attr->nexthop.s_addr, BGP_ATTR_NHLEN_IPV4);
1756 0 : bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR,
1757 : BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
1758 : data, 7);
1759 0 : return BGP_ATTR_PARSE_ERROR;
1760 : }
1761 :
1762 : return BGP_ATTR_PARSE_PROCEED;
1763 : }
1764 :
1765 : /* Nexthop attribute. */
1766 : static enum bgp_attr_parse_ret
1767 3 : bgp_attr_nexthop(struct bgp_attr_parser_args *args)
1768 : {
1769 3 : struct peer *const peer = args->peer;
1770 3 : struct attr *const attr = args->attr;
1771 3 : const bgp_size_t length = args->length;
1772 :
1773 : /* Check nexthop attribute length. */
1774 3 : if (length != 4) {
1775 0 : flog_err(EC_BGP_ATTR_LEN,
1776 : "Nexthop attribute length isn't four [%d]", length);
1777 :
1778 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1779 0 : args->total);
1780 : }
1781 :
1782 3 : attr->nexthop.s_addr = stream_get_ipv4(peer->curr);
1783 3 : attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
1784 :
1785 3 : return BGP_ATTR_PARSE_PROCEED;
1786 : }
1787 :
1788 : /* MED atrribute. */
1789 2 : static enum bgp_attr_parse_ret bgp_attr_med(struct bgp_attr_parser_args *args)
1790 : {
1791 2 : struct peer *const peer = args->peer;
1792 2 : struct attr *const attr = args->attr;
1793 2 : const bgp_size_t length = args->length;
1794 :
1795 : /* Length check. */
1796 2 : if (length != 4) {
1797 0 : flog_err(EC_BGP_ATTR_LEN,
1798 : "MED attribute length isn't four [%d]", length);
1799 :
1800 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1801 0 : args->total);
1802 : }
1803 :
1804 2 : attr->med = stream_getl(peer->curr);
1805 :
1806 2 : attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
1807 :
1808 2 : return BGP_ATTR_PARSE_PROCEED;
1809 : }
1810 :
1811 : /* Local preference attribute. */
1812 : static enum bgp_attr_parse_ret
1813 0 : bgp_attr_local_pref(struct bgp_attr_parser_args *args)
1814 : {
1815 0 : struct peer *const peer = args->peer;
1816 0 : struct attr *const attr = args->attr;
1817 0 : const bgp_size_t length = args->length;
1818 :
1819 : /* if received from an internal neighbor, it SHALL be considered
1820 : * malformed if its length is not equal to 4. If malformed, the
1821 : * UPDATE message SHALL be handled using the approach of "treat-as-
1822 : * withdraw".
1823 : */
1824 0 : if (peer->sort == BGP_PEER_IBGP && length != 4) {
1825 0 : flog_err(EC_BGP_ATTR_LEN,
1826 : "LOCAL_PREF attribute length isn't 4 [%u]", length);
1827 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1828 0 : args->total);
1829 : }
1830 :
1831 : /* If it is contained in an UPDATE message that is received from an
1832 : external peer, then this attribute MUST be ignored by the
1833 : receiving speaker. */
1834 0 : if (peer->sort == BGP_PEER_EBGP) {
1835 0 : STREAM_FORWARD_GETP(peer->curr, length);
1836 : return BGP_ATTR_PARSE_PROCEED;
1837 : }
1838 :
1839 0 : STREAM_GETL(peer->curr, attr->local_pref);
1840 :
1841 : /* Set the local-pref flag. */
1842 0 : attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
1843 :
1844 0 : return BGP_ATTR_PARSE_PROCEED;
1845 :
1846 0 : stream_failure:
1847 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1848 0 : args->total);
1849 : }
1850 :
1851 : /* Atomic aggregate. */
1852 0 : static int bgp_attr_atomic(struct bgp_attr_parser_args *args)
1853 : {
1854 0 : struct peer *const peer = args->peer;
1855 0 : struct attr *const attr = args->attr;
1856 0 : const bgp_size_t length = args->length;
1857 :
1858 : /* Length check. */
1859 0 : if (length != 0) {
1860 0 : flog_err(EC_BGP_ATTR_LEN,
1861 : "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1862 : length);
1863 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1864 0 : args->total);
1865 : }
1866 :
1867 0 : if (peer->discard_attrs[args->type])
1868 0 : goto atomic_ignore;
1869 :
1870 : /* Set atomic aggregate flag. */
1871 0 : attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE);
1872 :
1873 0 : return BGP_ATTR_PARSE_PROCEED;
1874 :
1875 0 : atomic_ignore:
1876 0 : stream_forward_getp(peer->curr, length);
1877 :
1878 0 : if (bgp_debug_update(peer, NULL, NULL, 1))
1879 0 : zlog_debug("%pBP: Ignoring attribute %s", peer,
1880 : lookup_msg(attr_str, args->type, NULL));
1881 :
1882 : return BGP_ATTR_PARSE_PROCEED;
1883 : }
1884 :
1885 : /* Aggregator attribute */
1886 0 : static int bgp_attr_aggregator(struct bgp_attr_parser_args *args)
1887 : {
1888 0 : struct peer *const peer = args->peer;
1889 0 : struct attr *const attr = args->attr;
1890 0 : const bgp_size_t length = args->length;
1891 0 : as_t aggregator_as;
1892 :
1893 0 : int wantedlen = 6;
1894 :
1895 : /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1896 0 : if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)
1897 0 : && CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV))
1898 0 : wantedlen = 8;
1899 :
1900 0 : if (length != wantedlen) {
1901 0 : flog_err(EC_BGP_ATTR_LEN,
1902 : "AGGREGATOR attribute length isn't %u [%u]", wantedlen,
1903 : length);
1904 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1905 0 : args->total);
1906 : }
1907 :
1908 0 : if (peer->discard_attrs[args->type])
1909 0 : goto aggregator_ignore;
1910 :
1911 0 : if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV))
1912 0 : aggregator_as = stream_getl(peer->curr);
1913 : else
1914 0 : aggregator_as = stream_getw(peer->curr);
1915 :
1916 0 : attr->aggregator_as = aggregator_as;
1917 0 : attr->aggregator_addr.s_addr = stream_get_ipv4(peer->curr);
1918 :
1919 : /* Codification of AS 0 Processing */
1920 0 : if (aggregator_as == BGP_AS_ZERO) {
1921 0 : flog_err(EC_BGP_ATTR_LEN,
1922 : "%s: AGGREGATOR AS number is 0 for aspath: %s",
1923 : peer->host, aspath_print(attr->aspath));
1924 :
1925 0 : if (bgp_debug_update(peer, NULL, NULL, 1)) {
1926 0 : char attr_str[BUFSIZ] = {0};
1927 :
1928 0 : bgp_dump_attr(attr, attr_str, sizeof(attr_str));
1929 :
1930 0 : zlog_debug("%s: attributes: %s", __func__, attr_str);
1931 : }
1932 : } else {
1933 0 : attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR);
1934 : }
1935 :
1936 : return BGP_ATTR_PARSE_PROCEED;
1937 :
1938 0 : aggregator_ignore:
1939 0 : stream_forward_getp(peer->curr, length);
1940 :
1941 0 : if (bgp_debug_update(peer, NULL, NULL, 1))
1942 0 : zlog_debug("%pBP: Ignoring attribute %s", peer,
1943 : lookup_msg(attr_str, args->type, NULL));
1944 :
1945 : return BGP_ATTR_PARSE_PROCEED;
1946 : }
1947 :
1948 : /* New Aggregator attribute */
1949 : static enum bgp_attr_parse_ret
1950 0 : bgp_attr_as4_aggregator(struct bgp_attr_parser_args *args,
1951 : as_t *as4_aggregator_as,
1952 : struct in_addr *as4_aggregator_addr)
1953 : {
1954 0 : struct peer *const peer = args->peer;
1955 0 : struct attr *const attr = args->attr;
1956 0 : const bgp_size_t length = args->length;
1957 0 : as_t aggregator_as;
1958 :
1959 0 : if (length != 8) {
1960 0 : flog_err(EC_BGP_ATTR_LEN, "New Aggregator length is not 8 [%d]",
1961 : length);
1962 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1963 : 0);
1964 : }
1965 :
1966 0 : if (peer->discard_attrs[args->type])
1967 0 : goto as4_aggregator_ignore;
1968 :
1969 0 : aggregator_as = stream_getl(peer->curr);
1970 :
1971 0 : *as4_aggregator_as = aggregator_as;
1972 0 : as4_aggregator_addr->s_addr = stream_get_ipv4(peer->curr);
1973 :
1974 : /* Codification of AS 0 Processing */
1975 0 : if (aggregator_as == BGP_AS_ZERO) {
1976 0 : flog_err(EC_BGP_ATTR_LEN,
1977 : "%s: AS4_AGGREGATOR AS number is 0 for aspath: %s",
1978 : peer->host, aspath_print(attr->aspath));
1979 :
1980 0 : if (bgp_debug_update(peer, NULL, NULL, 1)) {
1981 0 : char attr_str[BUFSIZ] = {0};
1982 :
1983 0 : bgp_dump_attr(attr, attr_str, sizeof(attr_str));
1984 :
1985 0 : zlog_debug("%s: attributes: %s", __func__, attr_str);
1986 : }
1987 : } else {
1988 0 : attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR);
1989 : }
1990 :
1991 : return BGP_ATTR_PARSE_PROCEED;
1992 :
1993 0 : as4_aggregator_ignore:
1994 0 : stream_forward_getp(peer->curr, length);
1995 :
1996 0 : if (bgp_debug_update(peer, NULL, NULL, 1))
1997 0 : zlog_debug("%pBP: Ignoring attribute %s", peer,
1998 : lookup_msg(attr_str, args->type, NULL));
1999 :
2000 : return BGP_ATTR_PARSE_PROCEED;
2001 : }
2002 :
2003 : /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
2004 : */
2005 : static enum bgp_attr_parse_ret
2006 3 : bgp_attr_munge_as4_attrs(struct peer *const peer, struct attr *const attr,
2007 : struct aspath *as4_path, as_t as4_aggregator,
2008 : struct in_addr *as4_aggregator_addr)
2009 : {
2010 3 : int ignore_as4_path = 0;
2011 3 : struct aspath *newpath;
2012 :
2013 3 : if (!attr->aspath) {
2014 : /* NULL aspath shouldn't be possible as bgp_attr_parse should
2015 : * have
2016 : * checked that all well-known, mandatory attributes were
2017 : * present.
2018 : *
2019 : * Can only be a problem with peer itself - hard error
2020 : */
2021 : return BGP_ATTR_PARSE_ERROR;
2022 : }
2023 :
2024 3 : if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) {
2025 : /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
2026 : * if given.
2027 : * It is worth a warning though, because the peer really
2028 : * should not send them
2029 : */
2030 2 : if (BGP_DEBUG(as4, AS4)) {
2031 0 : if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
2032 0 : zlog_debug("[AS4] %s %s AS4_PATH", peer->host,
2033 : "AS4 capable peer, yet it sent");
2034 :
2035 0 : if (attr->flag
2036 0 : & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
2037 0 : zlog_debug("[AS4] %s %s AS4_AGGREGATOR",
2038 : peer->host,
2039 : "AS4 capable peer, yet it sent");
2040 : }
2041 :
2042 2 : return BGP_ATTR_PARSE_PROCEED;
2043 : }
2044 :
2045 : /* We have a asn16 peer. First, look for AS4_AGGREGATOR
2046 : * because that may override AS4_PATH
2047 : */
2048 1 : if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR))) {
2049 0 : if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR))) {
2050 : /* received both.
2051 : * if the as_number in aggregator is not AS_TRANS,
2052 : * then AS4_AGGREGATOR and AS4_PATH shall be ignored
2053 : * and the Aggregator shall be taken as
2054 : * info on the aggregating node, and the AS_PATH
2055 : * shall be taken as the AS_PATH
2056 : * otherwise
2057 : * the Aggregator shall be ignored and the
2058 : * AS4_AGGREGATOR shall be taken as the
2059 : * Aggregating node and the AS_PATH is to be
2060 : * constructed "as in all other cases"
2061 : */
2062 0 : if (attr->aggregator_as != BGP_AS_TRANS) {
2063 : /* ignore */
2064 0 : if (BGP_DEBUG(as4, AS4))
2065 0 : zlog_debug(
2066 : "[AS4] %s BGP not AS4 capable peer send AGGREGATOR != AS_TRANS and AS4_AGGREGATOR, so ignore AS4_AGGREGATOR and AS4_PATH",
2067 : peer->host);
2068 : ignore_as4_path = 1;
2069 : } else {
2070 : /* "New_aggregator shall be taken as aggregator"
2071 : */
2072 0 : attr->aggregator_as = as4_aggregator;
2073 0 : attr->aggregator_addr.s_addr =
2074 0 : as4_aggregator_addr->s_addr;
2075 : }
2076 : } else {
2077 : /* We received a AS4_AGGREGATOR but no AGGREGATOR.
2078 : * That is bogus - but reading the conditions
2079 : * we have to handle AS4_AGGREGATOR as if it were
2080 : * AGGREGATOR in that case
2081 : */
2082 0 : if (BGP_DEBUG(as4, AS4))
2083 0 : zlog_debug(
2084 : "[AS4] %s BGP not AS4 capable peer send AS4_AGGREGATOR but no AGGREGATOR, will take it as if AGGREGATOR with AS_TRANS had been there",
2085 : peer->host);
2086 0 : attr->aggregator_as = as4_aggregator;
2087 : /* sweep it under the carpet and simulate a "good"
2088 : * AGGREGATOR */
2089 0 : attr->flag |= (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR));
2090 : }
2091 : }
2092 :
2093 : /* need to reconcile NEW_AS_PATH and AS_PATH */
2094 0 : if (!ignore_as4_path
2095 1 : && (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))) {
2096 0 : newpath = aspath_reconcile_as4(attr->aspath, as4_path);
2097 0 : if (!newpath)
2098 : return BGP_ATTR_PARSE_ERROR;
2099 :
2100 0 : aspath_unintern(&attr->aspath);
2101 0 : attr->aspath = aspath_intern(newpath);
2102 : }
2103 : return BGP_ATTR_PARSE_PROCEED;
2104 : }
2105 :
2106 : /* Community attribute. */
2107 : static enum bgp_attr_parse_ret
2108 0 : bgp_attr_community(struct bgp_attr_parser_args *args)
2109 : {
2110 0 : struct peer *const peer = args->peer;
2111 0 : struct attr *const attr = args->attr;
2112 0 : const bgp_size_t length = args->length;
2113 :
2114 0 : if (length == 0) {
2115 0 : bgp_attr_set_community(attr, NULL);
2116 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2117 0 : args->total);
2118 : }
2119 :
2120 0 : if (peer->discard_attrs[args->type])
2121 0 : goto community_ignore;
2122 :
2123 0 : bgp_attr_set_community(
2124 : attr,
2125 0 : community_parse((uint32_t *)stream_pnt(peer->curr), length));
2126 :
2127 : /* XXX: fix community_parse to use stream API and remove this */
2128 0 : stream_forward_getp(peer->curr, length);
2129 :
2130 : /* The Community attribute SHALL be considered malformed if its
2131 : * length is not a non-zero multiple of 4.
2132 : */
2133 0 : if (!bgp_attr_get_community(attr))
2134 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2135 0 : args->total);
2136 :
2137 : return BGP_ATTR_PARSE_PROCEED;
2138 :
2139 0 : community_ignore:
2140 0 : stream_forward_getp(peer->curr, length);
2141 :
2142 0 : if (bgp_debug_update(peer, NULL, NULL, 1))
2143 0 : zlog_debug("%pBP: Ignoring attribute %s", peer,
2144 : lookup_msg(attr_str, args->type, NULL));
2145 :
2146 : return BGP_ATTR_PARSE_PROCEED;
2147 : }
2148 :
2149 : /* Originator ID attribute. */
2150 : static enum bgp_attr_parse_ret
2151 0 : bgp_attr_originator_id(struct bgp_attr_parser_args *args)
2152 : {
2153 0 : struct peer *const peer = args->peer;
2154 0 : struct attr *const attr = args->attr;
2155 0 : const bgp_size_t length = args->length;
2156 :
2157 : /* if received from an internal neighbor, it SHALL be considered
2158 : * malformed if its length is not equal to 4. If malformed, the
2159 : * UPDATE message SHALL be handled using the approach of "treat-as-
2160 : * withdraw".
2161 : */
2162 0 : if (length != 4) {
2163 0 : flog_err(EC_BGP_ATTR_LEN, "Bad originator ID length %d",
2164 : length);
2165 :
2166 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2167 0 : args->total);
2168 : }
2169 :
2170 0 : if (peer->discard_attrs[args->type])
2171 0 : goto originator_id_ignore;
2172 :
2173 0 : attr->originator_id.s_addr = stream_get_ipv4(peer->curr);
2174 :
2175 0 : attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID);
2176 :
2177 0 : return BGP_ATTR_PARSE_PROCEED;
2178 :
2179 0 : originator_id_ignore:
2180 0 : stream_forward_getp(peer->curr, length);
2181 :
2182 0 : if (bgp_debug_update(peer, NULL, NULL, 1))
2183 0 : zlog_debug("%pBP: Ignoring attribute %s", peer,
2184 : lookup_msg(attr_str, args->type, NULL));
2185 :
2186 : return BGP_ATTR_PARSE_PROCEED;
2187 : }
2188 :
2189 : /* Cluster list attribute. */
2190 : static enum bgp_attr_parse_ret
2191 0 : bgp_attr_cluster_list(struct bgp_attr_parser_args *args)
2192 : {
2193 0 : struct peer *const peer = args->peer;
2194 0 : struct attr *const attr = args->attr;
2195 0 : const bgp_size_t length = args->length;
2196 :
2197 : /* if received from an internal neighbor, it SHALL be considered
2198 : * malformed if its length is not a non-zero multiple of 4. If
2199 : * malformed, the UPDATE message SHALL be handled using the approach
2200 : * of "treat-as-withdraw".
2201 : */
2202 0 : if (length == 0 || length % 4) {
2203 0 : flog_err(EC_BGP_ATTR_LEN, "Bad cluster list length %d", length);
2204 :
2205 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2206 0 : args->total);
2207 : }
2208 :
2209 0 : if (peer->discard_attrs[args->type])
2210 0 : goto cluster_list_ignore;
2211 :
2212 0 : bgp_attr_set_cluster(
2213 0 : attr, cluster_parse((struct in_addr *)stream_pnt(peer->curr),
2214 : length));
2215 :
2216 : /* XXX: Fix cluster_parse to use stream API and then remove this */
2217 0 : stream_forward_getp(peer->curr, length);
2218 :
2219 0 : attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST);
2220 :
2221 0 : return BGP_ATTR_PARSE_PROCEED;
2222 :
2223 0 : cluster_list_ignore:
2224 0 : stream_forward_getp(peer->curr, length);
2225 :
2226 0 : if (bgp_debug_update(peer, NULL, NULL, 1))
2227 0 : zlog_debug("%pBP: Ignoring attribute %s", peer,
2228 : lookup_msg(attr_str, args->type, NULL));
2229 :
2230 : return BGP_ATTR_PARSE_PROCEED;
2231 : }
2232 :
2233 : /* Multiprotocol reachability information parse. */
2234 0 : int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
2235 : struct bgp_nlri *mp_update)
2236 : {
2237 0 : iana_afi_t pkt_afi;
2238 0 : afi_t afi;
2239 0 : iana_safi_t pkt_safi;
2240 0 : safi_t safi;
2241 0 : bgp_size_t nlri_len;
2242 0 : size_t start;
2243 0 : struct stream *s;
2244 0 : struct peer *const peer = args->peer;
2245 0 : struct attr *const attr = args->attr;
2246 0 : const bgp_size_t length = args->length;
2247 :
2248 : /* Set end of packet. */
2249 0 : s = BGP_INPUT(peer);
2250 0 : start = stream_get_getp(s);
2251 :
2252 : /* safe to read statically sized header? */
2253 : #define BGP_MP_REACH_MIN_SIZE 5
2254 : #define LEN_LEFT (length - (stream_get_getp(s) - start))
2255 0 : if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE)) {
2256 0 : zlog_info("%s: %s sent invalid length, %lu, of MP_REACH_NLRI",
2257 : __func__, peer->host, (unsigned long)length);
2258 0 : return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
2259 : }
2260 :
2261 : /* Load AFI, SAFI. */
2262 0 : pkt_afi = stream_getw(s);
2263 0 : pkt_safi = stream_getc(s);
2264 :
2265 : /* Convert AFI, SAFI to internal values, check. */
2266 0 : if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) {
2267 : /* Log if AFI or SAFI is unrecognized. This is not an error
2268 : * unless
2269 : * the attribute is otherwise malformed.
2270 : */
2271 0 : if (bgp_debug_update(peer, NULL, NULL, 0))
2272 0 : zlog_debug(
2273 : "%s sent unrecognizable AFI, %s or, SAFI, %s, of MP_REACH_NLRI",
2274 : peer->host, iana_afi2str(pkt_afi),
2275 : iana_safi2str(pkt_safi));
2276 0 : return BGP_ATTR_PARSE_ERROR;
2277 : }
2278 :
2279 : /* Get nexthop length. */
2280 0 : attr->mp_nexthop_len = stream_getc(s);
2281 :
2282 0 : if (LEN_LEFT < attr->mp_nexthop_len) {
2283 0 : zlog_info(
2284 : "%s: %s sent next-hop length, %u, in MP_REACH_NLRI which goes past the end of attribute",
2285 : __func__, peer->host, attr->mp_nexthop_len);
2286 0 : return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
2287 : }
2288 :
2289 : /* Nexthop length check. */
2290 0 : switch (attr->mp_nexthop_len) {
2291 0 : case 0:
2292 0 : if (safi != SAFI_FLOWSPEC) {
2293 0 : zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
2294 : __func__, peer->host, attr->mp_nexthop_len);
2295 0 : return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
2296 : }
2297 : break;
2298 0 : case BGP_ATTR_NHLEN_VPNV4:
2299 0 : stream_getl(s); /* RD high */
2300 0 : stream_getl(s); /* RD low */
2301 : /*
2302 : * NOTE: intentional fall through
2303 : * - for consistency in rx processing
2304 : *
2305 : * The following comment is to signal GCC this intention
2306 : * and suppress the warning
2307 : */
2308 : /* FALLTHRU */
2309 0 : case BGP_ATTR_NHLEN_IPV4:
2310 0 : stream_get(&attr->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN);
2311 : /* Probably needed for RFC 2283 */
2312 0 : if (attr->nexthop.s_addr == INADDR_ANY)
2313 0 : memcpy(&attr->nexthop.s_addr,
2314 : &attr->mp_nexthop_global_in, IPV4_MAX_BYTELEN);
2315 : break;
2316 0 : case BGP_ATTR_NHLEN_IPV6_GLOBAL:
2317 : case BGP_ATTR_NHLEN_VPNV6_GLOBAL:
2318 0 : if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL) {
2319 0 : stream_getl(s); /* RD high */
2320 0 : stream_getl(s); /* RD low */
2321 : }
2322 0 : stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
2323 0 : if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
2324 0 : if (!peer->nexthop.ifp) {
2325 0 : zlog_warn("%s sent a v6 global attribute but address is a V6 LL and there's no peer interface information. Hence, withdrawing",
2326 : peer->host);
2327 0 : return BGP_ATTR_PARSE_WITHDRAW;
2328 : }
2329 0 : attr->nh_ifindex = peer->nexthop.ifp->ifindex;
2330 : }
2331 : break;
2332 0 : case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
2333 : case BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL:
2334 0 : if (attr->mp_nexthop_len
2335 : == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
2336 0 : stream_getl(s); /* RD high */
2337 0 : stream_getl(s); /* RD low */
2338 : }
2339 0 : stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
2340 0 : if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
2341 0 : if (!peer->nexthop.ifp) {
2342 0 : zlog_warn("%s sent a v6 global and LL attribute but global address is a V6 LL and there's no peer interface information. Hence, withdrawing",
2343 : peer->host);
2344 0 : return BGP_ATTR_PARSE_WITHDRAW;
2345 : }
2346 0 : attr->nh_ifindex = peer->nexthop.ifp->ifindex;
2347 : }
2348 0 : if (attr->mp_nexthop_len
2349 : == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
2350 0 : stream_getl(s); /* RD high */
2351 0 : stream_getl(s); /* RD low */
2352 : }
2353 0 : stream_get(&attr->mp_nexthop_local, s, IPV6_MAX_BYTELEN);
2354 0 : if (!IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_local)) {
2355 0 : if (bgp_debug_update(peer, NULL, NULL, 1))
2356 0 : zlog_debug(
2357 : "%s sent next-hops %pI6 and %pI6. Ignoring non-LL value",
2358 : peer->host, &attr->mp_nexthop_global,
2359 : &attr->mp_nexthop_local);
2360 :
2361 0 : attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
2362 : }
2363 0 : if (!peer->nexthop.ifp) {
2364 0 : zlog_warn("%s sent a v6 LL next-hop and there's no peer interface information. Hence, withdrawing",
2365 : peer->host);
2366 0 : return BGP_ATTR_PARSE_WITHDRAW;
2367 : }
2368 0 : attr->nh_lla_ifindex = peer->nexthop.ifp->ifindex;
2369 0 : break;
2370 0 : default:
2371 0 : zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
2372 : __func__, peer->host, attr->mp_nexthop_len);
2373 0 : return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
2374 : }
2375 :
2376 0 : if (!LEN_LEFT) {
2377 0 : zlog_info("%s: %s sent SNPA which couldn't be read",
2378 : __func__, peer->host);
2379 0 : return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
2380 : }
2381 :
2382 : {
2383 0 : uint8_t val;
2384 0 : if ((val = stream_getc(s)))
2385 0 : flog_warn(
2386 : EC_BGP_DEFUNCT_SNPA_LEN,
2387 : "%s sent non-zero value, %u, for defunct SNPA-length field",
2388 : peer->host, val);
2389 : }
2390 :
2391 : /* must have nrli_len, what is left of the attribute */
2392 0 : nlri_len = LEN_LEFT;
2393 0 : if (nlri_len > STREAM_READABLE(s)) {
2394 0 : zlog_info("%s: %s sent MP_REACH_NLRI which couldn't be read",
2395 : __func__, peer->host);
2396 0 : return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
2397 : }
2398 :
2399 0 : if (!nlri_len) {
2400 0 : zlog_info("%s: %s sent a zero-length NLRI. Hence, treating as a EOR marker",
2401 : __func__, peer->host);
2402 :
2403 0 : mp_update->afi = afi;
2404 0 : mp_update->safi = safi;
2405 0 : return BGP_ATTR_PARSE_EOR;
2406 : }
2407 :
2408 0 : mp_update->afi = afi;
2409 0 : mp_update->safi = safi;
2410 0 : mp_update->nlri = stream_pnt(s);
2411 0 : mp_update->length = nlri_len;
2412 :
2413 0 : stream_forward_getp(s, nlri_len);
2414 :
2415 0 : attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI);
2416 :
2417 0 : return BGP_ATTR_PARSE_PROCEED;
2418 : #undef LEN_LEFT
2419 : }
2420 :
2421 : /* Multiprotocol unreachable parse */
2422 0 : int bgp_mp_unreach_parse(struct bgp_attr_parser_args *args,
2423 : struct bgp_nlri *mp_withdraw)
2424 : {
2425 0 : struct stream *s;
2426 0 : iana_afi_t pkt_afi;
2427 0 : afi_t afi;
2428 0 : iana_safi_t pkt_safi;
2429 0 : safi_t safi;
2430 0 : uint16_t withdraw_len;
2431 0 : struct peer *const peer = args->peer;
2432 0 : struct attr *const attr = args->attr;
2433 0 : const bgp_size_t length = args->length;
2434 :
2435 0 : s = peer->curr;
2436 :
2437 : #define BGP_MP_UNREACH_MIN_SIZE 3
2438 0 : if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
2439 : return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
2440 :
2441 0 : pkt_afi = stream_getw(s);
2442 0 : pkt_safi = stream_getc(s);
2443 :
2444 : /* Convert AFI, SAFI to internal values, check. */
2445 0 : if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) {
2446 : /* Log if AFI or SAFI is unrecognized. This is not an error
2447 : * unless
2448 : * the attribute is otherwise malformed.
2449 : */
2450 0 : if (bgp_debug_update(peer, NULL, NULL, 0))
2451 0 : zlog_debug(
2452 : "%s: MP_UNREACH received AFI %s or SAFI %s is unrecognized",
2453 : peer->host, iana_afi2str(pkt_afi),
2454 : iana_safi2str(pkt_safi));
2455 0 : return BGP_ATTR_PARSE_ERROR;
2456 : }
2457 :
2458 0 : withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
2459 :
2460 0 : mp_withdraw->afi = afi;
2461 0 : mp_withdraw->safi = safi;
2462 0 : mp_withdraw->nlri = stream_pnt(s);
2463 0 : mp_withdraw->length = withdraw_len;
2464 :
2465 0 : stream_forward_getp(s, withdraw_len);
2466 :
2467 0 : attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI);
2468 :
2469 0 : return BGP_ATTR_PARSE_PROCEED;
2470 : }
2471 :
2472 : /* Large Community attribute. */
2473 : static enum bgp_attr_parse_ret
2474 0 : bgp_attr_large_community(struct bgp_attr_parser_args *args)
2475 : {
2476 0 : struct peer *const peer = args->peer;
2477 0 : struct attr *const attr = args->attr;
2478 0 : const bgp_size_t length = args->length;
2479 :
2480 : /*
2481 : * Large community follows new attribute format.
2482 : */
2483 0 : if (length == 0) {
2484 0 : bgp_attr_set_lcommunity(attr, NULL);
2485 : /* Empty extcomm doesn't seem to be invalid per se */
2486 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2487 0 : args->total);
2488 : }
2489 :
2490 0 : if (peer->discard_attrs[args->type])
2491 0 : goto large_community_ignore;
2492 :
2493 0 : bgp_attr_set_lcommunity(
2494 : attr, lcommunity_parse(stream_pnt(peer->curr), length));
2495 : /* XXX: fix ecommunity_parse to use stream API */
2496 0 : stream_forward_getp(peer->curr, length);
2497 :
2498 0 : if (!bgp_attr_get_lcommunity(attr))
2499 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2500 0 : args->total);
2501 :
2502 : return BGP_ATTR_PARSE_PROCEED;
2503 :
2504 0 : large_community_ignore:
2505 0 : stream_forward_getp(peer->curr, length);
2506 :
2507 0 : if (bgp_debug_update(peer, NULL, NULL, 1))
2508 0 : zlog_debug("%pBP: Ignoring attribute %s", peer,
2509 : lookup_msg(attr_str, args->type, NULL));
2510 :
2511 : return BGP_ATTR_PARSE_PROCEED;
2512 : }
2513 :
2514 : /* Extended Community attribute. */
2515 : static enum bgp_attr_parse_ret
2516 0 : bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
2517 : {
2518 0 : struct peer *const peer = args->peer;
2519 0 : struct attr *const attr = args->attr;
2520 0 : const bgp_size_t length = args->length;
2521 0 : uint8_t sticky = 0;
2522 0 : bool proxy = false;
2523 0 : struct ecommunity *ecomm;
2524 :
2525 0 : if (length == 0) {
2526 0 : bgp_attr_set_ecommunity(attr, NULL);
2527 : /* Empty extcomm doesn't seem to be invalid per se */
2528 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2529 0 : args->total);
2530 : }
2531 :
2532 0 : ecomm = ecommunity_parse(
2533 : stream_pnt(peer->curr), length,
2534 0 : CHECK_FLAG(peer->flags,
2535 : PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE));
2536 0 : bgp_attr_set_ecommunity(attr, ecomm);
2537 : /* XXX: fix ecommunity_parse to use stream API */
2538 0 : stream_forward_getp(peer->curr, length);
2539 :
2540 : /* The Extended Community attribute SHALL be considered malformed if
2541 : * its length is not a non-zero multiple of 8.
2542 : */
2543 0 : if (!bgp_attr_get_ecommunity(attr))
2544 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2545 0 : args->total);
2546 :
2547 : /* Extract DF election preference and mobility sequence number */
2548 0 : attr->df_pref = bgp_attr_df_pref_from_ec(attr, &attr->df_alg);
2549 :
2550 : /* Extract MAC mobility sequence number, if any. */
2551 0 : attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr, &sticky);
2552 0 : attr->sticky = sticky;
2553 :
2554 : /* Check if this is a Gateway MAC-IP advertisement */
2555 0 : attr->default_gw = bgp_attr_default_gw(attr);
2556 :
2557 : /* Handle scenario where router flag ecommunity is not
2558 : * set but default gw ext community is present.
2559 : * Use default gateway, set and propogate R-bit.
2560 : */
2561 0 : if (attr->default_gw)
2562 0 : attr->router_flag = 1;
2563 :
2564 : /* Check EVPN Neighbor advertisement flags, R-bit */
2565 0 : bgp_attr_evpn_na_flag(attr, &attr->router_flag, &proxy);
2566 0 : if (proxy)
2567 0 : attr->es_flags |= ATTR_ES_PROXY_ADVERT;
2568 :
2569 : /* Extract the Rmac, if any */
2570 0 : if (bgp_attr_rmac(attr, &attr->rmac)) {
2571 0 : if (bgp_debug_update(peer, NULL, NULL, 1)
2572 0 : && bgp_mac_exist(&attr->rmac))
2573 0 : zlog_debug("%s: router mac %pEA is self mac", __func__,
2574 : &attr->rmac);
2575 : }
2576 :
2577 : /* Get the tunnel type from encap extended community */
2578 0 : bgp_attr_extcom_tunnel_type(attr,
2579 0 : (bgp_encap_types *)&attr->encap_tunneltype);
2580 :
2581 : /* Extract link bandwidth, if any. */
2582 0 : (void)ecommunity_linkbw_present(bgp_attr_get_ecommunity(attr),
2583 : &attr->link_bw);
2584 :
2585 0 : return BGP_ATTR_PARSE_PROCEED;
2586 : }
2587 :
2588 : /* IPv6 Extended Community attribute. */
2589 : static enum bgp_attr_parse_ret
2590 0 : bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args)
2591 : {
2592 0 : struct peer *const peer = args->peer;
2593 0 : struct attr *const attr = args->attr;
2594 0 : const bgp_size_t length = args->length;
2595 0 : struct ecommunity *ipv6_ecomm = NULL;
2596 :
2597 0 : if (length == 0) {
2598 0 : bgp_attr_set_ipv6_ecommunity(attr, ipv6_ecomm);
2599 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2600 0 : args->total);
2601 : }
2602 :
2603 0 : if (peer->discard_attrs[args->type])
2604 0 : goto ipv6_ext_community_ignore;
2605 :
2606 0 : ipv6_ecomm = ecommunity_parse_ipv6(
2607 : stream_pnt(peer->curr), length,
2608 0 : CHECK_FLAG(peer->flags,
2609 : PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE));
2610 0 : bgp_attr_set_ipv6_ecommunity(attr, ipv6_ecomm);
2611 :
2612 : /* XXX: fix ecommunity_parse to use stream API */
2613 0 : stream_forward_getp(peer->curr, length);
2614 :
2615 0 : if (!ipv6_ecomm)
2616 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2617 0 : args->total);
2618 :
2619 : return BGP_ATTR_PARSE_PROCEED;
2620 :
2621 0 : ipv6_ext_community_ignore:
2622 0 : stream_forward_getp(peer->curr, length);
2623 :
2624 0 : if (bgp_debug_update(peer, NULL, NULL, 1))
2625 0 : zlog_debug("%pBP: Ignoring attribute %s", peer,
2626 : lookup_msg(attr_str, args->type, NULL));
2627 :
2628 : return BGP_ATTR_PARSE_PROCEED;
2629 : }
2630 :
2631 : /* Parse Tunnel Encap attribute in an UPDATE */
2632 0 : static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */
2633 : bgp_size_t length, /* IN: attr's length field */
2634 : struct attr *attr, /* IN: caller already allocated */
2635 : uint8_t flag, /* IN: attr's flags field */
2636 : uint8_t *startp)
2637 : {
2638 0 : bgp_size_t total;
2639 0 : uint16_t tunneltype = 0;
2640 :
2641 0 : total = length + (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
2642 :
2643 0 : if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)
2644 0 : || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL)) {
2645 0 : zlog_info(
2646 : "Tunnel Encap attribute flag isn't optional and transitive %d",
2647 : flag);
2648 0 : bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR,
2649 : BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
2650 : startp, total);
2651 0 : return -1;
2652 : }
2653 :
2654 0 : if (BGP_ATTR_ENCAP == type) {
2655 : /* read outer TLV type and length */
2656 0 : uint16_t tlv_length;
2657 :
2658 0 : if (length < 4) {
2659 0 : zlog_info(
2660 : "Tunnel Encap attribute not long enough to contain outer T,L");
2661 0 : bgp_notify_send_with_data(
2662 : peer, BGP_NOTIFY_UPDATE_ERR,
2663 : BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, startp, total);
2664 0 : return -1;
2665 : }
2666 0 : tunneltype = stream_getw(BGP_INPUT(peer));
2667 0 : tlv_length = stream_getw(BGP_INPUT(peer));
2668 0 : length -= 4;
2669 :
2670 0 : if (tlv_length != length) {
2671 0 : zlog_info("%s: tlv_length(%d) != length(%d)",
2672 : __func__, tlv_length, length);
2673 : }
2674 : }
2675 :
2676 0 : while (length >= 4) {
2677 0 : uint16_t subtype = 0;
2678 0 : uint16_t sublength = 0;
2679 0 : struct bgp_attr_encap_subtlv *tlv;
2680 :
2681 0 : if (BGP_ATTR_ENCAP == type) {
2682 0 : subtype = stream_getc(BGP_INPUT(peer));
2683 0 : sublength = stream_getc(BGP_INPUT(peer));
2684 0 : length -= 2;
2685 : #ifdef ENABLE_BGP_VNC
2686 : } else {
2687 0 : subtype = stream_getw(BGP_INPUT(peer));
2688 0 : sublength = stream_getw(BGP_INPUT(peer));
2689 0 : length -= 4;
2690 : #endif
2691 : }
2692 :
2693 0 : if (sublength > length) {
2694 0 : zlog_info(
2695 : "Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d",
2696 : sublength, length);
2697 0 : bgp_notify_send_with_data(
2698 : peer, BGP_NOTIFY_UPDATE_ERR,
2699 : BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, startp, total);
2700 0 : return -1;
2701 : }
2702 :
2703 : /* alloc and copy sub-tlv */
2704 : /* TBD make sure these are freed when attributes are released */
2705 0 : tlv = XCALLOC(MTYPE_ENCAP_TLV,
2706 : sizeof(struct bgp_attr_encap_subtlv) + sublength);
2707 0 : tlv->type = subtype;
2708 0 : tlv->length = sublength;
2709 0 : stream_get(tlv->value, peer->curr, sublength);
2710 0 : length -= sublength;
2711 :
2712 : /* attach tlv to encap chain */
2713 0 : if (BGP_ATTR_ENCAP == type) {
2714 0 : struct bgp_attr_encap_subtlv *stlv_last;
2715 0 : for (stlv_last = attr->encap_subtlvs;
2716 0 : stlv_last && stlv_last->next;
2717 : stlv_last = stlv_last->next)
2718 : ;
2719 0 : if (stlv_last) {
2720 0 : stlv_last->next = tlv;
2721 : } else {
2722 0 : attr->encap_subtlvs = tlv;
2723 : }
2724 : #ifdef ENABLE_BGP_VNC
2725 : } else {
2726 0 : struct bgp_attr_encap_subtlv *stlv_last;
2727 0 : struct bgp_attr_encap_subtlv *vnc_subtlvs =
2728 0 : bgp_attr_get_vnc_subtlvs(attr);
2729 :
2730 0 : for (stlv_last = vnc_subtlvs;
2731 0 : stlv_last && stlv_last->next;
2732 : stlv_last = stlv_last->next)
2733 : ;
2734 0 : if (stlv_last)
2735 0 : stlv_last->next = tlv;
2736 : else
2737 0 : bgp_attr_set_vnc_subtlvs(attr, tlv);
2738 : #endif
2739 : }
2740 : }
2741 :
2742 0 : if (BGP_ATTR_ENCAP == type) {
2743 0 : attr->encap_tunneltype = tunneltype;
2744 : }
2745 :
2746 0 : if (length) {
2747 : /* spurious leftover data */
2748 0 : zlog_info(
2749 : "Tunnel Encap attribute length is bad: %d leftover octets",
2750 : length);
2751 0 : bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR,
2752 : BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2753 : startp, total);
2754 0 : return -1;
2755 : }
2756 :
2757 : return 0;
2758 : }
2759 :
2760 :
2761 : /* SRv6 Service Data Sub-Sub-TLV attribute
2762 : * draft-ietf-bess-srv6-services-07
2763 : */
2764 : static enum bgp_attr_parse_ret
2765 0 : bgp_attr_srv6_service_data(struct bgp_attr_parser_args *args)
2766 : {
2767 0 : struct peer *const peer = args->peer;
2768 0 : struct attr *const attr = args->attr;
2769 0 : uint8_t type, loc_block_len, loc_node_len, func_len, arg_len,
2770 : transposition_len, transposition_offset;
2771 0 : uint16_t length;
2772 0 : size_t headersz = sizeof(type) + sizeof(length);
2773 :
2774 0 : if (STREAM_READABLE(peer->curr) < headersz) {
2775 0 : flog_err(
2776 : EC_BGP_ATTR_LEN,
2777 : "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
2778 : headersz, STREAM_READABLE(peer->curr));
2779 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2780 0 : args->total);
2781 : }
2782 :
2783 0 : type = stream_getc(peer->curr);
2784 0 : length = stream_getw(peer->curr);
2785 :
2786 0 : if (STREAM_READABLE(peer->curr) < length) {
2787 0 : flog_err(
2788 : EC_BGP_ATTR_LEN,
2789 : "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)",
2790 : length, STREAM_READABLE(peer->curr));
2791 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2792 0 : args->total);
2793 : }
2794 :
2795 0 : if (length < BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH) {
2796 0 : flog_err(
2797 : EC_BGP_ATTR_LEN,
2798 : "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficient data (need %u, have %hu remaining in UPDATE)",
2799 : BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH,
2800 : length);
2801 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2802 0 : args->total);
2803 : }
2804 :
2805 0 : if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE) {
2806 0 : if (STREAM_READABLE(peer->curr) <
2807 : BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH) {
2808 0 : flog_err(
2809 : EC_BGP_ATTR_LEN,
2810 : "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficient data (need %u, have %zu remaining in UPDATE)",
2811 : BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH,
2812 : STREAM_READABLE(peer->curr));
2813 0 : return bgp_attr_malformed(
2814 : args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2815 0 : args->total);
2816 : }
2817 :
2818 0 : loc_block_len = stream_getc(peer->curr);
2819 0 : loc_node_len = stream_getc(peer->curr);
2820 0 : func_len = stream_getc(peer->curr);
2821 0 : arg_len = stream_getc(peer->curr);
2822 0 : transposition_len = stream_getc(peer->curr);
2823 0 : transposition_offset = stream_getc(peer->curr);
2824 :
2825 : /* Log SRv6 Service Data Sub-Sub-TLV */
2826 0 : if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
2827 0 : zlog_debug(
2828 : "%s: srv6-l3-srv-data loc-block-len=%u, loc-node-len=%u func-len=%u, arg-len=%u, transposition-len=%u, transposition-offset=%u",
2829 : __func__, loc_block_len, loc_node_len, func_len,
2830 : arg_len, transposition_len,
2831 : transposition_offset);
2832 : }
2833 :
2834 0 : attr->srv6_l3vpn->loc_block_len = loc_block_len;
2835 0 : attr->srv6_l3vpn->loc_node_len = loc_node_len;
2836 0 : attr->srv6_l3vpn->func_len = func_len;
2837 0 : attr->srv6_l3vpn->arg_len = arg_len;
2838 0 : attr->srv6_l3vpn->transposition_len = transposition_len;
2839 0 : attr->srv6_l3vpn->transposition_offset = transposition_offset;
2840 : }
2841 :
2842 : else {
2843 0 : if (bgp_debug_update(peer, NULL, NULL, 1))
2844 0 : zlog_debug(
2845 : "%s attr SRv6 Service Data Sub-Sub-TLV sub-sub-type=%u is not supported, skipped",
2846 : peer->host, type);
2847 :
2848 0 : stream_forward_getp(peer->curr, length);
2849 : }
2850 :
2851 : return BGP_ATTR_PARSE_PROCEED;
2852 : }
2853 :
2854 : /* SRv6 Service Sub-TLV attribute
2855 : * draft-ietf-bess-srv6-services-07
2856 : */
2857 : static enum bgp_attr_parse_ret
2858 0 : bgp_attr_srv6_service(struct bgp_attr_parser_args *args)
2859 : {
2860 0 : struct peer *const peer = args->peer;
2861 0 : struct attr *const attr = args->attr;
2862 0 : struct in6_addr ipv6_sid;
2863 0 : uint8_t type, sid_flags;
2864 0 : uint16_t length, endpoint_behavior;
2865 0 : size_t headersz = sizeof(type) + sizeof(length);
2866 0 : enum bgp_attr_parse_ret err;
2867 :
2868 0 : if (STREAM_READABLE(peer->curr) < headersz) {
2869 0 : flog_err(
2870 : EC_BGP_ATTR_LEN,
2871 : "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
2872 : headersz, STREAM_READABLE(peer->curr));
2873 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2874 0 : args->total);
2875 : }
2876 :
2877 0 : type = stream_getc(peer->curr);
2878 0 : length = stream_getw(peer->curr);
2879 :
2880 0 : if (STREAM_READABLE(peer->curr) < length) {
2881 0 : flog_err(
2882 : EC_BGP_ATTR_LEN,
2883 : "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)",
2884 : length, STREAM_READABLE(peer->curr));
2885 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2886 0 : args->total);
2887 : }
2888 :
2889 0 : if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO) {
2890 0 : if (STREAM_READABLE(peer->curr) <
2891 : BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH) {
2892 0 : flog_err(
2893 : EC_BGP_ATTR_LEN,
2894 : "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %d for attribute data, have %zu remaining in UPDATE)",
2895 : BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH,
2896 : STREAM_READABLE(peer->curr));
2897 0 : return bgp_attr_malformed(
2898 : args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2899 0 : args->total);
2900 : }
2901 0 : stream_getc(peer->curr);
2902 0 : stream_get(&ipv6_sid, peer->curr, sizeof(ipv6_sid));
2903 0 : sid_flags = stream_getc(peer->curr);
2904 0 : endpoint_behavior = stream_getw(peer->curr);
2905 0 : stream_getc(peer->curr);
2906 :
2907 : /* Log SRv6 Service Sub-TLV */
2908 0 : if (BGP_DEBUG(vpn, VPN_LEAK_LABEL))
2909 0 : zlog_debug(
2910 : "%s: srv6-l3-srv sid %pI6, sid-flags 0x%02x, end-behaviour 0x%04x",
2911 : __func__, &ipv6_sid, sid_flags,
2912 : endpoint_behavior);
2913 :
2914 : /* Configure from Info */
2915 0 : if (attr->srv6_l3vpn) {
2916 0 : flog_err(EC_BGP_ATTRIBUTE_REPEATED,
2917 : "Prefix SID SRv6 L3VPN field repeated");
2918 0 : return bgp_attr_malformed(
2919 0 : args, BGP_NOTIFY_UPDATE_MAL_ATTR, args->total);
2920 : }
2921 0 : attr->srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN,
2922 : sizeof(struct bgp_attr_srv6_l3vpn));
2923 0 : sid_copy(&attr->srv6_l3vpn->sid, &ipv6_sid);
2924 0 : attr->srv6_l3vpn->sid_flags = sid_flags;
2925 0 : attr->srv6_l3vpn->endpoint_behavior = endpoint_behavior;
2926 0 : attr->srv6_l3vpn->loc_block_len = 0;
2927 0 : attr->srv6_l3vpn->loc_node_len = 0;
2928 0 : attr->srv6_l3vpn->func_len = 0;
2929 0 : attr->srv6_l3vpn->arg_len = 0;
2930 0 : attr->srv6_l3vpn->transposition_len = 0;
2931 0 : attr->srv6_l3vpn->transposition_offset = 0;
2932 :
2933 : // Sub-Sub-TLV found
2934 0 : if (length > BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH) {
2935 0 : err = bgp_attr_srv6_service_data(args);
2936 :
2937 0 : if (err != BGP_ATTR_PARSE_PROCEED)
2938 : return err;
2939 : }
2940 :
2941 0 : attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn);
2942 : }
2943 :
2944 : /* Placeholder code for unsupported type */
2945 : else {
2946 0 : if (bgp_debug_update(peer, NULL, NULL, 1))
2947 0 : zlog_debug(
2948 : "%s attr SRv6 Service Sub-TLV sub-type=%u is not supported, skipped",
2949 : peer->host, type);
2950 :
2951 0 : stream_forward_getp(peer->curr, length);
2952 : }
2953 :
2954 : return BGP_ATTR_PARSE_PROCEED;
2955 : }
2956 :
2957 : /*
2958 : * Read an individual SID value returning how much data we have read
2959 : * Returns 0 if there was an error that needs to be passed up the stack
2960 : */
2961 : static enum bgp_attr_parse_ret
2962 0 : bgp_attr_psid_sub(uint8_t type, uint16_t length,
2963 : struct bgp_attr_parser_args *args)
2964 : {
2965 0 : struct peer *const peer = args->peer;
2966 0 : struct attr *const attr = args->attr;
2967 0 : uint32_t label_index;
2968 0 : struct in6_addr ipv6_sid;
2969 0 : uint32_t srgb_base;
2970 0 : uint32_t srgb_range;
2971 0 : int srgb_count;
2972 0 : uint8_t sid_type, sid_flags;
2973 :
2974 0 : if (type == BGP_PREFIX_SID_LABEL_INDEX) {
2975 0 : if (STREAM_READABLE(peer->curr) < length
2976 0 : || length != BGP_PREFIX_SID_LABEL_INDEX_LENGTH) {
2977 0 : flog_err(EC_BGP_ATTR_LEN,
2978 : "Prefix SID label index length is %hu instead of %u",
2979 : length, BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
2980 0 : return bgp_attr_malformed(args,
2981 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2982 0 : args->total);
2983 : }
2984 :
2985 : /* Ignore flags and reserved */
2986 0 : stream_getc(peer->curr);
2987 0 : stream_getw(peer->curr);
2988 :
2989 : /* Fetch the label index and see if it is valid. */
2990 0 : label_index = stream_getl(peer->curr);
2991 0 : if (label_index == BGP_INVALID_LABEL_INDEX)
2992 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2993 0 : args->total);
2994 :
2995 : /* Store label index; subsequently, we'll check on
2996 : * address-family */
2997 0 : attr->label_index = label_index;
2998 : }
2999 :
3000 : /* Placeholder code for the IPv6 SID type */
3001 0 : else if (type == BGP_PREFIX_SID_IPV6) {
3002 0 : if (STREAM_READABLE(peer->curr) < length
3003 0 : || length != BGP_PREFIX_SID_IPV6_LENGTH) {
3004 0 : flog_err(EC_BGP_ATTR_LEN,
3005 : "Prefix SID IPv6 length is %hu instead of %u",
3006 : length, BGP_PREFIX_SID_IPV6_LENGTH);
3007 0 : return bgp_attr_malformed(args,
3008 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3009 0 : args->total);
3010 : }
3011 :
3012 : /* Ignore reserved */
3013 0 : stream_getc(peer->curr);
3014 0 : stream_getw(peer->curr);
3015 :
3016 0 : stream_get(&ipv6_sid, peer->curr, 16);
3017 : }
3018 :
3019 : /* Placeholder code for the Originator SRGB type */
3020 0 : else if (type == BGP_PREFIX_SID_ORIGINATOR_SRGB) {
3021 : /*
3022 : * ietf-idr-bgp-prefix-sid-05:
3023 : * Length is the total length of the value portion of the
3024 : * TLV: 2 + multiple of 6.
3025 : *
3026 : * peer->curr stream readp should be at the beginning of the 16
3027 : * bit flag field at this point in the code.
3028 : */
3029 :
3030 : /*
3031 : * Check that the TLV length field is sane: at least 2 bytes of
3032 : * flag, and at least 1 SRGB (these are 6 bytes each)
3033 : */
3034 0 : if (length < (2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH)) {
3035 0 : flog_err(
3036 : EC_BGP_ATTR_LEN,
3037 : "Prefix SID Originator SRGB length field claims length of %hu bytes, but the minimum for this TLV type is %u",
3038 : length,
3039 : 2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH);
3040 0 : return bgp_attr_malformed(
3041 : args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3042 0 : args->total);
3043 : }
3044 :
3045 : /*
3046 : * Check that we actually have at least as much data as
3047 : * specified by the length field
3048 : */
3049 0 : if (STREAM_READABLE(peer->curr) < length) {
3050 0 : flog_err(EC_BGP_ATTR_LEN,
3051 : "Prefix SID Originator SRGB specifies length %hu, but only %zu bytes remain",
3052 : length, STREAM_READABLE(peer->curr));
3053 0 : return bgp_attr_malformed(
3054 : args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3055 0 : args->total);
3056 : }
3057 :
3058 : /*
3059 : * Check that the portion of the TLV containing the sequence of
3060 : * SRGBs corresponds to a multiple of the SRGB size; to get
3061 : * that length, we skip the 16 bit flags field
3062 : */
3063 0 : stream_getw(peer->curr);
3064 0 : length -= 2;
3065 0 : if (length % BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH) {
3066 0 : flog_err(
3067 : EC_BGP_ATTR_LEN,
3068 : "Prefix SID Originator SRGB length field claims attribute SRGB sequence section is %hubytes, but it must be a multiple of %u",
3069 : length, BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH);
3070 0 : return bgp_attr_malformed(
3071 : args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3072 0 : args->total);
3073 : }
3074 :
3075 0 : srgb_count = length / BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH;
3076 :
3077 0 : for (int i = 0; i < srgb_count; i++) {
3078 0 : stream_get(&srgb_base, peer->curr, 3);
3079 0 : stream_get(&srgb_range, peer->curr, 3);
3080 : }
3081 : }
3082 :
3083 : /* Placeholder code for the VPN-SID Service type */
3084 0 : else if (type == BGP_PREFIX_SID_VPN_SID) {
3085 0 : if (STREAM_READABLE(peer->curr) < length
3086 0 : || length != BGP_PREFIX_SID_VPN_SID_LENGTH) {
3087 0 : flog_err(EC_BGP_ATTR_LEN,
3088 : "Prefix SID VPN SID length is %hu instead of %u",
3089 : length, BGP_PREFIX_SID_VPN_SID_LENGTH);
3090 0 : return bgp_attr_malformed(args,
3091 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3092 0 : args->total);
3093 : }
3094 :
3095 : /* Parse VPN-SID Sub-TLV */
3096 0 : stream_getc(peer->curr); /* reserved */
3097 0 : sid_type = stream_getc(peer->curr); /* sid_type */
3098 0 : sid_flags = stream_getc(peer->curr); /* sid_flags */
3099 0 : stream_get(&ipv6_sid, peer->curr,
3100 : sizeof(ipv6_sid)); /* sid_value */
3101 :
3102 : /* Log VPN-SID Sub-TLV */
3103 0 : if (BGP_DEBUG(vpn, VPN_LEAK_LABEL))
3104 0 : zlog_debug(
3105 : "%s: vpn-sid: sid %pI6, sid-type 0x%02x sid-flags 0x%02x",
3106 : __func__, &ipv6_sid, sid_type, sid_flags);
3107 :
3108 : /* Configure from Info */
3109 0 : if (attr->srv6_vpn) {
3110 0 : flog_err(EC_BGP_ATTRIBUTE_REPEATED,
3111 : "Prefix SID SRv6 VPN field repeated");
3112 0 : return bgp_attr_malformed(
3113 0 : args, BGP_NOTIFY_UPDATE_MAL_ATTR, args->total);
3114 : }
3115 0 : attr->srv6_vpn = XCALLOC(MTYPE_BGP_SRV6_VPN,
3116 : sizeof(struct bgp_attr_srv6_vpn));
3117 0 : attr->srv6_vpn->sid_flags = sid_flags;
3118 0 : sid_copy(&attr->srv6_vpn->sid, &ipv6_sid);
3119 0 : attr->srv6_vpn = srv6_vpn_intern(attr->srv6_vpn);
3120 : }
3121 :
3122 : /* Placeholder code for the SRv6 L3 Service type */
3123 0 : else if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE) {
3124 0 : if (STREAM_READABLE(peer->curr) < length) {
3125 0 : flog_err(
3126 : EC_BGP_ATTR_LEN,
3127 : "Prefix SID SRv6 L3-Service length is %hu, but only %zu bytes remain",
3128 : length, STREAM_READABLE(peer->curr));
3129 0 : return bgp_attr_malformed(args,
3130 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3131 0 : args->total);
3132 : }
3133 :
3134 : /* ignore reserved */
3135 0 : stream_getc(peer->curr);
3136 :
3137 0 : return bgp_attr_srv6_service(args);
3138 : }
3139 :
3140 : /* Placeholder code for Unsupported TLV */
3141 : else {
3142 :
3143 0 : if (STREAM_READABLE(peer->curr) < length) {
3144 0 : flog_err(
3145 : EC_BGP_ATTR_LEN,
3146 : "Prefix SID SRv6 length is %hu - too long, only %zu remaining in this UPDATE",
3147 : length, STREAM_READABLE(peer->curr));
3148 0 : return bgp_attr_malformed(
3149 : args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3150 0 : args->total);
3151 : }
3152 :
3153 0 : if (bgp_debug_update(peer, NULL, NULL, 1))
3154 0 : zlog_debug(
3155 : "%s attr Prefix-SID sub-type=%u is not supported, skipped",
3156 : peer->host, type);
3157 :
3158 0 : stream_forward_getp(peer->curr, length);
3159 : }
3160 :
3161 : return BGP_ATTR_PARSE_PROCEED;
3162 : }
3163 :
3164 : /* Prefix SID attribute
3165 : * draft-ietf-idr-bgp-prefix-sid-05
3166 : */
3167 0 : enum bgp_attr_parse_ret bgp_attr_prefix_sid(struct bgp_attr_parser_args *args)
3168 : {
3169 0 : struct peer *const peer = args->peer;
3170 0 : struct attr *const attr = args->attr;
3171 0 : enum bgp_attr_parse_ret ret;
3172 :
3173 0 : attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID);
3174 :
3175 0 : uint8_t type;
3176 0 : uint16_t length;
3177 0 : size_t headersz = sizeof(type) + sizeof(length);
3178 0 : size_t psid_parsed_length = 0;
3179 :
3180 0 : while (STREAM_READABLE(peer->curr) > 0
3181 0 : && psid_parsed_length < args->length) {
3182 :
3183 0 : if (STREAM_READABLE(peer->curr) < headersz) {
3184 0 : flog_err(
3185 : EC_BGP_ATTR_LEN,
3186 : "Malformed Prefix SID attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
3187 : headersz, STREAM_READABLE(peer->curr));
3188 0 : return bgp_attr_malformed(
3189 : args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3190 0 : args->total);
3191 : }
3192 :
3193 0 : type = stream_getc(peer->curr);
3194 0 : length = stream_getw(peer->curr);
3195 :
3196 0 : if (STREAM_READABLE(peer->curr) < length) {
3197 0 : flog_err(
3198 : EC_BGP_ATTR_LEN,
3199 : "Malformed Prefix SID attribute - insufficient data (need %hu for attribute body, have %zu remaining in UPDATE)",
3200 : length, STREAM_READABLE(peer->curr));
3201 0 : return bgp_attr_malformed(args,
3202 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3203 0 : args->total);
3204 : }
3205 :
3206 0 : ret = bgp_attr_psid_sub(type, length, args);
3207 :
3208 0 : if (ret != BGP_ATTR_PARSE_PROCEED)
3209 0 : return ret;
3210 :
3211 0 : psid_parsed_length += length + headersz;
3212 :
3213 0 : if (psid_parsed_length > args->length) {
3214 0 : flog_err(
3215 : EC_BGP_ATTR_LEN,
3216 : "Malformed Prefix SID attribute - TLV overflow by attribute (need %zu for TLV length, have %zu overflowed in UPDATE)",
3217 : length + headersz, psid_parsed_length - (length + headersz));
3218 0 : return bgp_attr_malformed(
3219 : args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3220 0 : args->total);
3221 : }
3222 : }
3223 :
3224 : return BGP_ATTR_PARSE_PROCEED;
3225 : }
3226 :
3227 : /* PMSI tunnel attribute (RFC 6514)
3228 : * Basic validation checks done here.
3229 : */
3230 : static enum bgp_attr_parse_ret
3231 0 : bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args)
3232 : {
3233 0 : struct peer *const peer = args->peer;
3234 0 : struct attr *const attr = args->attr;
3235 0 : const bgp_size_t length = args->length;
3236 0 : uint8_t tnl_type;
3237 0 : int attr_parse_len = 2 + BGP_LABEL_BYTES;
3238 :
3239 : /* Verify that the receiver is expecting "ingress replication" as we
3240 : * can only support that.
3241 : */
3242 0 : if (length < attr_parse_len) {
3243 0 : flog_err(EC_BGP_ATTR_LEN, "Bad PMSI tunnel attribute length %d",
3244 : length);
3245 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3246 0 : args->total);
3247 : }
3248 0 : stream_getc(peer->curr); /* Flags */
3249 0 : tnl_type = stream_getc(peer->curr);
3250 0 : if (tnl_type > PMSI_TNLTYPE_MAX) {
3251 0 : flog_err(EC_BGP_ATTR_PMSI_TYPE,
3252 : "Invalid PMSI tunnel attribute type %d", tnl_type);
3253 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
3254 0 : args->total);
3255 : }
3256 0 : if (tnl_type == PMSI_TNLTYPE_INGR_REPL) {
3257 0 : if (length != 9) {
3258 0 : flog_err(EC_BGP_ATTR_PMSI_LEN,
3259 : "Bad PMSI tunnel attribute length %d for IR",
3260 : length);
3261 0 : return bgp_attr_malformed(
3262 : args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3263 0 : args->total);
3264 : }
3265 : }
3266 :
3267 0 : attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
3268 0 : bgp_attr_set_pmsi_tnl_type(attr, tnl_type);
3269 0 : stream_get(&attr->label, peer->curr, BGP_LABEL_BYTES);
3270 :
3271 : /* Forward read pointer of input stream. */
3272 0 : stream_forward_getp(peer->curr, length - attr_parse_len);
3273 :
3274 0 : return BGP_ATTR_PARSE_PROCEED;
3275 : }
3276 :
3277 : /* AIGP attribute (rfc7311) */
3278 0 : static enum bgp_attr_parse_ret bgp_attr_aigp(struct bgp_attr_parser_args *args)
3279 : {
3280 0 : struct peer *const peer = args->peer;
3281 0 : struct attr *const attr = args->attr;
3282 0 : const bgp_size_t length = args->length;
3283 0 : uint8_t *s = stream_pnt(peer->curr);
3284 0 : uint64_t aigp = 0;
3285 :
3286 : /* If an AIGP attribute is received on a BGP session for which
3287 : * AIGP_SESSION is disabled, the attribute MUST be treated exactly
3288 : * as if it were an unrecognized non-transitive attribute.
3289 : * That is, it "MUST be quietly ignored and not passed along to
3290 : * other BGP peers".
3291 : * For Internal BGP (IBGP) sessions, and for External BGP (EBGP)
3292 : * sessions between members of the same BGP Confederation,
3293 : * the default value of AIGP_SESSION SHOULD be "enabled".
3294 : */
3295 0 : if (peer->sort == BGP_PEER_EBGP &&
3296 0 : !CHECK_FLAG(peer->flags, PEER_FLAG_AIGP)) {
3297 0 : zlog_warn(
3298 : "%pBP received AIGP attribute, but eBGP peer do not support it",
3299 : peer);
3300 0 : goto aigp_ignore;
3301 : }
3302 :
3303 0 : if (peer->discard_attrs[args->type])
3304 0 : goto aigp_ignore;
3305 :
3306 0 : if (!bgp_attr_aigp_valid(s, length))
3307 0 : goto aigp_ignore;
3308 :
3309 : /* Extract AIGP Metric TLV */
3310 0 : if (bgp_attr_aigp_get_tlv_metric(s, length, &aigp))
3311 0 : bgp_attr_set_aigp_metric(attr, aigp);
3312 :
3313 0 : aigp_ignore:
3314 0 : stream_forward_getp(peer->curr, length);
3315 :
3316 0 : if (bgp_debug_update(peer, NULL, NULL, 1))
3317 0 : zlog_debug("%pBP: Ignoring attribute %s", peer,
3318 : lookup_msg(attr_str, args->type, NULL));
3319 :
3320 0 : return BGP_ATTR_PARSE_PROCEED;
3321 : }
3322 :
3323 : /* OTC attribute. */
3324 0 : static enum bgp_attr_parse_ret bgp_attr_otc(struct bgp_attr_parser_args *args)
3325 : {
3326 0 : struct peer *const peer = args->peer;
3327 0 : struct attr *const attr = args->attr;
3328 0 : const bgp_size_t length = args->length;
3329 :
3330 : /* Length check. */
3331 0 : if (length != 4) {
3332 0 : flog_err(EC_BGP_ATTR_LEN, "OTC attribute length isn't 4 [%u]",
3333 : length);
3334 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3335 0 : args->total);
3336 : }
3337 :
3338 0 : if (peer->discard_attrs[args->type])
3339 0 : goto otc_ignore;
3340 :
3341 0 : attr->otc = stream_getl(peer->curr);
3342 0 : if (!attr->otc) {
3343 0 : flog_err(EC_BGP_ATTR_MAL_AS_PATH, "OTC attribute value is 0");
3344 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
3345 0 : args->total);
3346 : }
3347 :
3348 0 : attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_OTC);
3349 :
3350 0 : return BGP_ATTR_PARSE_PROCEED;
3351 :
3352 0 : otc_ignore:
3353 0 : stream_forward_getp(peer->curr, length);
3354 :
3355 0 : if (bgp_debug_update(peer, NULL, NULL, 1))
3356 0 : zlog_debug("%pBP: Ignoring attribute %s", peer,
3357 : lookup_msg(attr_str, args->type, NULL));
3358 :
3359 : return BGP_ATTR_PARSE_PROCEED;
3360 : }
3361 :
3362 : /* BGP unknown attribute treatment. */
3363 : static enum bgp_attr_parse_ret
3364 0 : bgp_attr_unknown(struct bgp_attr_parser_args *args)
3365 : {
3366 0 : bgp_size_t total = args->total;
3367 0 : struct transit *transit;
3368 0 : struct peer *const peer = args->peer;
3369 0 : struct attr *const attr = args->attr;
3370 0 : uint8_t *const startp = args->startp;
3371 0 : const uint8_t type = args->type;
3372 0 : const uint8_t flag = args->flags;
3373 0 : const bgp_size_t length = args->length;
3374 :
3375 0 : if (bgp_debug_update(peer, NULL, NULL, 1))
3376 0 : zlog_debug(
3377 : "%s Unknown attribute is received (type %d, length %d)",
3378 : peer->host, type, length);
3379 :
3380 : /* Forward read pointer of input stream. */
3381 0 : stream_forward_getp(peer->curr, length);
3382 :
3383 0 : if (peer->discard_attrs[type]) {
3384 0 : if (bgp_debug_update(peer, NULL, NULL, 1))
3385 0 : zlog_debug("%pBP: Ignoring attribute %s", peer,
3386 : lookup_msg(attr_str, args->type, NULL));
3387 :
3388 0 : return BGP_ATTR_PARSE_PROCEED;
3389 : }
3390 :
3391 : /* If any of the mandatory well-known attributes are not recognized,
3392 : then the Error Subcode is set to Unrecognized Well-known
3393 : Attribute. The Data field contains the unrecognized attribute
3394 : (type, length and value). */
3395 0 : if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL)) {
3396 0 : return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_UNREC_ATTR,
3397 0 : args->total);
3398 : }
3399 :
3400 : /* Unrecognized non-transitive optional attributes must be quietly
3401 : ignored and not passed along to other BGP peers. */
3402 0 : if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS))
3403 : return BGP_ATTR_PARSE_PROCEED;
3404 :
3405 : /* If a path with recognized transitive optional attribute is
3406 : accepted and passed along to other BGP peers and the Partial bit
3407 : in the Attribute Flags octet is set to 1 by some previous AS, it
3408 : is not set back to 0 by the current AS. */
3409 0 : SET_FLAG(*startp, BGP_ATTR_FLAG_PARTIAL);
3410 :
3411 : /* Store transitive attribute to the end of attr->transit. */
3412 0 : transit = bgp_attr_get_transit(attr);
3413 0 : if (!transit)
3414 0 : transit = XCALLOC(MTYPE_TRANSIT, sizeof(struct transit));
3415 :
3416 0 : transit->val = XREALLOC(MTYPE_TRANSIT_VAL, transit->val,
3417 : transit->length + total);
3418 :
3419 0 : memcpy(transit->val + transit->length, startp, total);
3420 0 : transit->length += total;
3421 0 : bgp_attr_set_transit(attr, transit);
3422 :
3423 0 : return BGP_ATTR_PARSE_PROCEED;
3424 : }
3425 :
3426 : /* Well-known attribute check. */
3427 3 : static int bgp_attr_check(struct peer *peer, struct attr *attr)
3428 : {
3429 3 : uint8_t type = 0;
3430 :
3431 : /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an
3432 : * empty UPDATE. */
3433 3 : if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV) && !attr->flag)
3434 : return BGP_ATTR_PARSE_PROCEED;
3435 :
3436 : /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required
3437 : to carry any other path attributes.", though if MP_REACH_NLRI or NLRI
3438 : are present, it should. Check for any other attribute being present
3439 : instead.
3440 : */
3441 3 : if ((!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI)) &&
3442 : CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI))))
3443 : return BGP_ATTR_PARSE_PROCEED;
3444 :
3445 3 : if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN)))
3446 0 : type = BGP_ATTR_ORIGIN;
3447 :
3448 3 : if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
3449 0 : type = BGP_ATTR_AS_PATH;
3450 :
3451 : /* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present
3452 : * and
3453 : * NLRI is empty. We can't easily check NLRI empty here though.
3454 : */
3455 3 : if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP))
3456 3 : && !CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI)))
3457 0 : type = BGP_ATTR_NEXT_HOP;
3458 :
3459 3 : if (peer->sort == BGP_PEER_IBGP
3460 0 : && !CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)))
3461 : type = BGP_ATTR_LOCAL_PREF;
3462 :
3463 : /* If any of the well-known mandatory attributes are not present
3464 : * in an UPDATE message, then "treat-as-withdraw" MUST be used.
3465 : */
3466 3 : if (type) {
3467 0 : flog_warn(EC_BGP_MISSING_ATTRIBUTE,
3468 : "%s Missing well-known attribute %s.", peer->host,
3469 : lookup_msg(attr_str, type, NULL));
3470 0 : return BGP_ATTR_PARSE_WITHDRAW;
3471 : }
3472 : return BGP_ATTR_PARSE_PROCEED;
3473 : }
3474 :
3475 : /* Read attribute of update packet. This function is called from
3476 : bgp_update_receive() in bgp_packet.c. */
3477 3 : enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr,
3478 : bgp_size_t size,
3479 : struct bgp_nlri *mp_update,
3480 : struct bgp_nlri *mp_withdraw)
3481 : {
3482 3 : enum bgp_attr_parse_ret ret;
3483 3 : uint8_t flag = 0;
3484 3 : uint8_t type = 0;
3485 3 : bgp_size_t length;
3486 3 : uint8_t *startp, *endp;
3487 3 : uint8_t *attr_endp;
3488 3 : uint8_t seen[BGP_ATTR_BITMAP_SIZE];
3489 : /* we need the as4_path only until we have synthesized the as_path with
3490 : * it */
3491 : /* same goes for as4_aggregator */
3492 3 : struct aspath *as4_path = NULL;
3493 3 : as_t as4_aggregator = 0;
3494 3 : struct in_addr as4_aggregator_addr = {.s_addr = 0};
3495 3 : struct transit *transit;
3496 :
3497 : /* Initialize bitmap. */
3498 3 : memset(seen, 0, BGP_ATTR_BITMAP_SIZE);
3499 :
3500 : /* End pointer of BGP attribute. */
3501 3 : endp = BGP_INPUT_PNT(peer) + size;
3502 :
3503 : /* Get attributes to the end of attribute length. */
3504 14 : while (BGP_INPUT_PNT(peer) < endp) {
3505 : /* Check remaining length check.*/
3506 11 : if (endp - BGP_INPUT_PNT(peer) < BGP_ATTR_MIN_LEN) {
3507 : /* XXX warning: long int format, int arg (arg 5) */
3508 0 : flog_warn(
3509 : EC_BGP_ATTRIBUTE_TOO_SMALL,
3510 : "%s: error BGP attribute length %lu is smaller than min len",
3511 : peer->host,
3512 : (unsigned long)(endp
3513 : - stream_pnt(BGP_INPUT(peer))));
3514 :
3515 0 : bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
3516 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
3517 0 : ret = BGP_ATTR_PARSE_ERROR;
3518 0 : goto done;
3519 : }
3520 :
3521 : /* Fetch attribute flag and type. */
3522 11 : startp = BGP_INPUT_PNT(peer);
3523 : /* "The lower-order four bits of the Attribute Flags octet are
3524 : unused. They MUST be zero when sent and MUST be ignored when
3525 : received." */
3526 11 : flag = 0xF0 & stream_getc(BGP_INPUT(peer));
3527 11 : type = stream_getc(BGP_INPUT(peer));
3528 :
3529 : /* Check whether Extended-Length applies and is in bounds */
3530 11 : if (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN)
3531 3 : && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1))) {
3532 0 : flog_warn(
3533 : EC_BGP_EXT_ATTRIBUTE_TOO_SMALL,
3534 : "%s: Extended length set, but just %lu bytes of attr header",
3535 : peer->host,
3536 : (unsigned long)(endp
3537 : - stream_pnt(BGP_INPUT(peer))));
3538 :
3539 0 : bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
3540 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
3541 0 : ret = BGP_ATTR_PARSE_ERROR;
3542 0 : goto done;
3543 : }
3544 :
3545 : /* Check extended attribue length bit. */
3546 11 : if (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN))
3547 3 : length = stream_getw(BGP_INPUT(peer));
3548 : else
3549 8 : length = stream_getc(BGP_INPUT(peer));
3550 :
3551 : /* If any attribute appears more than once in the UPDATE
3552 : message, then the Error Subcode is set to Malformed Attribute
3553 : List. */
3554 :
3555 11 : if (CHECK_BITMAP(seen, type)) {
3556 0 : flog_warn(
3557 : EC_BGP_ATTRIBUTE_REPEATED,
3558 : "%s: error BGP attribute type %d appears twice in a message",
3559 : peer->host, type);
3560 :
3561 0 : bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
3562 : BGP_NOTIFY_UPDATE_MAL_ATTR);
3563 0 : ret = BGP_ATTR_PARSE_ERROR;
3564 0 : goto done;
3565 : }
3566 :
3567 : /* Set type to bitmap to check duplicate attribute. `type' is
3568 : unsigned char so it never overflow bitmap range. */
3569 :
3570 11 : SET_BITMAP(seen, type);
3571 :
3572 : /* Overflow check. */
3573 11 : attr_endp = BGP_INPUT_PNT(peer) + length;
3574 :
3575 11 : if (attr_endp > endp) {
3576 0 : flog_warn(
3577 : EC_BGP_ATTRIBUTE_TOO_LARGE,
3578 : "%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p",
3579 : peer->host, type, length, size, attr_endp,
3580 : endp);
3581 : /*
3582 : * RFC 4271 6.3
3583 : * If any recognized attribute has an Attribute
3584 : * Length that conflicts with the expected length
3585 : * (based on the attribute type code), then the
3586 : * Error Subcode MUST be set to Attribute Length
3587 : * Error. The Data field MUST contain the erroneous
3588 : * attribute (type, length, and value).
3589 : * ----------
3590 : * We do not currently have a good way to determine the
3591 : * length of the attribute independent of the length
3592 : * received in the message. Instead we send the
3593 : * minimum between the amount of data we have and the
3594 : * amount specified by the attribute length field.
3595 : *
3596 : * Instead of directly passing in the packet buffer and
3597 : * offset we use the stream_get* functions to read into
3598 : * a stack buffer, since they perform bounds checking
3599 : * and we are working with untrusted data.
3600 : */
3601 0 : unsigned char ndata[peer->max_packet_size];
3602 0 : memset(ndata, 0x00, sizeof(ndata));
3603 0 : size_t lfl =
3604 0 : CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN) ? 2 : 1;
3605 : /* Rewind to end of flag field */
3606 0 : stream_rewind_getp(BGP_INPUT(peer), (1 + lfl));
3607 : /* Type */
3608 0 : stream_get(&ndata[0], BGP_INPUT(peer), 1);
3609 : /* Length */
3610 0 : stream_get(&ndata[1], BGP_INPUT(peer), lfl);
3611 : /* Value */
3612 0 : size_t atl = attr_endp - startp;
3613 0 : size_t ndl = MIN(atl, STREAM_READABLE(BGP_INPUT(peer)));
3614 0 : stream_get(&ndata[lfl + 1], BGP_INPUT(peer), ndl);
3615 :
3616 0 : bgp_notify_send_with_data(
3617 : peer, BGP_NOTIFY_UPDATE_ERR,
3618 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, ndata,
3619 0 : ndl + lfl + 1);
3620 :
3621 0 : ret = BGP_ATTR_PARSE_ERROR;
3622 0 : goto done;
3623 : }
3624 :
3625 11 : struct bgp_attr_parser_args attr_args = {
3626 : .peer = peer,
3627 : .length = length,
3628 : .attr = attr,
3629 : .type = type,
3630 : .flags = flag,
3631 : .startp = startp,
3632 11 : .total = attr_endp - startp,
3633 : };
3634 :
3635 :
3636 : /* If any recognized attribute has Attribute Flags that conflict
3637 : with the Attribute Type Code, then the Error Subcode is set
3638 : to
3639 : Attribute Flags Error. The Data field contains the erroneous
3640 : attribute (type, length and value). */
3641 11 : if (bgp_attr_flag_invalid(&attr_args)) {
3642 0 : ret = bgp_attr_malformed(
3643 : &attr_args, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
3644 : attr_args.total);
3645 0 : if (ret == BGP_ATTR_PARSE_PROCEED)
3646 0 : continue;
3647 0 : goto done;
3648 : }
3649 :
3650 : /* OK check attribute and store it's value. */
3651 11 : switch (type) {
3652 3 : case BGP_ATTR_ORIGIN:
3653 3 : ret = bgp_attr_origin(&attr_args);
3654 3 : break;
3655 3 : case BGP_ATTR_AS_PATH:
3656 3 : ret = bgp_attr_aspath(&attr_args);
3657 3 : break;
3658 0 : case BGP_ATTR_AS4_PATH:
3659 0 : ret = bgp_attr_as4_path(&attr_args, &as4_path);
3660 0 : break;
3661 3 : case BGP_ATTR_NEXT_HOP:
3662 3 : ret = bgp_attr_nexthop(&attr_args);
3663 3 : break;
3664 2 : case BGP_ATTR_MULTI_EXIT_DISC:
3665 2 : ret = bgp_attr_med(&attr_args);
3666 2 : break;
3667 0 : case BGP_ATTR_LOCAL_PREF:
3668 0 : ret = bgp_attr_local_pref(&attr_args);
3669 0 : break;
3670 0 : case BGP_ATTR_ATOMIC_AGGREGATE:
3671 0 : ret = bgp_attr_atomic(&attr_args);
3672 0 : break;
3673 0 : case BGP_ATTR_AGGREGATOR:
3674 0 : ret = bgp_attr_aggregator(&attr_args);
3675 0 : break;
3676 0 : case BGP_ATTR_AS4_AGGREGATOR:
3677 0 : ret = bgp_attr_as4_aggregator(&attr_args,
3678 : &as4_aggregator,
3679 : &as4_aggregator_addr);
3680 0 : break;
3681 0 : case BGP_ATTR_COMMUNITIES:
3682 0 : ret = bgp_attr_community(&attr_args);
3683 0 : break;
3684 0 : case BGP_ATTR_LARGE_COMMUNITIES:
3685 0 : ret = bgp_attr_large_community(&attr_args);
3686 0 : break;
3687 0 : case BGP_ATTR_ORIGINATOR_ID:
3688 0 : ret = bgp_attr_originator_id(&attr_args);
3689 0 : break;
3690 0 : case BGP_ATTR_CLUSTER_LIST:
3691 0 : ret = bgp_attr_cluster_list(&attr_args);
3692 0 : break;
3693 0 : case BGP_ATTR_MP_REACH_NLRI:
3694 0 : ret = bgp_mp_reach_parse(&attr_args, mp_update);
3695 0 : break;
3696 0 : case BGP_ATTR_MP_UNREACH_NLRI:
3697 0 : ret = bgp_mp_unreach_parse(&attr_args, mp_withdraw);
3698 0 : break;
3699 0 : case BGP_ATTR_EXT_COMMUNITIES:
3700 0 : ret = bgp_attr_ext_communities(&attr_args);
3701 0 : break;
3702 : #ifdef ENABLE_BGP_VNC_ATTR
3703 : case BGP_ATTR_VNC:
3704 : #endif
3705 0 : case BGP_ATTR_ENCAP:
3706 0 : ret = bgp_attr_encap(type, peer, length, attr, flag,
3707 : startp);
3708 0 : break;
3709 0 : case BGP_ATTR_PREFIX_SID:
3710 0 : ret = bgp_attr_prefix_sid(&attr_args);
3711 0 : break;
3712 0 : case BGP_ATTR_PMSI_TUNNEL:
3713 0 : ret = bgp_attr_pmsi_tunnel(&attr_args);
3714 0 : break;
3715 0 : case BGP_ATTR_IPV6_EXT_COMMUNITIES:
3716 0 : ret = bgp_attr_ipv6_ext_communities(&attr_args);
3717 0 : break;
3718 0 : case BGP_ATTR_OTC:
3719 0 : ret = bgp_attr_otc(&attr_args);
3720 0 : break;
3721 0 : case BGP_ATTR_AIGP:
3722 0 : ret = bgp_attr_aigp(&attr_args);
3723 0 : break;
3724 0 : default:
3725 0 : ret = bgp_attr_unknown(&attr_args);
3726 0 : break;
3727 : }
3728 :
3729 11 : if (ret == BGP_ATTR_PARSE_ERROR_NOTIFYPLS) {
3730 0 : bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
3731 : BGP_NOTIFY_UPDATE_MAL_ATTR);
3732 0 : ret = BGP_ATTR_PARSE_ERROR;
3733 0 : goto done;
3734 : }
3735 :
3736 11 : if (ret == BGP_ATTR_PARSE_EOR) {
3737 0 : goto done;
3738 : }
3739 :
3740 11 : if (ret == BGP_ATTR_PARSE_ERROR) {
3741 0 : flog_warn(EC_BGP_ATTRIBUTE_PARSE_ERROR,
3742 : "%s: Attribute %s, parse error", peer->host,
3743 : lookup_msg(attr_str, type, NULL));
3744 0 : goto done;
3745 : }
3746 11 : if (ret == BGP_ATTR_PARSE_WITHDRAW) {
3747 0 : flog_warn(
3748 : EC_BGP_ATTRIBUTE_PARSE_WITHDRAW,
3749 : "%s: Attribute %s, parse error - treating as withdrawal",
3750 : peer->host, lookup_msg(attr_str, type, NULL));
3751 0 : goto done;
3752 : }
3753 :
3754 : /* Check the fetched length. */
3755 11 : if (BGP_INPUT_PNT(peer) != attr_endp) {
3756 0 : flog_warn(EC_BGP_ATTRIBUTE_FETCH_ERROR,
3757 : "%s: BGP attribute %s, fetch error",
3758 : peer->host, lookup_msg(attr_str, type, NULL));
3759 0 : bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
3760 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
3761 0 : ret = BGP_ATTR_PARSE_ERROR;
3762 0 : goto done;
3763 : }
3764 : }
3765 :
3766 : /*
3767 : * draft-ietf-idr-bgp-prefix-sid-27#section-3:
3768 : * About Prefix-SID path attribute,
3769 : * Label-Index TLV(type1) and The Originator SRGB TLV(type-3)
3770 : * may only appear in a BGP Prefix-SID attribute attached to
3771 : * IPv4/IPv6 Labeled Unicast prefixes ([RFC8277]).
3772 : * It MUST be ignored when received for other BGP AFI/SAFI combinations.
3773 : */
3774 3 : if (!attr->mp_nexthop_len || mp_update->safi != SAFI_LABELED_UNICAST)
3775 3 : attr->label_index = BGP_INVALID_LABEL_INDEX;
3776 :
3777 : /* Check final read pointer is same as end pointer. */
3778 3 : if (BGP_INPUT_PNT(peer) != endp) {
3779 0 : flog_warn(EC_BGP_ATTRIBUTES_MISMATCH,
3780 : "%s: BGP attribute %s, length mismatch", peer->host,
3781 : lookup_msg(attr_str, type, NULL));
3782 0 : bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
3783 : BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
3784 :
3785 0 : ret = BGP_ATTR_PARSE_ERROR;
3786 0 : goto done;
3787 : }
3788 :
3789 : /*
3790 : * RFC4271: If the NEXT_HOP attribute field is syntactically incorrect,
3791 : * then the Error Subcode MUST be set to Invalid NEXT_HOP Attribute.
3792 : * This is implemented below and will result in a NOTIFICATION. If the
3793 : * NEXT_HOP attribute is semantically incorrect, the error SHOULD be
3794 : * logged, and the route SHOULD be ignored. In this case, a NOTIFICATION
3795 : * message SHOULD NOT be sent. This is implemented elsewhere.
3796 : *
3797 : * RFC4760: An UPDATE message that carries no NLRI, other than the one
3798 : * encoded in the MP_REACH_NLRI attribute, SHOULD NOT carry the NEXT_HOP
3799 : * attribute. If such a message contains the NEXT_HOP attribute, the BGP
3800 : * speaker that receives the message SHOULD ignore this attribute.
3801 : */
3802 3 : if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP))
3803 3 : && !CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI))) {
3804 3 : if (bgp_attr_nexthop_valid(peer, attr) < 0) {
3805 0 : ret = BGP_ATTR_PARSE_ERROR;
3806 0 : goto done;
3807 : }
3808 : }
3809 :
3810 : /* Check all mandatory well-known attributes are present */
3811 3 : ret = bgp_attr_check(peer, attr);
3812 3 : if (ret < 0)
3813 0 : goto done;
3814 :
3815 : /*
3816 : * At this place we can see whether we got AS4_PATH and/or
3817 : * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
3818 : * We can not do this before we've read all attributes because
3819 : * the as4 handling does not say whether AS4_PATH has to be sent
3820 : * after AS_PATH or not - and when AS4_AGGREGATOR will be send
3821 : * in relationship to AGGREGATOR.
3822 : * So, to be defensive, we are not relying on any order and read
3823 : * all attributes first, including these 32bit ones, and now,
3824 : * afterwards, we look what and if something is to be done for as4.
3825 : *
3826 : * It is possible to not have AS_PATH, e.g. GR EoR and sole
3827 : * MP_UNREACH_NLRI.
3828 : */
3829 : /* actually... this doesn't ever return failure currently, but
3830 : * better safe than sorry */
3831 3 : if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH))
3832 3 : && bgp_attr_munge_as4_attrs(peer, attr, as4_path, as4_aggregator,
3833 : &as4_aggregator_addr)) {
3834 0 : bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
3835 : BGP_NOTIFY_UPDATE_MAL_ATTR);
3836 0 : ret = BGP_ATTR_PARSE_ERROR;
3837 0 : goto done;
3838 : }
3839 :
3840 : /*
3841 : * Finally do the checks on the aspath we did not do yet
3842 : * because we waited for a potentially synthesized aspath.
3843 : */
3844 3 : if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH))) {
3845 3 : ret = bgp_attr_aspath_check(peer, attr);
3846 3 : if (ret != BGP_ATTR_PARSE_PROCEED)
3847 0 : goto done;
3848 : }
3849 :
3850 : ret = BGP_ATTR_PARSE_PROCEED;
3851 3 : done:
3852 :
3853 : /*
3854 : * At this stage, we have done all fiddling with as4, and the
3855 : * resulting info is in attr->aggregator resp. attr->aspath so
3856 : * we can chuck as4_aggregator and as4_path alltogether in order
3857 : * to save memory
3858 : */
3859 : /*
3860 : * unintern - it is in the hash
3861 : * The flag that we got this is still there, but that
3862 : * does not do any trouble
3863 : */
3864 3 : aspath_unintern(&as4_path);
3865 :
3866 3 : transit = bgp_attr_get_transit(attr);
3867 3 : if (ret != BGP_ATTR_PARSE_ERROR) {
3868 : /* Finally intern unknown attribute. */
3869 3 : if (transit)
3870 0 : bgp_attr_set_transit(attr, transit_intern(transit));
3871 3 : if (attr->encap_subtlvs)
3872 0 : attr->encap_subtlvs = encap_intern(attr->encap_subtlvs,
3873 : ENCAP_SUBTLV_TYPE);
3874 : #ifdef ENABLE_BGP_VNC
3875 3 : struct bgp_attr_encap_subtlv *vnc_subtlvs =
3876 3 : bgp_attr_get_vnc_subtlvs(attr);
3877 :
3878 3 : if (vnc_subtlvs)
3879 0 : bgp_attr_set_vnc_subtlvs(
3880 : attr,
3881 : encap_intern(vnc_subtlvs, VNC_SUBTLV_TYPE));
3882 : #endif
3883 : } else {
3884 0 : if (transit) {
3885 0 : transit_free(transit);
3886 0 : bgp_attr_set_transit(attr, NULL);
3887 : }
3888 :
3889 0 : bgp_attr_flush_encap(attr);
3890 3 : };
3891 :
3892 : /* Sanity checks */
3893 3 : transit = bgp_attr_get_transit(attr);
3894 3 : if (transit)
3895 0 : assert(transit->refcnt > 0);
3896 3 : if (attr->encap_subtlvs)
3897 0 : assert(attr->encap_subtlvs->refcnt > 0);
3898 : #ifdef ENABLE_BGP_VNC
3899 3 : struct bgp_attr_encap_subtlv *vnc_subtlvs =
3900 3 : bgp_attr_get_vnc_subtlvs(attr);
3901 :
3902 3 : if (vnc_subtlvs)
3903 0 : assert(vnc_subtlvs->refcnt > 0);
3904 : #endif
3905 :
3906 3 : return ret;
3907 : }
3908 :
3909 : /*
3910 : * Extract the tunnel type from extended community
3911 : */
3912 0 : void bgp_attr_extcom_tunnel_type(struct attr *attr,
3913 : bgp_encap_types *tunnel_type)
3914 : {
3915 0 : struct ecommunity *ecom;
3916 0 : uint32_t i;
3917 :
3918 0 : if (!attr)
3919 : return;
3920 :
3921 0 : ecom = bgp_attr_get_ecommunity(attr);
3922 0 : if (!ecom || !ecom->size)
3923 : return;
3924 :
3925 0 : for (i = 0; i < ecom->size; i++) {
3926 0 : uint8_t *pnt;
3927 0 : uint8_t type, sub_type;
3928 :
3929 0 : pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
3930 0 : type = pnt[0];
3931 0 : sub_type = pnt[1];
3932 0 : if (!(type == ECOMMUNITY_ENCODE_OPAQUE &&
3933 0 : sub_type == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP))
3934 0 : continue;
3935 0 : *tunnel_type = ((pnt[6] << 8) | pnt[7]);
3936 0 : return;
3937 : }
3938 :
3939 : return;
3940 : }
3941 :
3942 0 : size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
3943 : safi_t safi, struct bpacket_attr_vec_arr *vecarr,
3944 : struct attr *attr)
3945 : {
3946 0 : size_t sizep;
3947 0 : iana_afi_t pkt_afi = IANA_AFI_IPV4;
3948 0 : iana_safi_t pkt_safi = IANA_SAFI_UNICAST;
3949 0 : afi_t nh_afi;
3950 :
3951 : /* Set extended bit always to encode the attribute length as 2 bytes */
3952 0 : stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_EXTLEN);
3953 0 : stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
3954 0 : sizep = stream_get_endp(s);
3955 0 : stream_putw(s, 0); /* Marker: Attribute length. */
3956 :
3957 :
3958 : /* Convert AFI, SAFI to values for packet. */
3959 0 : bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);
3960 :
3961 0 : stream_putw(s, pkt_afi); /* AFI */
3962 0 : stream_putc(s, pkt_safi); /* SAFI */
3963 :
3964 : /* Nexthop AFI */
3965 0 : if (afi == AFI_IP
3966 0 : && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST
3967 0 : || safi == SAFI_MPLS_VPN || safi == SAFI_MULTICAST))
3968 0 : nh_afi = peer_cap_enhe(peer, afi, safi) ? AFI_IP6 : AFI_IP;
3969 0 : else if (safi == SAFI_FLOWSPEC)
3970 : nh_afi = afi;
3971 : else
3972 0 : nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len);
3973 :
3974 : /* Nexthop */
3975 0 : bpacket_attr_vec_arr_set_vec(vecarr, BGP_ATTR_VEC_NH, s, attr);
3976 0 : switch (nh_afi) {
3977 0 : case AFI_IP:
3978 0 : switch (safi) {
3979 0 : case SAFI_UNICAST:
3980 : case SAFI_MULTICAST:
3981 : case SAFI_LABELED_UNICAST:
3982 0 : stream_putc(s, 4);
3983 0 : stream_put_ipv4(s, attr->nexthop.s_addr);
3984 0 : break;
3985 0 : case SAFI_MPLS_VPN:
3986 0 : stream_putc(s, 12);
3987 0 : stream_putl(s, 0); /* RD = 0, per RFC */
3988 0 : stream_putl(s, 0);
3989 0 : stream_put(s, &attr->mp_nexthop_global_in, 4);
3990 0 : break;
3991 0 : case SAFI_ENCAP:
3992 : case SAFI_EVPN:
3993 0 : stream_putc(s, 4);
3994 0 : stream_put(s, &attr->mp_nexthop_global_in, 4);
3995 0 : break;
3996 0 : case SAFI_FLOWSPEC:
3997 0 : if (attr->mp_nexthop_len == 0)
3998 0 : stream_putc(s, 0); /* no nexthop for flowspec */
3999 : else {
4000 0 : stream_putc(s, attr->mp_nexthop_len);
4001 0 : stream_put_ipv4(s, attr->nexthop.s_addr);
4002 : }
4003 : break;
4004 : case SAFI_UNSPEC:
4005 : case SAFI_MAX:
4006 0 : assert(!"SAFI's UNSPEC or MAX being specified are a DEV ESCAPE");
4007 : break;
4008 : }
4009 : break;
4010 0 : case AFI_IP6:
4011 0 : switch (safi) {
4012 0 : case SAFI_UNICAST:
4013 : case SAFI_MULTICAST:
4014 : case SAFI_LABELED_UNICAST:
4015 : case SAFI_EVPN: {
4016 0 : if (attr->mp_nexthop_len
4017 : == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
4018 0 : stream_putc(s,
4019 : BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL);
4020 0 : stream_put(s, &attr->mp_nexthop_global,
4021 : IPV6_MAX_BYTELEN);
4022 0 : stream_put(s, &attr->mp_nexthop_local,
4023 : IPV6_MAX_BYTELEN);
4024 : } else {
4025 0 : stream_putc(s, IPV6_MAX_BYTELEN);
4026 0 : stream_put(s, &attr->mp_nexthop_global,
4027 : IPV6_MAX_BYTELEN);
4028 : }
4029 : } break;
4030 0 : case SAFI_MPLS_VPN: {
4031 0 : if (attr->mp_nexthop_len ==
4032 : BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
4033 0 : stream_putc(s, 48);
4034 0 : stream_putl(s, 0); /* RD = 0, per RFC */
4035 0 : stream_putl(s, 0);
4036 0 : stream_put(s, &attr->mp_nexthop_global,
4037 : IPV6_MAX_BYTELEN);
4038 0 : stream_putl(s, 0); /* RD = 0, per RFC */
4039 0 : stream_putl(s, 0);
4040 0 : stream_put(s, &attr->mp_nexthop_local,
4041 : IPV6_MAX_BYTELEN);
4042 : } else {
4043 0 : stream_putc(s, 24);
4044 0 : stream_putl(s, 0); /* RD = 0, per RFC */
4045 0 : stream_putl(s, 0);
4046 0 : stream_put(s, &attr->mp_nexthop_global,
4047 : IPV6_MAX_BYTELEN);
4048 : }
4049 : } break;
4050 0 : case SAFI_ENCAP:
4051 0 : stream_putc(s, IPV6_MAX_BYTELEN);
4052 0 : stream_put(s, &attr->mp_nexthop_global,
4053 : IPV6_MAX_BYTELEN);
4054 0 : break;
4055 0 : case SAFI_FLOWSPEC:
4056 0 : stream_putc(s, 0); /* no nexthop for flowspec */
4057 0 : break;
4058 : case SAFI_UNSPEC:
4059 : case SAFI_MAX:
4060 0 : assert(!"SAFI's UNSPEC or MAX being specified are a DEV ESCAPE");
4061 : break;
4062 : }
4063 : break;
4064 0 : case AFI_L2VPN:
4065 0 : if (safi != SAFI_FLOWSPEC)
4066 0 : flog_err(
4067 : EC_BGP_ATTR_NH_SEND_LEN,
4068 : "Bad nexthop when sending to %s, AFI %u SAFI %u nhlen %d",
4069 : peer->host, afi, safi, attr->mp_nexthop_len);
4070 : break;
4071 : case AFI_UNSPEC:
4072 : case AFI_MAX:
4073 0 : assert(!"DEV ESCAPE: AFI_UNSPEC or AFI_MAX should not be used here");
4074 : break;
4075 : }
4076 :
4077 : /* SNPA */
4078 0 : stream_putc(s, 0);
4079 0 : return sizep;
4080 : }
4081 :
4082 0 : void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
4083 : const struct prefix *p,
4084 : const struct prefix_rd *prd, mpls_label_t *label,
4085 : uint32_t num_labels, bool addpath_capable,
4086 : uint32_t addpath_tx_id, struct attr *attr)
4087 : {
4088 0 : switch (safi) {
4089 : case SAFI_UNSPEC:
4090 : case SAFI_MAX:
4091 0 : assert(!"Dev escape usage of SAFI_UNSPEC or MAX");
4092 : break;
4093 0 : case SAFI_MPLS_VPN:
4094 0 : if (addpath_capable)
4095 0 : stream_putl(s, addpath_tx_id);
4096 : /* Label, RD, Prefix write. */
4097 0 : stream_putc(s, p->prefixlen + 88);
4098 0 : stream_put(s, label, BGP_LABEL_BYTES);
4099 0 : stream_put(s, prd->val, 8);
4100 0 : stream_put(s, &p->u.prefix, PSIZE(p->prefixlen));
4101 0 : break;
4102 0 : case SAFI_EVPN:
4103 0 : if (afi == AFI_L2VPN)
4104 : /* EVPN prefix - contents depend on type */
4105 0 : bgp_evpn_encode_prefix(s, p, prd, label, num_labels,
4106 : attr, addpath_capable,
4107 : addpath_tx_id);
4108 : else
4109 0 : assert(!"Add encoding bits here for other AFI's");
4110 0 : break;
4111 0 : case SAFI_LABELED_UNICAST:
4112 : /* Prefix write with label. */
4113 0 : stream_put_labeled_prefix(s, p, label, addpath_capable,
4114 : addpath_tx_id);
4115 0 : break;
4116 0 : case SAFI_FLOWSPEC:
4117 0 : stream_putc(s, p->u.prefix_flowspec.prefixlen);
4118 0 : stream_put(s, (const void *)p->u.prefix_flowspec.ptr,
4119 0 : p->u.prefix_flowspec.prefixlen);
4120 0 : break;
4121 :
4122 0 : case SAFI_UNICAST:
4123 : case SAFI_MULTICAST:
4124 0 : stream_put_prefix_addpath(s, p, addpath_capable, addpath_tx_id);
4125 0 : break;
4126 : case SAFI_ENCAP:
4127 0 : assert(!"Please add proper encoding of SAFI_ENCAP");
4128 : break;
4129 : }
4130 0 : }
4131 :
4132 7 : size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi,
4133 : const struct prefix *p)
4134 : {
4135 7 : int size = PSIZE(p->prefixlen);
4136 :
4137 7 : switch (safi) {
4138 : case SAFI_UNSPEC:
4139 : case SAFI_MAX:
4140 0 : assert(!"Attempting to figure size for a SAFI_UNSPEC/SAFI_MAX this is a DEV ESCAPE");
4141 : break;
4142 : case SAFI_UNICAST:
4143 : case SAFI_MULTICAST:
4144 : break;
4145 0 : case SAFI_MPLS_VPN:
4146 0 : size += 88;
4147 0 : break;
4148 : case SAFI_ENCAP:
4149 : /* This has to be wrong, but I don't know what to put here */
4150 0 : assert(!"Do we try to use this?");
4151 : break;
4152 0 : case SAFI_LABELED_UNICAST:
4153 0 : size += BGP_LABEL_BYTES;
4154 0 : break;
4155 0 : case SAFI_EVPN:
4156 : /*
4157 : * TODO: Maximum possible for type-2, type-3 and type-5
4158 : */
4159 0 : if (afi == AFI_L2VPN)
4160 0 : size += 232;
4161 : else
4162 0 : assert(!"Attempting to figure size for SAFI_EVPN and !AFI_L2VPN and FRR will not have the proper values");
4163 0 : break;
4164 0 : case SAFI_FLOWSPEC:
4165 0 : size = ((struct prefix_fs *)p)->prefix.prefixlen;
4166 0 : break;
4167 : }
4168 :
4169 7 : return size;
4170 : }
4171 :
4172 : /*
4173 : * Encodes the tunnel encapsulation attribute,
4174 : * and with ENABLE_BGP_VNC the VNC attribute which uses
4175 : * almost the same TLV format
4176 : */
4177 0 : static void bgp_packet_mpattr_tea(struct bgp *bgp, struct peer *peer,
4178 : struct stream *s, struct attr *attr,
4179 : uint8_t attrtype)
4180 : {
4181 0 : unsigned int attrlenfield = 0;
4182 0 : unsigned int attrhdrlen = 0;
4183 0 : struct bgp_attr_encap_subtlv *subtlvs;
4184 0 : struct bgp_attr_encap_subtlv *st;
4185 0 : const char *attrname;
4186 :
4187 0 : if (!attr || (attrtype == BGP_ATTR_ENCAP
4188 0 : && (!attr->encap_tunneltype
4189 0 : || attr->encap_tunneltype == BGP_ENCAP_TYPE_MPLS)))
4190 : return;
4191 :
4192 0 : switch (attrtype) {
4193 : case BGP_ATTR_ENCAP:
4194 0 : attrname = "Tunnel Encap";
4195 0 : subtlvs = attr->encap_subtlvs;
4196 0 : if (subtlvs == NULL) /* nothing to do */
4197 : return;
4198 : /*
4199 : * The tunnel encap attr has an "outer" tlv.
4200 : * T = tunneltype,
4201 : * L = total length of subtlvs,
4202 : * V = concatenated subtlvs.
4203 : */
4204 : attrlenfield = 2 + 2; /* T + L */
4205 0 : attrhdrlen = 1 + 1; /* subTLV T + L */
4206 : break;
4207 :
4208 : #ifdef ENABLE_BGP_VNC_ATTR
4209 : case BGP_ATTR_VNC:
4210 : attrname = "VNC";
4211 : subtlvs = bgp_attr_get_vnc_subtlvs(attr);
4212 : if (subtlvs == NULL) /* nothing to do */
4213 : return;
4214 : attrlenfield = 0; /* no outer T + L */
4215 : attrhdrlen = 2 + 2; /* subTLV T + L */
4216 : break;
4217 : #endif
4218 :
4219 : default:
4220 0 : assert(0);
4221 : }
4222 :
4223 : /* compute attr length */
4224 0 : for (st = subtlvs; st; st = st->next) {
4225 0 : attrlenfield += (attrhdrlen + st->length);
4226 : }
4227 :
4228 0 : if (attrlenfield > 0xffff) {
4229 0 : zlog_info("%s attribute is too long (length=%d), can't send it",
4230 : attrname, attrlenfield);
4231 0 : return;
4232 : }
4233 :
4234 0 : if (attrlenfield > 0xff) {
4235 : /* 2-octet length field */
4236 0 : stream_putc(s,
4237 : BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
4238 : | BGP_ATTR_FLAG_EXTLEN);
4239 0 : stream_putc(s, attrtype);
4240 0 : stream_putw(s, attrlenfield & 0xffff);
4241 : } else {
4242 : /* 1-octet length field */
4243 0 : stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL);
4244 0 : stream_putc(s, attrtype);
4245 0 : stream_putc(s, attrlenfield & 0xff);
4246 : }
4247 :
4248 0 : if (attrtype == BGP_ATTR_ENCAP) {
4249 : /* write outer T+L */
4250 0 : stream_putw(s, attr->encap_tunneltype);
4251 0 : stream_putw(s, attrlenfield - 4);
4252 : }
4253 :
4254 : /* write each sub-tlv */
4255 0 : for (st = subtlvs; st; st = st->next) {
4256 0 : if (attrtype == BGP_ATTR_ENCAP) {
4257 0 : stream_putc(s, st->type);
4258 0 : stream_putc(s, st->length);
4259 : #ifdef ENABLE_BGP_VNC
4260 : } else {
4261 : stream_putw(s, st->type);
4262 : stream_putw(s, st->length);
4263 : #endif
4264 : }
4265 0 : stream_put(s, st->value, st->length);
4266 : }
4267 : }
4268 :
4269 0 : void bgp_packet_mpattr_end(struct stream *s, size_t sizep)
4270 : {
4271 : /* Set MP attribute length. Don't count the (2) bytes used to encode
4272 : the attr length */
4273 0 : stream_putw_at(s, sizep, (stream_get_endp(s) - sizep) - 2);
4274 0 : }
4275 :
4276 0 : static bool bgp_append_local_as(struct peer *peer, afi_t afi, safi_t safi)
4277 : {
4278 0 : if (!BGP_AS_IS_PRIVATE(peer->local_as)
4279 0 : || (BGP_AS_IS_PRIVATE(peer->local_as)
4280 0 : && !CHECK_FLAG(peer->af_flags[afi][safi],
4281 : PEER_FLAG_REMOVE_PRIVATE_AS)
4282 0 : && !CHECK_FLAG(peer->af_flags[afi][safi],
4283 : PEER_FLAG_REMOVE_PRIVATE_AS_ALL)
4284 0 : && !CHECK_FLAG(peer->af_flags[afi][safi],
4285 : PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE)
4286 0 : && !CHECK_FLAG(peer->af_flags[afi][safi],
4287 : PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE)))
4288 0 : return true;
4289 : return false;
4290 : }
4291 :
4292 : /* Make attribute packet. */
4293 3 : bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
4294 : struct stream *s, struct attr *attr,
4295 : struct bpacket_attr_vec_arr *vecarr,
4296 : struct prefix *p, afi_t afi, safi_t safi,
4297 : struct peer *from, struct prefix_rd *prd,
4298 : mpls_label_t *label, uint32_t num_labels,
4299 : bool addpath_capable, uint32_t addpath_tx_id,
4300 : struct bgp_path_info *bpi)
4301 : {
4302 3 : size_t cp;
4303 3 : size_t aspath_sizep;
4304 3 : struct aspath *aspath;
4305 3 : int send_as4_path = 0;
4306 3 : int send_as4_aggregator = 0;
4307 3 : bool use32bit = CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)
4308 3 : && CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV);
4309 :
4310 3 : if (!bgp)
4311 3 : bgp = peer->bgp;
4312 :
4313 : /* Remember current pointer. */
4314 3 : cp = stream_get_endp(s);
4315 :
4316 3 : if (p
4317 0 : && !((afi == AFI_IP && safi == SAFI_UNICAST)
4318 0 : && !peer_cap_enhe(peer, afi, safi))) {
4319 0 : size_t mpattrlen_pos = 0;
4320 :
4321 0 : mpattrlen_pos = bgp_packet_mpattr_start(s, peer, afi, safi,
4322 : vecarr, attr);
4323 0 : bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label,
4324 : num_labels, addpath_capable,
4325 : addpath_tx_id, attr);
4326 0 : bgp_packet_mpattr_end(s, mpattrlen_pos);
4327 : }
4328 :
4329 : /* Origin attribute. */
4330 3 : stream_putc(s, BGP_ATTR_FLAG_TRANS);
4331 3 : stream_putc(s, BGP_ATTR_ORIGIN);
4332 3 : stream_putc(s, 1);
4333 3 : stream_putc(s, attr->origin);
4334 :
4335 : /* AS path attribute. */
4336 :
4337 : /* If remote-peer is EBGP */
4338 3 : if (peer->sort == BGP_PEER_EBGP
4339 3 : && (!CHECK_FLAG(peer->af_flags[afi][safi],
4340 : PEER_FLAG_AS_PATH_UNCHANGED)
4341 0 : || attr->aspath->segments == NULL)
4342 3 : && (!CHECK_FLAG(peer->af_flags[afi][safi],
4343 : PEER_FLAG_RSERVER_CLIENT))) {
4344 3 : aspath = aspath_dup(attr->aspath);
4345 :
4346 : /* Even though we may not be configured for confederations we
4347 : * may have
4348 : * RXed an AS_PATH with AS_CONFED_SEQUENCE or AS_CONFED_SET */
4349 3 : aspath = aspath_delete_confed_seq(aspath);
4350 :
4351 3 : if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) {
4352 : /* Stuff our path CONFED_ID on the front */
4353 0 : aspath = aspath_add_seq(aspath, bgp->confed_id);
4354 : } else {
4355 3 : if (peer->change_local_as) {
4356 : /* If replace-as is specified, we only use the
4357 : change_local_as when
4358 : advertising routes. */
4359 0 : if (!CHECK_FLAG(peer->flags,
4360 : PEER_FLAG_LOCAL_AS_REPLACE_AS))
4361 0 : if (bgp_append_local_as(peer, afi,
4362 : safi))
4363 0 : aspath = aspath_add_seq(
4364 : aspath, peer->local_as);
4365 0 : aspath = aspath_add_seq(aspath,
4366 : peer->change_local_as);
4367 : } else {
4368 3 : aspath = aspath_add_seq(aspath, peer->local_as);
4369 : }
4370 : }
4371 0 : } else if (peer->sort == BGP_PEER_CONFED) {
4372 : /* A confed member, so we need to do the AS_CONFED_SEQUENCE
4373 : * thing */
4374 0 : aspath = aspath_dup(attr->aspath);
4375 0 : aspath = aspath_add_confed_seq(aspath, peer->local_as);
4376 : } else
4377 0 : aspath = attr->aspath;
4378 :
4379 : /* If peer is not AS4 capable, then:
4380 : * - send the created AS_PATH out as AS4_PATH (optional, transitive),
4381 : * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path
4382 : * segment
4383 : * types are in it (i.e. exclude them if they are there)
4384 : * AND do this only if there is at least one asnum > 65535 in the
4385 : * path!
4386 : * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and
4387 : * change
4388 : * all ASnums > 65535 to BGP_AS_TRANS
4389 : */
4390 :
4391 3 : stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_EXTLEN);
4392 3 : stream_putc(s, BGP_ATTR_AS_PATH);
4393 3 : aspath_sizep = stream_get_endp(s);
4394 3 : stream_putw(s, 0);
4395 3 : stream_putw_at(s, aspath_sizep, aspath_put(s, aspath, use32bit));
4396 :
4397 : /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
4398 : * in the path
4399 : */
4400 3 : if (!use32bit && aspath_has_as4(aspath))
4401 3 : send_as4_path =
4402 : 1; /* we'll do this later, at the correct place */
4403 :
4404 : /* Nexthop attribute. */
4405 3 : if (afi == AFI_IP && safi == SAFI_UNICAST
4406 3 : && !peer_cap_enhe(peer, afi, safi)) {
4407 3 : afi_t nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len);
4408 :
4409 3 : if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) {
4410 3 : stream_putc(s, BGP_ATTR_FLAG_TRANS);
4411 3 : stream_putc(s, BGP_ATTR_NEXT_HOP);
4412 3 : bpacket_attr_vec_arr_set_vec(vecarr, BGP_ATTR_VEC_NH, s,
4413 : attr);
4414 3 : stream_putc(s, 4);
4415 3 : stream_put_ipv4(s, attr->nexthop.s_addr);
4416 0 : } else if (peer_cap_enhe(from, afi, safi)
4417 0 : || (nh_afi == AFI_IP6)) {
4418 : /*
4419 : * Likely this is the case when an IPv4 prefix was
4420 : * received with Extended Next-hop capability in this
4421 : * or another vrf and is now being advertised to
4422 : * non-ENHE peers. Since peer_cap_enhe only checks
4423 : * peers in this vrf, also check the nh_afi to catch
4424 : * the case where the originator was in another vrf.
4425 : * Setting the mandatory (ipv4) next-hop attribute here
4426 : * to enable implicit next-hop self with correct A-F
4427 : * (ipv4 address family).
4428 : */
4429 0 : stream_putc(s, BGP_ATTR_FLAG_TRANS);
4430 0 : stream_putc(s, BGP_ATTR_NEXT_HOP);
4431 0 : bpacket_attr_vec_arr_set_vec(vecarr, BGP_ATTR_VEC_NH, s,
4432 : NULL);
4433 0 : stream_putc(s, 4);
4434 0 : stream_put_ipv4(s, 0);
4435 : }
4436 : }
4437 :
4438 : /* MED attribute. */
4439 3 : if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)
4440 1 : || bgp->maxmed_active) {
4441 2 : stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
4442 2 : stream_putc(s, BGP_ATTR_MULTI_EXIT_DISC);
4443 2 : stream_putc(s, 4);
4444 2 : stream_putl(s, (bgp->maxmed_active ? bgp->maxmed_value
4445 : : attr->med));
4446 : }
4447 :
4448 : /* Local preference. */
4449 3 : if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) {
4450 0 : stream_putc(s, BGP_ATTR_FLAG_TRANS);
4451 0 : stream_putc(s, BGP_ATTR_LOCAL_PREF);
4452 0 : stream_putc(s, 4);
4453 0 : stream_putl(s, attr->local_pref);
4454 : }
4455 :
4456 : /* Atomic aggregate. */
4457 3 : if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) {
4458 0 : stream_putc(s, BGP_ATTR_FLAG_TRANS);
4459 0 : stream_putc(s, BGP_ATTR_ATOMIC_AGGREGATE);
4460 0 : stream_putc(s, 0);
4461 : }
4462 :
4463 : /* Aggregator. */
4464 3 : if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)) {
4465 : /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
4466 0 : stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
4467 0 : stream_putc(s, BGP_ATTR_AGGREGATOR);
4468 :
4469 0 : if (use32bit) {
4470 : /* AS4 capable peer */
4471 0 : stream_putc(s, 8);
4472 0 : stream_putl(s, attr->aggregator_as);
4473 : } else {
4474 : /* 2-byte AS peer */
4475 0 : stream_putc(s, 6);
4476 :
4477 : /* Is ASN representable in 2-bytes? Or must AS_TRANS be
4478 : * used? */
4479 0 : if (attr->aggregator_as > UINT16_MAX) {
4480 0 : stream_putw(s, BGP_AS_TRANS);
4481 :
4482 : /* we have to send AS4_AGGREGATOR, too.
4483 : * we'll do that later in order to send
4484 : * attributes in ascending
4485 : * order.
4486 : */
4487 0 : send_as4_aggregator = 1;
4488 : } else
4489 0 : stream_putw(s, (uint16_t)attr->aggregator_as);
4490 : }
4491 0 : stream_put_ipv4(s, attr->aggregator_addr.s_addr);
4492 : }
4493 :
4494 : /* Community attribute. */
4495 3 : if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
4496 3 : && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) {
4497 0 : struct community *comm = NULL;
4498 :
4499 0 : comm = bgp_attr_get_community(attr);
4500 0 : if (comm->size * 4 > 255) {
4501 0 : stream_putc(s,
4502 : BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
4503 : | BGP_ATTR_FLAG_EXTLEN);
4504 0 : stream_putc(s, BGP_ATTR_COMMUNITIES);
4505 0 : stream_putw(s, comm->size * 4);
4506 : } else {
4507 0 : stream_putc(s,
4508 : BGP_ATTR_FLAG_OPTIONAL
4509 : | BGP_ATTR_FLAG_TRANS);
4510 0 : stream_putc(s, BGP_ATTR_COMMUNITIES);
4511 0 : stream_putc(s, comm->size * 4);
4512 : }
4513 0 : stream_put(s, comm->val, comm->size * 4);
4514 : }
4515 :
4516 : /*
4517 : * Large Community attribute.
4518 : */
4519 3 : if (CHECK_FLAG(peer->af_flags[afi][safi],
4520 : PEER_FLAG_SEND_LARGE_COMMUNITY)
4521 3 : && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) {
4522 0 : if (lcom_length(bgp_attr_get_lcommunity(attr)) > 255) {
4523 0 : stream_putc(s,
4524 : BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
4525 : | BGP_ATTR_FLAG_EXTLEN);
4526 0 : stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
4527 0 : stream_putw(s,
4528 0 : lcom_length(bgp_attr_get_lcommunity(attr)));
4529 : } else {
4530 0 : stream_putc(s,
4531 : BGP_ATTR_FLAG_OPTIONAL
4532 : | BGP_ATTR_FLAG_TRANS);
4533 0 : stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
4534 0 : stream_putc(s,
4535 0 : lcom_length(bgp_attr_get_lcommunity(attr)));
4536 : }
4537 0 : stream_put(s, bgp_attr_get_lcommunity(attr)->val,
4538 0 : lcom_length(bgp_attr_get_lcommunity(attr)));
4539 : }
4540 :
4541 : /* Route Reflector. */
4542 3 : if (peer->sort == BGP_PEER_IBGP && from
4543 0 : && from->sort == BGP_PEER_IBGP) {
4544 0 : struct cluster_list *cluster = bgp_attr_get_cluster(attr);
4545 :
4546 : /* Originator ID. */
4547 0 : stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
4548 0 : stream_putc(s, BGP_ATTR_ORIGINATOR_ID);
4549 0 : stream_putc(s, 4);
4550 :
4551 0 : if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
4552 0 : stream_put_in_addr(s, &attr->originator_id);
4553 : else
4554 0 : stream_put_in_addr(s, &from->remote_id);
4555 :
4556 : /* Cluster list. */
4557 0 : stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
4558 0 : stream_putc(s, BGP_ATTR_CLUSTER_LIST);
4559 :
4560 0 : if (cluster) {
4561 0 : stream_putc(s, cluster->length + 4);
4562 : /* If this peer configuration's parent BGP has
4563 : * cluster_id. */
4564 0 : if (bgp->config & BGP_CONFIG_CLUSTER_ID)
4565 0 : stream_put_in_addr(s, &bgp->cluster_id);
4566 : else
4567 0 : stream_put_in_addr(s, &bgp->router_id);
4568 0 : stream_put(s, cluster->list, cluster->length);
4569 : } else {
4570 0 : stream_putc(s, 4);
4571 : /* If this peer configuration's parent BGP has
4572 : * cluster_id. */
4573 0 : if (bgp->config & BGP_CONFIG_CLUSTER_ID)
4574 0 : stream_put_in_addr(s, &bgp->cluster_id);
4575 : else
4576 0 : stream_put_in_addr(s, &bgp->router_id);
4577 : }
4578 : }
4579 :
4580 : /* Extended Communities attribute. */
4581 3 : if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
4582 3 : && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) {
4583 0 : struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr);
4584 0 : bool transparent = CHECK_FLAG(peer->af_flags[afi][safi],
4585 0 : PEER_FLAG_RSERVER_CLIENT) &&
4586 0 : from &&
4587 0 : CHECK_FLAG(from->af_flags[afi][safi],
4588 : PEER_FLAG_RSERVER_CLIENT);
4589 :
4590 0 : if (peer->sort == BGP_PEER_IBGP ||
4591 0 : peer->sort == BGP_PEER_CONFED || transparent) {
4592 0 : if (ecomm->size * 8 > 255) {
4593 0 : stream_putc(s,
4594 : BGP_ATTR_FLAG_OPTIONAL
4595 : | BGP_ATTR_FLAG_TRANS
4596 : | BGP_ATTR_FLAG_EXTLEN);
4597 0 : stream_putc(s, BGP_ATTR_EXT_COMMUNITIES);
4598 0 : stream_putw(s, ecomm->size * 8);
4599 : } else {
4600 0 : stream_putc(s,
4601 : BGP_ATTR_FLAG_OPTIONAL
4602 : | BGP_ATTR_FLAG_TRANS);
4603 0 : stream_putc(s, BGP_ATTR_EXT_COMMUNITIES);
4604 0 : stream_putc(s, ecomm->size * 8);
4605 : }
4606 0 : stream_put(s, ecomm->val, ecomm->size * 8);
4607 : } else {
4608 : uint8_t *pnt;
4609 : int tbit;
4610 : int ecom_tr_size = 0;
4611 : uint32_t i;
4612 :
4613 0 : for (i = 0; i < ecomm->size; i++) {
4614 0 : pnt = ecomm->val + (i * 8);
4615 0 : tbit = *pnt;
4616 :
4617 0 : if (CHECK_FLAG(tbit,
4618 : ECOMMUNITY_FLAG_NON_TRANSITIVE))
4619 0 : continue;
4620 :
4621 0 : ecom_tr_size++;
4622 : }
4623 :
4624 0 : if (ecom_tr_size) {
4625 0 : if (ecom_tr_size * 8 > 255) {
4626 0 : stream_putc(
4627 : s,
4628 : BGP_ATTR_FLAG_OPTIONAL
4629 : | BGP_ATTR_FLAG_TRANS
4630 : | BGP_ATTR_FLAG_EXTLEN);
4631 0 : stream_putc(s,
4632 : BGP_ATTR_EXT_COMMUNITIES);
4633 0 : stream_putw(s, ecom_tr_size * 8);
4634 : } else {
4635 0 : stream_putc(
4636 : s,
4637 : BGP_ATTR_FLAG_OPTIONAL
4638 : | BGP_ATTR_FLAG_TRANS);
4639 0 : stream_putc(s,
4640 : BGP_ATTR_EXT_COMMUNITIES);
4641 0 : stream_putc(s, ecom_tr_size * 8);
4642 : }
4643 :
4644 0 : for (i = 0; i < ecomm->size; i++) {
4645 0 : pnt = ecomm->val + (i * 8);
4646 0 : tbit = *pnt;
4647 :
4648 0 : if (CHECK_FLAG(
4649 : tbit,
4650 : ECOMMUNITY_FLAG_NON_TRANSITIVE))
4651 0 : continue;
4652 :
4653 0 : stream_put(s, pnt, 8);
4654 : }
4655 : }
4656 : }
4657 : }
4658 :
4659 : /* Label index attribute. */
4660 3 : if (safi == SAFI_LABELED_UNICAST) {
4661 0 : if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) {
4662 0 : uint32_t label_index;
4663 :
4664 0 : label_index = attr->label_index;
4665 :
4666 0 : if (label_index != BGP_INVALID_LABEL_INDEX) {
4667 0 : stream_putc(s,
4668 : BGP_ATTR_FLAG_OPTIONAL
4669 : | BGP_ATTR_FLAG_TRANS);
4670 0 : stream_putc(s, BGP_ATTR_PREFIX_SID);
4671 0 : stream_putc(s, 10);
4672 0 : stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX);
4673 0 : stream_putw(s,
4674 : BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
4675 0 : stream_putc(s, 0); // reserved
4676 0 : stream_putw(s, 0); // flags
4677 0 : stream_putl(s, label_index);
4678 : }
4679 : }
4680 : }
4681 :
4682 : /* SRv6 Service Information Attribute. */
4683 3 : if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_MPLS_VPN) {
4684 0 : if (attr->srv6_l3vpn) {
4685 0 : uint8_t subtlv_len =
4686 : BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
4687 : + BGP_ATTR_MIN_LEN
4688 : + BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH;
4689 0 : uint8_t tlv_len = subtlv_len + BGP_ATTR_MIN_LEN + 1;
4690 0 : uint8_t attr_len = tlv_len + BGP_ATTR_MIN_LEN;
4691 0 : stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
4692 : | BGP_ATTR_FLAG_TRANS);
4693 0 : stream_putc(s, BGP_ATTR_PREFIX_SID);
4694 0 : stream_putc(s, attr_len);
4695 0 : stream_putc(s, BGP_PREFIX_SID_SRV6_L3_SERVICE);
4696 0 : stream_putw(s, tlv_len);
4697 0 : stream_putc(s, 0); /* reserved */
4698 0 : stream_putc(s, BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO);
4699 0 : stream_putw(s, subtlv_len);
4700 0 : stream_putc(s, 0); /* reserved */
4701 0 : stream_put(s, &attr->srv6_l3vpn->sid,
4702 : sizeof(attr->srv6_l3vpn->sid)); /* sid */
4703 0 : stream_putc(s, 0); /* sid_flags */
4704 0 : stream_putw(s,
4705 0 : attr->srv6_l3vpn
4706 0 : ->endpoint_behavior); /* endpoint */
4707 0 : stream_putc(s, 0); /* reserved */
4708 0 : stream_putc(
4709 : s,
4710 : BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE);
4711 0 : stream_putw(
4712 : s,
4713 : BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH);
4714 0 : stream_putc(s, attr->srv6_l3vpn->loc_block_len);
4715 0 : stream_putc(s, attr->srv6_l3vpn->loc_node_len);
4716 0 : stream_putc(s, attr->srv6_l3vpn->func_len);
4717 0 : stream_putc(s, attr->srv6_l3vpn->arg_len);
4718 0 : stream_putc(s, attr->srv6_l3vpn->transposition_len);
4719 0 : stream_putc(s, attr->srv6_l3vpn->transposition_offset);
4720 0 : } else if (attr->srv6_vpn) {
4721 0 : stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
4722 : | BGP_ATTR_FLAG_TRANS);
4723 0 : stream_putc(s, BGP_ATTR_PREFIX_SID);
4724 0 : stream_putc(s, 22); /* tlv len */
4725 0 : stream_putc(s, BGP_PREFIX_SID_VPN_SID);
4726 0 : stream_putw(s, 0x13); /* tlv len */
4727 0 : stream_putc(s, 0x00); /* reserved */
4728 0 : stream_putc(s, 0x01); /* sid_type */
4729 0 : stream_putc(s, 0x00); /* sif_flags */
4730 0 : stream_put(s, &attr->srv6_vpn->sid,
4731 : sizeof(attr->srv6_vpn->sid)); /* sid */
4732 : }
4733 : }
4734 :
4735 3 : if (send_as4_path) {
4736 : /* If the peer is NOT As4 capable, AND */
4737 : /* there are ASnums > 65535 in path THEN
4738 : * give out AS4_PATH */
4739 :
4740 : /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
4741 : * path segments!
4742 : * Hm, I wonder... confederation things *should* only be at
4743 : * the beginning of an aspath, right? Then we should use
4744 : * aspath_delete_confed_seq for this, because it is already
4745 : * there! (JK)
4746 : * Folks, talk to me: what is reasonable here!?
4747 : */
4748 0 : aspath = aspath_delete_confed_seq(aspath);
4749 :
4750 0 : stream_putc(s,
4751 : BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
4752 : | BGP_ATTR_FLAG_EXTLEN);
4753 0 : stream_putc(s, BGP_ATTR_AS4_PATH);
4754 0 : aspath_sizep = stream_get_endp(s);
4755 0 : stream_putw(s, 0);
4756 0 : stream_putw_at(s, aspath_sizep, aspath_put(s, aspath, 1));
4757 : }
4758 :
4759 3 : if (aspath != attr->aspath)
4760 3 : aspath_free(aspath);
4761 :
4762 3 : if (send_as4_aggregator) {
4763 : /* send AS4_AGGREGATOR, at this place */
4764 : /* this section of code moved here in order to ensure the
4765 : * correct
4766 : * *ascending* order of attributes
4767 : */
4768 0 : stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
4769 0 : stream_putc(s, BGP_ATTR_AS4_AGGREGATOR);
4770 0 : stream_putc(s, 8);
4771 0 : stream_putl(s, attr->aggregator_as);
4772 0 : stream_put_ipv4(s, attr->aggregator_addr.s_addr);
4773 : }
4774 :
4775 3 : if (((afi == AFI_IP || afi == AFI_IP6)
4776 3 : && (safi == SAFI_ENCAP || safi == SAFI_MPLS_VPN))
4777 3 : || (afi == AFI_L2VPN && safi == SAFI_EVPN)) {
4778 : /* Tunnel Encap attribute */
4779 0 : bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_ENCAP);
4780 :
4781 : #ifdef ENABLE_BGP_VNC_ATTR
4782 : /* VNC attribute */
4783 : bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_VNC);
4784 : #endif
4785 : }
4786 :
4787 : /* PMSI Tunnel */
4788 3 : if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)) {
4789 0 : stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
4790 0 : stream_putc(s, BGP_ATTR_PMSI_TUNNEL);
4791 0 : stream_putc(s, 9); // Length
4792 0 : stream_putc(s, 0); // Flags
4793 0 : stream_putc(s, bgp_attr_get_pmsi_tnl_type(attr));
4794 0 : stream_put(s, &(attr->label),
4795 : BGP_LABEL_BYTES); // MPLS Label / VXLAN VNI
4796 0 : stream_put_ipv4(s, attr->nexthop.s_addr);
4797 : // Unicast tunnel endpoint IP address
4798 : }
4799 :
4800 : /* OTC */
4801 3 : if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_OTC)) {
4802 0 : stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
4803 0 : stream_putc(s, BGP_ATTR_OTC);
4804 0 : stream_putc(s, 4);
4805 0 : stream_putl(s, attr->otc);
4806 : }
4807 :
4808 : /* AIGP */
4809 3 : if (bpi && attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP) &&
4810 0 : (CHECK_FLAG(peer->flags, PEER_FLAG_AIGP) ||
4811 0 : peer->sort != BGP_PEER_EBGP)) {
4812 : /* At the moment only AIGP Metric TLV exists for AIGP
4813 : * attribute. If more comes in, do not forget to update
4814 : * attr_len variable to include new ones.
4815 : */
4816 0 : uint8_t attr_len = BGP_AIGP_TLV_METRIC_LEN;
4817 :
4818 0 : stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
4819 0 : stream_putc(s, BGP_ATTR_AIGP);
4820 0 : stream_putc(s, attr_len);
4821 0 : stream_put_bgp_aigp_tlv_metric(s, bpi);
4822 : }
4823 :
4824 : /* Unknown transit attribute. */
4825 3 : struct transit *transit = bgp_attr_get_transit(attr);
4826 :
4827 3 : if (transit)
4828 0 : stream_put(s, transit->val, transit->length);
4829 :
4830 : /* Return total size of attribute. */
4831 3 : return stream_get_endp(s) - cp;
4832 : }
4833 :
4834 0 : size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi)
4835 : {
4836 0 : unsigned long attrlen_pnt;
4837 0 : iana_afi_t pkt_afi = IANA_AFI_IPV4;
4838 0 : iana_safi_t pkt_safi = IANA_SAFI_UNICAST;
4839 :
4840 : /* Set extended bit always to encode the attribute length as 2 bytes */
4841 0 : stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_EXTLEN);
4842 0 : stream_putc(s, BGP_ATTR_MP_UNREACH_NLRI);
4843 :
4844 0 : attrlen_pnt = stream_get_endp(s);
4845 0 : stream_putw(s, 0); /* Length of this attribute. */
4846 :
4847 : /* Convert AFI, SAFI to values for packet. */
4848 0 : bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);
4849 :
4850 0 : stream_putw(s, pkt_afi);
4851 0 : stream_putc(s, pkt_safi);
4852 :
4853 0 : return attrlen_pnt;
4854 : }
4855 :
4856 0 : void bgp_packet_mpunreach_prefix(struct stream *s, const struct prefix *p,
4857 : afi_t afi, safi_t safi,
4858 : const struct prefix_rd *prd,
4859 : mpls_label_t *label, uint32_t num_labels,
4860 : bool addpath_capable, uint32_t addpath_tx_id,
4861 : struct attr *attr)
4862 : {
4863 0 : uint8_t wlabel[4] = {0x80, 0x00, 0x00};
4864 :
4865 0 : if (safi == SAFI_LABELED_UNICAST) {
4866 0 : label = (mpls_label_t *)wlabel;
4867 0 : num_labels = 1;
4868 : }
4869 :
4870 0 : bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label, num_labels,
4871 : addpath_capable, addpath_tx_id, attr);
4872 0 : }
4873 :
4874 0 : void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt)
4875 : {
4876 0 : bgp_packet_mpattr_end(s, attrlen_pnt);
4877 0 : }
4878 :
4879 : /* Initialization of attribute. */
4880 2 : void bgp_attr_init(void)
4881 : {
4882 2 : aspath_init();
4883 2 : attrhash_init();
4884 2 : community_init();
4885 2 : ecommunity_init();
4886 2 : lcommunity_init();
4887 2 : cluster_init();
4888 2 : transit_init();
4889 2 : encap_init();
4890 2 : srv6_init();
4891 2 : }
4892 :
4893 2 : void bgp_attr_finish(void)
4894 : {
4895 2 : aspath_finish();
4896 2 : attrhash_finish();
4897 2 : community_finish();
4898 2 : ecommunity_finish();
4899 2 : lcommunity_finish();
4900 2 : cluster_finish();
4901 2 : transit_finish();
4902 2 : encap_finish();
4903 2 : srv6_finish();
4904 2 : }
4905 :
4906 : /* Make attribute packet. */
4907 0 : void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
4908 : const struct prefix *prefix)
4909 : {
4910 0 : unsigned long cp;
4911 0 : unsigned long len;
4912 0 : size_t aspath_lenp;
4913 0 : struct aspath *aspath;
4914 0 : bool addpath_capable = false;
4915 0 : uint32_t addpath_tx_id = 0;
4916 0 : struct attr *attr = bpi->attr;
4917 :
4918 : /* Remember current pointer. */
4919 0 : cp = stream_get_endp(s);
4920 :
4921 : /* Place holder of length. */
4922 0 : stream_putw(s, 0);
4923 :
4924 : /* Origin attribute. */
4925 0 : stream_putc(s, BGP_ATTR_FLAG_TRANS);
4926 0 : stream_putc(s, BGP_ATTR_ORIGIN);
4927 0 : stream_putc(s, 1);
4928 0 : stream_putc(s, attr->origin);
4929 :
4930 0 : aspath = attr->aspath;
4931 :
4932 0 : stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_EXTLEN);
4933 0 : stream_putc(s, BGP_ATTR_AS_PATH);
4934 0 : aspath_lenp = stream_get_endp(s);
4935 0 : stream_putw(s, 0);
4936 :
4937 0 : stream_putw_at(s, aspath_lenp, aspath_put(s, aspath, 1));
4938 :
4939 : /* Nexthop attribute. */
4940 : /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
4941 0 : if (prefix != NULL && prefix->family != AF_INET6) {
4942 0 : stream_putc(s, BGP_ATTR_FLAG_TRANS);
4943 0 : stream_putc(s, BGP_ATTR_NEXT_HOP);
4944 0 : stream_putc(s, 4);
4945 0 : stream_put_ipv4(s, attr->nexthop.s_addr);
4946 : }
4947 :
4948 : /* MED attribute. */
4949 0 : if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) {
4950 0 : stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
4951 0 : stream_putc(s, BGP_ATTR_MULTI_EXIT_DISC);
4952 0 : stream_putc(s, 4);
4953 0 : stream_putl(s, attr->med);
4954 : }
4955 :
4956 : /* Local preference. */
4957 0 : if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) {
4958 0 : stream_putc(s, BGP_ATTR_FLAG_TRANS);
4959 0 : stream_putc(s, BGP_ATTR_LOCAL_PREF);
4960 0 : stream_putc(s, 4);
4961 0 : stream_putl(s, attr->local_pref);
4962 : }
4963 :
4964 : /* Atomic aggregate. */
4965 0 : if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) {
4966 0 : stream_putc(s, BGP_ATTR_FLAG_TRANS);
4967 0 : stream_putc(s, BGP_ATTR_ATOMIC_AGGREGATE);
4968 0 : stream_putc(s, 0);
4969 : }
4970 :
4971 : /* Aggregator. */
4972 0 : if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)) {
4973 0 : stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
4974 0 : stream_putc(s, BGP_ATTR_AGGREGATOR);
4975 0 : stream_putc(s, 8);
4976 0 : stream_putl(s, attr->aggregator_as);
4977 0 : stream_put_ipv4(s, attr->aggregator_addr.s_addr);
4978 : }
4979 :
4980 : /* Community attribute. */
4981 0 : if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) {
4982 0 : struct community *comm = NULL;
4983 :
4984 0 : comm = bgp_attr_get_community(attr);
4985 0 : if (comm->size * 4 > 255) {
4986 0 : stream_putc(s,
4987 : BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
4988 : | BGP_ATTR_FLAG_EXTLEN);
4989 0 : stream_putc(s, BGP_ATTR_COMMUNITIES);
4990 0 : stream_putw(s, comm->size * 4);
4991 : } else {
4992 0 : stream_putc(s,
4993 : BGP_ATTR_FLAG_OPTIONAL
4994 : | BGP_ATTR_FLAG_TRANS);
4995 0 : stream_putc(s, BGP_ATTR_COMMUNITIES);
4996 0 : stream_putc(s, comm->size * 4);
4997 : }
4998 0 : stream_put(s, comm->val, comm->size * 4);
4999 : }
5000 :
5001 : /* Large Community attribute. */
5002 0 : if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) {
5003 0 : if (lcom_length(bgp_attr_get_lcommunity(attr)) > 255) {
5004 0 : stream_putc(s,
5005 : BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
5006 : | BGP_ATTR_FLAG_EXTLEN);
5007 0 : stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
5008 0 : stream_putw(s,
5009 0 : lcom_length(bgp_attr_get_lcommunity(attr)));
5010 : } else {
5011 0 : stream_putc(s,
5012 : BGP_ATTR_FLAG_OPTIONAL
5013 : | BGP_ATTR_FLAG_TRANS);
5014 0 : stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
5015 0 : stream_putc(s,
5016 0 : lcom_length(bgp_attr_get_lcommunity(attr)));
5017 : }
5018 :
5019 0 : stream_put(s, bgp_attr_get_lcommunity(attr)->val,
5020 0 : lcom_length(bgp_attr_get_lcommunity(attr)));
5021 : }
5022 :
5023 : /* Add a MP_NLRI attribute to dump the IPv6 next hop */
5024 0 : if (prefix != NULL && prefix->family == AF_INET6
5025 0 : && (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL
5026 0 : || attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)) {
5027 0 : int sizep;
5028 :
5029 0 : stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
5030 0 : stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
5031 0 : sizep = stream_get_endp(s);
5032 :
5033 : /* MP header */
5034 0 : stream_putc(s, 0); /* Marker: Attribute length. */
5035 0 : stream_putw(s, AFI_IP6); /* AFI */
5036 0 : stream_putc(s, SAFI_UNICAST); /* SAFI */
5037 :
5038 : /* Next hop */
5039 0 : stream_putc(s, attr->mp_nexthop_len);
5040 0 : stream_put(s, &attr->mp_nexthop_global, IPV6_MAX_BYTELEN);
5041 0 : if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
5042 0 : stream_put(s, &attr->mp_nexthop_local,
5043 : IPV6_MAX_BYTELEN);
5044 :
5045 : /* SNPA */
5046 0 : stream_putc(s, 0);
5047 :
5048 : /* Prefix */
5049 0 : stream_put_prefix_addpath(s, prefix, addpath_capable,
5050 : addpath_tx_id);
5051 :
5052 : /* Set MP attribute length. */
5053 0 : stream_putc_at(s, sizep, (stream_get_endp(s) - sizep) - 1);
5054 : }
5055 :
5056 : /* Prefix SID */
5057 0 : if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) {
5058 0 : if (attr->label_index != BGP_INVALID_LABEL_INDEX) {
5059 0 : stream_putc(s,
5060 : BGP_ATTR_FLAG_OPTIONAL
5061 : | BGP_ATTR_FLAG_TRANS);
5062 0 : stream_putc(s, BGP_ATTR_PREFIX_SID);
5063 0 : stream_putc(s, 10);
5064 0 : stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX);
5065 0 : stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
5066 0 : stream_putc(s, 0); // reserved
5067 0 : stream_putw(s, 0); // flags
5068 0 : stream_putl(s, attr->label_index);
5069 : }
5070 : }
5071 :
5072 : /* OTC */
5073 0 : if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_OTC)) {
5074 0 : stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
5075 0 : stream_putc(s, BGP_ATTR_OTC);
5076 0 : stream_putc(s, 4);
5077 0 : stream_putl(s, attr->otc);
5078 : }
5079 :
5080 : /* AIGP */
5081 0 : if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP)) {
5082 : /* At the moment only AIGP Metric TLV exists for AIGP
5083 : * attribute. If more comes in, do not forget to update
5084 : * attr_len variable to include new ones.
5085 : */
5086 0 : uint8_t attr_len = BGP_AIGP_TLV_METRIC_LEN;
5087 :
5088 0 : stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
5089 0 : stream_putc(s, BGP_ATTR_AIGP);
5090 0 : stream_putc(s, attr_len);
5091 0 : stream_put_bgp_aigp_tlv_metric(s, bpi);
5092 : }
5093 :
5094 : /* Return total size of attribute. */
5095 0 : len = stream_get_endp(s) - cp - 2;
5096 0 : stream_putw_at(s, cp, len);
5097 0 : }
5098 :
5099 0 : void bgp_path_attribute_discard_vty(struct vty *vty, struct peer *peer,
5100 : const char *discard_attrs, bool set)
5101 : {
5102 0 : int i, num_attributes;
5103 0 : char **attributes;
5104 0 : afi_t afi;
5105 0 : safi_t safi;
5106 :
5107 :
5108 : /* If `no` command specified without arbitrary attributes,
5109 : * then flush all.
5110 : */
5111 0 : if (!discard_attrs) {
5112 0 : for (i = 0; i < BGP_ATTR_MAX; i++)
5113 0 : peer->discard_attrs[i] = false;
5114 0 : goto discard_soft_clear;
5115 : }
5116 :
5117 0 : if (discard_attrs) {
5118 0 : frrstr_split(discard_attrs, " ", &attributes, &num_attributes);
5119 :
5120 0 : if (set)
5121 0 : for (i = 0; i < BGP_ATTR_MAX; i++)
5122 0 : peer->discard_attrs[i] = false;
5123 :
5124 0 : for (i = 0; i < num_attributes; i++) {
5125 0 : uint8_t attr_num = strtoul(attributes[i], NULL, 10);
5126 :
5127 0 : XFREE(MTYPE_TMP, attributes[i]);
5128 :
5129 : /* Some of the attributes, just can't be ignored. */
5130 0 : if (attr_num == BGP_ATTR_ORIGIN ||
5131 : attr_num == BGP_ATTR_AS_PATH ||
5132 0 : attr_num == BGP_ATTR_NEXT_HOP ||
5133 0 : attr_num == BGP_ATTR_MULTI_EXIT_DISC ||
5134 0 : attr_num == BGP_ATTR_MP_REACH_NLRI ||
5135 0 : attr_num == BGP_ATTR_MP_UNREACH_NLRI ||
5136 : attr_num == BGP_ATTR_EXT_COMMUNITIES) {
5137 0 : vty_out(vty,
5138 : "%% Can't discard path-attribute %s, ignoring.\n",
5139 : lookup_msg(attr_str, attr_num, NULL));
5140 0 : continue;
5141 : }
5142 :
5143 : /* Ignore local-pref, originator-id, cluster-list only
5144 : * for eBGP.
5145 : */
5146 0 : if (peer->sort != BGP_PEER_EBGP &&
5147 0 : (attr_num == BGP_ATTR_LOCAL_PREF ||
5148 0 : attr_num == BGP_ATTR_ORIGINATOR_ID ||
5149 : attr_num == BGP_ATTR_CLUSTER_LIST)) {
5150 0 : vty_out(vty,
5151 : "%% Can discard path-attribute %s only for eBGP, ignoring.\n",
5152 : lookup_msg(attr_str, attr_num, NULL));
5153 0 : continue;
5154 : }
5155 :
5156 0 : peer->discard_attrs[attr_num] = set;
5157 : }
5158 0 : XFREE(MTYPE_TMP, attributes);
5159 : discard_soft_clear:
5160 : /* Configuring path attributes to be discarded will trigger
5161 : * an inbound Route Refresh to ensure that the routing table
5162 : * is up to date.
5163 : */
5164 0 : FOREACH_AFI_SAFI (afi, safi)
5165 0 : peer_clear_soft(peer, afi, safi, BGP_CLEAR_SOFT_IN);
5166 : }
5167 0 : }
|