]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_attr.c
bgpd: factorise ipv6 vpn nexthop encoding
[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,
97a52c82 1498 [BGP_ATTR_AIGP] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
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
1658 /* Confederation sanity check. */
1659 if ((peer->sort == BGP_PEER_CONFED
1660 && !aspath_left_confed_check(attr->aspath))
1661 || (peer->sort == BGP_PEER_EBGP
1662 && aspath_confed_check(attr->aspath))) {
e50f7cfd 1663 flog_err(EC_BGP_ATTR_MAL_AS_PATH, "Malformed AS path from %s",
1c50c1c0 1664 peer->host);
4ba5a9c5 1665 return BGP_ATTR_PARSE_WITHDRAW;
d62a17ae 1666 }
cddb8112 1667
d62a17ae 1668 /* First AS check for EBGP. */
47cbc09b 1669 if (CHECK_FLAG(peer->flags, PEER_FLAG_ENFORCE_FIRST_AS)) {
d62a17ae 1670 if (peer->sort == BGP_PEER_EBGP
1671 && !aspath_firstas_check(attr->aspath, peer->as)) {
e50f7cfd 1672 flog_err(EC_BGP_ATTR_FIRST_AS,
1c50c1c0
QY
1673 "%s incorrect first AS (must be %u)",
1674 peer->host, peer->as);
4ba5a9c5 1675 return BGP_ATTR_PARSE_WITHDRAW;
d62a17ae 1676 }
1677 }
0b2aa3a0 1678
88cc0ce4
DA
1679 /* Codification of AS 0 Processing */
1680 if (peer->sort == BGP_PEER_EBGP && aspath_check_as_zero(attr->aspath)) {
1681 flog_err(
1682 EC_BGP_ATTR_MAL_AS_PATH,
1683 "Malformed AS path, AS number is 0 in the path from %s",
1684 peer->host);
1685 return BGP_ATTR_PARSE_WITHDRAW;
1686 }
1687
d62a17ae 1688 /* local-as prepend */
1689 if (peer->change_local_as
1690 && !CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)) {
1691 aspath = aspath_dup(attr->aspath);
1692 aspath = aspath_add_seq(aspath, peer->change_local_as);
1693 aspath_unintern(&attr->aspath);
1694 attr->aspath = aspath_intern(aspath);
1695 }
0b2aa3a0 1696
d62a17ae 1697 return BGP_ATTR_PARSE_PROCEED;
0b2aa3a0
PJ
1698}
1699
ab005298
PJ
1700/* Parse AS4 path information. This function is another wrapper of
1701 aspath_parse. */
d62a17ae 1702static int bgp_attr_as4_path(struct bgp_attr_parser_args *args,
1703 struct aspath **as4_path)
ab005298 1704{
d62a17ae 1705 struct peer *const peer = args->peer;
1706 struct attr *const attr = args->attr;
1707 const bgp_size_t length = args->length;
ab005298 1708
424ab01d 1709 *as4_path = aspath_parse(peer->curr, length, 1);
b881c707 1710
d62a17ae 1711 /* In case of IBGP, length will be zero. */
1712 if (!*as4_path) {
e50f7cfd 1713 flog_err(EC_BGP_ATTR_MAL_AS_PATH,
1c50c1c0
QY
1714 "Malformed AS4 path from %s, length is %d", peer->host,
1715 length);
d62a17ae 1716 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
1717 0);
1718 }
ab005298 1719
1bd36763
DA
1720 /* Conformant BGP speakers SHOULD NOT send BGP
1721 * UPDATE messages containing AS_SET or AS_CONFED_SET. Upon receipt of
1722 * such messages, conformant BGP speakers SHOULD use the "Treat-as-
1723 * withdraw" error handling behavior as per [RFC7606].
1724 */
1725 if (peer->bgp->reject_as_sets && aspath_check_as_sets(attr->aspath)) {
1726 flog_err(EC_BGP_ATTR_MAL_AS_PATH,
1727 "AS_SET and AS_CONFED_SET are deprecated from %pBP",
1728 peer);
1729 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
1730 0);
1731 }
1732
d62a17ae 1733 /* Set aspath attribute flag. */
1734 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH);
1735
1736 return BGP_ATTR_PARSE_PROCEED;
0b2aa3a0
PJ
1737}
1738
9738e9aa 1739/*
1740 * Check that the nexthop attribute is valid.
1741 */
79288e4c
DA
1742enum bgp_attr_parse_ret bgp_attr_nexthop_valid(struct peer *peer,
1743 struct attr *attr)
9738e9aa 1744{
8666265e 1745 struct bgp *bgp = peer->bgp;
9738e9aa 1746
70632160 1747 if (ipv4_martian(&attr->nexthop) && !bgp->allow_martian) {
7decb30c 1748 uint8_t data[7]; /* type(2) + length(1) + nhop(4) */
9738e9aa 1749
07380148
DA
1750 flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %pI4",
1751 &attr->nexthop);
7decb30c
DS
1752 data[0] = BGP_ATTR_FLAG_TRANS;
1753 data[1] = BGP_ATTR_NEXT_HOP;
1754 data[2] = BGP_ATTR_NHLEN_IPV4;
1755 memcpy(&data[3], &attr->nexthop.s_addr, BGP_ATTR_NHLEN_IPV4);
1756 bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR,
1757 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
1758 data, 7);
9738e9aa 1759 return BGP_ATTR_PARSE_ERROR;
1760 }
1761
1762 return BGP_ATTR_PARSE_PROCEED;
1763}
1764
718e3744 1765/* Nexthop attribute. */
79288e4c
DA
1766static enum bgp_attr_parse_ret
1767bgp_attr_nexthop(struct bgp_attr_parser_args *args)
d62a17ae 1768{
1769 struct peer *const peer = args->peer;
1770 struct attr *const attr = args->attr;
1771 const bgp_size_t length = args->length;
1772
d62a17ae 1773 /* Check nexthop attribute length. */
1774 if (length != 4) {
e50f7cfd 1775 flog_err(EC_BGP_ATTR_LEN,
1c50c1c0 1776 "Nexthop attribute length isn't four [%d]", length);
d62a17ae 1777
1778 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1779 args->total);
1780 }
1781
88f33d66 1782 attr->nexthop.s_addr = stream_get_ipv4(peer->curr);
d62a17ae 1783 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
1784
1785 return BGP_ATTR_PARSE_PROCEED;
718e3744 1786}
1787
1788/* MED atrribute. */
79288e4c 1789static enum bgp_attr_parse_ret bgp_attr_med(struct bgp_attr_parser_args *args)
718e3744 1790{
d62a17ae 1791 struct peer *const peer = args->peer;
1792 struct attr *const attr = args->attr;
1793 const bgp_size_t length = args->length;
b881c707 1794
d62a17ae 1795 /* Length check. */
1796 if (length != 4) {
e50f7cfd 1797 flog_err(EC_BGP_ATTR_LEN,
1c50c1c0 1798 "MED attribute length isn't four [%d]", length);
718e3744 1799
d62a17ae 1800 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1801 args->total);
1802 }
1803
424ab01d 1804 attr->med = stream_getl(peer->curr);
718e3744 1805
d62a17ae 1806 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
718e3744 1807
d62a17ae 1808 return BGP_ATTR_PARSE_PROCEED;
718e3744 1809}
1810
1811/* Local preference attribute. */
79288e4c 1812static enum bgp_attr_parse_ret
d62a17ae 1813bgp_attr_local_pref(struct bgp_attr_parser_args *args)
1814{
1815 struct peer *const peer = args->peer;
1816 struct attr *const attr = args->attr;
1817 const bgp_size_t length = args->length;
1818
4ba5a9c5
DA
1819 /* if received from an internal neighbor, it SHALL be considered
1820 * malformed if its length is not equal to 4. If malformed, the
1821 * UPDATE message SHALL be handled using the approach of "treat-as-
1822 * withdraw".
1823 */
1824 if (peer->sort == BGP_PEER_IBGP && length != 4) {
e50f7cfd 1825 flog_err(EC_BGP_ATTR_LEN,
1c50c1c0 1826 "LOCAL_PREF attribute length isn't 4 [%u]", length);
d62a17ae 1827 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1828 args->total);
1829 }
1830
1831 /* If it is contained in an UPDATE message that is received from an
1832 external peer, then this attribute MUST be ignored by the
1833 receiving speaker. */
1834 if (peer->sort == BGP_PEER_EBGP) {
ad61f778 1835 STREAM_FORWARD_GETP(peer->curr, length);
d62a17ae 1836 return BGP_ATTR_PARSE_PROCEED;
1837 }
1838
ad61f778 1839 STREAM_GETL(peer->curr, attr->local_pref);
d62a17ae 1840
7f323236 1841 /* Set the local-pref flag. */
d62a17ae 1842 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
1843
1844 return BGP_ATTR_PARSE_PROCEED;
ad61f778
QY
1845
1846stream_failure:
1847 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1848 args->total);
718e3744 1849}
1850
1851/* Atomic aggregate. */
d62a17ae 1852static int bgp_attr_atomic(struct bgp_attr_parser_args *args)
718e3744 1853{
a5c6a9b1 1854 struct peer *const peer = args->peer;
d62a17ae 1855 struct attr *const attr = args->attr;
1856 const bgp_size_t length = args->length;
1857
1858 /* Length check. */
1859 if (length != 0) {
e50f7cfd 1860 flog_err(EC_BGP_ATTR_LEN,
1c50c1c0
QY
1861 "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1862 length);
d62a17ae 1863 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1864 args->total);
1865 }
718e3744 1866
e2863b4f 1867 if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
a5c6a9b1
DA
1868 goto atomic_ignore;
1869
d62a17ae 1870 /* Set atomic aggregate flag. */
1871 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE);
718e3744 1872
d62a17ae 1873 return BGP_ATTR_PARSE_PROCEED;
a5c6a9b1
DA
1874
1875atomic_ignore:
1876 stream_forward_getp(peer->curr, length);
1877
e2863b4f 1878 return bgp_attr_ignore(peer, args->type);
718e3744 1879}
1880
1881/* Aggregator attribute */
d62a17ae 1882static int bgp_attr_aggregator(struct bgp_attr_parser_args *args)
1883{
1884 struct peer *const peer = args->peer;
1885 struct attr *const attr = args->attr;
1886 const bgp_size_t length = args->length;
33d022bc 1887 as_t aggregator_as;
d62a17ae 1888
1889 int wantedlen = 6;
1890
1891 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
4ba5a9c5
DA
1892 if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)
1893 && CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV))
d62a17ae 1894 wantedlen = 8;
1895
1896 if (length != wantedlen) {
e50f7cfd 1897 flog_err(EC_BGP_ATTR_LEN,
1c50c1c0
QY
1898 "AGGREGATOR attribute length isn't %u [%u]", wantedlen,
1899 length);
d62a17ae 1900 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1901 args->total);
1902 }
1903
e2863b4f 1904 if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
a5c6a9b1
DA
1905 goto aggregator_ignore;
1906
d62a17ae 1907 if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV))
33d022bc 1908 aggregator_as = stream_getl(peer->curr);
d62a17ae 1909 else
33d022bc
DA
1910 aggregator_as = stream_getw(peer->curr);
1911
e8364238
DA
1912 attr->aggregator_as = aggregator_as;
1913 attr->aggregator_addr.s_addr = stream_get_ipv4(peer->curr);
1914
33d022bc 1915 /* Codification of AS 0 Processing */
4877b70b 1916 if (aggregator_as == BGP_AS_ZERO) {
33d022bc 1917 flog_err(EC_BGP_ATTR_LEN,
8085c9a7
DA
1918 "%s: AGGREGATOR AS number is 0 for aspath: %s",
1919 peer->host, aspath_print(attr->aspath));
4877b70b
DA
1920
1921 if (bgp_debug_update(peer, NULL, NULL, 1)) {
1922 char attr_str[BUFSIZ] = {0};
1923
1924 bgp_dump_attr(attr, attr_str, sizeof(attr_str));
1925
1926 zlog_debug("%s: attributes: %s", __func__, attr_str);
1927 }
1928 } else {
8085c9a7 1929 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR);
4877b70b 1930 }
33d022bc 1931
d62a17ae 1932 return BGP_ATTR_PARSE_PROCEED;
a5c6a9b1
DA
1933
1934aggregator_ignore:
1935 stream_forward_getp(peer->curr, length);
1936
e2863b4f 1937 return bgp_attr_ignore(peer, args->type);
718e3744 1938}
1939
0b2aa3a0 1940/* New Aggregator attribute */
79288e4c 1941static enum bgp_attr_parse_ret
d62a17ae 1942bgp_attr_as4_aggregator(struct bgp_attr_parser_args *args,
1943 as_t *as4_aggregator_as,
1944 struct in_addr *as4_aggregator_addr)
1945{
1946 struct peer *const peer = args->peer;
1947 struct attr *const attr = args->attr;
1948 const bgp_size_t length = args->length;
33d022bc 1949 as_t aggregator_as;
d62a17ae 1950
1951 if (length != 8) {
1c50c1c0
QY
1952 flog_err(EC_BGP_ATTR_LEN, "New Aggregator length is not 8 [%d]",
1953 length);
d62a17ae 1954 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1955 0);
1956 }
1957
e2863b4f 1958 if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
a5c6a9b1
DA
1959 goto as4_aggregator_ignore;
1960
33d022bc 1961 aggregator_as = stream_getl(peer->curr);
0f2a703d 1962
e8364238
DA
1963 *as4_aggregator_as = aggregator_as;
1964 as4_aggregator_addr->s_addr = stream_get_ipv4(peer->curr);
1965
0f2a703d 1966 /* Codification of AS 0 Processing */
4877b70b 1967 if (aggregator_as == BGP_AS_ZERO) {
33d022bc 1968 flog_err(EC_BGP_ATTR_LEN,
8085c9a7
DA
1969 "%s: AS4_AGGREGATOR AS number is 0 for aspath: %s",
1970 peer->host, aspath_print(attr->aspath));
4877b70b
DA
1971
1972 if (bgp_debug_update(peer, NULL, NULL, 1)) {
1973 char attr_str[BUFSIZ] = {0};
1974
1975 bgp_dump_attr(attr, attr_str, sizeof(attr_str));
1976
1977 zlog_debug("%s: attributes: %s", __func__, attr_str);
1978 }
1979 } else {
8085c9a7 1980 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR);
4877b70b 1981 }
33d022bc 1982
d62a17ae 1983 return BGP_ATTR_PARSE_PROCEED;
a5c6a9b1
DA
1984
1985as4_aggregator_ignore:
1986 stream_forward_getp(peer->curr, length);
1987
e2863b4f 1988 return bgp_attr_ignore(peer, args->type);
0b2aa3a0
PJ
1989}
1990
1991/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1992 */
79288e4c 1993static enum bgp_attr_parse_ret
d62a17ae 1994bgp_attr_munge_as4_attrs(struct peer *const peer, struct attr *const attr,
1995 struct aspath *as4_path, as_t as4_aggregator,
1996 struct in_addr *as4_aggregator_addr)
1997{
1998 int ignore_as4_path = 0;
1999 struct aspath *newpath;
2000
2001 if (!attr->aspath) {
2002 /* NULL aspath shouldn't be possible as bgp_attr_parse should
2003 * have
2004 * checked that all well-known, mandatory attributes were
2005 * present.
2006 *
2007 * Can only be a problem with peer itself - hard error
2008 */
2009 return BGP_ATTR_PARSE_ERROR;
2010 }
2011
2012 if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) {
2013 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
2014 * if given.
2015 * It is worth a warning though, because the peer really
2016 * should not send them
2017 */
2018 if (BGP_DEBUG(as4, AS4)) {
2019 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
2020 zlog_debug("[AS4] %s %s AS4_PATH", peer->host,
2021 "AS4 capable peer, yet it sent");
2022
2023 if (attr->flag
2024 & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
2025 zlog_debug("[AS4] %s %s AS4_AGGREGATOR",
2026 peer->host,
2027 "AS4 capable peer, yet it sent");
2028 }
2029
2030 return BGP_ATTR_PARSE_PROCEED;
2031 }
2032
2033 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
2034 * because that may override AS4_PATH
2035 */
2036 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR))) {
2037 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR))) {
2038 /* received both.
2039 * if the as_number in aggregator is not AS_TRANS,
2040 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
2041 * and the Aggregator shall be taken as
2042 * info on the aggregating node, and the AS_PATH
2043 * shall be taken as the AS_PATH
2044 * otherwise
2045 * the Aggregator shall be ignored and the
2046 * AS4_AGGREGATOR shall be taken as the
2047 * Aggregating node and the AS_PATH is to be
2048 * constructed "as in all other cases"
2049 */
2050 if (attr->aggregator_as != BGP_AS_TRANS) {
2051 /* ignore */
2052 if (BGP_DEBUG(as4, AS4))
2053 zlog_debug(
3efd0893 2054 "[AS4] %s BGP not AS4 capable peer send AGGREGATOR != AS_TRANS and AS4_AGGREGATOR, so ignore AS4_AGGREGATOR and AS4_PATH",
d62a17ae 2055 peer->host);
2056 ignore_as4_path = 1;
2057 } else {
2058 /* "New_aggregator shall be taken as aggregator"
2059 */
2060 attr->aggregator_as = as4_aggregator;
2061 attr->aggregator_addr.s_addr =
2062 as4_aggregator_addr->s_addr;
2063 }
2064 } else {
2065 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
2066 * That is bogus - but reading the conditions
2067 * we have to handle AS4_AGGREGATOR as if it were
2068 * AGGREGATOR in that case
2069 */
2070 if (BGP_DEBUG(as4, AS4))
2071 zlog_debug(
3efd0893 2072 "[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 2073 peer->host);
2074 attr->aggregator_as = as4_aggregator;
2075 /* sweep it under the carpet and simulate a "good"
2076 * AGGREGATOR */
2077 attr->flag |= (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR));
2078 }
2079 }
2080
2081 /* need to reconcile NEW_AS_PATH and AS_PATH */
2082 if (!ignore_as4_path
2083 && (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))) {
2084 newpath = aspath_reconcile_as4(attr->aspath, as4_path);
e8a3a0a0 2085 if (!newpath)
2086 return BGP_ATTR_PARSE_ERROR;
2087
d62a17ae 2088 aspath_unintern(&attr->aspath);
2089 attr->aspath = aspath_intern(newpath);
2090 }
2091 return BGP_ATTR_PARSE_PROCEED;
0b2aa3a0
PJ
2092}
2093
718e3744 2094/* Community attribute. */
79288e4c 2095static enum bgp_attr_parse_ret
d62a17ae 2096bgp_attr_community(struct bgp_attr_parser_args *args)
2097{
2098 struct peer *const peer = args->peer;
2099 struct attr *const attr = args->attr;
2100 const bgp_size_t length = args->length;
2101
2102 if (length == 0) {
9a706b42 2103 bgp_attr_set_community(attr, NULL);
6680b550
DA
2104 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2105 args->total);
d62a17ae 2106 }
2107
e2863b4f 2108 if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
a5c6a9b1
DA
2109 goto community_ignore;
2110
9a706b42
DA
2111 bgp_attr_set_community(
2112 attr,
2113 community_parse((uint32_t *)stream_pnt(peer->curr), length));
d62a17ae 2114
2115 /* XXX: fix community_parse to use stream API and remove this */
424ab01d 2116 stream_forward_getp(peer->curr, length);
d62a17ae 2117
4ba5a9c5
DA
2118 /* The Community attribute SHALL be considered malformed if its
2119 * length is not a non-zero multiple of 4.
2120 */
9a706b42 2121 if (!bgp_attr_get_community(attr))
d62a17ae 2122 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2123 args->total);
2124
d62a17ae 2125 return BGP_ATTR_PARSE_PROCEED;
a5c6a9b1
DA
2126
2127community_ignore:
2128 stream_forward_getp(peer->curr, length);
2129
e2863b4f 2130 return bgp_attr_ignore(peer, args->type);
718e3744 2131}
2132
2133/* Originator ID attribute. */
79288e4c 2134static enum bgp_attr_parse_ret
d62a17ae 2135bgp_attr_originator_id(struct bgp_attr_parser_args *args)
718e3744 2136{
d62a17ae 2137 struct peer *const peer = args->peer;
2138 struct attr *const attr = args->attr;
2139 const bgp_size_t length = args->length;
718e3744 2140
4ba5a9c5
DA
2141 /* if received from an internal neighbor, it SHALL be considered
2142 * malformed if its length is not equal to 4. If malformed, the
2143 * UPDATE message SHALL be handled using the approach of "treat-as-
2144 * withdraw".
2145 */
d62a17ae 2146 if (length != 4) {
e50f7cfd 2147 flog_err(EC_BGP_ATTR_LEN, "Bad originator ID length %d",
1c50c1c0 2148 length);
718e3744 2149
d62a17ae 2150 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2151 args->total);
2152 }
2153
e2863b4f 2154 if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
a5c6a9b1
DA
2155 goto originator_id_ignore;
2156
424ab01d 2157 attr->originator_id.s_addr = stream_get_ipv4(peer->curr);
718e3744 2158
d62a17ae 2159 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID);
718e3744 2160
d62a17ae 2161 return BGP_ATTR_PARSE_PROCEED;
a5c6a9b1
DA
2162
2163originator_id_ignore:
2164 stream_forward_getp(peer->curr, length);
2165
e2863b4f 2166 return bgp_attr_ignore(peer, args->type);
718e3744 2167}
2168
2169/* Cluster list attribute. */
79288e4c 2170static enum bgp_attr_parse_ret
d62a17ae 2171bgp_attr_cluster_list(struct bgp_attr_parser_args *args)
718e3744 2172{
d62a17ae 2173 struct peer *const peer = args->peer;
2174 struct attr *const attr = args->attr;
2175 const bgp_size_t length = args->length;
2176
4ba5a9c5
DA
2177 /* if received from an internal neighbor, it SHALL be considered
2178 * malformed if its length is not a non-zero multiple of 4. If
2179 * malformed, the UPDATE message SHALL be handled using the approach
2180 * of "treat-as-withdraw".
2181 */
33ba22c2 2182 if (length == 0 || length % 4) {
1c50c1c0 2183 flog_err(EC_BGP_ATTR_LEN, "Bad cluster list length %d", length);
718e3744 2184
d62a17ae 2185 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2186 args->total);
2187 }
2188
e2863b4f 2189 if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
a5c6a9b1
DA
2190 goto cluster_list_ignore;
2191
779fee93
DS
2192 bgp_attr_set_cluster(
2193 attr, cluster_parse((struct in_addr *)stream_pnt(peer->curr),
2194 length));
718e3744 2195
d62a17ae 2196 /* XXX: Fix cluster_parse to use stream API and then remove this */
424ab01d 2197 stream_forward_getp(peer->curr, length);
718e3744 2198
d62a17ae 2199 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST);
718e3744 2200
d62a17ae 2201 return BGP_ATTR_PARSE_PROCEED;
a5c6a9b1
DA
2202
2203cluster_list_ignore:
2204 stream_forward_getp(peer->curr, length);
2205
e2863b4f 2206 return bgp_attr_ignore(peer, args->type);
718e3744 2207}
2208
2209/* Multiprotocol reachability information parse. */
d62a17ae 2210int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
2211 struct bgp_nlri *mp_update)
2212{
2213 iana_afi_t pkt_afi;
2214 afi_t afi;
5c525538
RW
2215 iana_safi_t pkt_safi;
2216 safi_t safi;
d62a17ae 2217 bgp_size_t nlri_len;
2218 size_t start;
2219 struct stream *s;
2220 struct peer *const peer = args->peer;
2221 struct attr *const attr = args->attr;
2222 const bgp_size_t length = args->length;
2223
2224 /* Set end of packet. */
2225 s = BGP_INPUT(peer);
2226 start = stream_get_getp(s);
2227
2228/* safe to read statically sized header? */
6e4ab12f 2229#define BGP_MP_REACH_MIN_SIZE 5
03292809 2230#define LEN_LEFT (length - (stream_get_getp(s) - start))
d62a17ae 2231 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE)) {
4cb5e18b
NT
2232 zlog_info("%s: %s sent invalid length, %lu, of MP_REACH_NLRI",
2233 __func__, peer->host, (unsigned long)length);
d62a17ae 2234 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
2235 }
2236
2237 /* Load AFI, SAFI. */
2238 pkt_afi = stream_getw(s);
2239 pkt_safi = stream_getc(s);
2240
2241 /* Convert AFI, SAFI to internal values, check. */
2242 if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) {
2243 /* Log if AFI or SAFI is unrecognized. This is not an error
2244 * unless
2245 * the attribute is otherwise malformed.
2246 */
2247 if (bgp_debug_update(peer, NULL, NULL, 0))
2248 zlog_debug(
4cb5e18b 2249 "%s sent unrecognizable AFI, %s or, SAFI, %s, of MP_REACH_NLRI",
748a041f
DS
2250 peer->host, iana_afi2str(pkt_afi),
2251 iana_safi2str(pkt_safi));
d62a17ae 2252 return BGP_ATTR_PARSE_ERROR;
2253 }
2254
2255 /* Get nexthop length. */
2256 attr->mp_nexthop_len = stream_getc(s);
2257
2258 if (LEN_LEFT < attr->mp_nexthop_len) {
2259 zlog_info(
4cb5e18b 2260 "%s: %s sent next-hop length, %u, in MP_REACH_NLRI which goes past the end of attribute",
d62a17ae 2261 __func__, peer->host, attr->mp_nexthop_len);
2262 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
2263 }
2264
2265 /* Nexthop length check. */
2266 switch (attr->mp_nexthop_len) {
7c40bf39 2267 case 0:
2268 if (safi != SAFI_FLOWSPEC) {
4cb5e18b 2269 zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
7c40bf39 2270 __func__, peer->host, attr->mp_nexthop_len);
2271 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
2272 }
2273 break;
b6453163
LB
2274 case BGP_ATTR_NHLEN_VPNV4:
2275 stream_getl(s); /* RD high */
2276 stream_getl(s); /* RD low */
996c9314
LB
2277 /*
2278 * NOTE: intentional fall through
2279 * - for consistency in rx processing
2280 *
2281 * The following comment is to signal GCC this intention
0437e105 2282 * and suppress the warning
996c9314
LB
2283 */
2284 /* FALLTHRU */
d62a17ae 2285 case BGP_ATTR_NHLEN_IPV4:
2286 stream_get(&attr->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN);
2287 /* Probably needed for RFC 2283 */
975a328e 2288 if (attr->nexthop.s_addr == INADDR_ANY)
d62a17ae 2289 memcpy(&attr->nexthop.s_addr,
2290 &attr->mp_nexthop_global_in, IPV4_MAX_BYTELEN);
2291 break;
d62a17ae 2292 case BGP_ATTR_NHLEN_IPV6_GLOBAL:
2293 case BGP_ATTR_NHLEN_VPNV6_GLOBAL:
2294 if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL) {
2295 stream_getl(s); /* RD high */
2296 stream_getl(s); /* RD low */
2297 }
2298 stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
17cdd31e
DS
2299 if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
2300 if (!peer->nexthop.ifp) {
4cb5e18b 2301 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
2302 peer->host);
2303 return BGP_ATTR_PARSE_WITHDRAW;
2304 }
77e62f2b 2305 attr->nh_ifindex = peer->nexthop.ifp->ifindex;
17cdd31e 2306 }
d62a17ae 2307 break;
2308 case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
2309 case BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL:
2310 if (attr->mp_nexthop_len
2311 == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
2312 stream_getl(s); /* RD high */
2313 stream_getl(s); /* RD low */
2314 }
2315 stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
17cdd31e
DS
2316 if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
2317 if (!peer->nexthop.ifp) {
4cb5e18b 2318 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
2319 peer->host);
2320 return BGP_ATTR_PARSE_WITHDRAW;
2321 }
77e62f2b 2322 attr->nh_ifindex = peer->nexthop.ifp->ifindex;
17cdd31e 2323 }
d62a17ae 2324 if (attr->mp_nexthop_len
2325 == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
2326 stream_getl(s); /* RD high */
2327 stream_getl(s); /* RD low */
2328 }
2329 stream_get(&attr->mp_nexthop_local, s, IPV6_MAX_BYTELEN);
2330 if (!IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_local)) {
d62a17ae 2331 if (bgp_debug_update(peer, NULL, NULL, 1))
2332 zlog_debug(
c0d72166
DS
2333 "%s sent next-hops %pI6 and %pI6. Ignoring non-LL value",
2334 peer->host, &attr->mp_nexthop_global,
2335 &attr->mp_nexthop_local);
d62a17ae 2336
2337 attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
2338 }
17cdd31e 2339 if (!peer->nexthop.ifp) {
4cb5e18b 2340 zlog_warn("%s sent a v6 LL next-hop and there's no peer interface information. Hence, withdrawing",
17cdd31e
DS
2341 peer->host);
2342 return BGP_ATTR_PARSE_WITHDRAW;
2343 }
77e62f2b 2344 attr->nh_lla_ifindex = peer->nexthop.ifp->ifindex;
d62a17ae 2345 break;
2346 default:
4cb5e18b 2347 zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
d62a17ae 2348 __func__, peer->host, attr->mp_nexthop_len);
2349 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
2350 }
2351
2352 if (!LEN_LEFT) {
4cb5e18b
NT
2353 zlog_info("%s: %s sent SNPA which couldn't be read",
2354 __func__, peer->host);
d62a17ae 2355 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
2356 }
2357
718e3744 2358 {
d7c0a89a 2359 uint8_t val;
d62a17ae 2360 if ((val = stream_getc(s)))
ade6974d 2361 flog_warn(
e50f7cfd 2362 EC_BGP_DEFUNCT_SNPA_LEN,
ade6974d
QY
2363 "%s sent non-zero value, %u, for defunct SNPA-length field",
2364 peer->host, val);
d62a17ae 2365 }
2366
2367 /* must have nrli_len, what is left of the attribute */
2368 nlri_len = LEN_LEFT;
9b9df989 2369 if (nlri_len > STREAM_READABLE(s)) {
4cb5e18b
NT
2370 zlog_info("%s: %s sent MP_REACH_NLRI which couldn't be read",
2371 __func__, peer->host);
d62a17ae 2372 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
2373 }
2374
9b9df989 2375 if (!nlri_len) {
4cb5e18b 2376 zlog_info("%s: %s sent a zero-length NLRI. Hence, treating as a EOR marker",
9b9df989
DS
2377 __func__, peer->host);
2378
2379 mp_update->afi = afi;
2380 mp_update->safi = safi;
2381 return BGP_ATTR_PARSE_EOR;
2382 }
2383
d62a17ae 2384 mp_update->afi = afi;
2385 mp_update->safi = safi;
2386 mp_update->nlri = stream_pnt(s);
2387 mp_update->length = nlri_len;
2388
2389 stream_forward_getp(s, nlri_len);
2390
2391 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI);
2392
2393 return BGP_ATTR_PARSE_PROCEED;
03292809 2394#undef LEN_LEFT
718e3744 2395}
2396
2397/* Multiprotocol unreachable parse */
d62a17ae 2398int bgp_mp_unreach_parse(struct bgp_attr_parser_args *args,
2399 struct bgp_nlri *mp_withdraw)
2400{
2401 struct stream *s;
2402 iana_afi_t pkt_afi;
2403 afi_t afi;
5c525538
RW
2404 iana_safi_t pkt_safi;
2405 safi_t safi;
d7c0a89a 2406 uint16_t withdraw_len;
d62a17ae 2407 struct peer *const peer = args->peer;
2408 struct attr *const attr = args->attr;
2409 const bgp_size_t length = args->length;
9cabb64b 2410
424ab01d 2411 s = peer->curr;
9cabb64b 2412
d62a17ae 2413#define BGP_MP_UNREACH_MIN_SIZE 3
2414 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
2415 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
2416
2417 pkt_afi = stream_getw(s);
2418 pkt_safi = stream_getc(s);
2419
2420 /* Convert AFI, SAFI to internal values, check. */
2421 if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) {
2422 /* Log if AFI or SAFI is unrecognized. This is not an error
2423 * unless
2424 * the attribute is otherwise malformed.
2425 */
2426 if (bgp_debug_update(peer, NULL, NULL, 0))
2427 zlog_debug(
748a041f
DS
2428 "%s: MP_UNREACH received AFI %s or SAFI %s is unrecognized",
2429 peer->host, iana_afi2str(pkt_afi),
2430 iana_safi2str(pkt_safi));
d62a17ae 2431 return BGP_ATTR_PARSE_ERROR;
2432 }
718e3744 2433
d62a17ae 2434 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
718e3744 2435
d62a17ae 2436 mp_withdraw->afi = afi;
2437 mp_withdraw->safi = safi;
2438 mp_withdraw->nlri = stream_pnt(s);
2439 mp_withdraw->length = withdraw_len;
718e3744 2440
d62a17ae 2441 stream_forward_getp(s, withdraw_len);
37da8fa9 2442
d62a17ae 2443 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI);
2444
2445 return BGP_ATTR_PARSE_PROCEED;
718e3744 2446}
2447
57d187bc 2448/* Large Community attribute. */
79288e4c 2449static enum bgp_attr_parse_ret
d62a17ae 2450bgp_attr_large_community(struct bgp_attr_parser_args *args)
2451{
2452 struct peer *const peer = args->peer;
2453 struct attr *const attr = args->attr;
2454 const bgp_size_t length = args->length;
2455
2456 /*
2457 * Large community follows new attribute format.
2458 */
2459 if (length == 0) {
1bcf3a96 2460 bgp_attr_set_lcommunity(attr, NULL);
d62a17ae 2461 /* Empty extcomm doesn't seem to be invalid per se */
6680b550
DA
2462 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2463 args->total);
d62a17ae 2464 }
57d187bc 2465
e2863b4f 2466 if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
a5c6a9b1
DA
2467 goto large_community_ignore;
2468
1bcf3a96
DA
2469 bgp_attr_set_lcommunity(
2470 attr, lcommunity_parse(stream_pnt(peer->curr), length));
d62a17ae 2471 /* XXX: fix ecommunity_parse to use stream API */
424ab01d 2472 stream_forward_getp(peer->curr, length);
57d187bc 2473
1bcf3a96 2474 if (!bgp_attr_get_lcommunity(attr))
d62a17ae 2475 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2476 args->total);
57d187bc 2477
d62a17ae 2478 return BGP_ATTR_PARSE_PROCEED;
a5c6a9b1
DA
2479
2480large_community_ignore:
2481 stream_forward_getp(peer->curr, length);
2482
e2863b4f 2483 return bgp_attr_ignore(peer, args->type);
57d187bc
JS
2484}
2485
718e3744 2486/* Extended Community attribute. */
79288e4c 2487static enum bgp_attr_parse_ret
d62a17ae 2488bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
2489{
2490 struct peer *const peer = args->peer;
2491 struct attr *const attr = args->attr;
2492 const bgp_size_t length = args->length;
d7c0a89a 2493 uint8_t sticky = 0;
7904e9fd 2494 bool proxy = false;
b53e67a3 2495 struct ecommunity *ecomm;
d62a17ae 2496
2497 if (length == 0) {
b53e67a3 2498 bgp_attr_set_ecommunity(attr, NULL);
d62a17ae 2499 /* Empty extcomm doesn't seem to be invalid per se */
6680b550
DA
2500 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2501 args->total);
d62a17ae 2502 }
2503
b53e67a3 2504 ecomm = ecommunity_parse(
27aa23a4
DA
2505 stream_pnt(peer->curr), length,
2506 CHECK_FLAG(peer->flags,
2507 PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE));
b53e67a3 2508 bgp_attr_set_ecommunity(attr, ecomm);
d62a17ae 2509 /* XXX: fix ecommunity_parse to use stream API */
424ab01d 2510 stream_forward_getp(peer->curr, length);
d62a17ae 2511
4ba5a9c5
DA
2512 /* The Extended Community attribute SHALL be considered malformed if
2513 * its length is not a non-zero multiple of 8.
2514 */
b53e67a3 2515 if (!bgp_attr_get_ecommunity(attr))
d62a17ae 2516 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2517 args->total);
2518
74e2bd89
AK
2519 /* Extract DF election preference and mobility sequence number */
2520 attr->df_pref = bgp_attr_df_pref_from_ec(attr, &attr->df_alg);
2521
d62a17ae 2522 /* Extract MAC mobility sequence number, if any. */
2523 attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr, &sticky);
2524 attr->sticky = sticky;
2525
ead40654
MK
2526 /* Check if this is a Gateway MAC-IP advertisement */
2527 attr->default_gw = bgp_attr_default_gw(attr);
2528
68e33151
CS
2529 /* Handle scenario where router flag ecommunity is not
2530 * set but default gw ext community is present.
2531 * Use default gateway, set and propogate R-bit.
2532 */
2533 if (attr->default_gw)
2534 attr->router_flag = 1;
2535
2536 /* Check EVPN Neighbor advertisement flags, R-bit */
7904e9fd
AK
2537 bgp_attr_evpn_na_flag(attr, &attr->router_flag, &proxy);
2538 if (proxy)
2539 attr->es_flags |= ATTR_ES_PROXY_ADVERT;
68e33151 2540
bc59a672 2541 /* Extract the Rmac, if any */
eee353c5 2542 if (bgp_attr_rmac(attr, &attr->rmac)) {
c0d72166
DS
2543 if (bgp_debug_update(peer, NULL, NULL, 1)
2544 && bgp_mac_exist(&attr->rmac))
2545 zlog_debug("%s: router mac %pEA is self mac", __func__,
2546 &attr->rmac);
eee353c5 2547 }
bc59a672 2548
f4bd90c5
LK
2549 /* Get the tunnel type from encap extended community */
2550 bgp_attr_extcom_tunnel_type(attr,
2551 (bgp_encap_types *)&attr->encap_tunneltype);
2552
d901dc13 2553 /* Extract link bandwidth, if any. */
b53e67a3
DA
2554 (void)ecommunity_linkbw_present(bgp_attr_get_ecommunity(attr),
2555 &attr->link_bw);
d901dc13 2556
d62a17ae 2557 return BGP_ATTR_PARSE_PROCEED;
718e3744 2558}
2559
9a659715 2560/* IPv6 Extended Community attribute. */
79288e4c 2561static enum bgp_attr_parse_ret
9a659715
PG
2562bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args)
2563{
2564 struct peer *const peer = args->peer;
2565 struct attr *const attr = args->attr;
2566 const bgp_size_t length = args->length;
d04ac434 2567 struct ecommunity *ipv6_ecomm = NULL;
9a659715
PG
2568
2569 if (length == 0) {
d04ac434 2570 bgp_attr_set_ipv6_ecommunity(attr, ipv6_ecomm);
c6423c31
PG
2571 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2572 args->total);
9a659715
PG
2573 }
2574
e2863b4f 2575 if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
a5c6a9b1
DA
2576 goto ipv6_ext_community_ignore;
2577
27aa23a4
DA
2578 ipv6_ecomm = ecommunity_parse_ipv6(
2579 stream_pnt(peer->curr), length,
2580 CHECK_FLAG(peer->flags,
2581 PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE));
d04ac434
DS
2582 bgp_attr_set_ipv6_ecommunity(attr, ipv6_ecomm);
2583
9a659715
PG
2584 /* XXX: fix ecommunity_parse to use stream API */
2585 stream_forward_getp(peer->curr, length);
2586
d04ac434 2587 if (!ipv6_ecomm)
9a659715
PG
2588 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2589 args->total);
2590
9a659715 2591 return BGP_ATTR_PARSE_PROCEED;
a5c6a9b1
DA
2592
2593ipv6_ext_community_ignore:
2594 stream_forward_getp(peer->curr, length);
2595
e2863b4f 2596 return bgp_attr_ignore(peer, args->type);
9a659715
PG
2597}
2598
f4c89855 2599/* Parse Tunnel Encap attribute in an UPDATE */
d62a17ae 2600static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */
2601 bgp_size_t length, /* IN: attr's length field */
2602 struct attr *attr, /* IN: caller already allocated */
d7c0a89a
QY
2603 uint8_t flag, /* IN: attr's flags field */
2604 uint8_t *startp)
d62a17ae 2605{
2606 bgp_size_t total;
d62a17ae 2607 uint16_t tunneltype = 0;
2608
2609 total = length + (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
2610
2611 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)
2612 || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL)) {
2613 zlog_info(
2614 "Tunnel Encap attribute flag isn't optional and transitive %d",
2615 flag);
2616 bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR,
2617 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
2618 startp, total);
2619 return -1;
2620 }
2621
2622 if (BGP_ATTR_ENCAP == type) {
2623 /* read outer TLV type and length */
2624 uint16_t tlv_length;
2625
2626 if (length < 4) {
2627 zlog_info(
2628 "Tunnel Encap attribute not long enough to contain outer T,L");
2629 bgp_notify_send_with_data(
2630 peer, BGP_NOTIFY_UPDATE_ERR,
2631 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, startp, total);
2632 return -1;
2633 }
2634 tunneltype = stream_getw(BGP_INPUT(peer));
2635 tlv_length = stream_getw(BGP_INPUT(peer));
2636 length -= 4;
2637
2638 if (tlv_length != length) {
4cb5e18b
NT
2639 zlog_info("%s: tlv_length(%d) != length(%d)",
2640 __func__, tlv_length, length);
d62a17ae 2641 }
2642 }
2643
2644 while (length >= 4) {
2645 uint16_t subtype = 0;
2646 uint16_t sublength = 0;
2647 struct bgp_attr_encap_subtlv *tlv;
2648
2649 if (BGP_ATTR_ENCAP == type) {
2650 subtype = stream_getc(BGP_INPUT(peer));
2651 sublength = stream_getc(BGP_INPUT(peer));
2652 length -= 2;
1e20238a 2653#ifdef ENABLE_BGP_VNC
d62a17ae 2654 } else {
2655 subtype = stream_getw(BGP_INPUT(peer));
2656 sublength = stream_getw(BGP_INPUT(peer));
2657 length -= 4;
65efcfce 2658#endif
d62a17ae 2659 }
2660
2661 if (sublength > length) {
2662 zlog_info(
2663 "Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d",
2664 sublength, length);
2665 bgp_notify_send_with_data(
2666 peer, BGP_NOTIFY_UPDATE_ERR,
2667 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, startp, total);
2668 return -1;
2669 }
2670
2671 /* alloc and copy sub-tlv */
2672 /* TBD make sure these are freed when attributes are released */
2673 tlv = XCALLOC(MTYPE_ENCAP_TLV,
996c9314 2674 sizeof(struct bgp_attr_encap_subtlv) + sublength);
d62a17ae 2675 tlv->type = subtype;
2676 tlv->length = sublength;
424ab01d 2677 stream_get(tlv->value, peer->curr, sublength);
d62a17ae 2678 length -= sublength;
2679
2680 /* attach tlv to encap chain */
2681 if (BGP_ATTR_ENCAP == type) {
e4002056 2682 struct bgp_attr_encap_subtlv *stlv_last;
d62a17ae 2683 for (stlv_last = attr->encap_subtlvs;
2684 stlv_last && stlv_last->next;
2685 stlv_last = stlv_last->next)
2686 ;
2687 if (stlv_last) {
2688 stlv_last->next = tlv;
2689 } else {
2690 attr->encap_subtlvs = tlv;
2691 }
1e20238a 2692#ifdef ENABLE_BGP_VNC
d62a17ae 2693 } else {
e4002056 2694 struct bgp_attr_encap_subtlv *stlv_last;
91ebf12c
DS
2695 struct bgp_attr_encap_subtlv *vnc_subtlvs =
2696 bgp_attr_get_vnc_subtlvs(attr);
2697
2698 for (stlv_last = vnc_subtlvs;
d62a17ae 2699 stlv_last && stlv_last->next;
2700 stlv_last = stlv_last->next)
2701 ;
91ebf12c 2702 if (stlv_last)
d62a17ae 2703 stlv_last->next = tlv;
91ebf12c
DS
2704 else
2705 bgp_attr_set_vnc_subtlvs(attr, tlv);
aadc0905 2706#endif
d62a17ae 2707 }
d62a17ae 2708 }
f4c89855 2709
d62a17ae 2710 if (BGP_ATTR_ENCAP == type) {
2711 attr->encap_tunneltype = tunneltype;
2712 }
f4c89855 2713
d62a17ae 2714 if (length) {
2715 /* spurious leftover data */
2716 zlog_info(
2717 "Tunnel Encap attribute length is bad: %d leftover octets",
2718 length);
2719 bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR,
2720 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2721 startp, total);
2722 return -1;
2723 }
f4c89855 2724
d62a17ae 2725 return 0;
f4c89855
LB
2726}
2727
73604f82
RS
2728
2729/* SRv6 Service Data Sub-Sub-TLV attribute
2730 * draft-ietf-bess-srv6-services-07
2731 */
79288e4c 2732static enum bgp_attr_parse_ret
73604f82
RS
2733bgp_attr_srv6_service_data(struct bgp_attr_parser_args *args)
2734{
2735 struct peer *const peer = args->peer;
9299fd00 2736 struct attr *const attr = args->attr;
73604f82
RS
2737 uint8_t type, loc_block_len, loc_node_len, func_len, arg_len,
2738 transposition_len, transposition_offset;
2739 uint16_t length;
2740 size_t headersz = sizeof(type) + sizeof(length);
2741
2742 if (STREAM_READABLE(peer->curr) < headersz) {
2743 flog_err(
2744 EC_BGP_ATTR_LEN,
2745 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
2746 headersz, STREAM_READABLE(peer->curr));
2747 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2748 args->total);
2749 }
2750
2751 type = stream_getc(peer->curr);
2752 length = stream_getw(peer->curr);
2753
2754 if (STREAM_READABLE(peer->curr) < length) {
2755 flog_err(
2756 EC_BGP_ATTR_LEN,
2757 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)",
2758 length, STREAM_READABLE(peer->curr));
2759 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2760 args->total);
2761 }
2762
5c111a25
DS
2763 if (length < BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH) {
2764 flog_err(
2765 EC_BGP_ATTR_LEN,
c5fa4459 2766 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficient data (need %u, have %hu remaining in UPDATE)",
5c111a25
DS
2767 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH,
2768 length);
2769 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2770 args->total);
2771 }
2772
73604f82 2773 if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE) {
bc32d950
DS
2774 if (STREAM_READABLE(peer->curr) <
2775 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH) {
2776 flog_err(
2777 EC_BGP_ATTR_LEN,
2778 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficient data (need %u, have %zu remaining in UPDATE)",
2779 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH,
2780 STREAM_READABLE(peer->curr));
2781 return bgp_attr_malformed(
2782 args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2783 args->total);
2784 }
2785
73604f82
RS
2786 loc_block_len = stream_getc(peer->curr);
2787 loc_node_len = stream_getc(peer->curr);
2788 func_len = stream_getc(peer->curr);
2789 arg_len = stream_getc(peer->curr);
2790 transposition_len = stream_getc(peer->curr);
2791 transposition_offset = stream_getc(peer->curr);
2792
2793 /* Log SRv6 Service Data Sub-Sub-TLV */
2794 if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
2795 zlog_debug(
2796 "%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",
2797 __func__, loc_block_len, loc_node_len, func_len,
2798 arg_len, transposition_len,
2799 transposition_offset);
2800 }
9299fd00
RS
2801
2802 attr->srv6_l3vpn->loc_block_len = loc_block_len;
2803 attr->srv6_l3vpn->loc_node_len = loc_node_len;
2804 attr->srv6_l3vpn->func_len = func_len;
2805 attr->srv6_l3vpn->arg_len = arg_len;
2806 attr->srv6_l3vpn->transposition_len = transposition_len;
2807 attr->srv6_l3vpn->transposition_offset = transposition_offset;
73604f82
RS
2808 }
2809
2810 else {
2811 if (bgp_debug_update(peer, NULL, NULL, 1))
2812 zlog_debug(
2813 "%s attr SRv6 Service Data Sub-Sub-TLV sub-sub-type=%u is not supported, skipped",
2814 peer->host, type);
2815
2816 stream_forward_getp(peer->curr, length);
2817 }
2818
2819 return BGP_ATTR_PARSE_PROCEED;
2820}
2821
2822/* SRv6 Service Sub-TLV attribute
2823 * draft-ietf-bess-srv6-services-07
2824 */
79288e4c 2825static enum bgp_attr_parse_ret
73604f82
RS
2826bgp_attr_srv6_service(struct bgp_attr_parser_args *args)
2827{
2828 struct peer *const peer = args->peer;
2829 struct attr *const attr = args->attr;
2830 struct in6_addr ipv6_sid;
2831 uint8_t type, sid_flags;
2832 uint16_t length, endpoint_behavior;
2833 size_t headersz = sizeof(type) + sizeof(length);
79288e4c 2834 enum bgp_attr_parse_ret err;
73604f82
RS
2835
2836 if (STREAM_READABLE(peer->curr) < headersz) {
2837 flog_err(
2838 EC_BGP_ATTR_LEN,
2839 "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
2840 headersz, STREAM_READABLE(peer->curr));
2841 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2842 args->total);
2843 }
2844
2845 type = stream_getc(peer->curr);
2846 length = stream_getw(peer->curr);
2847
2848 if (STREAM_READABLE(peer->curr) < length) {
2849 flog_err(
2850 EC_BGP_ATTR_LEN,
2851 "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)",
2852 length, STREAM_READABLE(peer->curr));
2853 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2854 args->total);
2855 }
2856
2857 if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO) {
bc32d950
DS
2858 if (STREAM_READABLE(peer->curr) <
2859 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH) {
2860 flog_err(
2861 EC_BGP_ATTR_LEN,
2862 "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %d for attribute data, have %zu remaining in UPDATE)",
2863 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH,
2864 STREAM_READABLE(peer->curr));
2865 return bgp_attr_malformed(
2866 args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2867 args->total);
2868 }
73604f82
RS
2869 stream_getc(peer->curr);
2870 stream_get(&ipv6_sid, peer->curr, sizeof(ipv6_sid));
2871 sid_flags = stream_getc(peer->curr);
2872 endpoint_behavior = stream_getw(peer->curr);
2873 stream_getc(peer->curr);
2874
2875 /* Log SRv6 Service Sub-TLV */
07380148 2876 if (BGP_DEBUG(vpn, VPN_LEAK_LABEL))
73604f82 2877 zlog_debug(
07380148
DA
2878 "%s: srv6-l3-srv sid %pI6, sid-flags 0x%02x, end-behaviour 0x%04x",
2879 __func__, &ipv6_sid, sid_flags,
2880 endpoint_behavior);
73604f82
RS
2881
2882 /* Configure from Info */
2883 if (attr->srv6_l3vpn) {
2884 flog_err(EC_BGP_ATTRIBUTE_REPEATED,
2885 "Prefix SID SRv6 L3VPN field repeated");
2886 return bgp_attr_malformed(
2887 args, BGP_NOTIFY_UPDATE_MAL_ATTR, args->total);
2888 }
2889 attr->srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN,
2890 sizeof(struct bgp_attr_srv6_l3vpn));
9299fd00 2891 sid_copy(&attr->srv6_l3vpn->sid, &ipv6_sid);
73604f82
RS
2892 attr->srv6_l3vpn->sid_flags = sid_flags;
2893 attr->srv6_l3vpn->endpoint_behavior = endpoint_behavior;
9299fd00
RS
2894 attr->srv6_l3vpn->loc_block_len = 0;
2895 attr->srv6_l3vpn->loc_node_len = 0;
2896 attr->srv6_l3vpn->func_len = 0;
2897 attr->srv6_l3vpn->arg_len = 0;
2898 attr->srv6_l3vpn->transposition_len = 0;
2899 attr->srv6_l3vpn->transposition_offset = 0;
73604f82
RS
2900
2901 // Sub-Sub-TLV found
9299fd00
RS
2902 if (length > BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH) {
2903 err = bgp_attr_srv6_service_data(args);
2904
2905 if (err != BGP_ATTR_PARSE_PROCEED)
2906 return err;
2907 }
2908
2909 attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn);
73604f82
RS
2910 }
2911
2912 /* Placeholder code for unsupported type */
2913 else {
2914 if (bgp_debug_update(peer, NULL, NULL, 1))
2915 zlog_debug(
2916 "%s attr SRv6 Service Sub-TLV sub-type=%u is not supported, skipped",
2917 peer->host, type);
2918
2919 stream_forward_getp(peer->curr, length);
2920 }
2921
2922 return BGP_ATTR_PARSE_PROCEED;
2923}
2924
30adbd4e
DS
2925/*
2926 * Read an individual SID value returning how much data we have read
2927 * Returns 0 if there was an error that needs to be passed up the stack
c5a543b4 2928 */
79288e4c
DA
2929static enum bgp_attr_parse_ret
2930bgp_attr_psid_sub(uint8_t type, uint16_t length,
2931 struct bgp_attr_parser_args *args)
d62a17ae 2932{
2933 struct peer *const peer = args->peer;
2934 struct attr *const attr = args->attr;
d7c0a89a 2935 uint32_t label_index;
d62a17ae 2936 struct in6_addr ipv6_sid;
d7c0a89a
QY
2937 uint32_t srgb_base;
2938 uint32_t srgb_range;
d62a17ae 2939 int srgb_count;
e496b420 2940 uint8_t sid_type, sid_flags;
d62a17ae 2941
d62a17ae 2942 if (type == BGP_PREFIX_SID_LABEL_INDEX) {
f69aeb76
QY
2943 if (STREAM_READABLE(peer->curr) < length
2944 || length != BGP_PREFIX_SID_LABEL_INDEX_LENGTH) {
2945 flog_err(EC_BGP_ATTR_LEN,
6cde4b45 2946 "Prefix SID label index length is %hu instead of %u",
f69aeb76 2947 length, BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
30adbd4e
DS
2948 return bgp_attr_malformed(args,
2949 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2950 args->total);
d62a17ae 2951 }
2952
2953 /* Ignore flags and reserved */
424ab01d
QY
2954 stream_getc(peer->curr);
2955 stream_getw(peer->curr);
d62a17ae 2956
2957 /* Fetch the label index and see if it is valid. */
424ab01d 2958 label_index = stream_getl(peer->curr);
d62a17ae 2959 if (label_index == BGP_INVALID_LABEL_INDEX)
30adbd4e
DS
2960 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2961 args->total);
d62a17ae 2962
2963 /* Store label index; subsequently, we'll check on
2964 * address-family */
2965 attr->label_index = label_index;
d62a17ae 2966 }
2967
2968 /* Placeholder code for the IPv6 SID type */
2969 else if (type == BGP_PREFIX_SID_IPV6) {
f69aeb76
QY
2970 if (STREAM_READABLE(peer->curr) < length
2971 || length != BGP_PREFIX_SID_IPV6_LENGTH) {
e50f7cfd 2972 flog_err(EC_BGP_ATTR_LEN,
6cde4b45 2973 "Prefix SID IPv6 length is %hu instead of %u",
1c50c1c0 2974 length, BGP_PREFIX_SID_IPV6_LENGTH);
30adbd4e
DS
2975 return bgp_attr_malformed(args,
2976 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2977 args->total);
d62a17ae 2978 }
2979
2980 /* Ignore reserved */
424ab01d
QY
2981 stream_getc(peer->curr);
2982 stream_getw(peer->curr);
d62a17ae 2983
424ab01d 2984 stream_get(&ipv6_sid, peer->curr, 16);
d62a17ae 2985 }
2986
2987 /* Placeholder code for the Originator SRGB type */
2988 else if (type == BGP_PREFIX_SID_ORIGINATOR_SRGB) {
473046ee
QY
2989 /*
2990 * ietf-idr-bgp-prefix-sid-05:
2991 * Length is the total length of the value portion of the
2992 * TLV: 2 + multiple of 6.
2993 *
2994 * peer->curr stream readp should be at the beginning of the 16
2995 * bit flag field at this point in the code.
2996 */
d62a17ae 2997
473046ee
QY
2998 /*
2999 * Check that the TLV length field is sane: at least 2 bytes of
3000 * flag, and at least 1 SRGB (these are 6 bytes each)
3001 */
3002 if (length < (2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH)) {
3003 flog_err(
3004 EC_BGP_ATTR_LEN,
6cde4b45 3005 "Prefix SID Originator SRGB length field claims length of %hu bytes, but the minimum for this TLV type is %u",
473046ee
QY
3006 length,
3007 2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH);
3008 return bgp_attr_malformed(
3009 args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3010 args->total);
3011 }
d62a17ae 3012
473046ee
QY
3013 /*
3014 * Check that we actually have at least as much data as
3015 * specified by the length field
3016 */
3017 if (STREAM_READABLE(peer->curr) < length) {
f69aeb76 3018 flog_err(EC_BGP_ATTR_LEN,
6cde4b45 3019 "Prefix SID Originator SRGB specifies length %hu, but only %zu bytes remain",
473046ee 3020 length, STREAM_READABLE(peer->curr));
f69aeb76
QY
3021 return bgp_attr_malformed(
3022 args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3023 args->total);
3024 }
3025
473046ee
QY
3026 /*
3027 * Check that the portion of the TLV containing the sequence of
3028 * SRGBs corresponds to a multiple of the SRGB size; to get
3029 * that length, we skip the 16 bit flags field
3030 */
424ab01d 3031 stream_getw(peer->curr);
d62a17ae 3032 length -= 2;
d62a17ae 3033 if (length % BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH) {
af4c2728 3034 flog_err(
e50f7cfd 3035 EC_BGP_ATTR_LEN,
6cde4b45 3036 "Prefix SID Originator SRGB length field claims attribute SRGB sequence section is %hubytes, but it must be a multiple of %u",
d62a17ae 3037 length, BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH);
3038 return bgp_attr_malformed(
3039 args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3040 args->total);
3041 }
3042
3043 srgb_count = length / BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH;
3044
3045 for (int i = 0; i < srgb_count; i++) {
424ab01d
QY
3046 stream_get(&srgb_base, peer->curr, 3);
3047 stream_get(&srgb_range, peer->curr, 3);
d62a17ae 3048 }
3049 }
3050
e496b420
HS
3051 /* Placeholder code for the VPN-SID Service type */
3052 else if (type == BGP_PREFIX_SID_VPN_SID) {
3053 if (STREAM_READABLE(peer->curr) < length
3054 || length != BGP_PREFIX_SID_VPN_SID_LENGTH) {
3055 flog_err(EC_BGP_ATTR_LEN,
6cde4b45 3056 "Prefix SID VPN SID length is %hu instead of %u",
e496b420
HS
3057 length, BGP_PREFIX_SID_VPN_SID_LENGTH);
3058 return bgp_attr_malformed(args,
3059 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3060 args->total);
3061 }
3062
3063 /* Parse VPN-SID Sub-TLV */
3064 stream_getc(peer->curr); /* reserved */
3065 sid_type = stream_getc(peer->curr); /* sid_type */
3066 sid_flags = stream_getc(peer->curr); /* sid_flags */
3067 stream_get(&ipv6_sid, peer->curr,
3068 sizeof(ipv6_sid)); /* sid_value */
3069
3070 /* Log VPN-SID Sub-TLV */
07380148 3071 if (BGP_DEBUG(vpn, VPN_LEAK_LABEL))
e496b420 3072 zlog_debug(
07380148
DA
3073 "%s: vpn-sid: sid %pI6, sid-type 0x%02x sid-flags 0x%02x",
3074 __func__, &ipv6_sid, sid_type, sid_flags);
e496b420
HS
3075
3076 /* Configure from Info */
b502ca11
QY
3077 if (attr->srv6_vpn) {
3078 flog_err(EC_BGP_ATTRIBUTE_REPEATED,
3079 "Prefix SID SRv6 VPN field repeated");
3080 return bgp_attr_malformed(
3081 args, BGP_NOTIFY_UPDATE_MAL_ATTR, args->total);
3082 }
340594a9 3083 attr->srv6_vpn = XCALLOC(MTYPE_BGP_SRV6_VPN,
e496b420 3084 sizeof(struct bgp_attr_srv6_vpn));
e496b420
HS
3085 attr->srv6_vpn->sid_flags = sid_flags;
3086 sid_copy(&attr->srv6_vpn->sid, &ipv6_sid);
b83127e1 3087 attr->srv6_vpn = srv6_vpn_intern(attr->srv6_vpn);
e496b420
HS
3088 }
3089
3090 /* Placeholder code for the SRv6 L3 Service type */
3091 else if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE) {
73604f82
RS
3092 if (STREAM_READABLE(peer->curr) < length) {
3093 flog_err(
3094 EC_BGP_ATTR_LEN,
3095 "Prefix SID SRv6 L3-Service length is %hu, but only %zu bytes remain",
3096 length, STREAM_READABLE(peer->curr));
e496b420
HS
3097 return bgp_attr_malformed(args,
3098 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3099 args->total);
3100 }
3101
73604f82
RS
3102 /* ignore reserved */
3103 stream_getc(peer->curr);
e496b420 3104
73604f82 3105 return bgp_attr_srv6_service(args);
e496b420
HS
3106 }
3107
3108 /* Placeholder code for Unsupported TLV */
3109 else {
f69aeb76
QY
3110
3111 if (STREAM_READABLE(peer->curr) < length) {
3112 flog_err(
3113 EC_BGP_ATTR_LEN,
6cde4b45 3114 "Prefix SID SRv6 length is %hu - too long, only %zu remaining in this UPDATE",
f69aeb76
QY
3115 length, STREAM_READABLE(peer->curr));
3116 return bgp_attr_malformed(
3117 args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3118 args->total);
3119 }
3120
c6ca155d
HS
3121 if (bgp_debug_update(peer, NULL, NULL, 1))
3122 zlog_debug(
3123 "%s attr Prefix-SID sub-type=%u is not supported, skipped",
3124 peer->host, type);
f69aeb76
QY
3125
3126 stream_forward_getp(peer->curr, length);
c6ca155d
HS
3127 }
3128
d62a17ae 3129 return BGP_ATTR_PARSE_PROCEED;
6cf48acc
VV
3130}
3131
30adbd4e
DS
3132/* Prefix SID attribute
3133 * draft-ietf-idr-bgp-prefix-sid-05
3134 */
79288e4c 3135enum bgp_attr_parse_ret bgp_attr_prefix_sid(struct bgp_attr_parser_args *args)
30adbd4e
DS
3136{
3137 struct peer *const peer = args->peer;
3138 struct attr *const attr = args->attr;
79288e4c 3139 enum bgp_attr_parse_ret ret;
30adbd4e
DS
3140
3141 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID);
3142
f69aeb76
QY
3143 uint8_t type;
3144 uint16_t length;
3145 size_t headersz = sizeof(type) + sizeof(length);
38774fc5 3146 size_t psid_parsed_length = 0;
30adbd4e 3147
38774fc5
HS
3148 while (STREAM_READABLE(peer->curr) > 0
3149 && psid_parsed_length < args->length) {
30adbd4e 3150
f69aeb76
QY
3151 if (STREAM_READABLE(peer->curr) < headersz) {
3152 flog_err(
3153 EC_BGP_ATTR_LEN,
3154 "Malformed Prefix SID attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
3155 headersz, STREAM_READABLE(peer->curr));
3156 return bgp_attr_malformed(
3157 args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3158 args->total);
3159 }
30adbd4e 3160
f69aeb76
QY
3161 type = stream_getc(peer->curr);
3162 length = stream_getw(peer->curr);
30adbd4e 3163
f69aeb76 3164 if (STREAM_READABLE(peer->curr) < length) {
af4c2728 3165 flog_err(
e50f7cfd 3166 EC_BGP_ATTR_LEN,
6cde4b45 3167 "Malformed Prefix SID attribute - insufficient data (need %hu for attribute body, have %zu remaining in UPDATE)",
f69aeb76 3168 length, STREAM_READABLE(peer->curr));
30adbd4e
DS
3169 return bgp_attr_malformed(args,
3170 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3171 args->total);
3172 }
f69aeb76 3173
45a06b11 3174 ret = bgp_attr_psid_sub(type, length, args);
f69aeb76
QY
3175
3176 if (ret != BGP_ATTR_PARSE_PROCEED)
3177 return ret;
38774fc5
HS
3178
3179 psid_parsed_length += length + headersz;
3180
3181 if (psid_parsed_length > args->length) {
3182 flog_err(
3183 EC_BGP_ATTR_LEN,
3efd0893 3184 "Malformed Prefix SID attribute - TLV overflow by attribute (need %zu for TLV length, have %zu overflowed in UPDATE)",
38774fc5
HS
3185 length + headersz, psid_parsed_length - (length + headersz));
3186 return bgp_attr_malformed(
3187 args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3188 args->total);
3189 }
30adbd4e
DS
3190 }
3191
3192 return BGP_ATTR_PARSE_PROCEED;
3193}
3194
7fd077aa 3195/* PMSI tunnel attribute (RFC 6514)
3196 * Basic validation checks done here.
3197 */
79288e4c 3198static enum bgp_attr_parse_ret
7fd077aa 3199bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args)
3200{
3201 struct peer *const peer = args->peer;
3202 struct attr *const attr = args->attr;
3203 const bgp_size_t length = args->length;
d7c0a89a 3204 uint8_t tnl_type;
355f3c11 3205 int attr_parse_len = 2 + BGP_LABEL_BYTES;
7fd077aa 3206
3207 /* Verify that the receiver is expecting "ingress replication" as we
3208 * can only support that.
3209 */
355f3c11 3210 if (length < attr_parse_len) {
1c50c1c0
QY
3211 flog_err(EC_BGP_ATTR_LEN, "Bad PMSI tunnel attribute length %d",
3212 length);
7fd077aa 3213 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3214 args->total);
3215 }
3216 stream_getc(peer->curr); /* Flags */
3217 tnl_type = stream_getc(peer->curr);
3218 if (tnl_type > PMSI_TNLTYPE_MAX) {
e50f7cfd 3219 flog_err(EC_BGP_ATTR_PMSI_TYPE,
1c50c1c0 3220 "Invalid PMSI tunnel attribute type %d", tnl_type);
7fd077aa 3221 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
3222 args->total);
3223 }
3224 if (tnl_type == PMSI_TNLTYPE_INGR_REPL) {
3225 if (length != 9) {
e50f7cfd 3226 flog_err(EC_BGP_ATTR_PMSI_LEN,
1c50c1c0
QY
3227 "Bad PMSI tunnel attribute length %d for IR",
3228 length);
052ea98b 3229 return bgp_attr_malformed(
3230 args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3231 args->total);
7fd077aa 3232 }
3233 }
3234
3235 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
2a3f51cf 3236 bgp_attr_set_pmsi_tnl_type(attr, tnl_type);
355f3c11 3237 stream_get(&attr->label, peer->curr, BGP_LABEL_BYTES);
7fd077aa 3238
3239 /* Forward read pointer of input stream. */
355f3c11 3240 stream_forward_getp(peer->curr, length - attr_parse_len);
7fd077aa 3241
3242 return BGP_ATTR_PARSE_PROCEED;
3243}
3244
97a52c82
DA
3245/* AIGP attribute (rfc7311) */
3246static enum bgp_attr_parse_ret bgp_attr_aigp(struct bgp_attr_parser_args *args)
3247{
3248 struct peer *const peer = args->peer;
3249 struct attr *const attr = args->attr;
3250 const bgp_size_t length = args->length;
3251 uint8_t *s = stream_pnt(peer->curr);
3252 uint64_t aigp = 0;
3253
3254 /* If an AIGP attribute is received on a BGP session for which
3255 * AIGP_SESSION is disabled, the attribute MUST be treated exactly
3256 * as if it were an unrecognized non-transitive attribute.
3257 * That is, it "MUST be quietly ignored and not passed along to
3258 * other BGP peers".
3259 * For Internal BGP (IBGP) sessions, and for External BGP (EBGP)
3260 * sessions between members of the same BGP Confederation,
3261 * the default value of AIGP_SESSION SHOULD be "enabled".
3262 */
3263 if (peer->sort == BGP_PEER_EBGP &&
3264 !CHECK_FLAG(peer->flags, PEER_FLAG_AIGP)) {
3265 zlog_warn(
3266 "%pBP received AIGP attribute, but eBGP peer do not support it",
3267 peer);
3268 goto aigp_ignore;
3269 }
3270
e2863b4f 3271 if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
a5c6a9b1
DA
3272 goto aigp_ignore;
3273
97a52c82
DA
3274 if (!bgp_attr_aigp_valid(s, length))
3275 goto aigp_ignore;
3276
3277 /* Extract AIGP Metric TLV */
3278 if (bgp_attr_aigp_get_tlv_metric(s, length, &aigp))
3279 bgp_attr_set_aigp_metric(attr, aigp);
3280
3281aigp_ignore:
3282 stream_forward_getp(peer->curr, length);
3283
e2863b4f 3284 return bgp_attr_ignore(peer, args->type);
97a52c82
DA
3285}
3286
d864dd9e
EB
3287/* OTC attribute. */
3288static enum bgp_attr_parse_ret bgp_attr_otc(struct bgp_attr_parser_args *args)
3289{
3290 struct peer *const peer = args->peer;
3291 struct attr *const attr = args->attr;
3292 const bgp_size_t length = args->length;
3293
3294 /* Length check. */
3295 if (length != 4) {
3296 flog_err(EC_BGP_ATTR_LEN, "OTC attribute length isn't 4 [%u]",
3297 length);
3298 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
3299 args->total);
3300 }
3301
e2863b4f 3302 if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
a5c6a9b1
DA
3303 goto otc_ignore;
3304
d864dd9e 3305 attr->otc = stream_getl(peer->curr);
adc1c459
DA
3306 if (!attr->otc) {
3307 flog_err(EC_BGP_ATTR_MAL_AS_PATH, "OTC attribute value is 0");
3308 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
3309 args->total);
3310 }
d864dd9e
EB
3311
3312 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_OTC);
3313
3314 return BGP_ATTR_PARSE_PROCEED;
a5c6a9b1
DA
3315
3316otc_ignore:
3317 stream_forward_getp(peer->curr, length);
3318
e2863b4f 3319 return bgp_attr_ignore(peer, args->type);
d864dd9e
EB
3320}
3321
718e3744 3322/* BGP unknown attribute treatment. */
79288e4c
DA
3323static enum bgp_attr_parse_ret
3324bgp_attr_unknown(struct bgp_attr_parser_args *args)
d62a17ae 3325{
3326 bgp_size_t total = args->total;
3327 struct transit *transit;
3328 struct peer *const peer = args->peer;
3329 struct attr *const attr = args->attr;
d7c0a89a
QY
3330 uint8_t *const startp = args->startp;
3331 const uint8_t type = args->type;
3332 const uint8_t flag = args->flags;
d62a17ae 3333 const bgp_size_t length = args->length;
3334
3335 if (bgp_debug_update(peer, NULL, NULL, 1))
3336 zlog_debug(
3337 "%s Unknown attribute is received (type %d, length %d)",
3338 peer->host, type, length);
3339
3340 /* Forward read pointer of input stream. */
424ab01d 3341 stream_forward_getp(peer->curr, length);
d62a17ae 3342
e2863b4f
DA
3343 if (peer->discard_attrs[type] || peer->withdraw_attrs[type])
3344 return bgp_attr_ignore(peer, type);
a5c6a9b1 3345
d62a17ae 3346 /* If any of the mandatory well-known attributes are not recognized,
3347 then the Error Subcode is set to Unrecognized Well-known
3348 Attribute. The Data field contains the unrecognized attribute
3349 (type, length and value). */
3350 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL)) {
3351 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_UNREC_ATTR,
3352 args->total);
3353 }
3354
3355 /* Unrecognized non-transitive optional attributes must be quietly
3356 ignored and not passed along to other BGP peers. */
3357 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS))
3358 return BGP_ATTR_PARSE_PROCEED;
3359
3360 /* If a path with recognized transitive optional attribute is
3361 accepted and passed along to other BGP peers and the Partial bit
3362 in the Attribute Flags octet is set to 1 by some previous AS, it
3363 is not set back to 0 by the current AS. */
3364 SET_FLAG(*startp, BGP_ATTR_FLAG_PARTIAL);
3365
3366 /* Store transitive attribute to the end of attr->transit. */
04fb21e2
DS
3367 transit = bgp_attr_get_transit(attr);
3368 if (!transit)
3369 transit = XCALLOC(MTYPE_TRANSIT, sizeof(struct transit));
d62a17ae 3370
0b04fa0e
DS
3371 transit->val = XREALLOC(MTYPE_TRANSIT_VAL, transit->val,
3372 transit->length + total);
d62a17ae 3373
3374 memcpy(transit->val + transit->length, startp, total);
3375 transit->length += total;
04fb21e2 3376 bgp_attr_set_transit(attr, transit);
d62a17ae 3377
3378 return BGP_ATTR_PARSE_PROCEED;
718e3744 3379}
3380
bb7bef14 3381/* Well-known attribute check. */
d62a17ae 3382static int bgp_attr_check(struct peer *peer, struct attr *attr)
3383{
d7c0a89a 3384 uint8_t type = 0;
d62a17ae 3385
3386 /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an
3387 * empty UPDATE. */
3388 if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV) && !attr->flag)
3389 return BGP_ATTR_PARSE_PROCEED;
3390
3391 /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required
3392 to carry any other path attributes.", though if MP_REACH_NLRI or NLRI
3393 are present, it should. Check for any other attribute being present
3394 instead.
3395 */
404c82d5
PG
3396 if ((!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI)) &&
3397 CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI))))
d62a17ae 3398 return BGP_ATTR_PARSE_PROCEED;
3399
3400 if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN)))
3401 type = BGP_ATTR_ORIGIN;
3402
3403 if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
3404 type = BGP_ATTR_AS_PATH;
3405
3406 /* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present
3407 * and
3408 * NLRI is empty. We can't easily check NLRI empty here though.
3409 */
3410 if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP))
3411 && !CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI)))
3412 type = BGP_ATTR_NEXT_HOP;
3413
3414 if (peer->sort == BGP_PEER_IBGP
3415 && !CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)))
3416 type = BGP_ATTR_LOCAL_PREF;
3417
4ba5a9c5
DA
3418 /* If any of the well-known mandatory attributes are not present
3419 * in an UPDATE message, then "treat-as-withdraw" MUST be used.
3420 */
d62a17ae 3421 if (type) {
e50f7cfd 3422 flog_warn(EC_BGP_MISSING_ATTRIBUTE,
559aaa30 3423 "%s Missing well-known attribute %s.", peer->host,
d62a17ae 3424 lookup_msg(attr_str, type, NULL));
4ba5a9c5 3425 return BGP_ATTR_PARSE_WITHDRAW;
d62a17ae 3426 }
3427 return BGP_ATTR_PARSE_PROCEED;
bb7bef14
PJ
3428}
3429
718e3744 3430/* Read attribute of update packet. This function is called from
8b366b9c 3431 bgp_update_receive() in bgp_packet.c. */
79288e4c
DA
3432enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr,
3433 bgp_size_t size,
3434 struct bgp_nlri *mp_update,
3435 struct bgp_nlri *mp_withdraw)
d62a17ae 3436{
79288e4c 3437 enum bgp_attr_parse_ret ret;
d7c0a89a
QY
3438 uint8_t flag = 0;
3439 uint8_t type = 0;
d62a17ae 3440 bgp_size_t length;
d7c0a89a
QY
3441 uint8_t *startp, *endp;
3442 uint8_t *attr_endp;
3443 uint8_t seen[BGP_ATTR_BITMAP_SIZE];
d62a17ae 3444 /* we need the as4_path only until we have synthesized the as_path with
3445 * it */
3446 /* same goes for as4_aggregator */
3447 struct aspath *as4_path = NULL;
3448 as_t as4_aggregator = 0;
3449 struct in_addr as4_aggregator_addr = {.s_addr = 0};
04fb21e2 3450 struct transit *transit;
d62a17ae 3451
3452 /* Initialize bitmap. */
3453 memset(seen, 0, BGP_ATTR_BITMAP_SIZE);
3454
3455 /* End pointer of BGP attribute. */
3456 endp = BGP_INPUT_PNT(peer) + size;
3457
3458 /* Get attributes to the end of attribute length. */
3459 while (BGP_INPUT_PNT(peer) < endp) {
3460 /* Check remaining length check.*/
3461 if (endp - BGP_INPUT_PNT(peer) < BGP_ATTR_MIN_LEN) {
3462 /* XXX warning: long int format, int arg (arg 5) */
ade6974d 3463 flog_warn(
e50f7cfd 3464 EC_BGP_ATTRIBUTE_TOO_SMALL,
ade6974d
QY
3465 "%s: error BGP attribute length %lu is smaller than min len",
3466 peer->host,
3467 (unsigned long)(endp
3468 - stream_pnt(BGP_INPUT(peer))));
d62a17ae 3469
3470 bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
3471 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
b6a171c7
QY
3472 ret = BGP_ATTR_PARSE_ERROR;
3473 goto done;
d62a17ae 3474 }
718e3744 3475
d62a17ae 3476 /* Fetch attribute flag and type. */
3477 startp = BGP_INPUT_PNT(peer);
3478 /* "The lower-order four bits of the Attribute Flags octet are
3479 unused. They MUST be zero when sent and MUST be ignored when
3480 received." */
3481 flag = 0xF0 & stream_getc(BGP_INPUT(peer));
3482 type = stream_getc(BGP_INPUT(peer));
3483
3484 /* Check whether Extended-Length applies and is in bounds */
3485 if (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN)
3486 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1))) {
ade6974d 3487 flog_warn(
e50f7cfd 3488 EC_BGP_EXT_ATTRIBUTE_TOO_SMALL,
ade6974d
QY
3489 "%s: Extended length set, but just %lu bytes of attr header",
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 /* Check extended attribue length bit. */
3501 if (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN))
3502 length = stream_getw(BGP_INPUT(peer));
3503 else
3504 length = stream_getc(BGP_INPUT(peer));
718e3744 3505
d62a17ae 3506 /* If any attribute appears more than once in the UPDATE
3507 message, then the Error Subcode is set to Malformed Attribute
3508 List. */
718e3744 3509
d62a17ae 3510 if (CHECK_BITMAP(seen, type)) {
ade6974d 3511 flog_warn(
e50f7cfd 3512 EC_BGP_ATTRIBUTE_REPEATED,
ade6974d
QY
3513 "%s: error BGP attribute type %d appears twice in a message",
3514 peer->host, type);
718e3744 3515
d62a17ae 3516 bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
3517 BGP_NOTIFY_UPDATE_MAL_ATTR);
b6a171c7
QY
3518 ret = BGP_ATTR_PARSE_ERROR;
3519 goto done;
d62a17ae 3520 }
3521
3522 /* Set type to bitmap to check duplicate attribute. `type' is
3523 unsigned char so it never overflow bitmap range. */
3524
3525 SET_BITMAP(seen, type);
3526
3527 /* Overflow check. */
3528 attr_endp = BGP_INPUT_PNT(peer) + length;
3529
3530 if (attr_endp > endp) {
ade6974d 3531 flog_warn(
e50f7cfd 3532 EC_BGP_ATTRIBUTE_TOO_LARGE,
ade6974d
QY
3533 "%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p",
3534 peer->host, type, length, size, attr_endp,
3535 endp);
dacffad4
QY
3536 /*
3537 * RFC 4271 6.3
3538 * If any recognized attribute has an Attribute
3539 * Length that conflicts with the expected length
3540 * (based on the attribute type code), then the
3541 * Error Subcode MUST be set to Attribute Length
3542 * Error. The Data field MUST contain the erroneous
3543 * attribute (type, length, and value).
3544 * ----------
3545 * We do not currently have a good way to determine the
3546 * length of the attribute independent of the length
3547 * received in the message. Instead we send the
3548 * minimum between the amount of data we have and the
3549 * amount specified by the attribute length field.
3550 *
3551 * Instead of directly passing in the packet buffer and
3552 * offset we use the stream_get* functions to read into
3553 * a stack buffer, since they perform bounds checking
3554 * and we are working with untrusted data.
3555 */
ef56aee4 3556 unsigned char ndata[peer->max_packet_size];
dacffad4
QY
3557 memset(ndata, 0x00, sizeof(ndata));
3558 size_t lfl =
3559 CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN) ? 2 : 1;
3560 /* Rewind to end of flag field */
763a5d3c 3561 stream_rewind_getp(BGP_INPUT(peer), (1 + lfl));
dacffad4
QY
3562 /* Type */
3563 stream_get(&ndata[0], BGP_INPUT(peer), 1);
3564 /* Length */
3565 stream_get(&ndata[1], BGP_INPUT(peer), lfl);
3566 /* Value */
3567 size_t atl = attr_endp - startp;
3568 size_t ndl = MIN(atl, STREAM_READABLE(BGP_INPUT(peer)));
3569 stream_get(&ndata[lfl + 1], BGP_INPUT(peer), ndl);
3570
d62a17ae 3571 bgp_notify_send_with_data(
3572 peer, BGP_NOTIFY_UPDATE_ERR,
dacffad4
QY
3573 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, ndata,
3574 ndl + lfl + 1);
3575
b6a171c7
QY
3576 ret = BGP_ATTR_PARSE_ERROR;
3577 goto done;
d62a17ae 3578 }
3579
3580 struct bgp_attr_parser_args attr_args = {
3581 .peer = peer,
3582 .length = length,
3583 .attr = attr,
3584 .type = type,
3585 .flags = flag,
3586 .startp = startp,
3587 .total = attr_endp - startp,
3588 };
3589
3590
3591 /* If any recognized attribute has Attribute Flags that conflict
3592 with the Attribute Type Code, then the Error Subcode is set
3593 to
3594 Attribute Flags Error. The Data field contains the erroneous
3595 attribute (type, length and value). */
3596 if (bgp_attr_flag_invalid(&attr_args)) {
d62a17ae 3597 ret = bgp_attr_malformed(
3598 &attr_args, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
3599 attr_args.total);
3600 if (ret == BGP_ATTR_PARSE_PROCEED)
3601 continue;
b6a171c7 3602 goto done;
d62a17ae 3603 }
3604
3605 /* OK check attribute and store it's value. */
3606 switch (type) {
3607 case BGP_ATTR_ORIGIN:
3608 ret = bgp_attr_origin(&attr_args);
3609 break;
3610 case BGP_ATTR_AS_PATH:
3611 ret = bgp_attr_aspath(&attr_args);
3612 break;
3613 case BGP_ATTR_AS4_PATH:
3614 ret = bgp_attr_as4_path(&attr_args, &as4_path);
3615 break;
3616 case BGP_ATTR_NEXT_HOP:
3617 ret = bgp_attr_nexthop(&attr_args);
3618 break;
3619 case BGP_ATTR_MULTI_EXIT_DISC:
3620 ret = bgp_attr_med(&attr_args);
3621 break;
3622 case BGP_ATTR_LOCAL_PREF:
3623 ret = bgp_attr_local_pref(&attr_args);
3624 break;
3625 case BGP_ATTR_ATOMIC_AGGREGATE:
3626 ret = bgp_attr_atomic(&attr_args);
3627 break;
3628 case BGP_ATTR_AGGREGATOR:
3629 ret = bgp_attr_aggregator(&attr_args);
3630 break;
3631 case BGP_ATTR_AS4_AGGREGATOR:
3632 ret = bgp_attr_as4_aggregator(&attr_args,
3633 &as4_aggregator,
3634 &as4_aggregator_addr);
3635 break;
3636 case BGP_ATTR_COMMUNITIES:
3637 ret = bgp_attr_community(&attr_args);
3638 break;
3639 case BGP_ATTR_LARGE_COMMUNITIES:
3640 ret = bgp_attr_large_community(&attr_args);
3641 break;
3642 case BGP_ATTR_ORIGINATOR_ID:
3643 ret = bgp_attr_originator_id(&attr_args);
3644 break;
3645 case BGP_ATTR_CLUSTER_LIST:
3646 ret = bgp_attr_cluster_list(&attr_args);
3647 break;
3648 case BGP_ATTR_MP_REACH_NLRI:
3649 ret = bgp_mp_reach_parse(&attr_args, mp_update);
3650 break;
3651 case BGP_ATTR_MP_UNREACH_NLRI:
3652 ret = bgp_mp_unreach_parse(&attr_args, mp_withdraw);
3653 break;
3654 case BGP_ATTR_EXT_COMMUNITIES:
3655 ret = bgp_attr_ext_communities(&attr_args);
3656 break;
1e20238a 3657#ifdef ENABLE_BGP_VNC_ATTR
d62a17ae 3658 case BGP_ATTR_VNC:
65efcfce 3659#endif
d62a17ae 3660 case BGP_ATTR_ENCAP:
3661 ret = bgp_attr_encap(type, peer, length, attr, flag,
3662 startp);
3663 break;
3664 case BGP_ATTR_PREFIX_SID:
45a06b11 3665 ret = bgp_attr_prefix_sid(&attr_args);
d62a17ae 3666 break;
7fd077aa 3667 case BGP_ATTR_PMSI_TUNNEL:
3668 ret = bgp_attr_pmsi_tunnel(&attr_args);
3669 break;
9a659715
PG
3670 case BGP_ATTR_IPV6_EXT_COMMUNITIES:
3671 ret = bgp_attr_ipv6_ext_communities(&attr_args);
3672 break;
d864dd9e
EB
3673 case BGP_ATTR_OTC:
3674 ret = bgp_attr_otc(&attr_args);
3675 break;
97a52c82
DA
3676 case BGP_ATTR_AIGP:
3677 ret = bgp_attr_aigp(&attr_args);
3678 break;
d62a17ae 3679 default:
3680 ret = bgp_attr_unknown(&attr_args);
3681 break;
3682 }
3683
3684 if (ret == BGP_ATTR_PARSE_ERROR_NOTIFYPLS) {
3685 bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
3686 BGP_NOTIFY_UPDATE_MAL_ATTR);
3687 ret = BGP_ATTR_PARSE_ERROR;
b6a171c7 3688 goto done;
d62a17ae 3689 }
3690
9b9df989 3691 if (ret == BGP_ATTR_PARSE_EOR) {
b6a171c7 3692 goto done;
9b9df989
DS
3693 }
3694
d62a17ae 3695 if (ret == BGP_ATTR_PARSE_ERROR) {
e50f7cfd 3696 flog_warn(EC_BGP_ATTRIBUTE_PARSE_ERROR,
559aaa30 3697 "%s: Attribute %s, parse error", peer->host,
d62a17ae 3698 lookup_msg(attr_str, type, NULL));
b6a171c7 3699 goto done;
d62a17ae 3700 }
3701 if (ret == BGP_ATTR_PARSE_WITHDRAW) {
ade6974d 3702 flog_warn(
e50f7cfd 3703 EC_BGP_ATTRIBUTE_PARSE_WITHDRAW,
d62a17ae 3704 "%s: Attribute %s, parse error - treating as withdrawal",
3705 peer->host, lookup_msg(attr_str, type, NULL));
b6a171c7 3706 goto done;
d62a17ae 3707 }
3708
3709 /* Check the fetched length. */
3710 if (BGP_INPUT_PNT(peer) != attr_endp) {
e50f7cfd 3711 flog_warn(EC_BGP_ATTRIBUTE_FETCH_ERROR,
559aaa30 3712 "%s: BGP attribute %s, fetch error",
d62a17ae 3713 peer->host, lookup_msg(attr_str, type, NULL));
3714 bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
3715 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
b6a171c7
QY
3716 ret = BGP_ATTR_PARSE_ERROR;
3717 goto done;
d62a17ae 3718 }
718e3744 3719 }
d62a17ae 3720
e5d4cda0
HS
3721 /*
3722 * draft-ietf-idr-bgp-prefix-sid-27#section-3:
3723 * About Prefix-SID path attribute,
3724 * Label-Index TLV(type1) and The Originator SRGB TLV(type-3)
3725 * may only appear in a BGP Prefix-SID attribute attached to
3726 * IPv4/IPv6 Labeled Unicast prefixes ([RFC8277]).
3727 * It MUST be ignored when received for other BGP AFI/SAFI combinations.
3728 */
3729 if (!attr->mp_nexthop_len || mp_update->safi != SAFI_LABELED_UNICAST)
3730 attr->label_index = BGP_INVALID_LABEL_INDEX;
3731
d62a17ae 3732 /* Check final read pointer is same as end pointer. */
3733 if (BGP_INPUT_PNT(peer) != endp) {
e50f7cfd 3734 flog_warn(EC_BGP_ATTRIBUTES_MISMATCH,
559aaa30 3735 "%s: BGP attribute %s, length mismatch", peer->host,
d62a17ae 3736 lookup_msg(attr_str, type, NULL));
3737 bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
3738 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
b6a171c7
QY
3739
3740 ret = BGP_ATTR_PARSE_ERROR;
3741 goto done;
d62a17ae 3742 }
3743
88f33d66 3744 /*
3745 * RFC4271: If the NEXT_HOP attribute field is syntactically incorrect,
3746 * then the Error Subcode MUST be set to Invalid NEXT_HOP Attribute.
3747 * This is implemented below and will result in a NOTIFICATION. If the
3748 * NEXT_HOP attribute is semantically incorrect, the error SHOULD be
3749 * logged, and the route SHOULD be ignored. In this case, a NOTIFICATION
3750 * message SHOULD NOT be sent. This is implemented elsewhere.
3751 *
3752 * RFC4760: An UPDATE message that carries no NLRI, other than the one
3753 * encoded in the MP_REACH_NLRI attribute, SHOULD NOT carry the NEXT_HOP
3754 * attribute. If such a message contains the NEXT_HOP attribute, the BGP
3755 * speaker that receives the message SHOULD ignore this attribute.
3756 */
3757 if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP))
3758 && !CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI))) {
9738e9aa 3759 if (bgp_attr_nexthop_valid(peer, attr) < 0) {
b6a171c7
QY
3760 ret = BGP_ATTR_PARSE_ERROR;
3761 goto done;
88f33d66 3762 }
3763 }
3764
d62a17ae 3765 /* Check all mandatory well-known attributes are present */
11dbcdd3
DA
3766 ret = bgp_attr_check(peer, attr);
3767 if (ret < 0)
b6a171c7 3768 goto done;
d62a17ae 3769
3770 /*
3771 * At this place we can see whether we got AS4_PATH and/or
3772 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
3773 * We can not do this before we've read all attributes because
3774 * the as4 handling does not say whether AS4_PATH has to be sent
3775 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
3776 * in relationship to AGGREGATOR.
3777 * So, to be defensive, we are not relying on any order and read
3778 * all attributes first, including these 32bit ones, and now,
3779 * afterwards, we look what and if something is to be done for as4.
3780 *
3781 * It is possible to not have AS_PATH, e.g. GR EoR and sole
3782 * MP_UNREACH_NLRI.
3783 */
3784 /* actually... this doesn't ever return failure currently, but
3785 * better safe than sorry */
3786 if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH))
3787 && bgp_attr_munge_as4_attrs(peer, attr, as4_path, as4_aggregator,
3788 &as4_aggregator_addr)) {
3789 bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
3790 BGP_NOTIFY_UPDATE_MAL_ATTR);
b6a171c7
QY
3791 ret = BGP_ATTR_PARSE_ERROR;
3792 goto done;
d62a17ae 3793 }
3794
d62a17ae 3795 /*
3796 * Finally do the checks on the aspath we did not do yet
3797 * because we waited for a potentially synthesized aspath.
3798 */
3799 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH))) {
3800 ret = bgp_attr_aspath_check(peer, attr);
3801 if (ret != BGP_ATTR_PARSE_PROCEED)
b6a171c7 3802 goto done;
d62a17ae 3803 }
718e3744 3804
b6a171c7 3805 ret = BGP_ATTR_PARSE_PROCEED;
b6a171c7 3806done:
5e0e9c09 3807
b6a171c7
QY
3808 /*
3809 * At this stage, we have done all fiddling with as4, and the
3810 * resulting info is in attr->aggregator resp. attr->aspath so
3811 * we can chuck as4_aggregator and as4_path alltogether in order
3812 * to save memory
3813 */
b7b3e63c
DA
3814 /*
3815 * unintern - it is in the hash
3816 * The flag that we got this is still there, but that
3817 * does not do any trouble
3818 */
3819 aspath_unintern(&as4_path);
b6a171c7 3820
04fb21e2 3821 transit = bgp_attr_get_transit(attr);
b6a171c7
QY
3822 if (ret != BGP_ATTR_PARSE_ERROR) {
3823 /* Finally intern unknown attribute. */
04fb21e2
DS
3824 if (transit)
3825 bgp_attr_set_transit(attr, transit_intern(transit));
b6a171c7
QY
3826 if (attr->encap_subtlvs)
3827 attr->encap_subtlvs = encap_intern(attr->encap_subtlvs,
3828 ENCAP_SUBTLV_TYPE);
1e20238a 3829#ifdef ENABLE_BGP_VNC
91ebf12c
DS
3830 struct bgp_attr_encap_subtlv *vnc_subtlvs =
3831 bgp_attr_get_vnc_subtlvs(attr);
3832
3833 if (vnc_subtlvs)
3834 bgp_attr_set_vnc_subtlvs(
3835 attr,
3836 encap_intern(vnc_subtlvs, VNC_SUBTLV_TYPE));
5e0e9c09
QY
3837#endif
3838 } else {
04fb21e2
DS
3839 if (transit) {
3840 transit_free(transit);
3841 bgp_attr_set_transit(attr, NULL);
5e0e9c09
QY
3842 }
3843
3844 bgp_attr_flush_encap(attr);
3845 };
3846
3847 /* Sanity checks */
04fb21e2
DS
3848 transit = bgp_attr_get_transit(attr);
3849 if (transit)
3850 assert(transit->refcnt > 0);
d62a17ae 3851 if (attr->encap_subtlvs)
5e0e9c09 3852 assert(attr->encap_subtlvs->refcnt > 0);
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 assert(vnc_subtlvs->refcnt > 0);
bede7744 3859#endif
718e3744 3860
b6a171c7 3861 return ret;
d62a17ae 3862}
3863
f4bd90c5
LK
3864/*
3865 * Extract the tunnel type from extended community
3866 */
3867void bgp_attr_extcom_tunnel_type(struct attr *attr,
fa346686 3868 bgp_encap_types *tunnel_type)
f4bd90c5
LK
3869{
3870 struct ecommunity *ecom;
f6e07e1b
DS
3871 uint32_t i;
3872
f4bd90c5 3873 if (!attr)
fa346686 3874 return;
f4bd90c5 3875
b53e67a3 3876 ecom = bgp_attr_get_ecommunity(attr);
f4bd90c5 3877 if (!ecom || !ecom->size)
fa346686 3878 return;
f4bd90c5
LK
3879
3880 for (i = 0; i < ecom->size; i++) {
3881 uint8_t *pnt;
3882 uint8_t type, sub_type;
3883
3884 pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
3885 type = pnt[0];
3886 sub_type = pnt[1];
3887 if (!(type == ECOMMUNITY_ENCODE_OPAQUE &&
3888 sub_type == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP))
3889 continue;
3890 *tunnel_type = ((pnt[6] << 8) | pnt[7]);
fa346686 3891 return;
f4bd90c5
LK
3892 }
3893
fa346686 3894 return;
f4bd90c5
LK
3895}
3896
d62a17ae 3897size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
3898 safi_t safi, struct bpacket_attr_vec_arr *vecarr,
3899 struct attr *attr)
3900{
3901 size_t sizep;
617975d1
DS
3902 iana_afi_t pkt_afi = IANA_AFI_IPV4;
3903 iana_safi_t pkt_safi = IANA_SAFI_UNICAST;
d62a17ae 3904 afi_t nh_afi;
3905
3906 /* Set extended bit always to encode the attribute length as 2 bytes */
3907 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_EXTLEN);
3908 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
3909 sizep = stream_get_endp(s);
3910 stream_putw(s, 0); /* Marker: Attribute length. */
3911
3912
3913 /* Convert AFI, SAFI to values for packet. */
3914 bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);
3915
3916 stream_putw(s, pkt_afi); /* AFI */
3917 stream_putc(s, pkt_safi); /* SAFI */
3918
3919 /* Nexthop AFI */
ce78a6fb 3920 if (afi == AFI_IP
e496b420
HS
3921 && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST
3922 || safi == SAFI_MPLS_VPN || safi == SAFI_MULTICAST))
d62a17ae 3923 nh_afi = peer_cap_enhe(peer, afi, safi) ? AFI_IP6 : AFI_IP;
211ee7aa
PG
3924 else if (safi == SAFI_FLOWSPEC)
3925 nh_afi = afi;
d62a17ae 3926 else
3927 nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len);
3928
3929 /* Nexthop */
3930 bpacket_attr_vec_arr_set_vec(vecarr, BGP_ATTR_VEC_NH, s, attr);
3931 switch (nh_afi) {
3932 case AFI_IP:
3933 switch (safi) {
3934 case SAFI_UNICAST:
3935 case SAFI_MULTICAST:
3936 case SAFI_LABELED_UNICAST:
3937 stream_putc(s, 4);
3938 stream_put_ipv4(s, attr->nexthop.s_addr);
3939 break;
3940 case SAFI_MPLS_VPN:
3941 stream_putc(s, 12);
3942 stream_putl(s, 0); /* RD = 0, per RFC */
3943 stream_putl(s, 0);
3944 stream_put(s, &attr->mp_nexthop_global_in, 4);
3945 break;
3946 case SAFI_ENCAP:
3947 case SAFI_EVPN:
3948 stream_putc(s, 4);
3949 stream_put(s, &attr->mp_nexthop_global_in, 4);
3950 break;
7c40bf39 3951 case SAFI_FLOWSPEC:
211ee7aa
PG
3952 if (attr->mp_nexthop_len == 0)
3953 stream_putc(s, 0); /* no nexthop for flowspec */
3954 else {
3955 stream_putc(s, attr->mp_nexthop_len);
3956 stream_put_ipv4(s, attr->nexthop.s_addr);
3957 }
722e8011
DS
3958 break;
3959 case SAFI_UNSPEC:
3960 case SAFI_MAX:
3961 assert(!"SAFI's UNSPEC or MAX being specified are a DEV ESCAPE");
d62a17ae 3962 break;
3963 }
3964 break;
3965 case AFI_IP6:
3966 switch (safi) {
3967 case SAFI_UNICAST:
3968 case SAFI_MULTICAST:
3969 case SAFI_LABELED_UNICAST:
3970 case SAFI_EVPN: {
3971 if (attr->mp_nexthop_len
3972 == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
3973 stream_putc(s,
3974 BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL);
3975 stream_put(s, &attr->mp_nexthop_global,
3976 IPV6_MAX_BYTELEN);
3977 stream_put(s, &attr->mp_nexthop_local,
3978 IPV6_MAX_BYTELEN);
3979 } else {
3980 stream_putc(s, IPV6_MAX_BYTELEN);
3981 stream_put(s, &attr->mp_nexthop_global,
3982 IPV6_MAX_BYTELEN);
3983 }
3984 } break;
3985 case SAFI_MPLS_VPN: {
558e8f58
PG
3986 if (attr->mp_nexthop_len ==
3987 BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL)
3988 stream_putc(s, attr->mp_nexthop_len);
3989 else
3990 stream_putc(s, BGP_ATTR_NHLEN_VPNV6_GLOBAL);
3991 stream_putl(s, 0); /* RD = 0, per RFC */
3992 stream_putl(s, 0);
3993 stream_put(s, &attr->mp_nexthop_global,
3994 IPV6_MAX_BYTELEN);
35ac9b53
PG
3995 if (attr->mp_nexthop_len ==
3996 BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
d62a17ae 3997 stream_putl(s, 0); /* RD = 0, per RFC */
3998 stream_putl(s, 0);
3999 stream_put(s, &attr->mp_nexthop_local,
4000 IPV6_MAX_BYTELEN);
4001 }
4002 } break;
4003 case SAFI_ENCAP:
4004 stream_putc(s, IPV6_MAX_BYTELEN);
4005 stream_put(s, &attr->mp_nexthop_global,
4006 IPV6_MAX_BYTELEN);
4007 break;
7c40bf39 4008 case SAFI_FLOWSPEC:
4009 stream_putc(s, 0); /* no nexthop for flowspec */
722e8011
DS
4010 break;
4011 case SAFI_UNSPEC:
4012 case SAFI_MAX:
4013 assert(!"SAFI's UNSPEC or MAX being specified are a DEV ESCAPE");
d62a17ae 4014 break;
4015 }
4016 break;
722e8011 4017 case AFI_L2VPN:
a83da8e1 4018 if (safi != SAFI_FLOWSPEC)
af4c2728 4019 flog_err(
e50f7cfd 4020 EC_BGP_ATTR_NH_SEND_LEN,
14454c9f
DS
4021 "Bad nexthop when sending to %s, AFI %u SAFI %u nhlen %d",
4022 peer->host, afi, safi, attr->mp_nexthop_len);
d62a17ae 4023 break;
722e8011
DS
4024 case AFI_UNSPEC:
4025 case AFI_MAX:
4026 assert(!"DEV ESCAPE: AFI_UNSPEC or AFI_MAX should not be used here");
4027 break;
d62a17ae 4028 }
4029
4030 /* SNPA */
4031 stream_putc(s, 0);
4032 return sizep;
4033}
4034
4035void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
5f040085
DS
4036 const struct prefix *p,
4037 const struct prefix_rd *prd, mpls_label_t *label,
be92fc9f 4038 uint32_t num_labels, bool addpath_capable,
5f040085 4039 uint32_t addpath_tx_id, struct attr *attr)
d62a17ae 4040{
233b1a38
DS
4041 switch (safi) {
4042 case SAFI_UNSPEC:
4043 case SAFI_MAX:
4044 assert(!"Dev escape usage of SAFI_UNSPEC or MAX");
4045 break;
4046 case SAFI_MPLS_VPN:
be92fc9f 4047 if (addpath_capable)
d62a17ae 4048 stream_putl(s, addpath_tx_id);
4049 /* Label, RD, Prefix write. */
4050 stream_putc(s, p->prefixlen + 88);
4051 stream_put(s, label, BGP_LABEL_BYTES);
4052 stream_put(s, prd->val, 8);
4053 stream_put(s, &p->u.prefix, PSIZE(p->prefixlen));
233b1a38
DS
4054 break;
4055 case SAFI_EVPN:
4056 if (afi == AFI_L2VPN)
4057 /* EVPN prefix - contents depend on type */
4058 bgp_evpn_encode_prefix(s, p, prd, label, num_labels,
4059 attr, addpath_capable,
4060 addpath_tx_id);
4061 else
4062 assert(!"Add encoding bits here for other AFI's");
4063 break;
4064 case SAFI_LABELED_UNICAST:
d62a17ae 4065 /* Prefix write with label. */
be92fc9f 4066 stream_put_labeled_prefix(s, p, label, addpath_capable,
ec15e1b5 4067 addpath_tx_id);
233b1a38
DS
4068 break;
4069 case SAFI_FLOWSPEC:
f1af8f04
PG
4070 stream_putc(s, p->u.prefix_flowspec.prefixlen);
4071 stream_put(s, (const void *)p->u.prefix_flowspec.ptr,
4072 p->u.prefix_flowspec.prefixlen);
233b1a38
DS
4073 break;
4074
4075 case SAFI_UNICAST:
4076 case SAFI_MULTICAST:
be92fc9f 4077 stream_put_prefix_addpath(s, p, addpath_capable, addpath_tx_id);
233b1a38
DS
4078 break;
4079 case SAFI_ENCAP:
4080 assert(!"Please add proper encoding of SAFI_ENCAP");
4081 break;
4082 }
d62a17ae 4083}
4084
5f040085
DS
4085size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi,
4086 const struct prefix *p)
d62a17ae 4087{
4088 int size = PSIZE(p->prefixlen);
4487f0bd
DS
4089
4090 switch (safi) {
4091 case SAFI_UNSPEC:
4092 case SAFI_MAX:
4093 assert(!"Attempting to figure size for a SAFI_UNSPEC/SAFI_MAX this is a DEV ESCAPE");
4094 break;
4095 case SAFI_UNICAST:
4096 case SAFI_MULTICAST:
4097 break;
4098 case SAFI_MPLS_VPN:
d62a17ae 4099 size += 88;
4487f0bd
DS
4100 break;
4101 case SAFI_ENCAP:
4102 /* This has to be wrong, but I don't know what to put here */
4103 assert(!"Do we try to use this?");
4104 break;
4105 case SAFI_LABELED_UNICAST:
4195afbf 4106 size += BGP_LABEL_BYTES;
4487f0bd
DS
4107 break;
4108 case SAFI_EVPN:
4109 /*
4110 * TODO: Maximum possible for type-2, type-3 and type-5
4111 */
4112 if (afi == AFI_L2VPN)
4113 size += 232;
4114 else
4115 assert(!"Attempting to figure size for SAFI_EVPN and !AFI_L2VPN and FRR will not have the proper values");
4116 break;
4117 case SAFI_FLOWSPEC:
0a9705a1 4118 size = ((struct prefix_fs *)p)->prefix.prefixlen;
4487f0bd
DS
4119 break;
4120 }
4121
d62a17ae 4122 return size;
8c71e481
PM
4123}
4124
f4c89855 4125/*
65efcfce 4126 * Encodes the tunnel encapsulation attribute,
d62a17ae 4127 * and with ENABLE_BGP_VNC the VNC attribute which uses
65efcfce 4128 * almost the same TLV format
f4c89855 4129 */
d62a17ae 4130static void bgp_packet_mpattr_tea(struct bgp *bgp, struct peer *peer,
4131 struct stream *s, struct attr *attr,
4132 uint8_t attrtype)
4133{
4134 unsigned int attrlenfield = 0;
4135 unsigned int attrhdrlen = 0;
4136 struct bgp_attr_encap_subtlv *subtlvs;
4137 struct bgp_attr_encap_subtlv *st;
4138 const char *attrname;
4139
9d303b37
DL
4140 if (!attr || (attrtype == BGP_ATTR_ENCAP
4141 && (!attr->encap_tunneltype
4142 || attr->encap_tunneltype == BGP_ENCAP_TYPE_MPLS)))
d62a17ae 4143 return;
4144
4145 switch (attrtype) {
f4c89855 4146 case BGP_ATTR_ENCAP:
d62a17ae 4147 attrname = "Tunnel Encap";
4148 subtlvs = attr->encap_subtlvs;
4149 if (subtlvs == NULL) /* nothing to do */
4150 return;
4151 /*
4152 * The tunnel encap attr has an "outer" tlv.
4153 * T = tunneltype,
4154 * L = total length of subtlvs,
4155 * V = concatenated subtlvs.
4156 */
4157 attrlenfield = 2 + 2; /* T + L */
4158 attrhdrlen = 1 + 1; /* subTLV T + L */
4159 break;
f4c89855 4160
1e20238a 4161#ifdef ENABLE_BGP_VNC_ATTR
65efcfce 4162 case BGP_ATTR_VNC:
d62a17ae 4163 attrname = "VNC";
91ebf12c 4164 subtlvs = bgp_attr_get_vnc_subtlvs(attr);
d62a17ae 4165 if (subtlvs == NULL) /* nothing to do */
4166 return;
4167 attrlenfield = 0; /* no outer T + L */
4168 attrhdrlen = 2 + 2; /* subTLV T + L */
4169 break;
65efcfce
LB
4170#endif
4171
f4c89855 4172 default:
d62a17ae 4173 assert(0);
4174 }
4175
4176 /* compute attr length */
4177 for (st = subtlvs; st; st = st->next) {
4178 attrlenfield += (attrhdrlen + st->length);
4179 }
4180
4181 if (attrlenfield > 0xffff) {
4182 zlog_info("%s attribute is too long (length=%d), can't send it",
4183 attrname, attrlenfield);
4184 return;
4185 }
4186
4187 if (attrlenfield > 0xff) {
4188 /* 2-octet length field */
996c9314
LB
4189 stream_putc(s,
4190 BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
4191 | BGP_ATTR_FLAG_EXTLEN);
d62a17ae 4192 stream_putc(s, attrtype);
4193 stream_putw(s, attrlenfield & 0xffff);
4194 } else {
4195 /* 1-octet length field */
4196 stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL);
4197 stream_putc(s, attrtype);
4198 stream_putc(s, attrlenfield & 0xff);
4199 }
4200
4201 if (attrtype == BGP_ATTR_ENCAP) {
4202 /* write outer T+L */
4203 stream_putw(s, attr->encap_tunneltype);
4204 stream_putw(s, attrlenfield - 4);
4205 }
4206
4207 /* write each sub-tlv */
4208 for (st = subtlvs; st; st = st->next) {
4209 if (attrtype == BGP_ATTR_ENCAP) {
4210 stream_putc(s, st->type);
4211 stream_putc(s, st->length);
1e20238a 4212#ifdef ENABLE_BGP_VNC
d62a17ae 4213 } else {
4214 stream_putw(s, st->type);
4215 stream_putw(s, st->length);
65efcfce 4216#endif
d62a17ae 4217 }
4218 stream_put(s, st->value, st->length);
4219 }
f4c89855 4220}
f4c89855 4221
d62a17ae 4222void bgp_packet_mpattr_end(struct stream *s, size_t sizep)
8c71e481 4223{
d62a17ae 4224 /* Set MP attribute length. Don't count the (2) bytes used to encode
4225 the attr length */
4226 stream_putw_at(s, sizep, (stream_get_endp(s) - sizep) - 2);
8c71e481
PM
4227}
4228
3dc339cd 4229static bool bgp_append_local_as(struct peer *peer, afi_t afi, safi_t safi)
6b5a72a3
DA
4230{
4231 if (!BGP_AS_IS_PRIVATE(peer->local_as)
4232 || (BGP_AS_IS_PRIVATE(peer->local_as)
4233 && !CHECK_FLAG(peer->af_flags[afi][safi],
4234 PEER_FLAG_REMOVE_PRIVATE_AS)
4235 && !CHECK_FLAG(peer->af_flags[afi][safi],
4236 PEER_FLAG_REMOVE_PRIVATE_AS_ALL)
4237 && !CHECK_FLAG(peer->af_flags[afi][safi],
4238 PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE)
4239 && !CHECK_FLAG(peer->af_flags[afi][safi],
4240 PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE)))
3dc339cd
DA
4241 return true;
4242 return false;
6b5a72a3
DA
4243}
4244
718e3744 4245/* Make attribute packet. */
d62a17ae 4246bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
4247 struct stream *s, struct attr *attr,
4248 struct bpacket_attr_vec_arr *vecarr,
4249 struct prefix *p, afi_t afi, safi_t safi,
4250 struct peer *from, struct prefix_rd *prd,
d7c0a89a 4251 mpls_label_t *label, uint32_t num_labels,
97a52c82
DA
4252 bool addpath_capable, uint32_t addpath_tx_id,
4253 struct bgp_path_info *bpi)
d62a17ae 4254{
4255 size_t cp;
4256 size_t aspath_sizep;
4257 struct aspath *aspath;
4258 int send_as4_path = 0;
4259 int send_as4_aggregator = 0;
8cff42ad
DA
4260 bool use32bit = CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)
4261 && CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV);
d62a17ae 4262
4263 if (!bgp)
4264 bgp = peer->bgp;
4265
4266 /* Remember current pointer. */
4267 cp = stream_get_endp(s);
4268
4269 if (p
4270 && !((afi == AFI_IP && safi == SAFI_UNICAST)
4271 && !peer_cap_enhe(peer, afi, safi))) {
4272 size_t mpattrlen_pos = 0;
4273
4274 mpattrlen_pos = bgp_packet_mpattr_start(s, peer, afi, safi,
4275 vecarr, attr);
996c9314 4276 bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label,
be92fc9f 4277 num_labels, addpath_capable,
996c9314 4278 addpath_tx_id, attr);
d62a17ae 4279 bgp_packet_mpattr_end(s, mpattrlen_pos);
718e3744 4280 }
d62a17ae 4281
4282 /* Origin attribute. */
4283 stream_putc(s, BGP_ATTR_FLAG_TRANS);
4284 stream_putc(s, BGP_ATTR_ORIGIN);
4285 stream_putc(s, 1);
4286 stream_putc(s, attr->origin);
4287
4288 /* AS path attribute. */
4289
4290 /* If remote-peer is EBGP */
4291 if (peer->sort == BGP_PEER_EBGP
4292 && (!CHECK_FLAG(peer->af_flags[afi][safi],
4293 PEER_FLAG_AS_PATH_UNCHANGED)
4294 || attr->aspath->segments == NULL)
4295 && (!CHECK_FLAG(peer->af_flags[afi][safi],
4296 PEER_FLAG_RSERVER_CLIENT))) {
4297 aspath = aspath_dup(attr->aspath);
4298
4299 /* Even though we may not be configured for confederations we
4300 * may have
4301 * RXed an AS_PATH with AS_CONFED_SEQUENCE or AS_CONFED_SET */
4302 aspath = aspath_delete_confed_seq(aspath);
4303
4304 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) {
4305 /* Stuff our path CONFED_ID on the front */
4306 aspath = aspath_add_seq(aspath, bgp->confed_id);
4307 } else {
4308 if (peer->change_local_as) {
4309 /* If replace-as is specified, we only use the
4310 change_local_as when
4311 advertising routes. */
6b5a72a3
DA
4312 if (!CHECK_FLAG(peer->flags,
4313 PEER_FLAG_LOCAL_AS_REPLACE_AS))
4314 if (bgp_append_local_as(peer, afi,
4315 safi))
4316 aspath = aspath_add_seq(
4317 aspath, peer->local_as);
d62a17ae 4318 aspath = aspath_add_seq(aspath,
4319 peer->change_local_as);
4320 } else {
4321 aspath = aspath_add_seq(aspath, peer->local_as);
4322 }
4323 }
4324 } else if (peer->sort == BGP_PEER_CONFED) {
4325 /* A confed member, so we need to do the AS_CONFED_SEQUENCE
4326 * thing */
4327 aspath = aspath_dup(attr->aspath);
4328 aspath = aspath_add_confed_seq(aspath, peer->local_as);
4329 } else
4330 aspath = attr->aspath;
4331
4332 /* If peer is not AS4 capable, then:
4333 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
4334 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path
4335 * segment
4336 * types are in it (i.e. exclude them if they are there)
4337 * AND do this only if there is at least one asnum > 65535 in the
4338 * path!
4339 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and
4340 * change
4341 * all ASnums > 65535 to BGP_AS_TRANS
4342 */
4343
4344 stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_EXTLEN);
4345 stream_putc(s, BGP_ATTR_AS_PATH);
4346 aspath_sizep = stream_get_endp(s);
4347 stream_putw(s, 0);
4348 stream_putw_at(s, aspath_sizep, aspath_put(s, aspath, use32bit));
4349
4350 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
4351 * in the path
4352 */
4353 if (!use32bit && aspath_has_as4(aspath))
4354 send_as4_path =
4355 1; /* we'll do this later, at the correct place */
4356
4357 /* Nexthop attribute. */
4358 if (afi == AFI_IP && safi == SAFI_UNICAST
4359 && !peer_cap_enhe(peer, afi, safi)) {
b96306f0
DS
4360 afi_t nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len);
4361
d62a17ae 4362 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) {
4363 stream_putc(s, BGP_ATTR_FLAG_TRANS);
4364 stream_putc(s, BGP_ATTR_NEXT_HOP);
4365 bpacket_attr_vec_arr_set_vec(vecarr, BGP_ATTR_VEC_NH, s,
4366 attr);
4367 stream_putc(s, 4);
4368 stream_put_ipv4(s, attr->nexthop.s_addr);
b96306f0
DS
4369 } else if (peer_cap_enhe(from, afi, safi)
4370 || (nh_afi == AFI_IP6)) {
d62a17ae 4371 /*
4372 * Likely this is the case when an IPv4 prefix was
b96306f0
DS
4373 * received with Extended Next-hop capability in this
4374 * or another vrf and is now being advertised to
4375 * non-ENHE peers. Since peer_cap_enhe only checks
4376 * peers in this vrf, also check the nh_afi to catch
4377 * the case where the originator was in another vrf.
d62a17ae 4378 * Setting the mandatory (ipv4) next-hop attribute here
b96306f0
DS
4379 * to enable implicit next-hop self with correct A-F
4380 * (ipv4 address family).
d62a17ae 4381 */
4382 stream_putc(s, BGP_ATTR_FLAG_TRANS);
4383 stream_putc(s, BGP_ATTR_NEXT_HOP);
4384 bpacket_attr_vec_arr_set_vec(vecarr, BGP_ATTR_VEC_NH, s,
4385 NULL);
4386 stream_putc(s, 4);
4387 stream_put_ipv4(s, 0);
4388 }
718e3744 4389 }
d62a17ae 4390
4391 /* MED attribute. */
4392 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)
4393 || bgp->maxmed_active) {
4394 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
4395 stream_putc(s, BGP_ATTR_MULTI_EXIT_DISC);
4396 stream_putc(s, 4);
4397 stream_putl(s, (bgp->maxmed_active ? bgp->maxmed_value
4398 : attr->med));
4399 }
4400
4401 /* Local preference. */
4402 if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) {
4403 stream_putc(s, BGP_ATTR_FLAG_TRANS);
4404 stream_putc(s, BGP_ATTR_LOCAL_PREF);
4405 stream_putc(s, 4);
4406 stream_putl(s, attr->local_pref);
4407 }
4408
4409 /* Atomic aggregate. */
4410 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) {
4411 stream_putc(s, BGP_ATTR_FLAG_TRANS);
4412 stream_putc(s, BGP_ATTR_ATOMIC_AGGREGATE);
4413 stream_putc(s, 0);
4414 }
4415
4416 /* Aggregator. */
4417 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)) {
4418 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
4419 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
4420 stream_putc(s, BGP_ATTR_AGGREGATOR);
4421
4422 if (use32bit) {
4423 /* AS4 capable peer */
4424 stream_putc(s, 8);
4425 stream_putl(s, attr->aggregator_as);
4426 } else {
4427 /* 2-byte AS peer */
4428 stream_putc(s, 6);
4429
4430 /* Is ASN representable in 2-bytes? Or must AS_TRANS be
4431 * used? */
48e1932b 4432 if (attr->aggregator_as > UINT16_MAX) {
d62a17ae 4433 stream_putw(s, BGP_AS_TRANS);
4434
4435 /* we have to send AS4_AGGREGATOR, too.
4436 * we'll do that later in order to send
4437 * attributes in ascending
4438 * order.
4439 */
4440 send_as4_aggregator = 1;
4441 } else
d7c0a89a 4442 stream_putw(s, (uint16_t)attr->aggregator_as);
d62a17ae 4443 }
4444 stream_put_ipv4(s, attr->aggregator_addr.s_addr);
4445 }
4446
4447 /* Community attribute. */
4448 if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
4449 && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) {
9a706b42
DA
4450 struct community *comm = NULL;
4451
4452 comm = bgp_attr_get_community(attr);
4453 if (comm->size * 4 > 255) {
996c9314
LB
4454 stream_putc(s,
4455 BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
4456 | BGP_ATTR_FLAG_EXTLEN);
d62a17ae 4457 stream_putc(s, BGP_ATTR_COMMUNITIES);
9a706b42 4458 stream_putw(s, comm->size * 4);
d62a17ae 4459 } else {
996c9314
LB
4460 stream_putc(s,
4461 BGP_ATTR_FLAG_OPTIONAL
4462 | BGP_ATTR_FLAG_TRANS);
d62a17ae 4463 stream_putc(s, BGP_ATTR_COMMUNITIES);
9a706b42 4464 stream_putc(s, comm->size * 4);
4372df71 4465 }
9a706b42 4466 stream_put(s, comm->val, comm->size * 4);
d62a17ae 4467 }
4468
4469 /*
4470 * Large Community attribute.
4471 */
4472 if (CHECK_FLAG(peer->af_flags[afi][safi],
4473 PEER_FLAG_SEND_LARGE_COMMUNITY)
4474 && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) {
1bcf3a96 4475 if (lcom_length(bgp_attr_get_lcommunity(attr)) > 255) {
996c9314
LB
4476 stream_putc(s,
4477 BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
4478 | BGP_ATTR_FLAG_EXTLEN);
d62a17ae 4479 stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
1bcf3a96
DA
4480 stream_putw(s,
4481 lcom_length(bgp_attr_get_lcommunity(attr)));
d62a17ae 4482 } else {
996c9314
LB
4483 stream_putc(s,
4484 BGP_ATTR_FLAG_OPTIONAL
4485 | BGP_ATTR_FLAG_TRANS);
d62a17ae 4486 stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
1bcf3a96
DA
4487 stream_putc(s,
4488 lcom_length(bgp_attr_get_lcommunity(attr)));
4372df71 4489 }
1bcf3a96
DA
4490 stream_put(s, bgp_attr_get_lcommunity(attr)->val,
4491 lcom_length(bgp_attr_get_lcommunity(attr)));
d62a17ae 4492 }
4372df71 4493
d62a17ae 4494 /* Route Reflector. */
4495 if (peer->sort == BGP_PEER_IBGP && from
4496 && from->sort == BGP_PEER_IBGP) {
779fee93
DS
4497 struct cluster_list *cluster = bgp_attr_get_cluster(attr);
4498
d62a17ae 4499 /* Originator ID. */
4500 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
4501 stream_putc(s, BGP_ATTR_ORIGINATOR_ID);
4502 stream_putc(s, 4);
4503
4504 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
4505 stream_put_in_addr(s, &attr->originator_id);
4506 else
4507 stream_put_in_addr(s, &from->remote_id);
4508
4509 /* Cluster list. */
4510 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
4511 stream_putc(s, BGP_ATTR_CLUSTER_LIST);
4512
779fee93
DS
4513 if (cluster) {
4514 stream_putc(s, cluster->length + 4);
d62a17ae 4515 /* If this peer configuration's parent BGP has
4516 * cluster_id. */
4517 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
4518 stream_put_in_addr(s, &bgp->cluster_id);
4519 else
4520 stream_put_in_addr(s, &bgp->router_id);
779fee93 4521 stream_put(s, cluster->list, cluster->length);
d62a17ae 4522 } else {
4523 stream_putc(s, 4);
4524 /* If this peer configuration's parent BGP has
4525 * cluster_id. */
4526 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
4527 stream_put_in_addr(s, &bgp->cluster_id);
4528 else
4529 stream_put_in_addr(s, &bgp->router_id);
4530 }
4531 }
4372df71 4532
d62a17ae 4533 /* Extended Communities attribute. */
4534 if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
4535 && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) {
b53e67a3 4536 struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr);
b17d5444
DA
4537 bool transparent = CHECK_FLAG(peer->af_flags[afi][safi],
4538 PEER_FLAG_RSERVER_CLIENT) &&
4539 from &&
4540 CHECK_FLAG(from->af_flags[afi][safi],
4541 PEER_FLAG_RSERVER_CLIENT);
4542
4543 if (peer->sort == BGP_PEER_IBGP ||
4544 peer->sort == BGP_PEER_CONFED || transparent) {
b53e67a3 4545 if (ecomm->size * 8 > 255) {
996c9314
LB
4546 stream_putc(s,
4547 BGP_ATTR_FLAG_OPTIONAL
4548 | BGP_ATTR_FLAG_TRANS
4549 | BGP_ATTR_FLAG_EXTLEN);
d62a17ae 4550 stream_putc(s, BGP_ATTR_EXT_COMMUNITIES);
b53e67a3 4551 stream_putw(s, ecomm->size * 8);
d62a17ae 4552 } else {
996c9314
LB
4553 stream_putc(s,
4554 BGP_ATTR_FLAG_OPTIONAL
4555 | BGP_ATTR_FLAG_TRANS);
d62a17ae 4556 stream_putc(s, BGP_ATTR_EXT_COMMUNITIES);
b53e67a3 4557 stream_putc(s, ecomm->size * 8);
d62a17ae 4558 }
b53e67a3 4559 stream_put(s, ecomm->val, ecomm->size * 8);
d62a17ae 4560 } else {
d7c0a89a 4561 uint8_t *pnt;
d62a17ae 4562 int tbit;
4563 int ecom_tr_size = 0;
f6e07e1b 4564 uint32_t i;
d62a17ae 4565
b53e67a3
DA
4566 for (i = 0; i < ecomm->size; i++) {
4567 pnt = ecomm->val + (i * 8);
d62a17ae 4568 tbit = *pnt;
4569
4570 if (CHECK_FLAG(tbit,
4571 ECOMMUNITY_FLAG_NON_TRANSITIVE))
4572 continue;
4573
4574 ecom_tr_size++;
4575 }
4576
4577 if (ecom_tr_size) {
4578 if (ecom_tr_size * 8 > 255) {
4579 stream_putc(
4580 s,
4581 BGP_ATTR_FLAG_OPTIONAL
4582 | BGP_ATTR_FLAG_TRANS
4583 | BGP_ATTR_FLAG_EXTLEN);
4584 stream_putc(s,
4585 BGP_ATTR_EXT_COMMUNITIES);
4586 stream_putw(s, ecom_tr_size * 8);
4587 } else {
4588 stream_putc(
4589 s,
4590 BGP_ATTR_FLAG_OPTIONAL
4591 | BGP_ATTR_FLAG_TRANS);
4592 stream_putc(s,
4593 BGP_ATTR_EXT_COMMUNITIES);
4594 stream_putc(s, ecom_tr_size * 8);
4595 }
4596
b53e67a3
DA
4597 for (i = 0; i < ecomm->size; i++) {
4598 pnt = ecomm->val + (i * 8);
d62a17ae 4599 tbit = *pnt;
4600
4601 if (CHECK_FLAG(
4602 tbit,
4603 ECOMMUNITY_FLAG_NON_TRANSITIVE))
4604 continue;
4605
4606 stream_put(s, pnt, 8);
4607 }
4608 }
4609 }
4610 }
4372df71 4611
d62a17ae 4612 /* Label index attribute. */
4613 if (safi == SAFI_LABELED_UNICAST) {
4614 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) {
d7c0a89a 4615 uint32_t label_index;
d62a17ae 4616
4617 label_index = attr->label_index;
4618
4619 if (label_index != BGP_INVALID_LABEL_INDEX) {
996c9314
LB
4620 stream_putc(s,
4621 BGP_ATTR_FLAG_OPTIONAL
4622 | BGP_ATTR_FLAG_TRANS);
d62a17ae 4623 stream_putc(s, BGP_ATTR_PREFIX_SID);
4624 stream_putc(s, 10);
4625 stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX);
4626 stream_putw(s,
4627 BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
4628 stream_putc(s, 0); // reserved
4629 stream_putw(s, 0); // flags
4630 stream_putl(s, label_index);
4631 }
4372df71 4632 }
d62a17ae 4633 }
4634
e496b420 4635 /* SRv6 Service Information Attribute. */
dbcf19b8 4636 if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_MPLS_VPN) {
e496b420 4637 if (attr->srv6_l3vpn) {
a3e3b5b0 4638 uint8_t subtlv_len =
a1a51008
RS
4639 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
4640 + BGP_ATTR_MIN_LEN
4641 + BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH;
4642 uint8_t tlv_len = subtlv_len + BGP_ATTR_MIN_LEN + 1;
4643 uint8_t attr_len = tlv_len + BGP_ATTR_MIN_LEN;
e496b420
HS
4644 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
4645 | BGP_ATTR_FLAG_TRANS);
4646 stream_putc(s, BGP_ATTR_PREFIX_SID);
a1a51008 4647 stream_putc(s, attr_len);
e496b420 4648 stream_putc(s, BGP_PREFIX_SID_SRV6_L3_SERVICE);
a1a51008 4649 stream_putw(s, tlv_len);
a3e3b5b0
RS
4650 stream_putc(s, 0); /* reserved */
4651 stream_putc(s, BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO);
a1a51008 4652 stream_putw(s, subtlv_len);
e496b420
HS
4653 stream_putc(s, 0); /* reserved */
4654 stream_put(s, &attr->srv6_l3vpn->sid,
4655 sizeof(attr->srv6_l3vpn->sid)); /* sid */
4656 stream_putc(s, 0); /* sid_flags */
05d99980
CS
4657 stream_putw(s,
4658 attr->srv6_l3vpn
4659 ->endpoint_behavior); /* endpoint */
e496b420 4660 stream_putc(s, 0); /* reserved */
a1a51008
RS
4661 stream_putc(
4662 s,
4663 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE);
4664 stream_putw(
4665 s,
4666 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH);
4667 stream_putc(s, attr->srv6_l3vpn->loc_block_len);
4668 stream_putc(s, attr->srv6_l3vpn->loc_node_len);
4669 stream_putc(s, attr->srv6_l3vpn->func_len);
4670 stream_putc(s, attr->srv6_l3vpn->arg_len);
4671 stream_putc(s, attr->srv6_l3vpn->transposition_len);
4672 stream_putc(s, attr->srv6_l3vpn->transposition_offset);
e496b420
HS
4673 } else if (attr->srv6_vpn) {
4674 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
4675 | BGP_ATTR_FLAG_TRANS);
4676 stream_putc(s, BGP_ATTR_PREFIX_SID);
4677 stream_putc(s, 22); /* tlv len */
4678 stream_putc(s, BGP_PREFIX_SID_VPN_SID);
4679 stream_putw(s, 0x13); /* tlv len */
4680 stream_putc(s, 0x00); /* reserved */
4681 stream_putc(s, 0x01); /* sid_type */
4682 stream_putc(s, 0x00); /* sif_flags */
4683 stream_put(s, &attr->srv6_vpn->sid,
4684 sizeof(attr->srv6_vpn->sid)); /* sid */
4685 }
4686 }
4687
d62a17ae 4688 if (send_as4_path) {
4689 /* If the peer is NOT As4 capable, AND */
4690 /* there are ASnums > 65535 in path THEN
4691 * give out AS4_PATH */
4692
4693 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
4694 * path segments!
4695 * Hm, I wonder... confederation things *should* only be at
4696 * the beginning of an aspath, right? Then we should use
4697 * aspath_delete_confed_seq for this, because it is already
4698 * there! (JK)
4699 * Folks, talk to me: what is reasonable here!?
4700 */
4701 aspath = aspath_delete_confed_seq(aspath);
4702
996c9314
LB
4703 stream_putc(s,
4704 BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
4705 | BGP_ATTR_FLAG_EXTLEN);
d62a17ae 4706 stream_putc(s, BGP_ATTR_AS4_PATH);
4707 aspath_sizep = stream_get_endp(s);
4708 stream_putw(s, 0);
4709 stream_putw_at(s, aspath_sizep, aspath_put(s, aspath, 1));
4710 }
4711
4712 if (aspath != attr->aspath)
4713 aspath_free(aspath);
4714
4715 if (send_as4_aggregator) {
4716 /* send AS4_AGGREGATOR, at this place */
4717 /* this section of code moved here in order to ensure the
4718 * correct
4719 * *ascending* order of attributes
4720 */
4721 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
4722 stream_putc(s, BGP_ATTR_AS4_AGGREGATOR);
4723 stream_putc(s, 8);
4724 stream_putl(s, attr->aggregator_as);
4725 stream_put_ipv4(s, attr->aggregator_addr.s_addr);
4726 }
4727
4728 if (((afi == AFI_IP || afi == AFI_IP6)
4729 && (safi == SAFI_ENCAP || safi == SAFI_MPLS_VPN))
4730 || (afi == AFI_L2VPN && safi == SAFI_EVPN)) {
4731 /* Tunnel Encap attribute */
4732 bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_ENCAP);
65efcfce 4733
1e20238a 4734#ifdef ENABLE_BGP_VNC_ATTR
d62a17ae 4735 /* VNC attribute */
4736 bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_VNC);
65efcfce 4737#endif
d62a17ae 4738 }
587ff0fd 4739
a21bd7a3
DW
4740 /* PMSI Tunnel */
4741 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)) {
4742 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
4743 stream_putc(s, BGP_ATTR_PMSI_TUNNEL);
4744 stream_putc(s, 9); // Length
4745 stream_putc(s, 0); // Flags
2a3f51cf 4746 stream_putc(s, bgp_attr_get_pmsi_tnl_type(attr));
996c9314
LB
4747 stream_put(s, &(attr->label),
4748 BGP_LABEL_BYTES); // MPLS Label / VXLAN VNI
30d85a30
LB
4749 stream_put_ipv4(s, attr->nexthop.s_addr);
4750 // Unicast tunnel endpoint IP address
a21bd7a3
DW
4751 }
4752
d864dd9e
EB
4753 /* OTC */
4754 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_OTC)) {
4755 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
4756 stream_putc(s, BGP_ATTR_OTC);
4757 stream_putc(s, 4);
4758 stream_putl(s, attr->otc);
4759 }
4760
97a52c82 4761 /* AIGP */
af9aee79 4762 if (bpi && attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP) &&
97a52c82
DA
4763 (CHECK_FLAG(peer->flags, PEER_FLAG_AIGP) ||
4764 peer->sort != BGP_PEER_EBGP)) {
4765 /* At the moment only AIGP Metric TLV exists for AIGP
4766 * attribute. If more comes in, do not forget to update
4767 * attr_len variable to include new ones.
4768 */
4769 uint8_t attr_len = BGP_AIGP_TLV_METRIC_LEN;
4770
4771 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
4772 stream_putc(s, BGP_ATTR_AIGP);
4773 stream_putc(s, attr_len);
4774 stream_put_bgp_aigp_tlv_metric(s, bpi);
4775 }
4776
d62a17ae 4777 /* Unknown transit attribute. */
04fb21e2
DS
4778 struct transit *transit = bgp_attr_get_transit(attr);
4779
4780 if (transit)
4781 stream_put(s, transit->val, transit->length);
718e3744 4782
d62a17ae 4783 /* Return total size of attribute. */
4784 return stream_get_endp(s) - cp;
718e3744 4785}
4786
d62a17ae 4787size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi)
718e3744 4788{
d62a17ae 4789 unsigned long attrlen_pnt;
617975d1
DS
4790 iana_afi_t pkt_afi = IANA_AFI_IPV4;
4791 iana_safi_t pkt_safi = IANA_SAFI_UNICAST;
718e3744 4792
d62a17ae 4793 /* Set extended bit always to encode the attribute length as 2 bytes */
4794 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_EXTLEN);
4795 stream_putc(s, BGP_ATTR_MP_UNREACH_NLRI);
718e3744 4796
d62a17ae 4797 attrlen_pnt = stream_get_endp(s);
4798 stream_putw(s, 0); /* Length of this attribute. */
718e3744 4799
d62a17ae 4800 /* Convert AFI, SAFI to values for packet. */
4801 bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);
9cabb64b 4802
d62a17ae 4803 stream_putw(s, pkt_afi);
4804 stream_putc(s, pkt_safi);
9cabb64b 4805
d62a17ae 4806 return attrlen_pnt;
8c71e481 4807}
718e3744 4808
5f040085
DS
4809void bgp_packet_mpunreach_prefix(struct stream *s, const struct prefix *p,
4810 afi_t afi, safi_t safi,
4811 const struct prefix_rd *prd,
d7c0a89a 4812 mpls_label_t *label, uint32_t num_labels,
be92fc9f 4813 bool addpath_capable, uint32_t addpath_tx_id,
b57ba6d2 4814 struct attr *attr)
8c71e481 4815{
d87c526b 4816 uint8_t wlabel[4] = {0x80, 0x00, 0x00};
cd1964ff 4817
b57ba6d2 4818 if (safi == SAFI_LABELED_UNICAST) {
d62a17ae 4819 label = (mpls_label_t *)wlabel;
b57ba6d2
MK
4820 num_labels = 1;
4821 }
cd1964ff 4822
d90b788e 4823 bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label, num_labels,
be92fc9f 4824 addpath_capable, addpath_tx_id, attr);
8c71e481 4825}
718e3744 4826
d62a17ae 4827void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt)
8c71e481 4828{
d62a17ae 4829 bgp_packet_mpattr_end(s, attrlen_pnt);
718e3744 4830}
4831
4832/* Initialization of attribute. */
d62a17ae 4833void bgp_attr_init(void)
718e3744 4834{
d62a17ae 4835 aspath_init();
4836 attrhash_init();
4837 community_init();
4838 ecommunity_init();
4839 lcommunity_init();
4840 cluster_init();
4841 transit_init();
4842 encap_init();
e496b420 4843 srv6_init();
718e3744 4844}
4845
d62a17ae 4846void bgp_attr_finish(void)
228da428 4847{
d62a17ae 4848 aspath_finish();
4849 attrhash_finish();
4850 community_finish();
4851 ecommunity_finish();
4852 lcommunity_finish();
4853 cluster_finish();
4854 transit_finish();
4855 encap_finish();
e496b420 4856 srv6_finish();
228da428
CC
4857}
4858
718e3744 4859/* Make attribute packet. */
97a52c82 4860void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
bd494ec5 4861 const struct prefix *prefix)
d62a17ae 4862{
4863 unsigned long cp;
4864 unsigned long len;
4865 size_t aspath_lenp;
4866 struct aspath *aspath;
be92fc9f 4867 bool addpath_capable = false;
d7c0a89a 4868 uint32_t addpath_tx_id = 0;
97a52c82 4869 struct attr *attr = bpi->attr;
d62a17ae 4870
4871 /* Remember current pointer. */
4872 cp = stream_get_endp(s);
4873
4874 /* Place holder of length. */
4875 stream_putw(s, 0);
4876
4877 /* Origin attribute. */
4878 stream_putc(s, BGP_ATTR_FLAG_TRANS);
4879 stream_putc(s, BGP_ATTR_ORIGIN);
4880 stream_putc(s, 1);
4881 stream_putc(s, attr->origin);
4882
4883 aspath = attr->aspath;
4884
4885 stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_EXTLEN);
4886 stream_putc(s, BGP_ATTR_AS_PATH);
4887 aspath_lenp = stream_get_endp(s);
4888 stream_putw(s, 0);
4889
4890 stream_putw_at(s, aspath_lenp, aspath_put(s, aspath, 1));
4891
4892 /* Nexthop attribute. */
4893 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
4894 if (prefix != NULL && prefix->family != AF_INET6) {
4895 stream_putc(s, BGP_ATTR_FLAG_TRANS);
4896 stream_putc(s, BGP_ATTR_NEXT_HOP);
4897 stream_putc(s, 4);
4898 stream_put_ipv4(s, attr->nexthop.s_addr);
718e3744 4899 }
d62a17ae 4900
4901 /* MED attribute. */
4902 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) {
4903 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
4904 stream_putc(s, BGP_ATTR_MULTI_EXIT_DISC);
4905 stream_putc(s, 4);
4906 stream_putl(s, attr->med);
4907 }
4908
4909 /* Local preference. */
4910 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) {
4911 stream_putc(s, BGP_ATTR_FLAG_TRANS);
4912 stream_putc(s, BGP_ATTR_LOCAL_PREF);
4913 stream_putc(s, 4);
4914 stream_putl(s, attr->local_pref);
4915 }
4916
4917 /* Atomic aggregate. */
4918 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) {
4919 stream_putc(s, BGP_ATTR_FLAG_TRANS);
4920 stream_putc(s, BGP_ATTR_ATOMIC_AGGREGATE);
4921 stream_putc(s, 0);
4922 }
4923
4924 /* Aggregator. */
4925 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)) {
4926 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
4927 stream_putc(s, BGP_ATTR_AGGREGATOR);
4928 stream_putc(s, 8);
4929 stream_putl(s, attr->aggregator_as);
4930 stream_put_ipv4(s, attr->aggregator_addr.s_addr);
4931 }
4932
4933 /* Community attribute. */
4934 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) {
9a706b42
DA
4935 struct community *comm = NULL;
4936
4937 comm = bgp_attr_get_community(attr);
4938 if (comm->size * 4 > 255) {
996c9314
LB
4939 stream_putc(s,
4940 BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
4941 | BGP_ATTR_FLAG_EXTLEN);
d62a17ae 4942 stream_putc(s, BGP_ATTR_COMMUNITIES);
9a706b42 4943 stream_putw(s, comm->size * 4);
d62a17ae 4944 } else {
996c9314
LB
4945 stream_putc(s,
4946 BGP_ATTR_FLAG_OPTIONAL
4947 | BGP_ATTR_FLAG_TRANS);
d62a17ae 4948 stream_putc(s, BGP_ATTR_COMMUNITIES);
9a706b42 4949 stream_putc(s, comm->size * 4);
d62a17ae 4950 }
9a706b42 4951 stream_put(s, comm->val, comm->size * 4);
d62a17ae 4952 }
4953
4954 /* Large Community attribute. */
4955 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) {
1bcf3a96 4956 if (lcom_length(bgp_attr_get_lcommunity(attr)) > 255) {
996c9314
LB
4957 stream_putc(s,
4958 BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
4959 | BGP_ATTR_FLAG_EXTLEN);
d62a17ae 4960 stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
1bcf3a96
DA
4961 stream_putw(s,
4962 lcom_length(bgp_attr_get_lcommunity(attr)));
d62a17ae 4963 } else {
996c9314
LB
4964 stream_putc(s,
4965 BGP_ATTR_FLAG_OPTIONAL
4966 | BGP_ATTR_FLAG_TRANS);
d62a17ae 4967 stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
1bcf3a96
DA
4968 stream_putc(s,
4969 lcom_length(bgp_attr_get_lcommunity(attr)));
d62a17ae 4970 }
4971
1bcf3a96
DA
4972 stream_put(s, bgp_attr_get_lcommunity(attr)->val,
4973 lcom_length(bgp_attr_get_lcommunity(attr)));
d62a17ae 4974 }
4975
4976 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
4977 if (prefix != NULL && prefix->family == AF_INET6
4978 && (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL
4979 || attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)) {
4980 int sizep;
4981
4982 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
4983 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
4984 sizep = stream_get_endp(s);
4985
4986 /* MP header */
4987 stream_putc(s, 0); /* Marker: Attribute length. */
4988 stream_putw(s, AFI_IP6); /* AFI */
4989 stream_putc(s, SAFI_UNICAST); /* SAFI */
4990
4991 /* Next hop */
4992 stream_putc(s, attr->mp_nexthop_len);
4993 stream_put(s, &attr->mp_nexthop_global, IPV6_MAX_BYTELEN);
4994 if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
4995 stream_put(s, &attr->mp_nexthop_local,
4996 IPV6_MAX_BYTELEN);
4997
4998 /* SNPA */
4999 stream_putc(s, 0);
5000
5001 /* Prefix */
be92fc9f 5002 stream_put_prefix_addpath(s, prefix, addpath_capable,
d62a17ae 5003 addpath_tx_id);
5004
5005 /* Set MP attribute length. */
5006 stream_putc_at(s, sizep, (stream_get_endp(s) - sizep) - 1);
5007 }
5008
5009 /* Prefix SID */
5010 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) {
5011 if (attr->label_index != BGP_INVALID_LABEL_INDEX) {
996c9314
LB
5012 stream_putc(s,
5013 BGP_ATTR_FLAG_OPTIONAL
5014 | BGP_ATTR_FLAG_TRANS);
d62a17ae 5015 stream_putc(s, BGP_ATTR_PREFIX_SID);
5016 stream_putc(s, 10);
5017 stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX);
5018 stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
5019 stream_putc(s, 0); // reserved
5020 stream_putw(s, 0); // flags
5021 stream_putl(s, attr->label_index);
5022 }
5023 }
5024
d864dd9e
EB
5025 /* OTC */
5026 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_OTC)) {
5027 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
5028 stream_putc(s, BGP_ATTR_OTC);
5029 stream_putc(s, 4);
5030 stream_putl(s, attr->otc);
5031 }
5032
97a52c82
DA
5033 /* AIGP */
5034 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP)) {
5035 /* At the moment only AIGP Metric TLV exists for AIGP
5036 * attribute. If more comes in, do not forget to update
5037 * attr_len variable to include new ones.
5038 */
5039 uint8_t attr_len = BGP_AIGP_TLV_METRIC_LEN;
5040
5041 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
5042 stream_putc(s, BGP_ATTR_AIGP);
5043 stream_putc(s, attr_len);
5044 stream_put_bgp_aigp_tlv_metric(s, bpi);
5045 }
5046
d62a17ae 5047 /* Return total size of attribute. */
5048 len = stream_get_endp(s) - cp - 2;
5049 stream_putw_at(s, cp, len);
718e3744 5050}
a5c6a9b1
DA
5051
5052void bgp_path_attribute_discard_vty(struct vty *vty, struct peer *peer,
b986d7f4 5053 const char *discard_attrs, bool set)
a5c6a9b1
DA
5054{
5055 int i, num_attributes;
5056 char **attributes;
5057 afi_t afi;
5058 safi_t safi;
5059
a5c6a9b1 5060
b986d7f4
DA
5061 /* If `no` command specified without arbitrary attributes,
5062 * then flush all.
5063 */
5064 if (!discard_attrs) {
a5c6a9b1
DA
5065 for (i = 0; i < BGP_ATTR_MAX; i++)
5066 peer->discard_attrs[i] = false;
b986d7f4
DA
5067 goto discard_soft_clear;
5068 }
5069
5070 if (discard_attrs) {
5071 frrstr_split(discard_attrs, " ", &attributes, &num_attributes);
5072
5073 if (set)
5074 for (i = 0; i < BGP_ATTR_MAX; i++)
5075 peer->discard_attrs[i] = false;
a5c6a9b1
DA
5076
5077 for (i = 0; i < num_attributes; i++) {
5078 uint8_t attr_num = strtoul(attributes[i], NULL, 10);
5079
5080 XFREE(MTYPE_TMP, attributes[i]);
5081
5082 /* Some of the attributes, just can't be ignored. */
5083 if (attr_num == BGP_ATTR_ORIGIN ||
5084 attr_num == BGP_ATTR_AS_PATH ||
5085 attr_num == BGP_ATTR_NEXT_HOP ||
5086 attr_num == BGP_ATTR_MULTI_EXIT_DISC ||
5087 attr_num == BGP_ATTR_MP_REACH_NLRI ||
5088 attr_num == BGP_ATTR_MP_UNREACH_NLRI ||
5089 attr_num == BGP_ATTR_EXT_COMMUNITIES) {
5090 vty_out(vty,
5091 "%% Can't discard path-attribute %s, ignoring.\n",
5092 lookup_msg(attr_str, attr_num, NULL));
5093 continue;
5094 }
5095
5096 /* Ignore local-pref, originator-id, cluster-list only
5097 * for eBGP.
5098 */
5099 if (peer->sort != BGP_PEER_EBGP &&
5100 (attr_num == BGP_ATTR_LOCAL_PREF ||
5101 attr_num == BGP_ATTR_ORIGINATOR_ID ||
5102 attr_num == BGP_ATTR_CLUSTER_LIST)) {
5103 vty_out(vty,
5104 "%% Can discard path-attribute %s only for eBGP, ignoring.\n",
5105 lookup_msg(attr_str, attr_num, NULL));
5106 continue;
5107 }
5108
b986d7f4 5109 peer->discard_attrs[attr_num] = set;
a5c6a9b1
DA
5110 }
5111 XFREE(MTYPE_TMP, attributes);
b986d7f4 5112 discard_soft_clear:
a5c6a9b1
DA
5113 /* Configuring path attributes to be discarded will trigger
5114 * an inbound Route Refresh to ensure that the routing table
5115 * is up to date.
5116 */
5117 FOREACH_AFI_SAFI (afi, safi)
5118 peer_clear_soft(peer, afi, safi, BGP_CLEAR_SOFT_IN);
5119 }
5120}
e2863b4f
DA
5121
5122void bgp_path_attribute_withdraw_vty(struct vty *vty, struct peer *peer,
5123 const char *withdraw_attrs, bool set)
5124{
5125 int i, num_attributes;
5126 char **attributes;
5127 afi_t afi;
5128 safi_t safi;
5129
5130 /* If `no` command specified without arbitrary attributes,
5131 * then flush all.
5132 */
5133 if (!withdraw_attrs) {
5134 for (i = 0; i < BGP_ATTR_MAX; i++)
5135 peer->withdraw_attrs[i] = false;
5136 goto withdraw_soft_clear;
5137 }
5138
5139 if (withdraw_attrs) {
5140 frrstr_split(withdraw_attrs, " ", &attributes, &num_attributes);
5141
5142 if (set)
5143 for (i = 0; i < BGP_ATTR_MAX; i++)
5144 peer->withdraw_attrs[i] = false;
5145
5146 for (i = 0; i < num_attributes; i++) {
5147 uint8_t attr_num = strtoul(attributes[i], NULL, 10);
5148
5149 XFREE(MTYPE_TMP, attributes[i]);
5150
5151 /* Some of the attributes, just can't be ignored. */
5152 if (attr_num == BGP_ATTR_ORIGIN ||
5153 attr_num == BGP_ATTR_AS_PATH ||
5154 attr_num == BGP_ATTR_NEXT_HOP ||
5155 attr_num == BGP_ATTR_MULTI_EXIT_DISC ||
5156 attr_num == BGP_ATTR_MP_REACH_NLRI ||
5157 attr_num == BGP_ATTR_MP_UNREACH_NLRI ||
5158 attr_num == BGP_ATTR_EXT_COMMUNITIES) {
5159 vty_out(vty,
5160 "%% Can't treat-as-withdraw path-attribute %s, ignoring.\n",
5161 lookup_msg(attr_str, attr_num, NULL));
5162 continue;
5163 }
5164
5165 /* Ignore local-pref, originator-id, cluster-list only
5166 * for eBGP.
5167 */
5168 if (peer->sort != BGP_PEER_EBGP &&
5169 (attr_num == BGP_ATTR_LOCAL_PREF ||
5170 attr_num == BGP_ATTR_ORIGINATOR_ID ||
5171 attr_num == BGP_ATTR_CLUSTER_LIST)) {
5172 vty_out(vty,
5173 "%% Can treat-as-withdraw path-attribute %s only for eBGP, ignoring.\n",
5174 lookup_msg(attr_str, attr_num, NULL));
5175 continue;
5176 }
5177
5178 peer->withdraw_attrs[attr_num] = set;
5179 }
5180 XFREE(MTYPE_TMP, attributes);
5181 withdraw_soft_clear:
5182 /* Configuring path attributes to be treated as withdraw will
5183 * trigger
5184 * an inbound Route Refresh to ensure that the routing table
5185 * is up to date.
5186 */
5187 FOREACH_AFI_SAFI (afi, safi)
5188 peer_clear_soft(peer, afi, safi, BGP_CLEAR_SOFT_IN);
5189 }
5190}
5191
5192enum bgp_attr_parse_ret bgp_attr_ignore(struct peer *peer, uint8_t type)
5193{
5194 bool discard = peer->discard_attrs[type];
5195 bool withdraw = peer->withdraw_attrs[type];
5196
5197 if (bgp_debug_update(peer, NULL, NULL, 1) && (discard || withdraw))
5198 zlog_debug("%pBP: Ignoring attribute %s (%s)", peer,
5199 lookup_msg(attr_str, type, NULL),
5200 withdraw ? "treat-as-withdraw" : "discard");
5201
5202 return withdraw ? BGP_ATTR_PARSE_WITHDRAW : BGP_ATTR_PARSE_PROCEED;
5203}