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