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