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