]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_attr.c
lib/zebra: remove code duplication in redist_del_instance()
[mirror_frr.git] / bgpd / bgp_attr.c
CommitLineData
718e3744 1/* BGP attributes management routines.
2 Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
20
21#include <zebra.h>
22
23#include "linklist.h"
24#include "prefix.h"
25#include "memory.h"
26#include "vector.h"
27#include "vty.h"
28#include "stream.h"
29#include "log.h"
30#include "hash.h"
c8e7b895 31#include "jhash.h"
3f9c7369 32#include "queue.h"
f4c89855 33#include "table.h"
039f3a34 34#include "filter.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"
42#include "bgpd/bgp_packet.h"
43#include "bgpd/bgp_ecommunity.h"
3f9c7369 44#include "bgpd/bgp_updgrp.h"
6407da5a 45#include "bgpd/bgp_encap_types.h"
65efcfce 46#if ENABLE_BGP_VNC
f8b6f499 47# include "bgpd/rfapi/bgp_rfapi_cfg.h"
65efcfce
LB
48# include "bgp_encap_types.h"
49# include "bgp_vnc_types.h"
50#endif
6b0655a2 51
718e3744 52/* Attribute strings for logging. */
9bddac4b 53static const struct message attr_str [] =
718e3744 54{
55 { BGP_ATTR_ORIGIN, "ORIGIN" },
56 { BGP_ATTR_AS_PATH, "AS_PATH" },
57 { BGP_ATTR_NEXT_HOP, "NEXT_HOP" },
58 { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
59 { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" },
60 { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
61 { BGP_ATTR_AGGREGATOR, "AGGREGATOR" },
62 { BGP_ATTR_COMMUNITIES, "COMMUNITY" },
63 { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" },
f8627ff1 64 { BGP_ATTR_CLUSTER_LIST, "CLUSTER_LIST" },
718e3744 65 { BGP_ATTR_DPA, "DPA" },
66 { BGP_ATTR_ADVERTISER, "ADVERTISER"} ,
67 { BGP_ATTR_RCID_PATH, "RCID_PATH" },
68 { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
69 { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
0b2aa3a0
PJ
70 { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" },
71 { BGP_ATTR_AS4_PATH, "AS4_PATH" },
72 { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" },
73 { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" },
f4c89855 74 { BGP_ATTR_ENCAP, "ENCAP" },
65efcfce
LB
75#if ENABLE_BGP_VNC
76 { BGP_ATTR_VNC, "VNC" },
77#endif
718e3744 78};
837d16cc 79static const int attr_str_max = array_size(attr_str);
afcb7679
DO
80
81static const struct message attr_flag_str[] =
82{
83 { BGP_ATTR_FLAG_OPTIONAL, "Optional" },
84 { BGP_ATTR_FLAG_TRANS, "Transitive" },
85 { BGP_ATTR_FLAG_PARTIAL, "Partial" },
86 /* bgp_attr_flags_diagnose() relies on this bit being last in this list */
87 { BGP_ATTR_FLAG_EXTLEN, "Extended Length" },
88};
6b0655a2 89
9bddac4b 90static struct hash *cluster_hash;
718e3744 91
94f2b392 92static void *
923de654 93cluster_hash_alloc (void *p)
718e3744 94{
ffd0c037 95 const struct cluster_list *val = (const struct cluster_list *) p;
718e3744 96 struct cluster_list *cluster;
97
98 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
99 cluster->length = val->length;
100
101 if (cluster->length)
102 {
103 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
104 memcpy (cluster->list, val->list, val->length);
105 }
106 else
107 cluster->list = NULL;
108
109 cluster->refcnt = 0;
110
111 return cluster;
112}
113
114/* Cluster list related functions. */
94f2b392 115static struct cluster_list *
5228ad27 116cluster_parse (struct in_addr * pnt, int length)
718e3744 117{
118 struct cluster_list tmp;
119 struct cluster_list *cluster;
120
121 tmp.length = length;
5228ad27 122 tmp.list = pnt;
718e3744 123
124 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
125 cluster->refcnt++;
126 return cluster;
127}
128
129int
130cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
131{
132 int i;
133
134 for (i = 0; i < cluster->length / 4; i++)
135 if (cluster->list[i].s_addr == originator.s_addr)
136 return 1;
137 return 0;
138}
139
94f2b392 140static unsigned int
923de654 141cluster_hash_key_make (void *p)
718e3744 142{
c8e7b895 143 const struct cluster_list *cluster = p;
718e3744 144
c8e7b895 145 return jhash(cluster->list, cluster->length, 0);
718e3744 146}
147
94f2b392 148static int
ffe11cfb 149cluster_hash_cmp (const void *p1, const void *p2)
718e3744 150{
ffe11cfb
SH
151 const struct cluster_list * cluster1 = p1;
152 const struct cluster_list * cluster2 = p2;
923de654 153
ffe11cfb
SH
154 return (cluster1->length == cluster2->length &&
155 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
718e3744 156}
157
94f2b392 158static void
718e3744 159cluster_free (struct cluster_list *cluster)
160{
161 if (cluster->list)
162 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
163 XFREE (MTYPE_CLUSTER, cluster);
164}
165
94f2b392 166static struct cluster_list *
718e3744 167cluster_dup (struct cluster_list *cluster)
168{
169 struct cluster_list *new;
170
393deb9b 171 new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
718e3744 172 new->length = cluster->length;
173
174 if (cluster->length)
175 {
176 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
177 memcpy (new->list, cluster->list, cluster->length);
178 }
179 else
180 new->list = NULL;
181
182 return new;
183}
184
94f2b392 185static struct cluster_list *
718e3744 186cluster_intern (struct cluster_list *cluster)
187{
188 struct cluster_list *find;
189
190 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
191 find->refcnt++;
192
193 return find;
194}
195
196void
197cluster_unintern (struct cluster_list *cluster)
198{
718e3744 199 if (cluster->refcnt)
200 cluster->refcnt--;
201
202 if (cluster->refcnt == 0)
203 {
9206f9ec 204 hash_release (cluster_hash, cluster);
718e3744 205 cluster_free (cluster);
206 }
207}
208
94f2b392 209static void
210cluster_init (void)
718e3744 211{
212 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
213}
228da428
CC
214
215static void
216cluster_finish (void)
217{
218 hash_free (cluster_hash);
219 cluster_hash = NULL;
220}
6b0655a2 221
f4c89855
LB
222struct bgp_attr_encap_subtlv *
223encap_tlv_dup(struct bgp_attr_encap_subtlv *orig)
224{
225 struct bgp_attr_encap_subtlv *new;
226 struct bgp_attr_encap_subtlv *tail;
227 struct bgp_attr_encap_subtlv *p;
228
229 for (p = orig, tail = new = NULL; p; p = p->next) {
230 int size = sizeof(struct bgp_attr_encap_subtlv) - 1 + p->length;
231 if (tail) {
232 tail->next = XCALLOC(MTYPE_ENCAP_TLV, size);
233 tail = tail->next;
234 } else {
235 tail = new = XCALLOC(MTYPE_ENCAP_TLV, size);
236 }
237 assert(tail);
238 memcpy(tail, p, size);
239 tail->next = NULL;
240 }
241
242 return new;
243}
244
245static void
246encap_free(struct bgp_attr_encap_subtlv *p)
247{
248 struct bgp_attr_encap_subtlv *next;
249 while (p) {
250 next = p->next;
251 p->next = NULL;
252 XFREE(MTYPE_ENCAP_TLV, p);
253 p = next;
254 }
255}
256
257void
258bgp_attr_flush_encap(struct attr *attr)
259{
260 if (!attr || !attr->extra)
261 return;
262
263 if (attr->extra->encap_subtlvs) {
264 encap_free(attr->extra->encap_subtlvs);
265 attr->extra->encap_subtlvs = NULL;
266 }
65efcfce
LB
267#if ENABLE_BGP_VNC
268 if (attr->extra->vnc_subtlvs) {
269 encap_free(attr->extra->vnc_subtlvs);
270 attr->extra->vnc_subtlvs = NULL;
271 }
272#endif
f4c89855
LB
273}
274
275/*
276 * Compare encap sub-tlv chains
277 *
278 * 1 = equivalent
279 * 0 = not equivalent
280 *
281 * This algorithm could be made faster if needed
282 */
283static int
284encap_same(struct bgp_attr_encap_subtlv *h1, struct bgp_attr_encap_subtlv *h2)
285{
286 struct bgp_attr_encap_subtlv *p;
287 struct bgp_attr_encap_subtlv *q;
288
289 if (!h1 && !h2)
290 return 1;
291 if (h1 && !h2)
292 return 0;
293 if (!h1 && h2)
294 return 0;
295 if (h1 == h2)
296 return 1;
297
298 for (p = h1; p; p = p->next) {
299 for (q = h2; q; q = q->next) {
300 if ((p->type == q->type) &&
301 (p->length == q->length) &&
302 !memcmp(p->value, q->value, p->length)) {
303
304 break;
305 }
306 }
307 if (!q)
308 return 0;
309 }
310
311 for (p = h2; p; p = p->next) {
312 for (q = h1; q; q = q->next) {
313 if ((p->type == q->type) &&
314 (p->length == q->length) &&
315 !memcmp(p->value, q->value, p->length)) {
316
317 break;
318 }
319 }
320 if (!q)
321 return 0;
322 }
323
324 return 1;
325}
326
718e3744 327/* Unknown transit attribute. */
9bddac4b 328static struct hash *transit_hash;
718e3744 329
94f2b392 330static void
718e3744 331transit_free (struct transit *transit)
332{
333 if (transit->val)
334 XFREE (MTYPE_TRANSIT_VAL, transit->val);
335 XFREE (MTYPE_TRANSIT, transit);
336}
337
73ac8160
DS
338static struct transit *
339transit_dup (struct transit *transit)
340{
341 struct transit *new;
342
343 new = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
344 new->length = transit->length;
345 if (new->length)
346 {
347 new->val = XMALLOC (MTYPE_TRANSIT_VAL, transit->length);
348 memcpy (new->val, transit->val, transit->length);
349 }
350 else
351 new->val = NULL;
352
353 return new;
354}
923de654 355
94f2b392 356static void *
923de654 357transit_hash_alloc (void *p)
718e3744 358{
359 /* Transit structure is already allocated. */
923de654 360 return p;
718e3744 361}
362
94f2b392 363static struct transit *
718e3744 364transit_intern (struct transit *transit)
365{
366 struct transit *find;
367
368 find = hash_get (transit_hash, transit, transit_hash_alloc);
369 if (find != transit)
370 transit_free (transit);
371 find->refcnt++;
372
373 return find;
374}
375
376void
377transit_unintern (struct transit *transit)
378{
718e3744 379 if (transit->refcnt)
380 transit->refcnt--;
381
382 if (transit->refcnt == 0)
383 {
9206f9ec 384 hash_release (transit_hash, transit);
718e3744 385 transit_free (transit);
386 }
387}
388
94f2b392 389static unsigned int
923de654 390transit_hash_key_make (void *p)
718e3744 391{
c8e7b895 392 const struct transit * transit = p;
718e3744 393
c8e7b895 394 return jhash(transit->val, transit->length, 0);
718e3744 395}
396
94f2b392 397static int
ffe11cfb 398transit_hash_cmp (const void *p1, const void *p2)
718e3744 399{
ffe11cfb
SH
400 const struct transit * transit1 = p1;
401 const struct transit * transit2 = p2;
923de654 402
ffe11cfb
SH
403 return (transit1->length == transit2->length &&
404 memcmp (transit1->val, transit2->val, transit1->length) == 0);
718e3744 405}
406
94f2b392 407static void
66e5cd87 408transit_init (void)
718e3744 409{
410 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
411}
228da428
CC
412
413static void
414transit_finish (void)
415{
416 hash_free (transit_hash);
417 transit_hash = NULL;
418}
6b0655a2 419
718e3744 420/* Attribute hash routines. */
9bddac4b 421static struct hash *attrhash;
718e3744 422
fb982c25
PJ
423static struct attr_extra *
424bgp_attr_extra_new (void)
425{
426 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
427}
428
429void
430bgp_attr_extra_free (struct attr *attr)
431{
432 if (attr->extra)
433 {
f4c89855
LB
434 if (attr->extra->encap_subtlvs) {
435 encap_free(attr->extra->encap_subtlvs);
436 attr->extra->encap_subtlvs = NULL;
437 }
65efcfce
LB
438#if ENABLE_BGP_VNC
439 if (attr->extra->vnc_subtlvs) {
440 encap_free(attr->extra->vnc_subtlvs);
441 attr->extra->vnc_subtlvs = NULL;
442 }
443#endif
fb982c25
PJ
444 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
445 attr->extra = NULL;
446 }
447}
448
449struct attr_extra *
450bgp_attr_extra_get (struct attr *attr)
451{
452 if (!attr->extra)
453 attr->extra = bgp_attr_extra_new();
454 return attr->extra;
455}
456
457/* Shallow copy of an attribute
458 * Though, not so shallow that it doesn't copy the contents
459 * of the attr_extra pointed to by 'extra'
460 */
461void
462bgp_attr_dup (struct attr *new, struct attr *orig)
463{
558d1fec
JBD
464 struct attr_extra *extra = new->extra;
465
fb982c25 466 *new = *orig;
a0de1d16
CF
467 /* if caller provided attr_extra space, use it in any case.
468 *
469 * This is neccesary even if orig->extra equals NULL, because otherwise
470 * memory may be later allocated on the heap by bgp_attr_extra_get.
471 *
472 * That memory would eventually be leaked, because the caller must not
473 * call bgp_attr_extra_free if he provided attr_extra on the stack.
474 */
475 if (extra)
476 {
477 new->extra = extra;
478 memset(new->extra, 0, sizeof(struct attr_extra));
f4c89855 479 if (orig->extra) {
a0de1d16 480 *new->extra = *orig->extra;
f4c89855
LB
481 if (orig->extra->encap_subtlvs) {
482 new->extra->encap_subtlvs = encap_tlv_dup(orig->extra->encap_subtlvs);
483 }
65efcfce
LB
484#if ENABLE_BGP_VNC
485 if (orig->extra->vnc_subtlvs) {
486 new->extra->vnc_subtlvs = encap_tlv_dup(orig->extra->vnc_subtlvs);
487 }
488#endif
f4c89855 489 }
a0de1d16
CF
490 }
491 else if (orig->extra)
fb982c25 492 {
a0de1d16 493 new->extra = bgp_attr_extra_new();
fb982c25 494 *new->extra = *orig->extra;
f4c89855
LB
495 if (orig->extra->encap_subtlvs) {
496 new->extra->encap_subtlvs = encap_tlv_dup(orig->extra->encap_subtlvs);
497 }
65efcfce
LB
498#if ENABLE_BGP_VNC
499 if (orig->extra->vnc_subtlvs) {
500 new->extra->vnc_subtlvs = encap_tlv_dup(orig->extra->vnc_subtlvs);
501 }
502#endif
fb982c25
PJ
503 }
504}
505
73ac8160
DS
506void
507bgp_attr_deep_dup (struct attr *new, struct attr *orig)
508{
509 if (orig->aspath)
510 new->aspath = aspath_dup(orig->aspath);
511
512 if (orig->community)
513 new->community = community_dup(orig->community);
514
515 if (orig->extra)
516 {
517 if (orig->extra->ecommunity)
518 new->extra->ecommunity = ecommunity_dup(orig->extra->ecommunity);
519 if (orig->extra->cluster)
520 new->extra->cluster = cluster_dup(orig->extra->cluster);
521 if (orig->extra->transit)
522 new->extra->transit = transit_dup(orig->extra->transit);
523 }
524}
525
526void
527bgp_attr_deep_free (struct attr *attr)
528{
529 if (attr->aspath)
530 aspath_free(attr->aspath);
531
532 if (attr->community)
533 community_free(attr->community);
534
535 if (attr->extra)
536 {
537 if (attr->extra->ecommunity)
538 ecommunity_free(&attr->extra->ecommunity);
539 if (attr->extra->cluster)
540 cluster_free(attr->extra->cluster);
541 if (attr->extra->transit)
542 transit_free(attr->extra->transit);
543 }
544}
545
cbdfbaa5
PJ
546unsigned long int
547attr_count (void)
548{
549 return attrhash->count;
550}
551
552unsigned long int
553attr_unknown_count (void)
554{
555 return transit_hash->count;
556}
557
718e3744 558unsigned int
923de654 559attrhash_key_make (void *p)
718e3744 560{
7fb0cd82
JBD
561 const struct attr *attr = (struct attr *) p;
562 const struct attr_extra *extra = attr->extra;
c8e7b895
SH
563 uint32_t key = 0;
564#define MIX(val) key = jhash_1word(val, key)
565
566 MIX(attr->origin);
567 MIX(attr->nexthop.s_addr);
568 MIX(attr->med);
569 MIX(attr->local_pref);
718e3744 570
c8f3fe30
PJ
571 key += attr->origin;
572 key += attr->nexthop.s_addr;
573 key += attr->med;
574 key += attr->local_pref;
fb982c25 575
7fb0cd82 576 if (extra)
fb982c25 577 {
7fb0cd82
JBD
578 MIX(extra->aggregator_as);
579 MIX(extra->aggregator_addr.s_addr);
580 MIX(extra->weight);
581 MIX(extra->mp_nexthop_global_in.s_addr);
689bb66c 582 MIX(extra->originator_id.s_addr);
0d9551dc 583 MIX(extra->tag);
fb982c25
PJ
584 }
585
718e3744 586 if (attr->aspath)
c8e7b895 587 MIX(aspath_key_make (attr->aspath));
718e3744 588 if (attr->community)
c8e7b895 589 MIX(community_hash_make (attr->community));
fb982c25 590
7fb0cd82 591 if (extra)
fb982c25 592 {
7fb0cd82
JBD
593 if (extra->ecommunity)
594 MIX(ecommunity_hash_make (extra->ecommunity));
595 if (extra->cluster)
596 MIX(cluster_hash_key_make (extra->cluster));
597 if (extra->transit)
598 MIX(transit_hash_key_make (extra->transit));
718e3744 599
600#ifdef HAVE_IPV6
7fb0cd82 601 MIX(extra->mp_nexthop_len);
801a9bcc
DS
602 key = jhash(extra->mp_nexthop_global.s6_addr, IPV6_MAX_BYTELEN, key);
603 key = jhash(extra->mp_nexthop_local.s6_addr, IPV6_MAX_BYTELEN, key);
718e3744 604#endif /* HAVE_IPV6 */
fb982c25 605 }
718e3744 606
607 return key;
608}
609
610int
ffe11cfb 611attrhash_cmp (const void *p1, const void *p2)
718e3744 612{
ffe11cfb
SH
613 const struct attr * attr1 = p1;
614 const struct attr * attr2 = p2;
923de654 615
718e3744 616 if (attr1->flag == attr2->flag
617 && attr1->origin == attr2->origin
618 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
fb982c25
PJ
619 && attr1->aspath == attr2->aspath
620 && attr1->community == attr2->community
718e3744 621 && attr1->med == attr2->med
3f9c7369
DS
622 && attr1->local_pref == attr2->local_pref
623 && attr1->rmap_change_flags == attr2->rmap_change_flags)
fb982c25 624 {
ffe11cfb
SH
625 const struct attr_extra *ae1 = attr1->extra;
626 const struct attr_extra *ae2 = attr2->extra;
fb982c25
PJ
627
628 if (ae1 && ae2
629 && ae1->aggregator_as == ae2->aggregator_as
630 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
631 && ae1->weight == ae2->weight
0d9551dc 632 && ae1->tag == ae2->tag
718e3744 633#ifdef HAVE_IPV6
fb982c25
PJ
634 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
635 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
636 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
718e3744 637#endif /* HAVE_IPV6 */
fb982c25
PJ
638 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
639 && ae1->ecommunity == ae2->ecommunity
640 && ae1->cluster == ae2->cluster
689bb66c 641 && ae1->transit == ae2->transit
f4c89855
LB
642 && (ae1->encap_tunneltype == ae2->encap_tunneltype)
643 && encap_same(ae1->encap_subtlvs, ae2->encap_subtlvs)
65efcfce
LB
644#if ENABLE_BGP_VNC
645 && encap_same(ae1->vnc_subtlvs, ae2->vnc_subtlvs)
646#endif
689bb66c 647 && IPV4_ADDR_SAME (&ae1->originator_id, &ae2->originator_id))
fb982c25
PJ
648 return 1;
649 else if (ae1 || ae2)
650 return 0;
651 /* neither attribute has extra attributes, so they're same */
652 return 1;
653 }
718e3744 654 else
655 return 0;
656}
657
94f2b392 658static void
ffe11cfb 659attrhash_init (void)
718e3744 660{
661 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
662}
663
228da428
CC
664static void
665attrhash_finish (void)
666{
667 hash_free (attrhash);
668 attrhash = NULL;
669}
670
94f2b392 671static void
718e3744 672attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
673{
674 struct attr *attr = backet->data;
675
676 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
677 inet_ntoa (attr->nexthop), VTY_NEWLINE);
678}
679
680void
681attr_show_all (struct vty *vty)
682{
683 hash_iterate (attrhash,
684 (void (*)(struct hash_backet *, void *))
685 attr_show_all_iterator,
686 vty);
687}
688
94f2b392 689static void *
923de654 690bgp_attr_hash_alloc (void *p)
718e3744 691{
ffd0c037 692 const struct attr * val = (const struct attr *) p;
718e3744 693 struct attr *attr;
694
695 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
696 *attr = *val;
fb982c25
PJ
697 if (val->extra)
698 {
699 attr->extra = bgp_attr_extra_new ();
700 *attr->extra = *val->extra;
f4c89855
LB
701
702 if (attr->extra->encap_subtlvs) {
703 attr->extra->encap_subtlvs = encap_tlv_dup(attr->extra->encap_subtlvs);
704 }
65efcfce
LB
705#if ENABLE_BGP_VNC
706 if (attr->extra->vnc_subtlvs) {
707 attr->extra->vnc_subtlvs = encap_tlv_dup(attr->extra->vnc_subtlvs);
708 }
709#endif
fb982c25 710 }
718e3744 711 attr->refcnt = 0;
712 return attr;
713}
714
715/* Internet argument attribute. */
716struct attr *
717bgp_attr_intern (struct attr *attr)
718{
719 struct attr *find;
720
721 /* Intern referenced strucutre. */
722 if (attr->aspath)
723 {
724 if (! attr->aspath->refcnt)
725 attr->aspath = aspath_intern (attr->aspath);
726 else
727 attr->aspath->refcnt++;
728 }
729 if (attr->community)
730 {
731 if (! attr->community->refcnt)
732 attr->community = community_intern (attr->community);
733 else
734 attr->community->refcnt++;
735 }
fb982c25 736 if (attr->extra)
718e3744 737 {
fb982c25
PJ
738 struct attr_extra *attre = attr->extra;
739
740 if (attre->ecommunity)
741 {
742 if (! attre->ecommunity->refcnt)
743 attre->ecommunity = ecommunity_intern (attre->ecommunity);
744 else
745 attre->ecommunity->refcnt++;
f6f434b2 746
fb982c25
PJ
747 }
748 if (attre->cluster)
749 {
750 if (! attre->cluster->refcnt)
751 attre->cluster = cluster_intern (attre->cluster);
752 else
753 attre->cluster->refcnt++;
754 }
755 if (attre->transit)
756 {
757 if (! attre->transit->refcnt)
758 attre->transit = transit_intern (attre->transit);
759 else
760 attre->transit->refcnt++;
761 }
718e3744 762 }
f6f434b2 763
718e3744 764 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
765 find->refcnt++;
f6f434b2 766
718e3744 767 return find;
768}
769
3f9c7369
DS
770/**
771 * Increment the refcount on various structures that attr holds.
772 * Note on usage: call _only_ when the 'attr' object has already
773 * been 'intern'ed and exists in 'attrhash' table. The function
774 * serves to hold a reference to that (real) object.
775 * Note also that the caller can safely call bgp_attr_unintern()
776 * after calling bgp_attr_refcount(). That would release the
777 * reference and could result in a free() of the attr object.
778 */
779struct attr *
780bgp_attr_refcount (struct attr *attr)
781{
782 /* Intern referenced strucutre. */
783 if (attr->aspath)
784 attr->aspath->refcnt++;
785
786 if (attr->community)
787 attr->community->refcnt++;
788
789 if (attr->extra)
790 {
791 struct attr_extra *attre = attr->extra;
792 if (attre->ecommunity)
793 attre->ecommunity->refcnt++;
794
795 if (attre->cluster)
796 attre->cluster->refcnt++;
797
798 if (attre->transit)
799 attre->transit->refcnt++;
800 }
801 attr->refcnt++;
802 return attr;
803}
03e214c8 804
718e3744 805/* Make network statement's attribute. */
806struct attr *
807bgp_attr_default_set (struct attr *attr, u_char origin)
808{
809 memset (attr, 0, sizeof (struct attr));
fb982c25
PJ
810 bgp_attr_extra_get (attr);
811
718e3744 812 attr->origin = origin;
813 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
814 attr->aspath = aspath_empty ();
815 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
fb982c25 816 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
0d9551dc 817 attr->extra->tag = 0;
718e3744 818 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
819#ifdef HAVE_IPV6
fb982c25 820 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
718e3744 821#endif
03e214c8 822
718e3744 823 return attr;
824}
825
03e214c8 826
718e3744 827/* Make network statement's attribute. */
828struct attr *
829bgp_attr_default_intern (u_char origin)
830{
831 struct attr attr;
832 struct attr *new;
e16a4133 833
f4c89855
LB
834 memset (&attr, 0, sizeof (struct attr));
835 bgp_attr_extra_get (&attr);
836
03e214c8 837 bgp_attr_default_set(&attr, origin);
718e3744 838
839 new = bgp_attr_intern (&attr);
fb982c25
PJ
840 bgp_attr_extra_free (&attr);
841
f6f434b2 842 aspath_unintern (&new->aspath);
718e3744 843 return new;
844}
845
b5d58c32 846/* Create the attributes for an aggregate */
718e3744 847struct attr *
848bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
849 struct aspath *aspath,
42f7e184
DS
850 struct community *community, int as_set,
851 u_char atomic_aggregate)
718e3744 852{
853 struct attr attr;
854 struct attr *new;
938ef3a2 855 struct attr_extra attre;
718e3744 856
857 memset (&attr, 0, sizeof (struct attr));
938ef3a2
JBD
858 memset (&attre, 0, sizeof (struct attr_extra));
859 attr.extra = &attre;
860
718e3744 861 /* Origin attribute. */
862 attr.origin = origin;
863 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
864
865 /* AS path attribute. */
866 if (aspath)
867 attr.aspath = aspath_intern (aspath);
868 else
869 attr.aspath = aspath_empty ();
870 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
871
872 /* Next hop attribute. */
873 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
874
875 if (community)
876 {
877 attr.community = community;
878 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
879 }
880
938ef3a2 881 attre.weight = BGP_ATTR_DEFAULT_WEIGHT;
718e3744 882#ifdef HAVE_IPV6
938ef3a2 883 attre.mp_nexthop_len = IPV6_MAX_BYTELEN;
718e3744 884#endif
42f7e184 885 if (! as_set || atomic_aggregate)
718e3744 886 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
887 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
888 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
938ef3a2 889 attre.aggregator_as = bgp->confed_id;
718e3744 890 else
938ef3a2
JBD
891 attre.aggregator_as = bgp->as;
892 attre.aggregator_addr = bgp->router_id;
718e3744 893
894 new = bgp_attr_intern (&attr);
938ef3a2 895
f6f434b2 896 aspath_unintern (&new->aspath);
718e3744 897 return new;
898}
899
b881c707
PJ
900/* Unintern just the sub-components of the attr, but not the attr */
901void
902bgp_attr_unintern_sub (struct attr *attr)
903{
904 /* aspath refcount shoud be decrement. */
905 if (attr->aspath)
906 aspath_unintern (&attr->aspath);
d92a2f39 907 UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH));
b881c707
PJ
908
909 if (attr->community)
910 community_unintern (&attr->community);
d92a2f39 911 UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES));
b881c707
PJ
912
913 if (attr->extra)
914 {
915 if (attr->extra->ecommunity)
916 ecommunity_unintern (&attr->extra->ecommunity);
d92a2f39 917 UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES));
b881c707
PJ
918
919 if (attr->extra->cluster)
920 cluster_unintern (attr->extra->cluster);
d92a2f39 921 UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST));
b881c707
PJ
922
923 if (attr->extra->transit)
924 transit_unintern (attr->extra->transit);
925 }
926}
927
718e3744 928/* Free bgp attribute and aspath. */
929void
1a2fd707 930bgp_attr_unintern (struct attr **pattr)
718e3744 931{
1a2fd707 932 struct attr *attr = *pattr;
718e3744 933 struct attr *ret;
b881c707 934 struct attr tmp;
b9f1dca1 935 struct attr_extra tmp_extra;
f6f434b2 936
718e3744 937 /* Decrement attribute reference. */
1a2fd707 938 attr->refcnt--;
b881c707 939
1a2fd707 940 tmp = *attr;
b881c707 941
1a2fd707 942 if (attr->extra)
fb982c25 943 {
b9f1dca1 944 tmp.extra = &tmp_extra;
1a2fd707 945 memcpy (tmp.extra, attr->extra, sizeof (struct attr_extra));
fb982c25 946 }
f6f434b2 947
718e3744 948 /* If reference becomes zero then free attribute object. */
1a2fd707
JBD
949 if (attr->refcnt == 0)
950 {
951 ret = hash_release (attrhash, attr);
718e3744 952 assert (ret != NULL);
1a2fd707
JBD
953 bgp_attr_extra_free (attr);
954 XFREE (MTYPE_ATTR, attr);
955 *pattr = NULL;
718e3744 956 }
957
b881c707 958 bgp_attr_unintern_sub (&tmp);
718e3744 959}
960
961void
962bgp_attr_flush (struct attr *attr)
963{
964 if (attr->aspath && ! attr->aspath->refcnt)
f9a3a260
LB
965 {
966 aspath_free (attr->aspath);
967 attr->aspath = NULL;
968 }
718e3744 969 if (attr->community && ! attr->community->refcnt)
f9a3a260
LB
970 {
971 community_free (attr->community);
972 attr->community = NULL;
973 }
fb982c25
PJ
974 if (attr->extra)
975 {
976 struct attr_extra *attre = attr->extra;
f6f434b2 977
fb982c25 978 if (attre->ecommunity && ! attre->ecommunity->refcnt)
f6f434b2 979 ecommunity_free (&attre->ecommunity);
fb982c25 980 if (attre->cluster && ! attre->cluster->refcnt)
f9a3a260
LB
981 {
982 cluster_free (attre->cluster);
983 attre->cluster = NULL;
984 }
fb982c25 985 if (attre->transit && ! attre->transit->refcnt)
f9a3a260
LB
986 {
987 transit_free (attre->transit);
988 attre->transit = NULL;
989 }
f4c89855
LB
990 encap_free(attre->encap_subtlvs);
991 attre->encap_subtlvs = NULL;
65efcfce
LB
992#if ENABLE_BGP_VNC
993 encap_free(attre->vnc_subtlvs);
994 attre->vnc_subtlvs = NULL;
995#endif
fb982c25 996 }
718e3744 997}
998
b881c707
PJ
999/* Implement draft-scudder-idr-optional-transitive behaviour and
1000 * avoid resetting sessions for malformed attributes which are
1001 * are partial/optional and hence where the error likely was not
1002 * introduced by the sending neighbour.
1003 */
1004static bgp_attr_parse_ret_t
835315bf
PJ
1005bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode,
1006 bgp_size_t length)
b881c707 1007{
835315bf
PJ
1008 struct peer *const peer = args->peer;
1009 const u_int8_t flags = args->flags;
1010 /* startp and length must be special-cased, as whether or not to
1011 * send the attribute data with the NOTIFY depends on the error,
1012 * the caller therefore signals this with the seperate length argument
1013 */
bd471fea 1014 u_char *notify_datap = (length > 0 ? args->startp : NULL);
835315bf 1015
b881c707 1016 /* Only relax error handling for eBGP peers */
6d85b15b 1017 if (peer->sort != BGP_PEER_EBGP)
b881c707
PJ
1018 {
1019 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
bd471fea 1020 notify_datap, length);
b881c707
PJ
1021 return BGP_ATTR_PARSE_ERROR;
1022
1023 }
1024
bd471fea
PJ
1025 /* Adjust the stream getp to the end of the attribute, in case we can
1026 * still proceed but the caller hasn't read all the attribute.
1027 */
1028 stream_set_getp (BGP_INPUT (peer),
1029 (args->startp - STREAM_DATA (BGP_INPUT (peer)))
1030 + args->total);
1031
835315bf 1032 switch (args->type) {
fa61e16d
PJ
1033 /* where an attribute is relatively inconsequential, e.g. it does not
1034 * affect route selection, and can be safely ignored, then any such
1035 * attributes which are malformed should just be ignored and the route
1036 * processed as normal.
b881c707
PJ
1037 */
1038 case BGP_ATTR_AS4_AGGREGATOR:
1039 case BGP_ATTR_AGGREGATOR:
1040 case BGP_ATTR_ATOMIC_AGGREGATE:
1041 return BGP_ATTR_PARSE_PROCEED;
1042
1043 /* Core attributes, particularly ones which may influence route
fa61e16d 1044 * selection, should always cause session resets
b881c707
PJ
1045 */
1046 case BGP_ATTR_ORIGIN:
1047 case BGP_ATTR_AS_PATH:
1048 case BGP_ATTR_NEXT_HOP:
1049 case BGP_ATTR_MULTI_EXIT_DISC:
1050 case BGP_ATTR_LOCAL_PREF:
1051 case BGP_ATTR_COMMUNITIES:
1052 case BGP_ATTR_ORIGINATOR_ID:
1053 case BGP_ATTR_CLUSTER_LIST:
1054 case BGP_ATTR_MP_REACH_NLRI:
1055 case BGP_ATTR_MP_UNREACH_NLRI:
1056 case BGP_ATTR_EXT_COMMUNITIES:
1057 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
bd471fea 1058 notify_datap, length);
b881c707
PJ
1059 return BGP_ATTR_PARSE_ERROR;
1060 }
1061
1062 /* Partial optional attributes that are malformed should not cause
1063 * the whole session to be reset. Instead treat it as a withdrawal
1064 * of the routes, if possible.
1065 */
835315bf
PJ
1066 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)
1067 && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
1068 && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
b881c707
PJ
1069 return BGP_ATTR_PARSE_WITHDRAW;
1070
1071 /* default to reset */
f57000c0 1072 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
b881c707
PJ
1073}
1074
afcb7679
DO
1075/* Find out what is wrong with the path attribute flag bits and log the error.
1076 "Flag bits" here stand for Optional, Transitive and Partial, but not for
1077 Extended Length. Checking O/T/P bits at once implies, that the attribute
1078 being diagnosed is defined by RFC as either a "well-known" or an "optional,
1079 non-transitive" attribute. */
1080static void
835315bf
PJ
1081bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args,
1082 u_int8_t desired_flags /* how RFC says it must be */
afcb7679
DO
1083)
1084{
1085 u_char seen = 0, i;
835315bf
PJ
1086 u_char real_flags = args->flags;
1087 const u_int8_t attr_code = args->type;
1088
afcb7679
DO
1089 desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
1090 real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
1091 for (i = 0; i <= 2; i++) /* O,T,P, but not E */
1092 if
1093 (
1094 CHECK_FLAG (desired_flags, attr_flag_str[i].key) !=
1095 CHECK_FLAG (real_flags, attr_flag_str[i].key)
1096 )
1097 {
16286195
DS
1098 zlog_err ("%s attribute must%s be flagged as \"%s\"",
1099 LOOKUP (attr_str, attr_code),
1100 CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
1101 attr_flag_str[i].str);
afcb7679
DO
1102 seen = 1;
1103 }
fa5831e8
PJ
1104 if (!seen)
1105 {
16286195
DS
1106 zlog_debug ("Strange, %s called for attr %s, but no problem found with flags"
1107 " (real flags 0x%x, desired 0x%x)",
1108 __func__, LOOKUP (attr_str, attr_code),
1109 real_flags, desired_flags);
fa5831e8 1110 }
afcb7679
DO
1111}
1112
3ecab4c8
PJ
1113/* Required flags for attributes. EXTLEN will be masked off when testing,
1114 * as will PARTIAL for optional+transitive attributes.
1115 */
1116const u_int8_t attr_flags_values [] = {
1117 [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS,
1118 [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS,
1119 [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS,
1120 [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL,
1121 [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS,
1122 [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
1123 [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
1124 [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
1125 [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL,
1126 [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL,
1127 [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
1128 [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
1129 [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
1130 [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
1131 [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
1132};
1133static const size_t attr_flags_values_max =
1134 sizeof (attr_flags_values) / sizeof (attr_flags_values[0]);
1135
1136static int
835315bf 1137bgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
3ecab4c8
PJ
1138{
1139 u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
835315bf
PJ
1140 const u_int8_t flags = args->flags;
1141 const u_int8_t attr_code = args->type;
3ecab4c8
PJ
1142
1143 /* there may be attributes we don't know about */
1144 if (attr_code > attr_flags_values_max)
1145 return 0;
1146 if (attr_flags_values[attr_code] == 0)
1147 return 0;
1148
1149 /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
1150 * 1."
1151 */
1152 if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags)
1153 && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags))
1154 {
16286195
DS
1155 zlog_err ("%s well-known attributes must have transitive flag set (%x)",
1156 LOOKUP (attr_str, attr_code), flags);
3ecab4c8
PJ
1157 return 1;
1158 }
1159
1160 /* "For well-known attributes and for optional non-transitive attributes,
1161 * the Partial bit MUST be set to 0."
1162 */
1163 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
1164 {
1165 if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL))
1166 {
16286195
DS
1167 zlog_err ("%s well-known attribute "
1168 "must NOT have the partial flag set (%x)",
1169 LOOKUP (attr_str, attr_code), flags);
3ecab4c8
PJ
1170 return 1;
1171 }
1172 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
1173 && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
1174 {
16286195
DS
1175 zlog_err ("%s optional + transitive attribute "
1176 "must NOT have the partial flag set (%x)",
1177 LOOKUP (attr_str, attr_code), flags);
3ecab4c8
PJ
1178 return 1;
1179 }
1180 }
1181
1182 /* Optional transitive attributes may go through speakers that don't
1183 * reocgnise them and set the Partial bit.
1184 */
1185 if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
1186 && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
1187 SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL);
1188
683f2b86 1189 if ((flags & ~mask)
3ecab4c8
PJ
1190 == attr_flags_values[attr_code])
1191 return 0;
1192
835315bf 1193 bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]);
3ecab4c8
PJ
1194 return 1;
1195}
1196
718e3744 1197/* Get origin attribute of the update message. */
b881c707 1198static bgp_attr_parse_ret_t
835315bf 1199bgp_attr_origin (struct bgp_attr_parser_args *args)
718e3744 1200{
835315bf
PJ
1201 struct peer *const peer = args->peer;
1202 struct attr *const attr = args->attr;
1203 const bgp_size_t length = args->length;
1204
718e3744 1205 /* If any recognized attribute has Attribute Length that conflicts
1206 with the expected length (based on the attribute type code), then
1207 the Error Subcode is set to Attribute Length Error. The Data
1208 field contains the erroneous attribute (type, length and
1209 value). */
1210 if (length != 1)
1211 {
16286195 1212 zlog_err ("Origin attribute length is not one %d", length);
835315bf 1213 return bgp_attr_malformed (args,
b881c707 1214 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
835315bf 1215 args->total);
718e3744 1216 }
1217
1218 /* Fetch origin attribute. */
1219 attr->origin = stream_getc (BGP_INPUT (peer));
1220
1221 /* If the ORIGIN attribute has an undefined value, then the Error
1222 Subcode is set to Invalid Origin Attribute. The Data field
1223 contains the unrecognized attribute (type, length and value). */
1224 if ((attr->origin != BGP_ORIGIN_IGP)
1225 && (attr->origin != BGP_ORIGIN_EGP)
1226 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
1227 {
16286195 1228 zlog_err ("Origin attribute value is invalid %d", attr->origin);
835315bf 1229 return bgp_attr_malformed (args,
b881c707 1230 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
835315bf 1231 args->total);
718e3744 1232 }
1233
1234 /* Set oring attribute flag. */
1235 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
1236
1237 return 0;
1238}
ab005298
PJ
1239
1240/* Parse AS path information. This function is wrapper of
1241 aspath_parse. */
1242static int
835315bf 1243bgp_attr_aspath (struct bgp_attr_parser_args *args)
718e3744 1244{
835315bf
PJ
1245 struct attr *const attr = args->attr;
1246 struct peer *const peer = args->peer;
1247 const bgp_size_t length = args->length;
3ecab4c8 1248
ab005298
PJ
1249 /*
1250 * peer with AS4 => will get 4Byte ASnums
1251 * otherwise, will get 16 Bit
0b2aa3a0 1252 */
ab005298
PJ
1253 attr->aspath = aspath_parse (peer->ibuf, length,
1254 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
0b2aa3a0 1255
ab005298
PJ
1256 /* In case of IBGP, length will be zero. */
1257 if (! attr->aspath)
cddb8112 1258 {
16286195 1259 zlog_err ("Malformed AS path from %s, length is %d", peer->host, length);
835315bf 1260 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0);
cddb8112 1261 }
cddb8112 1262
ab005298
PJ
1263 /* Set aspath attribute flag. */
1264 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
0b2aa3a0 1265
b881c707 1266 return BGP_ATTR_PARSE_PROCEED;
0b2aa3a0
PJ
1267}
1268
b881c707 1269static bgp_attr_parse_ret_t
835315bf 1270bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)
0b2aa3a0
PJ
1271{
1272 /* These checks were part of bgp_attr_aspath, but with
1273 * as4 we should to check aspath things when
1274 * aspath synthesizing with as4_path has already taken place.
1275 * Otherwise we check ASPATH and use the synthesized thing, and that is
1276 * not right.
1277 * So do the checks later, i.e. here
1278 */
1279 struct bgp *bgp = peer->bgp;
1280 struct aspath *aspath;
1281
ca87e1d3 1282 /* Confederation sanity check. */
6d85b15b
JBD
1283 if ((peer->sort == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
1284 (peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
ca87e1d3 1285 {
16286195 1286 zlog_err ("Malformed AS path from %s", peer->host);
835315bf
PJ
1287 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1288 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1289 return BGP_ATTR_PARSE_ERROR;
ca87e1d3
VT
1290 }
1291
718e3744 1292 /* First AS check for EBGP. */
1293 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
1294 {
6d85b15b 1295 if (peer->sort == BGP_PEER_EBGP
718e3744 1296 && ! aspath_firstas_check (attr->aspath, peer->as))
1297 {
16286195 1298 zlog_err ("%s incorrect first AS (must be %u)", peer->host, peer->as);
835315bf
PJ
1299 bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
1300 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
1301 return BGP_ATTR_PARSE_ERROR;
718e3744 1302 }
1303 }
1304
1305 /* local-as prepend */
1306 if (peer->change_local_as &&
1307 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
1308 {
1309 aspath = aspath_dup (attr->aspath);
1310 aspath = aspath_add_seq (aspath, peer->change_local_as);
f6f434b2 1311 aspath_unintern (&attr->aspath);
718e3744 1312 attr->aspath = aspath_intern (aspath);
1313 }
1314
b881c707 1315 return BGP_ATTR_PARSE_PROCEED;
0b2aa3a0
PJ
1316}
1317
ab005298
PJ
1318/* Parse AS4 path information. This function is another wrapper of
1319 aspath_parse. */
1320static int
835315bf 1321bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path)
ab005298 1322{
835315bf
PJ
1323 struct peer *const peer = args->peer;
1324 struct attr *const attr = args->attr;
1325 const bgp_size_t length = args->length;
3ecab4c8 1326
ab005298
PJ
1327 *as4_path = aspath_parse (peer->ibuf, length, 1);
1328
b881c707
PJ
1329 /* In case of IBGP, length will be zero. */
1330 if (!*as4_path)
1331 {
16286195 1332 zlog_err ("Malformed AS4 path from %s, length is %d", peer->host, length);
835315bf 1333 return bgp_attr_malformed (args,
b881c707 1334 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
835315bf 1335 0);
b881c707
PJ
1336 }
1337
ab005298
PJ
1338 /* Set aspath attribute flag. */
1339 if (as4_path)
1340 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
1341
b881c707 1342 return BGP_ATTR_PARSE_PROCEED;
0b2aa3a0
PJ
1343}
1344
718e3744 1345/* Nexthop attribute. */
b881c707 1346static bgp_attr_parse_ret_t
835315bf 1347bgp_attr_nexthop (struct bgp_attr_parser_args *args)
718e3744 1348{
835315bf
PJ
1349 struct peer *const peer = args->peer;
1350 struct attr *const attr = args->attr;
1351 const bgp_size_t length = args->length;
1352
bc3443eb 1353 in_addr_t nexthop_h, nexthop_n;
718e3744 1354
718e3744 1355 /* Check nexthop attribute length. */
1356 if (length != 4)
1357 {
16286195 1358 zlog_err ("Nexthop attribute length isn't four [%d]", length);
718e3744 1359
835315bf 1360 return bgp_attr_malformed (args,
b881c707 1361 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
835315bf 1362 args->total);
718e3744 1363 }
1364
58298ccd
DS
1365 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1366 attribute must result in a NOTIFICATION message (this is implemented below).
1367 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1368 logged locally (this is implemented somewhere else). The UPDATE message
1369 gets ignored in any of these cases. */
bc3443eb
DO
1370 nexthop_n = stream_get_ipv4 (peer->ibuf);
1371 nexthop_h = ntohl (nexthop_n);
cebb7440
LB
1372 if ((IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
1373 && !BGP_DEBUG (allow_martians, ALLOW_MARTIANS)) /* loopbacks may be used in testing */
bc3443eb
DO
1374 {
1375 char buf[INET_ADDRSTRLEN];
bb02b823 1376 inet_ntop (AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN);
16286195 1377 zlog_err ("Martian nexthop %s", buf);
835315bf 1378 return bgp_attr_malformed (args,
bc3443eb 1379 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
835315bf 1380 args->total);
bc3443eb
DO
1381 }
1382
1383 attr->nexthop.s_addr = nexthop_n;
718e3744 1384 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1385
b881c707 1386 return BGP_ATTR_PARSE_PROCEED;
718e3744 1387}
1388
1389/* MED atrribute. */
b881c707 1390static bgp_attr_parse_ret_t
835315bf 1391bgp_attr_med (struct bgp_attr_parser_args *args)
718e3744 1392{
835315bf
PJ
1393 struct peer *const peer = args->peer;
1394 struct attr *const attr = args->attr;
1395 const bgp_size_t length = args->length;
1396
718e3744 1397 /* Length check. */
1398 if (length != 4)
1399 {
16286195 1400 zlog_err ("MED attribute length isn't four [%d]", length);
b881c707 1401
835315bf 1402 return bgp_attr_malformed (args,
b881c707 1403 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
835315bf 1404 args->total);
718e3744 1405 }
1406
1407 attr->med = stream_getl (peer->ibuf);
1408
1409 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1410
b881c707 1411 return BGP_ATTR_PARSE_PROCEED;
718e3744 1412}
1413
1414/* Local preference attribute. */
b881c707 1415static bgp_attr_parse_ret_t
835315bf 1416bgp_attr_local_pref (struct bgp_attr_parser_args *args)
718e3744 1417{
835315bf
PJ
1418 struct peer *const peer = args->peer;
1419 struct attr *const attr = args->attr;
1420 const bgp_size_t length = args->length;
3ecab4c8 1421
a624cae2
DO
1422 /* Length check. */
1423 if (length != 4)
1424 {
16286195 1425 zlog_err ("LOCAL_PREF attribute length isn't 4 [%u]", length);
835315bf 1426 return bgp_attr_malformed (args,
a624cae2 1427 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
835315bf 1428 args->total);
a624cae2 1429 }
0ea968d2 1430
718e3744 1431 /* If it is contained in an UPDATE message that is received from an
1432 external peer, then this attribute MUST be ignored by the
1433 receiving speaker. */
6d85b15b 1434 if (peer->sort == BGP_PEER_EBGP)
718e3744 1435 {
9985f83c 1436 stream_forward_getp (peer->ibuf, length);
b881c707 1437 return BGP_ATTR_PARSE_PROCEED;
718e3744 1438 }
1439
a624cae2 1440 attr->local_pref = stream_getl (peer->ibuf);
718e3744 1441
1442 /* Set atomic aggregate flag. */
1443 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1444
b881c707 1445 return BGP_ATTR_PARSE_PROCEED;
718e3744 1446}
1447
1448/* Atomic aggregate. */
94f2b392 1449static int
835315bf 1450bgp_attr_atomic (struct bgp_attr_parser_args *args)
718e3744 1451{
835315bf
PJ
1452 struct attr *const attr = args->attr;
1453 const bgp_size_t length = args->length;
3ecab4c8 1454
9eba2ada 1455 /* Length check. */
718e3744 1456 if (length != 0)
1457 {
16286195 1458 zlog_err ("ATOMIC_AGGREGATE attribute length isn't 0 [%u]", length);
835315bf 1459 return bgp_attr_malformed (args,
b881c707 1460 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
835315bf 1461 args->total);
718e3744 1462 }
1463
1464 /* Set atomic aggregate flag. */
1465 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1466
b881c707 1467 return BGP_ATTR_PARSE_PROCEED;
718e3744 1468}
1469
1470/* Aggregator attribute */
94f2b392 1471static int
835315bf 1472bgp_attr_aggregator (struct bgp_attr_parser_args *args)
718e3744 1473{
835315bf
PJ
1474 struct peer *const peer = args->peer;
1475 struct attr *const attr = args->attr;
1476 const bgp_size_t length = args->length;
1477
0b2aa3a0 1478 int wantedlen = 6;
fb982c25 1479 struct attr_extra *attre = bgp_attr_extra_get (attr);
3ecab4c8 1480
0b2aa3a0 1481 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
b881c707 1482 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
0b2aa3a0
PJ
1483 wantedlen = 8;
1484
1485 if (length != wantedlen)
718e3744 1486 {
16286195 1487 zlog_err ("AGGREGATOR attribute length isn't %u [%u]", wantedlen, length);
835315bf 1488 return bgp_attr_malformed (args,
b881c707 1489 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
835315bf 1490 args->total);
718e3744 1491 }
0b2aa3a0
PJ
1492
1493 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1494 attre->aggregator_as = stream_getl (peer->ibuf);
1495 else
1496 attre->aggregator_as = stream_getw (peer->ibuf);
fb982c25 1497 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
718e3744 1498
1499 /* Set atomic aggregate flag. */
1500 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1501
b881c707 1502 return BGP_ATTR_PARSE_PROCEED;
718e3744 1503}
1504
0b2aa3a0 1505/* New Aggregator attribute */
b881c707 1506static bgp_attr_parse_ret_t
835315bf
PJ
1507bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args,
1508 as_t *as4_aggregator_as,
1509 struct in_addr *as4_aggregator_addr)
0b2aa3a0 1510{
835315bf
PJ
1511 struct peer *const peer = args->peer;
1512 struct attr *const attr = args->attr;
1513 const bgp_size_t length = args->length;
1514
0b2aa3a0
PJ
1515 if (length != 8)
1516 {
16286195 1517 zlog_err ("New Aggregator length is not 8 [%d]", length);
835315bf 1518 return bgp_attr_malformed (args,
b881c707 1519 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
835315bf 1520 0);
0b2aa3a0 1521 }
3ecab4c8 1522
0b2aa3a0
PJ
1523 *as4_aggregator_as = stream_getl (peer->ibuf);
1524 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1525
1526 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1527
b881c707 1528 return BGP_ATTR_PARSE_PROCEED;
0b2aa3a0
PJ
1529}
1530
1531/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1532 */
b881c707 1533static bgp_attr_parse_ret_t
835315bf
PJ
1534bgp_attr_munge_as4_attrs (struct peer *const peer,
1535 struct attr *const attr,
0b2aa3a0
PJ
1536 struct aspath *as4_path, as_t as4_aggregator,
1537 struct in_addr *as4_aggregator_addr)
1538{
1539 int ignore_as4_path = 0;
1540 struct aspath *newpath;
1541 struct attr_extra *attre = attr->extra;
bb7bef14
PJ
1542
1543 if (!attr->aspath)
1544 {
1545 /* NULL aspath shouldn't be possible as bgp_attr_parse should have
1546 * checked that all well-known, mandatory attributes were present.
1547 *
1548 * Can only be a problem with peer itself - hard error
1549 */
1550 return BGP_ATTR_PARSE_ERROR;
1551 }
1552
b881c707 1553 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
0b2aa3a0
PJ
1554 {
1555 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1556 * if given.
1557 * It is worth a warning though, because the peer really
1558 * should not send them
1559 */
1560 if (BGP_DEBUG(as4, AS4))
1561 {
1562 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1563 zlog_debug ("[AS4] %s %s AS4_PATH",
1564 peer->host, "AS4 capable peer, yet it sent");
1565
1566 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1567 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1568 peer->host, "AS4 capable peer, yet it sent");
1569 }
1570
b881c707 1571 return BGP_ATTR_PARSE_PROCEED;
0b2aa3a0
PJ
1572 }
1573
0b2aa3a0
PJ
1574 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1575 * because that may override AS4_PATH
1576 */
1577 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1578 {
b881c707 1579 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
0b2aa3a0 1580 {
370b64a2
PJ
1581 assert (attre);
1582
0b2aa3a0
PJ
1583 /* received both.
1584 * if the as_number in aggregator is not AS_TRANS,
1585 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1586 * and the Aggregator shall be taken as
1587 * info on the aggregating node, and the AS_PATH
1588 * shall be taken as the AS_PATH
1589 * otherwise
1590 * the Aggregator shall be ignored and the
1591 * AS4_AGGREGATOR shall be taken as the
1592 * Aggregating node and the AS_PATH is to be
1593 * constructed "as in all other cases"
1594 */
b881c707 1595 if (attre->aggregator_as != BGP_AS_TRANS)
0b2aa3a0
PJ
1596 {
1597 /* ignore */
1598 if ( BGP_DEBUG(as4, AS4))
1599 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1600 " send AGGREGATOR != AS_TRANS and"
1601 " AS4_AGGREGATOR, so ignore"
1602 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1603 ignore_as4_path = 1;
1604 }
1605 else
1606 {
1607 /* "New_aggregator shall be taken as aggregator" */
1608 attre->aggregator_as = as4_aggregator;
1609 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1610 }
1611 }
1612 else
1613 {
1614 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1615 * That is bogus - but reading the conditions
1616 * we have to handle AS4_AGGREGATOR as if it were
1617 * AGGREGATOR in that case
1618 */
1619 if ( BGP_DEBUG(as4, AS4))
1620 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1621 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1622 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
370b64a2 1623 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
0b2aa3a0
PJ
1624 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1625 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1626 }
1627 }
1628
1629 /* need to reconcile NEW_AS_PATH and AS_PATH */
b881c707 1630 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
0b2aa3a0 1631 {
bb7bef14
PJ
1632 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1633 aspath_unintern (&attr->aspath);
1634 attr->aspath = aspath_intern (newpath);
0b2aa3a0 1635 }
b881c707 1636 return BGP_ATTR_PARSE_PROCEED;
0b2aa3a0
PJ
1637}
1638
718e3744 1639/* Community attribute. */
b881c707 1640static bgp_attr_parse_ret_t
835315bf 1641bgp_attr_community (struct bgp_attr_parser_args *args)
718e3744 1642{
835315bf
PJ
1643 struct peer *const peer = args->peer;
1644 struct attr *const attr = args->attr;
1645 const bgp_size_t length = args->length;
b881c707 1646
718e3744 1647 if (length == 0)
b2ceea18
PJ
1648 {
1649 attr->community = NULL;
b881c707 1650 return BGP_ATTR_PARSE_PROCEED;
b2ceea18 1651 }
0c466381
PJ
1652
1653 attr->community =
1654 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1655
1656 /* XXX: fix community_parse to use stream API and remove this */
1657 stream_forward_getp (peer->ibuf, length);
718e3744 1658
0c466381 1659 if (!attr->community)
835315bf 1660 return bgp_attr_malformed (args,
b881c707 1661 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
835315bf 1662 args->total);
0c466381 1663
718e3744 1664 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1665
b881c707 1666 return BGP_ATTR_PARSE_PROCEED;
718e3744 1667}
1668
1669/* Originator ID attribute. */
b881c707 1670static bgp_attr_parse_ret_t
835315bf 1671bgp_attr_originator_id (struct bgp_attr_parser_args *args)
718e3744 1672{
835315bf
PJ
1673 struct peer *const peer = args->peer;
1674 struct attr *const attr = args->attr;
1675 const bgp_size_t length = args->length;
1676
d595b566 1677 /* Length check. */
718e3744 1678 if (length != 4)
1679 {
16286195 1680 zlog_err ("Bad originator ID length %d", length);
718e3744 1681
835315bf 1682 return bgp_attr_malformed (args,
b881c707 1683 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
835315bf 1684 args->total);
718e3744 1685 }
1686
fb982c25
PJ
1687 (bgp_attr_extra_get (attr))->originator_id.s_addr
1688 = stream_get_ipv4 (peer->ibuf);
718e3744 1689
1690 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1691
b881c707 1692 return BGP_ATTR_PARSE_PROCEED;
718e3744 1693}
1694
1695/* Cluster list attribute. */
b881c707 1696static bgp_attr_parse_ret_t
835315bf 1697bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
718e3744 1698{
835315bf
PJ
1699 struct peer *const peer = args->peer;
1700 struct attr *const attr = args->attr;
1701 const bgp_size_t length = args->length;
1702
718e3744 1703 /* Check length. */
1704 if (length % 4)
1705 {
16286195 1706 zlog_err ("Bad cluster list length %d", length);
718e3744 1707
835315bf
PJ
1708 return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1709 args->total);
718e3744 1710 }
1711
fb982c25
PJ
1712 (bgp_attr_extra_get (attr))->cluster
1713 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
b881c707
PJ
1714
1715 /* XXX: Fix cluster_parse to use stream API and then remove this */
1716 stream_forward_getp (peer->ibuf, length);
718e3744 1717
1718 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1719
b881c707 1720 return BGP_ATTR_PARSE_PROCEED;
718e3744 1721}
1722
1723/* Multiprotocol reachability information parse. */
03292809 1724int
835315bf
PJ
1725bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
1726 struct bgp_nlri *mp_update)
718e3744 1727{
4c9641ba
ML
1728 afi_t afi;
1729 safi_t safi;
718e3744 1730 bgp_size_t nlri_len;
6e4ab12f 1731 size_t start;
718e3744 1732 int ret;
d889623f 1733 int num_mp_pfx = 0;
718e3744 1734 struct stream *s;
835315bf
PJ
1735 struct peer *const peer = args->peer;
1736 struct attr *const attr = args->attr;
1737 const bgp_size_t length = args->length;
fb982c25 1738 struct attr_extra *attre = bgp_attr_extra_get(attr);
835315bf 1739
718e3744 1740 /* Set end of packet. */
6e4ab12f
PJ
1741 s = BGP_INPUT(peer);
1742 start = stream_get_getp(s);
1743
1744 /* safe to read statically sized header? */
1745#define BGP_MP_REACH_MIN_SIZE 5
03292809 1746#define LEN_LEFT (length - (stream_get_getp(s) - start))
6e4ab12f 1747 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
03292809
PJ
1748 {
1749 zlog_info ("%s: %s sent invalid length, %lu",
1750 __func__, peer->host, (unsigned long)length);
f57000c0 1751 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
03292809 1752 }
6e4ab12f 1753
718e3744 1754 /* Load AFI, SAFI. */
1755 afi = stream_getw (s);
1756 safi = stream_getc (s);
1757
1758 /* Get nexthop length. */
fb982c25 1759 attre->mp_nexthop_len = stream_getc (s);
6e4ab12f 1760
03292809
PJ
1761 if (LEN_LEFT < attre->mp_nexthop_len)
1762 {
1763 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1764 __func__, peer->host, attre->mp_nexthop_len);
f57000c0 1765 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
03292809 1766 }
6e4ab12f 1767
718e3744 1768 /* Nexthop length check. */
fb982c25 1769 switch (attre->mp_nexthop_len)
718e3744 1770 {
801a9bcc
DS
1771 case BGP_ATTR_NHLEN_IPV4:
1772 stream_get (&attre->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN);
66bed4f4
ML
1773 /* Probably needed for RFC 2283 */
1774 if (attr->nexthop.s_addr == 0)
801a9bcc 1775 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, IPV4_MAX_BYTELEN);
718e3744 1776 break;
801a9bcc 1777 case BGP_ATTR_NHLEN_VPNV4:
9206f9ec
SH
1778 stream_getl (s); /* RD high */
1779 stream_getl (s); /* RD low */
801a9bcc 1780 stream_get (&attre->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN);
718e3744 1781 break;
1782#ifdef HAVE_IPV6
801a9bcc 1783 case BGP_ATTR_NHLEN_IPV6_GLOBAL:
945c8fe9
LB
1784 case BGP_ATTR_NHLEN_VPNV6_GLOBAL:
1785 if (attre->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL)
1786 {
1787 stream_getl (s); /* RD high */
1788 stream_getl (s); /* RD low */
1789 }
801a9bcc 1790 stream_get (&attre->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
718e3744 1791 break;
801a9bcc 1792 case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
945c8fe9
LB
1793 case BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL:
1794 if (attre->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL)
1795 {
1796 stream_getl (s); /* RD high */
1797 stream_getl (s); /* RD low */
1798 }
801a9bcc 1799 stream_get (&attre->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
945c8fe9
LB
1800 if (attre->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL)
1801 {
1802 stream_getl (s); /* RD high */
1803 stream_getl (s); /* RD low */
1804 }
801a9bcc 1805 stream_get (&attre->mp_nexthop_local, s, IPV6_MAX_BYTELEN);
fb982c25 1806 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
718e3744 1807 {
1808 char buf1[INET6_ADDRSTRLEN];
1809 char buf2[INET6_ADDRSTRLEN];
1810
3f9c7369 1811 if (bgp_debug_update(peer, NULL, NULL, 1))
3dd32081
DS
1812 zlog_debug ("%s rcvd nexthops %s, %s -- ignoring non-LL value",
1813 peer->host,
fb982c25 1814 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
718e3744 1815 buf1, INET6_ADDRSTRLEN),
fb982c25 1816 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
718e3744 1817 buf2, INET6_ADDRSTRLEN));
1818
801a9bcc 1819 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
718e3744 1820 }
1821 break;
1822#endif /* HAVE_IPV6 */
1823 default:
03292809
PJ
1824 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1825 __func__, peer->host, attre->mp_nexthop_len);
f57000c0 1826 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
718e3744 1827 }
1828
03292809
PJ
1829 if (!LEN_LEFT)
1830 {
1831 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1832 __func__, peer->host);
f57000c0 1833 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
03292809 1834 }
718e3744 1835
6e4ab12f
PJ
1836 {
1837 u_char val;
1838 if ((val = stream_getc (s)))
1839 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1840 peer->host, val);
1841 }
1842
1843 /* must have nrli_len, what is left of the attribute */
03292809 1844 nlri_len = LEN_LEFT;
6e4ab12f 1845 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
03292809
PJ
1846 {
1847 zlog_info ("%s: (%s) Failed to read NLRI",
1848 __func__, peer->host);
f57000c0 1849 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
03292809 1850 }
718e3744 1851
42e6d745 1852 if (safi != SAFI_MPLS_LABELED_VPN)
718e3744 1853 {
a82478b9
DS
1854 ret = bgp_nlri_sanity_check (peer, afi, safi, stream_pnt (s),
1855 nlri_len, &num_mp_pfx);
03292809
PJ
1856 if (ret < 0)
1857 {
1858 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1859 __func__, peer->host);
f57000c0 1860 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
03292809 1861 }
718e3744 1862 }
1863
1864 mp_update->afi = afi;
1865 mp_update->safi = safi;
1866 mp_update->nlri = stream_pnt (s);
1867 mp_update->length = nlri_len;
1868
9985f83c 1869 stream_forward_getp (s, nlri_len);
718e3744 1870
37da8fa9
DL
1871 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI);
1872
b881c707 1873 return BGP_ATTR_PARSE_PROCEED;
03292809 1874#undef LEN_LEFT
718e3744 1875}
1876
1877/* Multiprotocol unreachable parse */
03292809 1878int
835315bf 1879bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
718e3744 1880 struct bgp_nlri *mp_withdraw)
1881{
1882 struct stream *s;
4c9641ba
ML
1883 afi_t afi;
1884 safi_t safi;
718e3744 1885 u_int16_t withdraw_len;
1886 int ret;
d889623f 1887 int num_mp_pfx = 0;
835315bf 1888 struct peer *const peer = args->peer;
37da8fa9 1889 struct attr *const attr = args->attr;
835315bf 1890 const bgp_size_t length = args->length;
718e3744 1891
1892 s = peer->ibuf;
6e4ab12f
PJ
1893
1894#define BGP_MP_UNREACH_MIN_SIZE 3
1895 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
f57000c0 1896 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
6e4ab12f 1897
718e3744 1898 afi = stream_getw (s);
1899 safi = stream_getc (s);
6e4ab12f
PJ
1900
1901 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
718e3744 1902
42e6d745 1903 if (safi != SAFI_MPLS_LABELED_VPN)
718e3744 1904 {
a82478b9
DS
1905 ret = bgp_nlri_sanity_check (peer, afi, safi, stream_pnt (s),
1906 withdraw_len, &num_mp_pfx);
718e3744 1907 if (ret < 0)
f57000c0 1908 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
718e3744 1909 }
1910
1911 mp_withdraw->afi = afi;
1912 mp_withdraw->safi = safi;
1913 mp_withdraw->nlri = stream_pnt (s);
1914 mp_withdraw->length = withdraw_len;
1915
9985f83c 1916 stream_forward_getp (s, withdraw_len);
718e3744 1917
37da8fa9
DL
1918 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI);
1919
b881c707 1920 return BGP_ATTR_PARSE_PROCEED;
718e3744 1921}
1922
1923/* Extended Community attribute. */
b881c707 1924static bgp_attr_parse_ret_t
835315bf 1925bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
718e3744 1926{
835315bf
PJ
1927 struct peer *const peer = args->peer;
1928 struct attr *const attr = args->attr;
1929 const bgp_size_t length = args->length;
b881c707 1930
718e3744 1931 if (length == 0)
fb982c25
PJ
1932 {
1933 if (attr->extra)
1934 attr->extra->ecommunity = NULL;
0c466381 1935 /* Empty extcomm doesn't seem to be invalid per se */
b881c707 1936 return BGP_ATTR_PARSE_PROCEED;
fb982c25 1937 }
0c466381
PJ
1938
1939 (bgp_attr_extra_get (attr))->ecommunity =
1940 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1941 /* XXX: fix ecommunity_parse to use stream API */
1942 stream_forward_getp (peer->ibuf, length);
1943
1944 if (!attr->extra->ecommunity)
835315bf
PJ
1945 return bgp_attr_malformed (args,
1946 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1947 args->total);
0c466381 1948
718e3744 1949 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1950
b881c707 1951 return BGP_ATTR_PARSE_PROCEED;
718e3744 1952}
1953
f4c89855
LB
1954/* Parse Tunnel Encap attribute in an UPDATE */
1955static int
1956bgp_attr_encap(
1957 uint8_t type,
1958 struct peer *peer, /* IN */
1959 bgp_size_t length, /* IN: attr's length field */
1960 struct attr *attr, /* IN: caller already allocated */
1961 u_char flag, /* IN: attr's flags field */
1962 u_char *startp)
1963{
1964 bgp_size_t total;
1965 struct attr_extra *attre = NULL;
1966 struct bgp_attr_encap_subtlv *stlv_last = NULL;
2de1475f 1967 uint16_t tunneltype = 0;
f4c89855
LB
1968
1969 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1970
1971 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)
1972 || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL))
1973 {
1974 zlog_info ("Tunnel Encap attribute flag isn't optional and transitive %d", flag);
1975 bgp_notify_send_with_data (peer,
1976 BGP_NOTIFY_UPDATE_ERR,
1977 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1978 startp, total);
1979 return -1;
1980 }
1981
1982 if (BGP_ATTR_ENCAP == type) {
1983 /* read outer TLV type and length */
1984 uint16_t tlv_length;
1985
1986 if (length < 4) {
1987 zlog_info ("Tunnel Encap attribute not long enough to contain outer T,L");
1988 bgp_notify_send_with_data(peer,
1989 BGP_NOTIFY_UPDATE_ERR,
1990 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1991 startp, total);
1992 return -1;
1993 }
1994 tunneltype = stream_getw (BGP_INPUT (peer));
1995 tlv_length = stream_getw (BGP_INPUT (peer));
1996 length -= 4;
1997
1998 if (tlv_length != length) {
1999 zlog_info ("%s: tlv_length(%d) != length(%d)",
2000 __func__, tlv_length, length);
2001 }
2002 }
2003
2004 while (length >= 4) {
0f2b4f4d 2005 uint16_t subtype = 0;
f4cafc65 2006 uint16_t sublength = 0;
f4c89855
LB
2007 struct bgp_attr_encap_subtlv *tlv;
2008
587ff0fd
LB
2009 if (BGP_ATTR_ENCAP == type) {
2010 subtype = stream_getc (BGP_INPUT (peer));
2011 sublength = stream_getc (BGP_INPUT (peer));
2012 length -= 2;
65efcfce
LB
2013#if ENABLE_BGP_VNC
2014 } else {
2015 subtype = stream_getw (BGP_INPUT (peer));
2016 sublength = stream_getw (BGP_INPUT (peer));
2017 length -= 4;
2018#endif
587ff0fd 2019 }
f4c89855
LB
2020
2021 if (sublength > length) {
2022 zlog_info ("Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d",
2023 sublength, length);
2024 bgp_notify_send_with_data (peer,
2025 BGP_NOTIFY_UPDATE_ERR,
2026 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2027 startp, total);
2028 return -1;
2029 }
2030
2031 /* alloc and copy sub-tlv */
2032 /* TBD make sure these are freed when attributes are released */
2033 tlv = XCALLOC (MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv)-1+sublength);
2034 tlv->type = subtype;
2035 tlv->length = sublength;
2036 stream_get(tlv->value, peer->ibuf, sublength);
2037 length -= sublength;
2038
2039 /* attach tlv to encap chain */
2040 if (!attre) {
2041 attre = bgp_attr_extra_get(attr);
2042 if (BGP_ATTR_ENCAP == type) {
2043 for (stlv_last = attre->encap_subtlvs; stlv_last && stlv_last->next;
2044 stlv_last = stlv_last->next);
2045 if (stlv_last) {
2046 stlv_last->next = tlv;
2047 } else {
2048 attre->encap_subtlvs = tlv;
2049 }
65efcfce
LB
2050#if ENABLE_BGP_VNC
2051 } else {
2052 for (stlv_last = attre->vnc_subtlvs; stlv_last && stlv_last->next;
2053 stlv_last = stlv_last->next);
2054 if (stlv_last) {
2055 stlv_last->next = tlv;
2056 } else {
2057 attre->vnc_subtlvs = tlv;
2058 }
2059#endif
f4c89855
LB
2060 }
2061 } else {
2062 stlv_last->next = tlv;
2063 }
2064 stlv_last = tlv;
2065 }
2066
2067 if (attre && (BGP_ATTR_ENCAP == type)) {
2068 attre->encap_tunneltype = tunneltype;
2069 }
2070
2071 if (length) {
2072 /* spurious leftover data */
2073 zlog_info ("Tunnel Encap attribute length is bad: %d leftover octets", length);
2074 bgp_notify_send_with_data (peer,
2075 BGP_NOTIFY_UPDATE_ERR,
2076 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
2077 startp, total);
2078 return -1;
2079 }
2080
2081 return 0;
2082}
2083
718e3744 2084/* BGP unknown attribute treatment. */
b881c707 2085static bgp_attr_parse_ret_t
835315bf 2086bgp_attr_unknown (struct bgp_attr_parser_args *args)
718e3744 2087{
8794e8d2 2088 bgp_size_t total = args->total;
718e3744 2089 struct transit *transit;
fb982c25 2090 struct attr_extra *attre;
835315bf
PJ
2091 struct peer *const peer = args->peer;
2092 struct attr *const attr = args->attr;
2093 u_char *const startp = args->startp;
2094 const u_char type = args->type;
2095 const u_char flag = args->flags;
2096 const bgp_size_t length = args->length;
2097
3f9c7369 2098 if (bgp_debug_update(peer, NULL, NULL, 1))
16286195
DS
2099 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
2100 peer->host, type, length);
f418446b 2101
718e3744 2102 /* Forward read pointer of input stream. */
9985f83c 2103 stream_forward_getp (peer->ibuf, length);
718e3744 2104
718e3744 2105 /* If any of the mandatory well-known attributes are not recognized,
2106 then the Error Subcode is set to Unrecognized Well-known
2107 Attribute. The Data field contains the unrecognized attribute
2108 (type, length and value). */
b881c707 2109 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
718e3744 2110 {
835315bf 2111 return bgp_attr_malformed (args,
b881c707 2112 BGP_NOTIFY_UPDATE_UNREC_ATTR,
835315bf 2113 args->total);
718e3744 2114 }
2115
2116 /* Unrecognized non-transitive optional attributes must be quietly
2117 ignored and not passed along to other BGP peers. */
2118 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
b881c707 2119 return BGP_ATTR_PARSE_PROCEED;
718e3744 2120
2121 /* If a path with recognized transitive optional attribute is
2122 accepted and passed along to other BGP peers and the Partial bit
2123 in the Attribute Flags octet is set to 1 by some previous AS, it
2124 is not set back to 0 by the current AS. */
2125 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
2126
2127 /* Store transitive attribute to the end of attr->transit. */
fb982c25 2128 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
393deb9b 2129 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
718e3744 2130
fb982c25 2131 transit = attre->transit;
718e3744 2132
2133 if (transit->val)
2134 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
2135 transit->length + total);
2136 else
2137 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
2138
2139 memcpy (transit->val + transit->length, startp, total);
2140 transit->length += total;
2141
b881c707 2142 return BGP_ATTR_PARSE_PROCEED;
718e3744 2143}
2144
bb7bef14
PJ
2145/* Well-known attribute check. */
2146static int
52a51fd3 2147bgp_attr_check (struct peer *peer, struct attr *attr)
bb7bef14
PJ
2148{
2149 u_char type = 0;
2150
67495ddb
PJ
2151 /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an
2152 * empty UPDATE. */
2153 if (CHECK_FLAG (peer->cap, PEER_CAP_RESTART_RCV) && !attr->flag)
2154 return BGP_ATTR_PARSE_PROCEED;
2155
2156 /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required
2157 to carry any other path attributes.", though if MP_REACH_NLRI or NLRI
2158 are present, it should. Check for any other attribute being present
2159 instead.
2160 */
2161 if (attr->flag == ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI))
2162 return BGP_ATTR_PARSE_PROCEED;
2163
bb7bef14
PJ
2164 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
2165 type = BGP_ATTR_ORIGIN;
2166
2167 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
2168 type = BGP_ATTR_AS_PATH;
2169
52a51fd3
DW
2170 /* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present and
2171 * NLRI is empty. We can't easily check NLRI empty here though.
bb7bef14 2172 */
52a51fd3
DW
2173 if (!CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))
2174 && !CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI)))
2175 type = BGP_ATTR_NEXT_HOP;
bb7bef14
PJ
2176
2177 if (peer->sort == BGP_PEER_IBGP
2178 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2179 type = BGP_ATTR_LOCAL_PREF;
2180
2181 if (type)
2182 {
52a51fd3
DW
2183 zlog_warn ("%s Missing well-known attribute %s.", peer->host,
2184 LOOKUP (attr_str, type));
bb7bef14
PJ
2185 bgp_notify_send_with_data (peer,
2186 BGP_NOTIFY_UPDATE_ERR,
2187 BGP_NOTIFY_UPDATE_MISS_ATTR,
2188 &type, 1);
2189 return BGP_ATTR_PARSE_ERROR;
2190 }
2191 return BGP_ATTR_PARSE_PROCEED;
2192}
2193
718e3744 2194/* Read attribute of update packet. This function is called from
8b366b9c 2195 bgp_update_receive() in bgp_packet.c. */
b881c707 2196bgp_attr_parse_ret_t
718e3744 2197bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
52a51fd3 2198 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
718e3744 2199{
2200 int ret;
b881c707 2201 u_char flag = 0;
0b2aa3a0 2202 u_char type = 0;
718e3744 2203 bgp_size_t length;
2204 u_char *startp, *endp;
2205 u_char *attr_endp;
2206 u_char seen[BGP_ATTR_BITMAP_SIZE];
0b2aa3a0
PJ
2207 /* we need the as4_path only until we have synthesized the as_path with it */
2208 /* same goes for as4_aggregator */
2209 struct aspath *as4_path = NULL;
2210 as_t as4_aggregator = 0;
19c3598b 2211 struct in_addr as4_aggregator_addr = { .s_addr = 0 };
718e3744 2212
2213 /* Initialize bitmap. */
2214 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
2215
2216 /* End pointer of BGP attribute. */
2217 endp = BGP_INPUT_PNT (peer) + size;
b881c707 2218
718e3744 2219 /* Get attributes to the end of attribute length. */
2220 while (BGP_INPUT_PNT (peer) < endp)
2221 {
2222 /* Check remaining length check.*/
2223 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
2224 {
c29fdba7 2225 /* XXX warning: long int format, int arg (arg 5) */
16286195
DS
2226 zlog_warn ("%s: error BGP attribute length %lu is smaller than min len",
2227 peer->host,
2228 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
718e3744 2229
2230 bgp_notify_send (peer,
2231 BGP_NOTIFY_UPDATE_ERR,
2232 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
b881c707 2233 return BGP_ATTR_PARSE_ERROR;
718e3744 2234 }
2235
2236 /* Fetch attribute flag and type. */
2237 startp = BGP_INPUT_PNT (peer);
2d42e68a
DO
2238 /* "The lower-order four bits of the Attribute Flags octet are
2239 unused. They MUST be zero when sent and MUST be ignored when
2240 received." */
2241 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
718e3744 2242 type = stream_getc (BGP_INPUT (peer));
2243
370b64a2
PJ
2244 /* Check whether Extended-Length applies and is in bounds */
2245 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
2246 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
2247 {
16286195
DS
2248 zlog_warn ("%s: Extended length set, but just %lu bytes of attr header",
2249 peer->host,
2250 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
370b64a2
PJ
2251
2252 bgp_notify_send (peer,
2253 BGP_NOTIFY_UPDATE_ERR,
2254 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
b881c707 2255 return BGP_ATTR_PARSE_ERROR;
370b64a2 2256 }
835315bf 2257
718e3744 2258 /* Check extended attribue length bit. */
2259 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
2260 length = stream_getw (BGP_INPUT (peer));
2261 else
2262 length = stream_getc (BGP_INPUT (peer));
2263
2264 /* If any attribute appears more than once in the UPDATE
2265 message, then the Error Subcode is set to Malformed Attribute
2266 List. */
2267
2268 if (CHECK_BITMAP (seen, type))
2269 {
16286195
DS
2270 zlog_warn ("%s: error BGP attribute type %d appears twice in a message",
2271 peer->host, type);
718e3744 2272
2273 bgp_notify_send (peer,
2274 BGP_NOTIFY_UPDATE_ERR,
2275 BGP_NOTIFY_UPDATE_MAL_ATTR);
b881c707 2276 return BGP_ATTR_PARSE_ERROR;
718e3744 2277 }
2278
2279 /* Set type to bitmap to check duplicate attribute. `type' is
2280 unsigned char so it never overflow bitmap range. */
2281
2282 SET_BITMAP (seen, type);
2283
2284 /* Overflow check. */
2285 attr_endp = BGP_INPUT_PNT (peer) + length;
2286
2287 if (attr_endp > endp)
2288 {
16286195 2289 zlog_warn ("%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p", peer->host, type, length, size, attr_endp, endp);
b184ccd8
DS
2290 bgp_notify_send_with_data (peer,
2291 BGP_NOTIFY_UPDATE_ERR,
2292 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
2293 startp, attr_endp - startp);
b881c707 2294 return BGP_ATTR_PARSE_ERROR;
718e3744 2295 }
835315bf
PJ
2296
2297 struct bgp_attr_parser_args attr_args = {
2298 .peer = peer,
2299 .length = length,
2300 .attr = attr,
2301 .type = type,
2302 .flags = flag,
2303 .startp = startp,
2304 .total = attr_endp - startp,
2305 };
2306
2307
2308 /* If any recognized attribute has Attribute Flags that conflict
2309 with the Attribute Type Code, then the Error Subcode is set to
2310 Attribute Flags Error. The Data field contains the erroneous
2311 attribute (type, length and value). */
2312 if (bgp_attr_flag_invalid (&attr_args))
fa61e16d
PJ
2313 {
2314 bgp_attr_parse_ret_t ret;
2315 ret = bgp_attr_malformed (&attr_args,
2316 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
2317 attr_args.total);
2318 if (ret == BGP_ATTR_PARSE_PROCEED)
2319 continue;
2320 return ret;
2321 }
718e3744 2322
2323 /* OK check attribute and store it's value. */
2324 switch (type)
2325 {
2326 case BGP_ATTR_ORIGIN:
835315bf 2327 ret = bgp_attr_origin (&attr_args);
718e3744 2328 break;
2329 case BGP_ATTR_AS_PATH:
835315bf 2330 ret = bgp_attr_aspath (&attr_args);
718e3744 2331 break;
0b2aa3a0 2332 case BGP_ATTR_AS4_PATH:
835315bf 2333 ret = bgp_attr_as4_path (&attr_args, &as4_path);
0b2aa3a0 2334 break;
718e3744 2335 case BGP_ATTR_NEXT_HOP:
835315bf 2336 ret = bgp_attr_nexthop (&attr_args);
718e3744 2337 break;
2338 case BGP_ATTR_MULTI_EXIT_DISC:
835315bf 2339 ret = bgp_attr_med (&attr_args);
718e3744 2340 break;
2341 case BGP_ATTR_LOCAL_PREF:
835315bf 2342 ret = bgp_attr_local_pref (&attr_args);
718e3744 2343 break;
2344 case BGP_ATTR_ATOMIC_AGGREGATE:
835315bf 2345 ret = bgp_attr_atomic (&attr_args);
718e3744 2346 break;
2347 case BGP_ATTR_AGGREGATOR:
835315bf 2348 ret = bgp_attr_aggregator (&attr_args);
718e3744 2349 break;
0b2aa3a0 2350 case BGP_ATTR_AS4_AGGREGATOR:
835315bf
PJ
2351 ret = bgp_attr_as4_aggregator (&attr_args,
2352 &as4_aggregator,
2353 &as4_aggregator_addr);
0b2aa3a0 2354 break;
718e3744 2355 case BGP_ATTR_COMMUNITIES:
835315bf 2356 ret = bgp_attr_community (&attr_args);
718e3744 2357 break;
2358 case BGP_ATTR_ORIGINATOR_ID:
835315bf 2359 ret = bgp_attr_originator_id (&attr_args);
718e3744 2360 break;
2361 case BGP_ATTR_CLUSTER_LIST:
835315bf 2362 ret = bgp_attr_cluster_list (&attr_args);
718e3744 2363 break;
2364 case BGP_ATTR_MP_REACH_NLRI:
835315bf 2365 ret = bgp_mp_reach_parse (&attr_args, mp_update);
718e3744 2366 break;
2367 case BGP_ATTR_MP_UNREACH_NLRI:
835315bf 2368 ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw);
718e3744 2369 break;
2370 case BGP_ATTR_EXT_COMMUNITIES:
835315bf 2371 ret = bgp_attr_ext_communities (&attr_args);
718e3744 2372 break;
65efcfce
LB
2373#if ENABLE_BGP_VNC
2374 case BGP_ATTR_VNC:
2375#endif
f4c89855
LB
2376 case BGP_ATTR_ENCAP:
2377 ret = bgp_attr_encap (type, peer, length, attr, flag, startp);
2378 break;
718e3744 2379 default:
835315bf 2380 ret = bgp_attr_unknown (&attr_args);
718e3744 2381 break;
2382 }
b881c707 2383
f57000c0
DL
2384 if (ret == BGP_ATTR_PARSE_ERROR_NOTIFYPLS)
2385 {
2386 bgp_notify_send (peer,
2387 BGP_NOTIFY_UPDATE_ERR,
2388 BGP_NOTIFY_UPDATE_MAL_ATTR);
2389 ret = BGP_ATTR_PARSE_ERROR;
2390 }
2391
b881c707
PJ
2392 /* If hard error occured immediately return to the caller. */
2393 if (ret == BGP_ATTR_PARSE_ERROR)
6e4ab12f 2394 {
16286195
DS
2395 zlog_warn ("%s: Attribute %s, parse error",
2396 peer->host,
2397 LOOKUP (attr_str, type));
b881c707
PJ
2398 if (as4_path)
2399 aspath_unintern (&as4_path);
2400 return ret;
6e4ab12f 2401 }
b881c707
PJ
2402 if (ret == BGP_ATTR_PARSE_WITHDRAW)
2403 {
2404
16286195
DS
2405 zlog_warn ("%s: Attribute %s, parse error - treating as withdrawal",
2406 peer->host,
2407 LOOKUP (attr_str, type));
b881c707
PJ
2408 if (as4_path)
2409 aspath_unintern (&as4_path);
2410 return ret;
2411 }
2412
718e3744 2413 /* Check the fetched length. */
2414 if (BGP_INPUT_PNT (peer) != attr_endp)
2415 {
16286195
DS
2416 zlog_warn ("%s: BGP attribute %s, fetch error",
2417 peer->host, LOOKUP (attr_str, type));
718e3744 2418 bgp_notify_send (peer,
2419 BGP_NOTIFY_UPDATE_ERR,
2420 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
b881c707
PJ
2421 if (as4_path)
2422 aspath_unintern (&as4_path);
2423 return BGP_ATTR_PARSE_ERROR;
718e3744 2424 }
2425 }
2426
2427 /* Check final read pointer is same as end pointer. */
2428 if (BGP_INPUT_PNT (peer) != endp)
2429 {
16286195
DS
2430 zlog_warn ("%s: BGP attribute %s, length mismatch",
2431 peer->host, LOOKUP (attr_str, type));
718e3744 2432 bgp_notify_send (peer,
2433 BGP_NOTIFY_UPDATE_ERR,
2434 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
b881c707
PJ
2435 if (as4_path)
2436 aspath_unintern (&as4_path);
2437 return BGP_ATTR_PARSE_ERROR;
718e3744 2438 }
2439
bb7bef14
PJ
2440 /* Check all mandatory well-known attributes are present */
2441 {
2442 bgp_attr_parse_ret_t ret;
52a51fd3 2443 if ((ret = bgp_attr_check (peer, attr)) < 0)
bb7bef14
PJ
2444 {
2445 if (as4_path)
2446 aspath_unintern (&as4_path);
2447 return ret;
2448 }
2449 }
2450
0b2aa3a0
PJ
2451 /*
2452 * At this place we can see whether we got AS4_PATH and/or
2453 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
2454 * We can not do this before we've read all attributes because
2455 * the as4 handling does not say whether AS4_PATH has to be sent
2456 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
2457 * in relationship to AGGREGATOR.
2458 * So, to be defensive, we are not relying on any order and read
2459 * all attributes first, including these 32bit ones, and now,
2460 * afterwards, we look what and if something is to be done for as4.
67495ddb
PJ
2461 *
2462 * It is possible to not have AS_PATH, e.g. GR EoR and sole
2463 * MP_UNREACH_NLRI.
0b2aa3a0 2464 */
f57000c0
DL
2465 /* actually... this doesn't ever return failure currently, but
2466 * better safe than sorry */
67495ddb
PJ
2467 if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))
2468 && bgp_attr_munge_as4_attrs (peer, attr, as4_path,
0b2aa3a0 2469 as4_aggregator, &as4_aggregator_addr))
b881c707 2470 {
f57000c0
DL
2471 bgp_notify_send (peer,
2472 BGP_NOTIFY_UPDATE_ERR,
2473 BGP_NOTIFY_UPDATE_MAL_ATTR);
b881c707
PJ
2474 if (as4_path)
2475 aspath_unintern (&as4_path);
2476 return BGP_ATTR_PARSE_ERROR;
2477 }
0b2aa3a0
PJ
2478
2479 /* At this stage, we have done all fiddling with as4, and the
2480 * resulting info is in attr->aggregator resp. attr->aspath
2481 * so we can chuck as4_aggregator and as4_path alltogether in
2482 * order to save memory
2483 */
b881c707 2484 if (as4_path)
0b2aa3a0 2485 {
f6f434b2 2486 aspath_unintern (&as4_path); /* unintern - it is in the hash */
0b2aa3a0
PJ
2487 /* The flag that we got this is still there, but that does not
2488 * do any trouble
2489 */
2490 }
2491 /*
2492 * The "rest" of the code does nothing with as4_aggregator.
2493 * there is no memory attached specifically which is not part
2494 * of the attr.
2495 * so ignoring just means do nothing.
2496 */
2497 /*
2498 * Finally do the checks on the aspath we did not do yet
2499 * because we waited for a potentially synthesized aspath.
2500 */
b881c707 2501 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
0b2aa3a0 2502 {
835315bf 2503 ret = bgp_attr_aspath_check (peer, attr);
b881c707 2504 if (ret != BGP_ATTR_PARSE_PROCEED)
0b2aa3a0
PJ
2505 return ret;
2506 }
2507
718e3744 2508 /* Finally intern unknown attribute. */
fb982c25
PJ
2509 if (attr->extra && attr->extra->transit)
2510 attr->extra->transit = transit_intern (attr->extra->transit);
718e3744 2511
b881c707 2512 return BGP_ATTR_PARSE_PROCEED;
718e3744 2513}
2514
8c71e481 2515size_t
8a92a8a0 2516bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi,
3f9c7369 2517 struct bpacket_attr_vec_arr *vecarr,
8c71e481
PM
2518 struct attr *attr)
2519{
2520 size_t sizep;
2521
2522 /* Set extended bit always to encode the attribute length as 2 bytes */
2523 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2524 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
2525 sizep = stream_get_endp (s);
2526 stream_putw (s, 0); /* Marker: Attribute length. */
93b73dfa
LB
2527
2528 stream_putw (s, afi);
2529 stream_putc (s, (safi == SAFI_MPLS_VPN) ? SAFI_MPLS_LABELED_VPN : safi);
8c71e481
PM
2530
2531 /* Nexthop */
8a92a8a0 2532 switch (nh_afi)
8c71e481
PM
2533 {
2534 case AFI_IP:
2535 switch (safi)
2536 {
6407da5a 2537 case SAFI_UNICAST:
8c71e481 2538 case SAFI_MULTICAST:
3f9c7369 2539 bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr);
8c71e481
PM
2540 stream_putc (s, 4);
2541 stream_put_ipv4 (s, attr->nexthop.s_addr);
2542 break;
2543 case SAFI_MPLS_VPN:
3f9c7369 2544 bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr);
8c71e481 2545 stream_putc (s, 12);
93b73dfa 2546 stream_putl (s, 0); /* RD = 0, per RFC */
8c71e481
PM
2547 stream_putl (s, 0);
2548 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
2549 break;
587ff0fd
LB
2550 case SAFI_ENCAP:
2551 stream_putc (s, 4);
2552 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
2553 break;
8c71e481
PM
2554 default:
2555 break;
2556 }
2557 break;
2558#ifdef HAVE_IPV6
2559 case AFI_IP6:
2560 switch (safi)
2561 {
2562 case SAFI_UNICAST:
2563 case SAFI_MULTICAST:
2564 {
8c71e481
PM
2565 struct attr_extra *attre = attr->extra;
2566
2567 assert (attr->extra);
3f9c7369 2568 bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr);
8c71e481 2569 stream_putc (s, attre->mp_nexthop_len);
801a9bcc
DS
2570 stream_put (s, &attre->mp_nexthop_global, IPV6_MAX_BYTELEN);
2571 if (attre->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
2572 stream_put (s, &attre->mp_nexthop_local, IPV6_MAX_BYTELEN);
8c71e481 2573 }
93b73dfa
LB
2574 break;
2575 case SAFI_MPLS_VPN:
2576 {
2577 struct attr_extra *attre = attr->extra;
2578
2579 assert (attr->extra);
6407da5a 2580 if (attre->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL) {
93b73dfa
LB
2581 stream_putc (s, 24);
2582 stream_putl (s, 0); /* RD = 0, per RFC */
2583 stream_putl (s, 0);
6407da5a 2584 stream_put (s, &attre->mp_nexthop_global, IPV6_MAX_BYTELEN);
2585 } else if (attre->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
93b73dfa
LB
2586 stream_putc (s, 48);
2587 stream_putl (s, 0); /* RD = 0, per RFC */
2588 stream_putl (s, 0);
6407da5a 2589 stream_put (s, &attre->mp_nexthop_global, IPV6_MAX_BYTELEN);
93b73dfa
LB
2590 stream_putl (s, 0); /* RD = 0, per RFC */
2591 stream_putl (s, 0);
6407da5a 2592 stream_put (s, &attre->mp_nexthop_local, IPV6_MAX_BYTELEN);
93b73dfa
LB
2593 }
2594 }
2595 break;
587ff0fd
LB
2596 case SAFI_ENCAP:
2597 assert (attr->extra);
2598 stream_putc (s, IPV6_MAX_BYTELEN);
2599 stream_put (s, &attr->extra->mp_nexthop_global, IPV6_MAX_BYTELEN);
2600 break;
8c71e481
PM
2601 default:
2602 break;
2603 }
2604 break;
2605#endif /*HAVE_IPV6*/
2606 default:
2607 break;
2608 }
2609
2610 /* SNPA */
2611 stream_putc (s, 0);
2612 return sizep;
2613}
2614
2615void
2616bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi,
2617 struct prefix *p, struct prefix_rd *prd,
adbac85e
DW
2618 u_char *tag, int addpath_encode,
2619 u_int32_t addpath_tx_id)
8c71e481 2620{
93b73dfa 2621 if (safi == SAFI_MPLS_VPN)
8c71e481 2622 {
adbac85e
DW
2623 if (addpath_encode)
2624 stream_putl(s, addpath_tx_id);
8c71e481
PM
2625 /* Tag, RD, Prefix write. */
2626 stream_putc (s, p->prefixlen + 88);
2627 stream_put (s, tag, 3);
2628 stream_put (s, prd->val, 8);
2629 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
8c71e481 2630 }
93b73dfa
LB
2631 else
2632 stream_put_prefix_addpath (s, p, addpath_encode, addpath_tx_id);
2633}
2634
2635size_t
2636bgp_packet_mpattr_prefix_size (afi_t afi, safi_t safi, struct prefix *p)
2637{
2638 int size = PSIZE (p->prefixlen);
2639 if (safi == SAFI_MPLS_VPN)
2640 size += 88;
2641 return size;
8c71e481
PM
2642}
2643
f4c89855 2644/*
65efcfce
LB
2645 * Encodes the tunnel encapsulation attribute,
2646 * and with ENABLE_BGP_VNC the VNC attribute which uses
2647 * almost the same TLV format
f4c89855
LB
2648 */
2649static void
2650bgp_packet_mpattr_tea(
2651 struct bgp *bgp,
2652 struct peer *peer,
2653 struct stream *s,
2654 struct attr *attr,
2655 uint8_t attrtype)
2656{
2657 unsigned int attrlenfield = 0;
587ff0fd 2658 unsigned int attrhdrlen = 0;
f4c89855
LB
2659 struct bgp_attr_encap_subtlv *subtlvs;
2660 struct bgp_attr_encap_subtlv *st;
2661 const char *attrname;
2662
2663 if (!attr || !attr->extra)
2664 return;
2665
2666 switch (attrtype) {
2667 case BGP_ATTR_ENCAP:
2668 attrname = "Tunnel Encap";
2669 subtlvs = attr->extra->encap_subtlvs;
2670
2671 /*
2672 * The tunnel encap attr has an "outer" tlv.
2673 * T = tunneltype,
2674 * L = total length of subtlvs,
2675 * V = concatenated subtlvs.
2676 */
2677 attrlenfield = 2 + 2; /* T + L */
587ff0fd 2678 attrhdrlen = 1 + 1; /* subTLV T + L */
f4c89855
LB
2679 break;
2680
65efcfce
LB
2681#if ENABLE_BGP_VNC
2682 case BGP_ATTR_VNC:
2683 attrname = "VNC";
2684 subtlvs = attr->extra->vnc_subtlvs;
2685 attrlenfield = 0; /* no outer T + L */
2686 attrhdrlen = 2 + 2; /* subTLV T + L */
2687 break;
2688#endif
2689
f4c89855
LB
2690 default:
2691 assert(0);
2692 }
2693
2694
587ff0fd
LB
2695 /* if no tlvs, don't make attr */
2696 if (subtlvs == NULL)
2697 return;
2698
f4c89855
LB
2699 /* compute attr length */
2700 for (st = subtlvs; st; st = st->next) {
587ff0fd 2701 attrlenfield += (attrhdrlen + st->length);
f4c89855
LB
2702 }
2703
f4c89855
LB
2704 if (attrlenfield > 0xffff) {
2705 zlog_info ("%s attribute is too long (length=%d), can't send it",
2706 attrname,
2707 attrlenfield);
2708 return;
2709 }
2710
2711 if (attrlenfield > 0xff) {
2712 /* 2-octet length field */
2713 stream_putc (s,
2714 BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2715 stream_putc (s, attrtype);
2716 stream_putw (s, attrlenfield & 0xffff);
2717 } else {
2718 /* 1-octet length field */
2719 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL);
2720 stream_putc (s, attrtype);
2721 stream_putc (s, attrlenfield & 0xff);
2722 }
2723
2724 if (attrtype == BGP_ATTR_ENCAP) {
2725 /* write outer T+L */
2726 stream_putw(s, attr->extra->encap_tunneltype);
2727 stream_putw(s, attrlenfield - 4);
2728 }
2729
2730 /* write each sub-tlv */
2731 for (st = subtlvs; st; st = st->next) {
587ff0fd
LB
2732 if (attrtype == BGP_ATTR_ENCAP) {
2733 stream_putc (s, st->type);
2734 stream_putc (s, st->length);
65efcfce
LB
2735#if ENABLE_BGP_VNC
2736 } else {
2737 stream_putw (s, st->type);
2738 stream_putw (s, st->length);
2739#endif
587ff0fd 2740 }
f4c89855
LB
2741 stream_put (s, st->value, st->length);
2742 }
2743}
f4c89855 2744
8c71e481
PM
2745void
2746bgp_packet_mpattr_end (struct stream *s, size_t sizep)
2747{
2748 /* Set MP attribute length. Don't count the (2) bytes used to encode
2749 the attr length */
2750 stream_putw_at (s, sizep, (stream_get_endp (s) - sizep) - 2);
2751}
2752
718e3744 2753/* Make attribute packet. */
2754bgp_size_t
2755bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
8c71e481 2756 struct stream *s, struct attr *attr,
3f9c7369 2757 struct bpacket_attr_vec_arr *vecarr,
8c71e481 2758 struct prefix *p, afi_t afi, safi_t safi,
adbac85e
DW
2759 struct peer *from, struct prefix_rd *prd, u_char *tag,
2760 int addpath_encode,
2761 u_int32_t addpath_tx_id)
718e3744 2762{
fe69a505 2763 size_t cp;
0b2aa3a0 2764 size_t aspath_sizep;
718e3744 2765 struct aspath *aspath;
0b2aa3a0
PJ
2766 int send_as4_path = 0;
2767 int send_as4_aggregator = 0;
2768 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
718e3744 2769
2770 if (! bgp)
75aead62 2771 bgp = peer->bgp;
718e3744 2772
2773 /* Remember current pointer. */
9985f83c 2774 cp = stream_get_endp (s);
718e3744 2775
8a92a8a0
DS
2776 if (p && !((afi == AFI_IP && safi == SAFI_UNICAST) &&
2777 !peer_cap_enhe(peer)))
8c71e481 2778 {
93b73dfa
LB
2779 size_t mpattrlen_pos = 0;
2780
8a92a8a0
DS
2781 mpattrlen_pos = bgp_packet_mpattr_start(s, afi, safi,
2782 (peer_cap_enhe(peer) ? AFI_IP6 : afi),
2783 vecarr, attr);
adbac85e
DW
2784 bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag,
2785 addpath_encode, addpath_tx_id);
8c71e481
PM
2786 bgp_packet_mpattr_end(s, mpattrlen_pos);
2787 }
2788
718e3744 2789 /* Origin attribute. */
2790 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2791 stream_putc (s, BGP_ATTR_ORIGIN);
2792 stream_putc (s, 1);
2793 stream_putc (s, attr->origin);
2794
2795 /* AS path attribute. */
2796
2797 /* If remote-peer is EBGP */
6d85b15b 2798 if (peer->sort == BGP_PEER_EBGP
718e3744 2799 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
fe69a505 2800 || attr->aspath->segments == NULL)
fee0f4c6 2801 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
718e3744 2802 {
2803 aspath = aspath_dup (attr->aspath);
2804
66b199b2
DS
2805 /* Even though we may not be configured for confederations we may have
2806 * RXed an AS_PATH with AS_CONFED_SEQUENCE or AS_CONFED_SET */
2807 aspath = aspath_delete_confed_seq (aspath);
2808
718e3744 2809 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2810 {
66b199b2 2811 /* Stuff our path CONFED_ID on the front */
718e3744 2812 aspath = aspath_add_seq (aspath, bgp->confed_id);
2813 }
2814 else
2815 {
9d3f9705
AC
2816 if (peer->change_local_as) {
2817 /* If replace-as is specified, we only use the change_local_as when
2818 advertising routes. */
2819 if( ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ) {
2820 aspath = aspath_add_seq (aspath, peer->local_as);
2821 }
718e3744 2822 aspath = aspath_add_seq (aspath, peer->change_local_as);
9d3f9705
AC
2823 } else {
2824 aspath = aspath_add_seq (aspath, peer->local_as);
2825 }
718e3744 2826 }
2827 }
6d85b15b 2828 else if (peer->sort == BGP_PEER_CONFED)
718e3744 2829 {
2830 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2831 aspath = aspath_dup (attr->aspath);
2832 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2833 }
2834 else
2835 aspath = attr->aspath;
2836
0b2aa3a0
PJ
2837 /* If peer is not AS4 capable, then:
2838 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2839 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2840 * types are in it (i.e. exclude them if they are there)
2841 * AND do this only if there is at least one asnum > 65535 in the path!
2842 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2843 * all ASnums > 65535 to BGP_AS_TRANS
2844 */
2845
2846 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2847 stream_putc (s, BGP_ATTR_AS_PATH);
2848 aspath_sizep = stream_get_endp (s);
2849 stream_putw (s, 0);
2850 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2851
2852 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2853 * in the path
2854 */
2855 if (!use32bit && aspath_has_as4 (aspath))
2856 send_as4_path = 1; /* we'll do this later, at the correct place */
2857
718e3744 2858 /* Nexthop attribute. */
93b73dfa 2859 if (afi == AFI_IP && safi == SAFI_UNICAST && !peer_cap_enhe(peer))
718e3744 2860 {
8a92a8a0
DS
2861 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))
2862 {
2863 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2864 stream_putc (s, BGP_ATTR_NEXT_HOP);
2865 bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr);
2866 stream_putc (s, 4);
2867 stream_put_ipv4 (s, attr->nexthop.s_addr);
2868 }
2869 else if (safi == SAFI_UNICAST && peer_cap_enhe(from))
2870 {
2871 /*
2872 * Likely this is the case when an IPv4 prefix was received with
2873 * Extended Next-hop capability and now being advertised to
2874 * non-ENHE peers.
2875 * Setting the mandatory (ipv4) next-hop attribute here to enable
2876 * implicit next-hop self with correct (ipv4 address family).
2877 */
2878 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2879 stream_putc (s, BGP_ATTR_NEXT_HOP);
2880 bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, NULL);
2881 stream_putc (s, 4);
2882 stream_put_ipv4 (s, 0);
2883 }
718e3744 2884 }
2885
2886 /* MED attribute. */
abc920f8
DS
2887 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC) ||
2888 bgp->maxmed_active)
718e3744 2889 {
2890 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2891 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2892 stream_putc (s, 4);
abc920f8 2893 stream_putl (s, (bgp->maxmed_active ? bgp->maxmed_value : attr->med));
718e3744 2894 }
2895
2896 /* Local preference. */
6d85b15b
JBD
2897 if (peer->sort == BGP_PEER_IBGP ||
2898 peer->sort == BGP_PEER_CONFED)
718e3744 2899 {
2900 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2901 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2902 stream_putc (s, 4);
2903 stream_putl (s, attr->local_pref);
2904 }
2905
2906 /* Atomic aggregate. */
2907 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2908 {
2909 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2910 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2911 stream_putc (s, 0);
2912 }
2913
2914 /* Aggregator. */
2915 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2916 {
fb982c25 2917 assert (attr->extra);
0b2aa3a0
PJ
2918
2919 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
718e3744 2920 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2921 stream_putc (s, BGP_ATTR_AGGREGATOR);
0b2aa3a0
PJ
2922
2923 if (use32bit)
2924 {
2925 /* AS4 capable peer */
2926 stream_putc (s, 8);
2927 stream_putl (s, attr->extra->aggregator_as);
2928 }
2929 else
2930 {
2931 /* 2-byte AS peer */
2932 stream_putc (s, 6);
2933
2934 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2935 if ( attr->extra->aggregator_as > 65535 )
2936 {
2937 stream_putw (s, BGP_AS_TRANS);
2938
2939 /* we have to send AS4_AGGREGATOR, too.
2940 * we'll do that later in order to send attributes in ascending
2941 * order.
2942 */
2943 send_as4_aggregator = 1;
2944 }
2945 else
2946 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2947 }
fb982c25 2948 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
718e3744 2949 }
2950
2951 /* Community attribute. */
2952 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2953 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2954 {
2955 if (attr->community->size * 4 > 255)
2956 {
2957 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2958 stream_putc (s, BGP_ATTR_COMMUNITIES);
2959 stream_putw (s, attr->community->size * 4);
2960 }
2961 else
2962 {
2963 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2964 stream_putc (s, BGP_ATTR_COMMUNITIES);
2965 stream_putc (s, attr->community->size * 4);
2966 }
2967 stream_put (s, attr->community->val, attr->community->size * 4);
2968 }
2969
2970 /* Route Reflector. */
6d85b15b 2971 if (peer->sort == BGP_PEER_IBGP
718e3744 2972 && from
6d85b15b 2973 && from->sort == BGP_PEER_IBGP)
718e3744 2974 {
2975 /* Originator ID. */
2976 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2977 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2978 stream_putc (s, 4);
2979
2980 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
fb982c25 2981 stream_put_in_addr (s, &attr->extra->originator_id);
34c3f81b
PJ
2982 else
2983 stream_put_in_addr (s, &from->remote_id);
718e3744 2984
2985 /* Cluster list. */
2986 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2987 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2988
9eda90ce 2989 if (attr->extra && attr->extra->cluster)
718e3744 2990 {
fb982c25 2991 stream_putc (s, attr->extra->cluster->length + 4);
718e3744 2992 /* If this peer configuration's parent BGP has cluster_id. */
2993 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2994 stream_put_in_addr (s, &bgp->cluster_id);
2995 else
2996 stream_put_in_addr (s, &bgp->router_id);
fb982c25
PJ
2997 stream_put (s, attr->extra->cluster->list,
2998 attr->extra->cluster->length);
718e3744 2999 }
3000 else
3001 {
3002 stream_putc (s, 4);
3003 /* If this peer configuration's parent BGP has cluster_id. */
3004 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
3005 stream_put_in_addr (s, &bgp->cluster_id);
3006 else
3007 stream_put_in_addr (s, &bgp->router_id);
3008 }
3009 }
3010
718e3744 3011 /* Extended Communities attribute. */
3012 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
3013 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
3014 {
fb982c25
PJ
3015 struct attr_extra *attre = attr->extra;
3016
3017 assert (attre);
3018
6d85b15b
JBD
3019 if (peer->sort == BGP_PEER_IBGP
3020 || peer->sort == BGP_PEER_CONFED)
718e3744 3021 {
fb982c25 3022 if (attre->ecommunity->size * 8 > 255)
4372df71 3023 {
3024 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
3025 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
fb982c25 3026 stream_putw (s, attre->ecommunity->size * 8);
4372df71 3027 }
3028 else
3029 {
3030 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
3031 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
fb982c25 3032 stream_putc (s, attre->ecommunity->size * 8);
4372df71 3033 }
fb982c25 3034 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
718e3744 3035 }
3036 else
3037 {
5228ad27 3038 u_int8_t *pnt;
4372df71 3039 int tbit;
3040 int ecom_tr_size = 0;
3041 int i;
3042
fb982c25 3043 for (i = 0; i < attre->ecommunity->size; i++)
4372df71 3044 {
fb982c25 3045 pnt = attre->ecommunity->val + (i * 8);
4372df71 3046 tbit = *pnt;
3047
3048 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
3049 continue;
3050
3051 ecom_tr_size++;
3052 }
3053
3054 if (ecom_tr_size)
3055 {
3056 if (ecom_tr_size * 8 > 255)
3057 {
3058 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
3059 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
3060 stream_putw (s, ecom_tr_size * 8);
3061 }
3062 else
3063 {
3064 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
3065 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
3066 stream_putc (s, ecom_tr_size * 8);
3067 }
3068
fb982c25 3069 for (i = 0; i < attre->ecommunity->size; i++)
4372df71 3070 {
fb982c25 3071 pnt = attre->ecommunity->val + (i * 8);
4372df71 3072 tbit = *pnt;
3073
3074 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
3075 continue;
3076
3077 stream_put (s, pnt, 8);
3078 }
3079 }
718e3744 3080 }
718e3744 3081 }
0b2aa3a0
PJ
3082
3083 if ( send_as4_path )
3084 {
3085 /* If the peer is NOT As4 capable, AND */
3086 /* there are ASnums > 65535 in path THEN
3087 * give out AS4_PATH */
3088
3089 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
3090 * path segments!
3091 * Hm, I wonder... confederation things *should* only be at
3092 * the beginning of an aspath, right? Then we should use
3093 * aspath_delete_confed_seq for this, because it is already
3094 * there! (JK)
3095 * Folks, talk to me: what is reasonable here!?
3096 */
3097 aspath = aspath_delete_confed_seq (aspath);
3098
3099 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
3100 stream_putc (s, BGP_ATTR_AS4_PATH);
3101 aspath_sizep = stream_get_endp (s);
3102 stream_putw (s, 0);
3103 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
3104 }
3105
3106 if (aspath != attr->aspath)
3107 aspath_free (aspath);
3108
3109 if ( send_as4_aggregator )
3110 {
3111 assert (attr->extra);
3112
3113 /* send AS4_AGGREGATOR, at this place */
3114 /* this section of code moved here in order to ensure the correct
3115 * *ascending* order of attributes
3116 */
3117 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
3118 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
3119 stream_putc (s, 8);
3120 stream_putl (s, attr->extra->aggregator_as);
3121 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
3122 }
587ff0fd
LB
3123
3124 if ((afi == AFI_IP || afi == AFI_IP6) &&
3125 (safi == SAFI_ENCAP || safi == SAFI_MPLS_VPN))
3126 {
3127 /* Tunnel Encap attribute */
3128 bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_ENCAP);
65efcfce
LB
3129
3130#if ENABLE_BGP_VNC
3131 /* VNC attribute */
3132 bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_VNC);
3133#endif
587ff0fd
LB
3134 }
3135
718e3744 3136 /* Unknown transit attribute. */
fb982c25
PJ
3137 if (attr->extra && attr->extra->transit)
3138 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
718e3744 3139
3140 /* Return total size of attribute. */
9985f83c 3141 return stream_get_endp (s) - cp;
718e3744 3142}
3143
8c71e481
PM
3144size_t
3145bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi)
718e3744 3146{
718e3744 3147 unsigned long attrlen_pnt;
718e3744 3148
8c71e481
PM
3149 /* Set extended bit always to encode the attribute length as 2 bytes */
3150 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
718e3744 3151 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
3152
9985f83c 3153 attrlen_pnt = stream_get_endp (s);
8c71e481 3154 stream_putw (s, 0); /* Length of this attribute. */
718e3744 3155
8c71e481 3156 stream_putw (s, afi);
93b73dfa 3157 stream_putc (s, (safi == SAFI_MPLS_VPN) ? SAFI_MPLS_LABELED_VPN : safi);
8c71e481
PM
3158 return attrlen_pnt;
3159}
718e3744 3160
8c71e481
PM
3161void
3162bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p,
3163 afi_t afi, safi_t safi, struct prefix_rd *prd,
adbac85e
DW
3164 u_char *tag, int addpath_encode,
3165 u_int32_t addpath_tx_id)
8c71e481 3166{
718e3744 3167 if (safi == SAFI_MPLS_VPN)
3168 {
adbac85e
DW
3169 /* addpath TX ID */
3170 if (addpath_encode)
3171 stream_putl(s, addpath_tx_id);
3172
718e3744 3173 stream_putc (s, p->prefixlen + 88);
3174 stream_put (s, tag, 3);
3175 stream_put (s, prd->val, 8);
3176 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
3177 }
3178 else
adbac85e 3179 stream_put_prefix_addpath (s, p, addpath_encode, addpath_tx_id);
8c71e481 3180}
718e3744 3181
8c71e481
PM
3182void
3183bgp_packet_mpunreach_end (struct stream *s, size_t attrlen_pnt)
3184{
93b73dfa 3185 bgp_packet_mpattr_end (s, attrlen_pnt);
718e3744 3186}
3187
3188/* Initialization of attribute. */
3189void
fe69a505 3190bgp_attr_init (void)
718e3744 3191{
718e3744 3192 aspath_init ();
3193 attrhash_init ();
3194 community_init ();
3195 ecommunity_init ();
3196 cluster_init ();
3197 transit_init ();
3198}
3199
228da428
CC
3200void
3201bgp_attr_finish (void)
3202{
3203 aspath_finish ();
3204 attrhash_finish ();
3205 community_finish ();
3206 ecommunity_finish ();
3207 cluster_finish ();
3208 transit_finish ();
3209}
3210
718e3744 3211/* Make attribute packet. */
3212void
a384592f 3213bgp_dump_routes_attr (struct stream *s, struct attr *attr,
3214 struct prefix *prefix)
718e3744 3215{
3216 unsigned long cp;
3217 unsigned long len;
0b2aa3a0 3218 size_t aspath_lenp;
718e3744 3219 struct aspath *aspath;
adbac85e
DW
3220 int addpath_encode = 0;
3221 u_int32_t addpath_tx_id = 0;
718e3744 3222
3223 /* Remember current pointer. */
9985f83c 3224 cp = stream_get_endp (s);
718e3744 3225
3226 /* Place holder of length. */
3227 stream_putw (s, 0);
3228
3229 /* Origin attribute. */
3230 stream_putc (s, BGP_ATTR_FLAG_TRANS);
3231 stream_putc (s, BGP_ATTR_ORIGIN);
3232 stream_putc (s, 1);
3233 stream_putc (s, attr->origin);
3234
3235 aspath = attr->aspath;
0b2aa3a0
PJ
3236
3237 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
3238 stream_putc (s, BGP_ATTR_AS_PATH);
3239 aspath_lenp = stream_get_endp (s);
3240 stream_putw (s, 0);
3241
3242 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
718e3744 3243
3244 /* Nexthop attribute. */
a384592f 3245 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
3246 if(prefix != NULL
3247#ifdef HAVE_IPV6
3248 && prefix->family != AF_INET6
3249#endif /* HAVE_IPV6 */
3250 )
3251 {
3252 stream_putc (s, BGP_ATTR_FLAG_TRANS);
3253 stream_putc (s, BGP_ATTR_NEXT_HOP);
3254 stream_putc (s, 4);
3255 stream_put_ipv4 (s, attr->nexthop.s_addr);
3256 }
718e3744 3257
3258 /* MED attribute. */
3259 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
3260 {
3261 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
3262 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
3263 stream_putc (s, 4);
3264 stream_putl (s, attr->med);
3265 }
3266
3267 /* Local preference. */
3268 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
3269 {
3270 stream_putc (s, BGP_ATTR_FLAG_TRANS);
3271 stream_putc (s, BGP_ATTR_LOCAL_PREF);
3272 stream_putc (s, 4);
3273 stream_putl (s, attr->local_pref);
3274 }
3275
3276 /* Atomic aggregate. */
3277 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
3278 {
3279 stream_putc (s, BGP_ATTR_FLAG_TRANS);
3280 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
3281 stream_putc (s, 0);
3282 }
3283
3284 /* Aggregator. */
3285 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
3286 {
fb982c25 3287 assert (attr->extra);
718e3744 3288 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
3289 stream_putc (s, BGP_ATTR_AGGREGATOR);
0b2aa3a0
PJ
3290 stream_putc (s, 8);
3291 stream_putl (s, attr->extra->aggregator_as);
fb982c25 3292 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
718e3744 3293 }
3294
3295 /* Community attribute. */
3296 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
3297 {
3298 if (attr->community->size * 4 > 255)
3299 {
3300 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
3301 stream_putc (s, BGP_ATTR_COMMUNITIES);
3302 stream_putw (s, attr->community->size * 4);
3303 }
3304 else
3305 {
3306 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
3307 stream_putc (s, BGP_ATTR_COMMUNITIES);
3308 stream_putc (s, attr->community->size * 4);
3309 }
3310 stream_put (s, attr->community->val, attr->community->size * 4);
3311 }
3312
a384592f 3313#ifdef HAVE_IPV6
3314 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
fb982c25 3315 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
801a9bcc
DS
3316 (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL ||
3317 attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) )
a384592f 3318 {
3319 int sizep;
fb982c25
PJ
3320 struct attr_extra *attre = attr->extra;
3321
a384592f 3322 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
3323 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
9985f83c 3324 sizep = stream_get_endp (s);
a384592f 3325
3326 /* MP header */
fb982c25 3327 stream_putc (s, 0); /* Marker: Attribute length. */
a384592f 3328 stream_putw(s, AFI_IP6); /* AFI */
3329 stream_putc(s, SAFI_UNICAST); /* SAFI */
3330
3331 /* Next hop */
fb982c25 3332 stream_putc(s, attre->mp_nexthop_len);
801a9bcc
DS
3333 stream_put(s, &attre->mp_nexthop_global, IPV6_MAX_BYTELEN);
3334 if (attre->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
3335 stream_put(s, &attre->mp_nexthop_local, IPV6_MAX_BYTELEN);
a384592f 3336
3337 /* SNPA */
3338 stream_putc(s, 0);
3339
3340 /* Prefix */
adbac85e 3341 stream_put_prefix_addpath (s, prefix, addpath_encode, addpath_tx_id);
a384592f 3342
3343 /* Set MP attribute length. */
9985f83c 3344 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
a384592f 3345 }
3346#endif /* HAVE_IPV6 */
3347
718e3744 3348 /* Return total size of attribute. */
9985f83c 3349 len = stream_get_endp (s) - cp - 2;
718e3744 3350 stream_putw_at (s, cp, len);
3351}