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