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