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