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