]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_attr.c
2005-06-28 Paul Jakma <paul.jakma@sun.com>
[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"
31
32#include "bgpd/bgpd.h"
33#include "bgpd/bgp_attr.h"
34#include "bgpd/bgp_route.h"
35#include "bgpd/bgp_aspath.h"
36#include "bgpd/bgp_community.h"
37#include "bgpd/bgp_debug.h"
38#include "bgpd/bgp_packet.h"
39#include "bgpd/bgp_ecommunity.h"
40\f
41/* Attribute strings for logging. */
42struct message attr_str [] =
43{
44 { BGP_ATTR_ORIGIN, "ORIGIN" },
45 { BGP_ATTR_AS_PATH, "AS_PATH" },
46 { BGP_ATTR_NEXT_HOP, "NEXT_HOP" },
47 { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
48 { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" },
49 { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
50 { BGP_ATTR_AGGREGATOR, "AGGREGATOR" },
51 { BGP_ATTR_COMMUNITIES, "COMMUNITY" },
52 { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" },
53 { BGP_ATTR_CLUSTER_LIST, "CLUSTERLIST" },
54 { BGP_ATTR_DPA, "DPA" },
55 { BGP_ATTR_ADVERTISER, "ADVERTISER"} ,
56 { BGP_ATTR_RCID_PATH, "RCID_PATH" },
57 { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
58 { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
59 { 0, NULL }
60};
61\f
62struct hash *cluster_hash;
63
94f2b392 64static void *
718e3744 65cluster_hash_alloc (struct cluster_list *val)
66{
67 struct cluster_list *cluster;
68
69 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
70 cluster->length = val->length;
71
72 if (cluster->length)
73 {
74 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
75 memcpy (cluster->list, val->list, val->length);
76 }
77 else
78 cluster->list = NULL;
79
80 cluster->refcnt = 0;
81
82 return cluster;
83}
84
85/* Cluster list related functions. */
94f2b392 86static struct cluster_list *
5228ad27 87cluster_parse (struct in_addr * pnt, int length)
718e3744 88{
89 struct cluster_list tmp;
90 struct cluster_list *cluster;
91
92 tmp.length = length;
5228ad27 93 tmp.list = pnt;
718e3744 94
95 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
96 cluster->refcnt++;
97 return cluster;
98}
99
100int
101cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
102{
103 int i;
104
105 for (i = 0; i < cluster->length / 4; i++)
106 if (cluster->list[i].s_addr == originator.s_addr)
107 return 1;
108 return 0;
109}
110
94f2b392 111static unsigned int
718e3744 112cluster_hash_key_make (struct cluster_list *cluster)
113{
114 unsigned int key = 0;
115 int length;
116 caddr_t pnt;
117
118 length = cluster->length;
119 pnt = (caddr_t) cluster->list;
120
121 while (length)
122 key += pnt[--length];
123
124 return key;
125}
126
94f2b392 127static int
718e3744 128cluster_hash_cmp (struct cluster_list *cluster1, struct cluster_list *cluster2)
129{
130 if (cluster1->length == cluster2->length &&
131 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0)
132 return 1;
133 return 0;
134}
135
94f2b392 136static void
718e3744 137cluster_free (struct cluster_list *cluster)
138{
139 if (cluster->list)
140 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
141 XFREE (MTYPE_CLUSTER, cluster);
142}
143
94f2b392 144static struct cluster_list *
718e3744 145cluster_dup (struct cluster_list *cluster)
146{
147 struct cluster_list *new;
148
149 new = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
150 memset (new, 0, sizeof (struct cluster_list));
151 new->length = cluster->length;
152
153 if (cluster->length)
154 {
155 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
156 memcpy (new->list, cluster->list, cluster->length);
157 }
158 else
159 new->list = NULL;
160
161 return new;
162}
163
94f2b392 164static struct cluster_list *
718e3744 165cluster_intern (struct cluster_list *cluster)
166{
167 struct cluster_list *find;
168
169 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
170 find->refcnt++;
171
172 return find;
173}
174
175void
176cluster_unintern (struct cluster_list *cluster)
177{
178 struct cluster_list *ret;
179
180 if (cluster->refcnt)
181 cluster->refcnt--;
182
183 if (cluster->refcnt == 0)
184 {
185 ret = hash_release (cluster_hash, cluster);
186 cluster_free (cluster);
187 }
188}
189
94f2b392 190static void
191cluster_init (void)
718e3744 192{
193 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
194}
195\f
196/* Unknown transit attribute. */
197struct hash *transit_hash;
198
94f2b392 199static void
718e3744 200transit_free (struct transit *transit)
201{
202 if (transit->val)
203 XFREE (MTYPE_TRANSIT_VAL, transit->val);
204 XFREE (MTYPE_TRANSIT, transit);
205}
206
94f2b392 207static void *
718e3744 208transit_hash_alloc (struct transit *transit)
209{
210 /* Transit structure is already allocated. */
211 return transit;
212}
213
94f2b392 214static struct transit *
718e3744 215transit_intern (struct transit *transit)
216{
217 struct transit *find;
218
219 find = hash_get (transit_hash, transit, transit_hash_alloc);
220 if (find != transit)
221 transit_free (transit);
222 find->refcnt++;
223
224 return find;
225}
226
227void
228transit_unintern (struct transit *transit)
229{
230 struct transit *ret;
231
232 if (transit->refcnt)
233 transit->refcnt--;
234
235 if (transit->refcnt == 0)
236 {
237 ret = hash_release (transit_hash, transit);
238 transit_free (transit);
239 }
240}
241
94f2b392 242static unsigned int
718e3744 243transit_hash_key_make (struct transit *transit)
244{
245 unsigned int key = 0;
246 int length;
247 caddr_t pnt;
248
249 length = transit->length;
250 pnt = (caddr_t) transit->val;
251
252 while (length)
253 key += pnt[--length];
254
255 return key;
256}
257
94f2b392 258static int
718e3744 259transit_hash_cmp (struct transit *transit1, struct transit *transit2)
260{
261 if (transit1->length == transit2->length &&
262 memcmp (transit1->val, transit2->val, transit1->length) == 0)
263 return 1;
264 return 0;
265}
266
94f2b392 267static void
718e3744 268transit_init ()
269{
270 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
271}
272\f
273/* Attribute hash routines. */
274
275struct hash *attrhash;
276
277unsigned int
278attrhash_key_make (struct attr *attr)
279{
280 unsigned int key = 0;
281
282 key += attr->origin;
283 key += attr->nexthop.s_addr;
284 key += attr->med;
285 key += attr->local_pref;
286 key += attr->aggregator_as;
287 key += attr->aggregator_addr.s_addr;
288 key += attr->weight;
289
290 key += attr->mp_nexthop_global_in.s_addr;
291 if (attr->aspath)
292 key += aspath_key_make (attr->aspath);
293 if (attr->community)
294 key += community_hash_make (attr->community);
295 if (attr->ecommunity)
296 key += ecommunity_hash_make (attr->ecommunity);
297 if (attr->cluster)
298 key += cluster_hash_key_make (attr->cluster);
299 if (attr->transit)
300 key += transit_hash_key_make (attr->transit);
301
302#ifdef HAVE_IPV6
303 {
304 int i;
305
306 key += attr->mp_nexthop_len;
307 for (i = 0; i < 16; i++)
308 key += attr->mp_nexthop_global.s6_addr[i];
309 for (i = 0; i < 16; i++)
310 key += attr->mp_nexthop_local.s6_addr[i];
311 }
312#endif /* HAVE_IPV6 */
313
314 return key;
315}
316
317int
318attrhash_cmp (struct attr *attr1, struct attr *attr2)
319{
320 if (attr1->flag == attr2->flag
321 && attr1->origin == attr2->origin
322 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
323 && attr1->med == attr2->med
324 && attr1->local_pref == attr2->local_pref
325 && attr1->aggregator_as == attr2->aggregator_as
326 && attr1->aggregator_addr.s_addr == attr2->aggregator_addr.s_addr
327 && attr1->weight == attr2->weight
328#ifdef HAVE_IPV6
329 && attr1->mp_nexthop_len == attr2->mp_nexthop_len
330 && IPV6_ADDR_SAME (&attr1->mp_nexthop_global, &attr2->mp_nexthop_global)
331 && IPV6_ADDR_SAME (&attr1->mp_nexthop_local, &attr2->mp_nexthop_local)
332#endif /* HAVE_IPV6 */
333 && IPV4_ADDR_SAME (&attr1->mp_nexthop_global_in, &attr2->mp_nexthop_global_in)
334 && attr1->aspath == attr2->aspath
335 && attr1->community == attr2->community
336 && attr1->ecommunity == attr2->ecommunity
337 && attr1->cluster == attr2->cluster
338 && attr1->transit == attr2->transit)
339 return 1;
340 else
341 return 0;
342}
343
94f2b392 344static void
718e3744 345attrhash_init ()
346{
347 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
348}
349
94f2b392 350static void
718e3744 351attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
352{
353 struct attr *attr = backet->data;
354
355 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
356 inet_ntoa (attr->nexthop), VTY_NEWLINE);
357}
358
359void
360attr_show_all (struct vty *vty)
361{
362 hash_iterate (attrhash,
363 (void (*)(struct hash_backet *, void *))
364 attr_show_all_iterator,
365 vty);
366}
367
94f2b392 368static void *
718e3744 369bgp_attr_hash_alloc (struct attr *val)
370{
371 struct attr *attr;
372
373 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
374 *attr = *val;
375 attr->refcnt = 0;
376 return attr;
377}
378
379/* Internet argument attribute. */
380struct attr *
381bgp_attr_intern (struct attr *attr)
382{
383 struct attr *find;
384
385 /* Intern referenced strucutre. */
386 if (attr->aspath)
387 {
388 if (! attr->aspath->refcnt)
389 attr->aspath = aspath_intern (attr->aspath);
390 else
391 attr->aspath->refcnt++;
392 }
393 if (attr->community)
394 {
395 if (! attr->community->refcnt)
396 attr->community = community_intern (attr->community);
397 else
398 attr->community->refcnt++;
399 }
400 if (attr->ecommunity)
401 {
402 if (! attr->ecommunity->refcnt)
403 attr->ecommunity = ecommunity_intern (attr->ecommunity);
404 else
405 attr->ecommunity->refcnt++;
406 }
407 if (attr->cluster)
408 {
409 if (! attr->cluster->refcnt)
410 attr->cluster = cluster_intern (attr->cluster);
411 else
412 attr->cluster->refcnt++;
413 }
414 if (attr->transit)
415 {
416 if (! attr->transit->refcnt)
417 attr->transit = transit_intern (attr->transit);
418 else
419 attr->transit->refcnt++;
420 }
421
422 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
423 find->refcnt++;
424
425 return find;
426}
427
428/* Make network statement's attribute. */
429struct attr *
430bgp_attr_default_set (struct attr *attr, u_char origin)
431{
432 memset (attr, 0, sizeof (struct attr));
433
434 attr->origin = origin;
435 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
436 attr->aspath = aspath_empty ();
437 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
438 attr->weight = 32768;
439 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
440#ifdef HAVE_IPV6
441 attr->mp_nexthop_len = 16;
442#endif
443 return attr;
444}
445
446/* Make network statement's attribute. */
447struct attr *
448bgp_attr_default_intern (u_char origin)
449{
450 struct attr attr;
451 struct attr *new;
452
453 memset (&attr, 0, sizeof (struct attr));
454
455 attr.origin = origin;
456 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
457 attr.aspath = aspath_empty ();
458 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
459 attr.weight = 32768;
460 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
461#ifdef HAVE_IPV6
462 attr.mp_nexthop_len = 16;
463#endif
464
465 new = bgp_attr_intern (&attr);
466 aspath_unintern (new->aspath);
467 return new;
468}
469
470struct attr *
471bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
472 struct aspath *aspath,
473 struct community *community, int as_set)
474{
475 struct attr attr;
476 struct attr *new;
477
478 memset (&attr, 0, sizeof (struct attr));
479
480 /* Origin attribute. */
481 attr.origin = origin;
482 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
483
484 /* AS path attribute. */
485 if (aspath)
486 attr.aspath = aspath_intern (aspath);
487 else
488 attr.aspath = aspath_empty ();
489 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
490
491 /* Next hop attribute. */
492 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
493
494 if (community)
495 {
496 attr.community = community;
497 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
498 }
499
500 attr.weight = 32768;
501#ifdef HAVE_IPV6
502 attr.mp_nexthop_len = 16;
503#endif
504 if (! as_set)
505 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
506 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
507 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
508 attr.aggregator_as = bgp->confed_id;
509 else
510 attr.aggregator_as = bgp->as;
511 attr.aggregator_addr = bgp->router_id;
512
513 new = bgp_attr_intern (&attr);
514 aspath_unintern (new->aspath);
515 return new;
516}
517
518/* Free bgp attribute and aspath. */
519void
520bgp_attr_unintern (struct attr *attr)
521{
522 struct attr *ret;
523 struct aspath *aspath;
524 struct community *community;
525 struct ecommunity *ecommunity;
526 struct cluster_list *cluster;
527 struct transit *transit;
528
529 /* Decrement attribute reference. */
530 attr->refcnt--;
531 aspath = attr->aspath;
532 community = attr->community;
533 ecommunity = attr->ecommunity;
534 cluster = attr->cluster;
535 transit = attr->transit;
536
537 /* If reference becomes zero then free attribute object. */
538 if (attr->refcnt == 0)
539 {
540 ret = hash_release (attrhash, attr);
541 assert (ret != NULL);
542 XFREE (MTYPE_ATTR, attr);
543 }
544
545 /* aspath refcount shoud be decrement. */
546 if (aspath)
547 aspath_unintern (aspath);
548 if (community)
549 community_unintern (community);
550 if (ecommunity)
551 ecommunity_unintern (ecommunity);
552 if (cluster)
553 cluster_unintern (cluster);
554 if (transit)
555 transit_unintern (transit);
556}
557
558void
559bgp_attr_flush (struct attr *attr)
560{
561 if (attr->aspath && ! attr->aspath->refcnt)
562 aspath_free (attr->aspath);
563 if (attr->community && ! attr->community->refcnt)
564 community_free (attr->community);
565 if (attr->ecommunity && ! attr->ecommunity->refcnt)
566 ecommunity_free (attr->ecommunity);
567 if (attr->cluster && ! attr->cluster->refcnt)
568 cluster_free (attr->cluster);
569 if (attr->transit && ! attr->transit->refcnt)
570 transit_free (attr->transit);
571}
572
573/* Get origin attribute of the update message. */
94f2b392 574static int
718e3744 575bgp_attr_origin (struct peer *peer, bgp_size_t length,
576 struct attr *attr, u_char flag, u_char *startp)
577{
578 bgp_size_t total;
579
580 /* total is entire attribute length include Attribute Flags (1),
581 Attribute Type code (1) and Attribute length (1 or 2). */
582 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
583
584 /* If any recognized attribute has Attribute Flags that conflict
585 with the Attribute Type Code, then the Error Subcode is set to
586 Attribute Flags Error. The Data field contains the erroneous
587 attribute (type, length and value). */
588 if (flag != BGP_ATTR_FLAG_TRANS)
589 {
590 zlog (peer->log, LOG_ERR,
591 "Origin attribute flag isn't transitive %d", flag);
592 bgp_notify_send_with_data (peer,
593 BGP_NOTIFY_UPDATE_ERR,
594 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
595 startp, total);
596 return -1;
597 }
598
599 /* If any recognized attribute has Attribute Length that conflicts
600 with the expected length (based on the attribute type code), then
601 the Error Subcode is set to Attribute Length Error. The Data
602 field contains the erroneous attribute (type, length and
603 value). */
604 if (length != 1)
605 {
606 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
607 length);
608 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
609 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
610 startp, total);
611 return -1;
612 }
613
614 /* Fetch origin attribute. */
615 attr->origin = stream_getc (BGP_INPUT (peer));
616
617 /* If the ORIGIN attribute has an undefined value, then the Error
618 Subcode is set to Invalid Origin Attribute. The Data field
619 contains the unrecognized attribute (type, length and value). */
620 if ((attr->origin != BGP_ORIGIN_IGP)
621 && (attr->origin != BGP_ORIGIN_EGP)
622 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
623 {
624 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
625 attr->origin);
626
627 bgp_notify_send_with_data (peer,
628 BGP_NOTIFY_UPDATE_ERR,
629 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
630 startp, total);
631 return -1;
632 }
633
634 /* Set oring attribute flag. */
635 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
636
637 return 0;
638}
639
640/* Parse AS path information. This function is wrapper of
641 aspath_parse. */
94f2b392 642static int
718e3744 643bgp_attr_aspath (struct peer *peer, bgp_size_t length,
644 struct attr *attr, u_char flag, u_char *startp)
645{
646 struct bgp *bgp;
647 struct aspath *aspath;
648 bgp_size_t total;
649
650 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
651
652 /* Flag check. */
653 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
654 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
655 {
656 zlog (peer->log, LOG_ERR,
657 "Origin attribute flag isn't transitive %d", flag);
658 bgp_notify_send_with_data (peer,
659 BGP_NOTIFY_UPDATE_ERR,
660 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
661 startp, total);
662 return -1;
663 }
664
665 /* In case of IBGP, length will be zero. */
666 attr->aspath = aspath_parse (stream_pnt (peer->ibuf), length);
667 if (! attr->aspath)
668 {
669 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
670 bgp_notify_send (peer,
671 BGP_NOTIFY_UPDATE_ERR,
672 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
673 return -1;
674 }
675
676 bgp = peer->bgp;
677
678 /* First AS check for EBGP. */
679 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
680 {
681 if (peer_sort (peer) == BGP_PEER_EBGP
682 && ! aspath_firstas_check (attr->aspath, peer->as))
683 {
684 zlog (peer->log, LOG_ERR,
685 "%s incorrect first AS (must be %d)", peer->host, peer->as);
686 bgp_notify_send (peer,
687 BGP_NOTIFY_UPDATE_ERR,
688 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
689 return -1;
690 }
691 }
692
693 /* local-as prepend */
694 if (peer->change_local_as &&
695 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
696 {
697 aspath = aspath_dup (attr->aspath);
698 aspath = aspath_add_seq (aspath, peer->change_local_as);
699 aspath_unintern (attr->aspath);
700 attr->aspath = aspath_intern (aspath);
701 }
702
703 /* Forward pointer. */
9985f83c 704 stream_forward_getp (peer->ibuf, length);
718e3744 705
706 /* Set aspath attribute flag. */
707 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
708
709 return 0;
710}
711
712/* Nexthop attribute. */
94f2b392 713static int
718e3744 714bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
715 struct attr *attr, u_char flag, u_char *startp)
716{
717 bgp_size_t total;
718
719 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
720
721 /* Flag check. */
722 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
723 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
724 {
725 zlog (peer->log, LOG_ERR,
726 "Origin attribute flag isn't transitive %d", flag);
727 bgp_notify_send_with_data (peer,
728 BGP_NOTIFY_UPDATE_ERR,
729 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
730 startp, total);
731 return -1;
732 }
733
734 /* Check nexthop attribute length. */
735 if (length != 4)
736 {
737 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
738 length);
739
740 bgp_notify_send_with_data (peer,
741 BGP_NOTIFY_UPDATE_ERR,
742 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
743 startp, total);
744 return -1;
745 }
746
747 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
748 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
749
750 return 0;
751}
752
753/* MED atrribute. */
94f2b392 754static int
718e3744 755bgp_attr_med (struct peer *peer, bgp_size_t length,
756 struct attr *attr, u_char flag, u_char *startp)
757{
758 bgp_size_t total;
759
760 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
761
762 /* Length check. */
763 if (length != 4)
764 {
765 zlog (peer->log, LOG_ERR,
766 "MED attribute length isn't four [%d]", length);
767
768 bgp_notify_send_with_data (peer,
769 BGP_NOTIFY_UPDATE_ERR,
770 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
771 startp, total);
772 return -1;
773 }
774
775 attr->med = stream_getl (peer->ibuf);
776
777 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
778
779 return 0;
780}
781
782/* Local preference attribute. */
94f2b392 783static int
718e3744 784bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
785 struct attr *attr, u_char flag)
786{
787 /* If it is contained in an UPDATE message that is received from an
788 external peer, then this attribute MUST be ignored by the
789 receiving speaker. */
790 if (peer_sort (peer) == BGP_PEER_EBGP)
791 {
9985f83c 792 stream_forward_getp (peer->ibuf, length);
718e3744 793 return 0;
794 }
795
796 if (length == 4)
797 attr->local_pref = stream_getl (peer->ibuf);
798 else
799 attr->local_pref = 0;
800
801 /* Set atomic aggregate flag. */
802 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
803
804 return 0;
805}
806
807/* Atomic aggregate. */
94f2b392 808static int
718e3744 809bgp_attr_atomic (struct peer *peer, bgp_size_t length,
810 struct attr *attr, u_char flag)
811{
812 if (length != 0)
813 {
814 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
815
816 bgp_notify_send (peer,
817 BGP_NOTIFY_UPDATE_ERR,
818 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
819 return -1;
820 }
821
822 /* Set atomic aggregate flag. */
823 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
824
825 return 0;
826}
827
828/* Aggregator attribute */
94f2b392 829static int
718e3744 830bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
831 struct attr *attr, u_char flag)
832{
833 if (length != 6)
834 {
835 zlog (peer->log, LOG_ERR, "Aggregator length is not 6 [%d]", length);
836
837 bgp_notify_send (peer,
838 BGP_NOTIFY_UPDATE_ERR,
839 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
840 return -1;
841 }
842 attr->aggregator_as = stream_getw (peer->ibuf);
843 attr->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
844
845 /* Set atomic aggregate flag. */
846 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
847
848 return 0;
849}
850
851/* Community attribute. */
94f2b392 852static int
718e3744 853bgp_attr_community (struct peer *peer, bgp_size_t length,
854 struct attr *attr, u_char flag)
855{
856 if (length == 0)
857 attr->community = NULL;
858 else
859 {
5228ad27 860 attr->community =
861 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
9985f83c 862 stream_forward_getp (peer->ibuf, length);
718e3744 863 }
864
865 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
866
867 return 0;
868}
869
870/* Originator ID attribute. */
94f2b392 871static int
718e3744 872bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
873 struct attr *attr, u_char flag)
874{
875 if (length != 4)
876 {
877 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
878
879 bgp_notify_send (peer,
880 BGP_NOTIFY_UPDATE_ERR,
881 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
882 return -1;
883 }
884
885 attr->originator_id.s_addr = stream_get_ipv4 (peer->ibuf);
886
887 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
888
889 return 0;
890}
891
892/* Cluster list attribute. */
94f2b392 893static int
718e3744 894bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
895 struct attr *attr, u_char flag)
896{
897 /* Check length. */
898 if (length % 4)
899 {
900 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
901
902 bgp_notify_send (peer,
903 BGP_NOTIFY_UPDATE_ERR,
904 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
905 return -1;
906 }
907
5228ad27 908 attr->cluster = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf),
909 length);
718e3744 910
9985f83c 911 stream_forward_getp (peer->ibuf, length);;
718e3744 912
913 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
914
915 return 0;
916}
917
918/* Multiprotocol reachability information parse. */
94f2b392 919static int
718e3744 920bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
921 struct bgp_nlri *mp_update)
922{
923 u_int16_t afi;
924 u_char safi;
925 u_char snpa_num;
926 u_char snpa_len;
927 u_char *lim;
928 bgp_size_t nlri_len;
929 int ret;
930 struct stream *s;
931
932 /* Set end of packet. */
933 s = peer->ibuf;
934 lim = stream_pnt (s) + length;
935
936 /* Load AFI, SAFI. */
937 afi = stream_getw (s);
938 safi = stream_getc (s);
939
940 /* Get nexthop length. */
941 attr->mp_nexthop_len = stream_getc (s);
942
943 /* Nexthop length check. */
944 switch (attr->mp_nexthop_len)
945 {
946 case 4:
947 stream_get (&attr->mp_nexthop_global_in, s, 4);
948 break;
949 case 12:
950 {
951 u_int32_t rd_high;
952 u_int32_t rd_low;
953
954 rd_high = stream_getl (s);
955 rd_low = stream_getl (s);
956 stream_get (&attr->mp_nexthop_global_in, s, 4);
957 }
958 break;
959#ifdef HAVE_IPV6
960 case 16:
961 stream_get (&attr->mp_nexthop_global, s, 16);
962 break;
963 case 32:
964 stream_get (&attr->mp_nexthop_global, s, 16);
965 stream_get (&attr->mp_nexthop_local, s, 16);
966 if (! IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local))
967 {
968 char buf1[INET6_ADDRSTRLEN];
969 char buf2[INET6_ADDRSTRLEN];
970
971 if (BGP_DEBUG (update, UPDATE_IN))
557865c2 972 zlog_debug ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host,
718e3744 973 inet_ntop (AF_INET6, &attr->mp_nexthop_global,
974 buf1, INET6_ADDRSTRLEN),
975 inet_ntop (AF_INET6, &attr->mp_nexthop_local,
976 buf2, INET6_ADDRSTRLEN));
977
978 attr->mp_nexthop_len = 16;
979 }
980 break;
981#endif /* HAVE_IPV6 */
982 default:
983 zlog_info ("Wrong multiprotocol next hop length: %d",
984 attr->mp_nexthop_len);
985 return -1;
986 break;
987 }
988
989 snpa_num = stream_getc (s);
990
991 while (snpa_num--)
992 {
993 snpa_len = stream_getc (s);
9985f83c 994 stream_forward_getp (s, (snpa_len + 1) >> 1);
718e3744 995 }
996
718e3744 997 nlri_len = lim - stream_pnt (s);
998
999 if (safi != BGP_SAFI_VPNV4)
1000 {
1001 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
1002 if (ret < 0)
1003 return -1;
1004 }
1005
1006 mp_update->afi = afi;
1007 mp_update->safi = safi;
1008 mp_update->nlri = stream_pnt (s);
1009 mp_update->length = nlri_len;
1010
9985f83c 1011 stream_forward_getp (s, nlri_len);
718e3744 1012
1013 return 0;
1014}
1015
1016/* Multiprotocol unreachable parse */
94f2b392 1017static int
718e3744 1018bgp_mp_unreach_parse (struct peer *peer, int length,
1019 struct bgp_nlri *mp_withdraw)
1020{
1021 struct stream *s;
1022 u_int16_t afi;
1023 u_char safi;
1024 u_char *lim;
1025 u_int16_t withdraw_len;
1026 int ret;
1027
1028 s = peer->ibuf;
1029 lim = stream_pnt (s) + length;
1030
1031 afi = stream_getw (s);
1032 safi = stream_getc (s);
1033
1034 withdraw_len = lim - stream_pnt (s);
1035
1036 if (safi != BGP_SAFI_VPNV4)
1037 {
1038 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1039 if (ret < 0)
1040 return -1;
1041 }
1042
1043 mp_withdraw->afi = afi;
1044 mp_withdraw->safi = safi;
1045 mp_withdraw->nlri = stream_pnt (s);
1046 mp_withdraw->length = withdraw_len;
1047
9985f83c 1048 stream_forward_getp (s, withdraw_len);
718e3744 1049
1050 return 0;
1051}
1052
1053/* Extended Community attribute. */
94f2b392 1054static int
718e3744 1055bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1056 struct attr *attr, u_char flag)
1057{
1058 if (length == 0)
1059 attr->ecommunity = NULL;
1060 else
1061 {
5228ad27 1062 attr->ecommunity =
1063 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
9985f83c 1064 stream_forward_getp (peer->ibuf, length);
718e3744 1065 }
1066 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1067
1068 return 0;
1069}
1070
1071/* BGP unknown attribute treatment. */
94f2b392 1072static int
718e3744 1073bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1074 u_char type, bgp_size_t length, u_char *startp)
1075{
1076 bgp_size_t total;
1077 struct transit *transit;
1078
f418446b 1079 if (BGP_DEBUG (normal, NORMAL))
1080 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1081 peer->host, type, length);
1082
718e3744 1083 if (BGP_DEBUG (events, EVENTS))
557865c2 1084 zlog (peer->log, LOG_DEBUG,
718e3744 1085 "Unknown attribute type %d length %d is received", type, length);
1086
1087 /* Forward read pointer of input stream. */
9985f83c 1088 stream_forward_getp (peer->ibuf, length);
718e3744 1089
1090 /* Adjest total length to include type and length. */
1091 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1092
1093 /* If any of the mandatory well-known attributes are not recognized,
1094 then the Error Subcode is set to Unrecognized Well-known
1095 Attribute. The Data field contains the unrecognized attribute
1096 (type, length and value). */
1097 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1098 {
1099 /* Adjust startp to do not include flag value. */
1100 bgp_notify_send_with_data (peer,
1101 BGP_NOTIFY_UPDATE_ERR,
1102 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1103 startp, total);
1104 return -1;
1105 }
1106
1107 /* Unrecognized non-transitive optional attributes must be quietly
1108 ignored and not passed along to other BGP peers. */
1109 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1110 return 0;
1111
1112 /* If a path with recognized transitive optional attribute is
1113 accepted and passed along to other BGP peers and the Partial bit
1114 in the Attribute Flags octet is set to 1 by some previous AS, it
1115 is not set back to 0 by the current AS. */
1116 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1117
1118 /* Store transitive attribute to the end of attr->transit. */
1119 if (! attr->transit)
1120 {
1121 attr->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit));
1122 memset (attr->transit, 0, sizeof (struct transit));
1123 }
1124
1125 transit = attr->transit;
1126
1127 if (transit->val)
1128 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1129 transit->length + total);
1130 else
1131 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1132
1133 memcpy (transit->val + transit->length, startp, total);
1134 transit->length += total;
1135
1136 return 0;
1137}
1138
1139/* Read attribute of update packet. This function is called from
1140 bgp_update() in bgpd.c. */
1141int
1142bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1143 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1144{
1145 int ret;
1146 u_char flag;
1147 u_char type;
1148 bgp_size_t length;
1149 u_char *startp, *endp;
1150 u_char *attr_endp;
1151 u_char seen[BGP_ATTR_BITMAP_SIZE];
1152
1153 /* Initialize bitmap. */
1154 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1155
1156 /* End pointer of BGP attribute. */
1157 endp = BGP_INPUT_PNT (peer) + size;
1158
1159 /* Get attributes to the end of attribute length. */
1160 while (BGP_INPUT_PNT (peer) < endp)
1161 {
1162 /* Check remaining length check.*/
1163 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1164 {
c29fdba7 1165 /* XXX warning: long int format, int arg (arg 5) */
718e3744 1166 zlog (peer->log, LOG_WARNING,
a2b1ecd2 1167 "%s error BGP attribute length %ld is smaller than min len",
718e3744 1168 peer->host, endp - STREAM_PNT (BGP_INPUT (peer)));
1169
1170 bgp_notify_send (peer,
1171 BGP_NOTIFY_UPDATE_ERR,
1172 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1173 return -1;
1174 }
1175
1176 /* Fetch attribute flag and type. */
1177 startp = BGP_INPUT_PNT (peer);
1178 flag = stream_getc (BGP_INPUT (peer));
1179 type = stream_getc (BGP_INPUT (peer));
1180
1181 /* Check extended attribue length bit. */
1182 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1183 length = stream_getw (BGP_INPUT (peer));
1184 else
1185 length = stream_getc (BGP_INPUT (peer));
1186
1187 /* If any attribute appears more than once in the UPDATE
1188 message, then the Error Subcode is set to Malformed Attribute
1189 List. */
1190
1191 if (CHECK_BITMAP (seen, type))
1192 {
1193 zlog (peer->log, LOG_WARNING,
1194 "%s error BGP attribute type %d appears twice in a message",
1195 peer->host, type);
1196
1197 bgp_notify_send (peer,
1198 BGP_NOTIFY_UPDATE_ERR,
1199 BGP_NOTIFY_UPDATE_MAL_ATTR);
1200 return -1;
1201 }
1202
1203 /* Set type to bitmap to check duplicate attribute. `type' is
1204 unsigned char so it never overflow bitmap range. */
1205
1206 SET_BITMAP (seen, type);
1207
1208 /* Overflow check. */
1209 attr_endp = BGP_INPUT_PNT (peer) + length;
1210
1211 if (attr_endp > endp)
1212 {
1213 zlog (peer->log, LOG_WARNING,
1214 "%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);
1215 bgp_notify_send (peer,
1216 BGP_NOTIFY_UPDATE_ERR,
1217 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1218 return -1;
1219 }
1220
1221 /* OK check attribute and store it's value. */
1222 switch (type)
1223 {
1224 case BGP_ATTR_ORIGIN:
1225 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1226 break;
1227 case BGP_ATTR_AS_PATH:
1228 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
1229 break;
1230 case BGP_ATTR_NEXT_HOP:
1231 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1232 break;
1233 case BGP_ATTR_MULTI_EXIT_DISC:
1234 ret = bgp_attr_med (peer, length, attr, flag, startp);
1235 break;
1236 case BGP_ATTR_LOCAL_PREF:
1237 ret = bgp_attr_local_pref (peer, length, attr, flag);
1238 break;
1239 case BGP_ATTR_ATOMIC_AGGREGATE:
1240 ret = bgp_attr_atomic (peer, length, attr, flag);
1241 break;
1242 case BGP_ATTR_AGGREGATOR:
1243 ret = bgp_attr_aggregator (peer, length, attr, flag);
1244 break;
1245 case BGP_ATTR_COMMUNITIES:
1246 ret = bgp_attr_community (peer, length, attr, flag);
1247 break;
1248 case BGP_ATTR_ORIGINATOR_ID:
1249 ret = bgp_attr_originator_id (peer, length, attr, flag);
1250 break;
1251 case BGP_ATTR_CLUSTER_LIST:
1252 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1253 break;
1254 case BGP_ATTR_MP_REACH_NLRI:
1255 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1256 break;
1257 case BGP_ATTR_MP_UNREACH_NLRI:
1258 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1259 break;
1260 case BGP_ATTR_EXT_COMMUNITIES:
1261 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1262 break;
1263 default:
1264 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1265 break;
1266 }
1267
1268 /* If error occured immediately return to the caller. */
1269 if (ret < 0)
1270 return ret;
1271
1272 /* Check the fetched length. */
1273 if (BGP_INPUT_PNT (peer) != attr_endp)
1274 {
1275 zlog (peer->log, LOG_WARNING,
1276 "%s BGP attribute fetch error", peer->host);
1277 bgp_notify_send (peer,
1278 BGP_NOTIFY_UPDATE_ERR,
1279 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1280 return -1;
1281 }
1282 }
1283
1284 /* Check final read pointer is same as end pointer. */
1285 if (BGP_INPUT_PNT (peer) != endp)
1286 {
1287 zlog (peer->log, LOG_WARNING,
1288 "%s BGP attribute length mismatch", peer->host);
1289 bgp_notify_send (peer,
1290 BGP_NOTIFY_UPDATE_ERR,
1291 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1292 return -1;
1293 }
1294
1295 /* Finally intern unknown attribute. */
1296 if (attr->transit)
1297 attr->transit = transit_intern (attr->transit);
1298
1299 return 0;
1300}
1301
1302/* Well-known attribute check. */
1303int
1304bgp_attr_check (struct peer *peer, struct attr *attr)
1305{
1306 u_char type = 0;
1307
1308 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1309 type = BGP_ATTR_ORIGIN;
1310
1311 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1312 type = BGP_ATTR_AS_PATH;
1313
1314 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1315 type = BGP_ATTR_NEXT_HOP;
1316
1317 if (peer_sort (peer) == BGP_PEER_IBGP
1318 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1319 type = BGP_ATTR_LOCAL_PREF;
1320
1321 if (type)
1322 {
1323 zlog (peer->log, LOG_WARNING,
1324 "%s Missing well-known attribute %d.",
1325 peer->host, type);
1326 bgp_notify_send_with_data (peer,
1327 BGP_NOTIFY_UPDATE_ERR,
1328 BGP_NOTIFY_UPDATE_MISS_ATTR,
1329 &type, 1);
1330 return -1;
1331 }
1332 return 0;
1333}
1334\f
1335int stream_put_prefix (struct stream *, struct prefix *);
1336
1337/* Make attribute packet. */
1338bgp_size_t
1339bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1340 struct stream *s, struct attr *attr, struct prefix *p,
1341 afi_t afi, safi_t safi, struct peer *from,
5228ad27 1342 struct prefix_rd *prd, char *tag)
718e3744 1343{
1344 unsigned long cp;
1345 struct aspath *aspath;
1346
1347 if (! bgp)
1348 bgp = bgp_get_default ();
1349
1350 /* Remember current pointer. */
9985f83c 1351 cp = stream_get_endp (s);
718e3744 1352
1353 /* Origin attribute. */
1354 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1355 stream_putc (s, BGP_ATTR_ORIGIN);
1356 stream_putc (s, 1);
1357 stream_putc (s, attr->origin);
1358
1359 /* AS path attribute. */
1360
1361 /* If remote-peer is EBGP */
1362 if (peer_sort (peer) == BGP_PEER_EBGP
1363 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
1364 || attr->aspath->length == 0)
fee0f4c6 1365 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
718e3744 1366 {
1367 aspath = aspath_dup (attr->aspath);
1368
1369 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1370 {
1371 /* Strip the confed info, and then stuff our path CONFED_ID
1372 on the front */
1373 aspath = aspath_delete_confed_seq (aspath);
1374 aspath = aspath_add_seq (aspath, bgp->confed_id);
1375 }
1376 else
1377 {
1378 aspath = aspath_add_seq (aspath, peer->local_as);
1379 if (peer->change_local_as)
1380 aspath = aspath_add_seq (aspath, peer->change_local_as);
1381 }
1382 }
1383 else if (peer_sort (peer) == BGP_PEER_CONFED)
1384 {
1385 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1386 aspath = aspath_dup (attr->aspath);
1387 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1388 }
1389 else
1390 aspath = attr->aspath;
1391
1392 /* AS path attribute extended length bit check. */
1393 if (aspath->length > 255)
1394 {
1395 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1396 stream_putc (s, BGP_ATTR_AS_PATH);
1397 stream_putw (s, aspath->length);
1398 }
1399 else
1400 {
1401 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1402 stream_putc(s, BGP_ATTR_AS_PATH);
1403 stream_putc (s, aspath->length);
1404 }
1405 stream_put (s, aspath->data, aspath->length);
1406
1407 if (aspath != attr->aspath)
1408 aspath_free (aspath);
1409
1410 /* Nexthop attribute. */
1411 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1412 {
1413 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1414 stream_putc (s, BGP_ATTR_NEXT_HOP);
1415 stream_putc (s, 4);
1416 if (safi == SAFI_MPLS_VPN)
1417 {
1418 if (attr->nexthop.s_addr == 0)
1419 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1420 else
1421 stream_put_ipv4 (s, attr->nexthop.s_addr);
1422 }
1423 else
1424 stream_put_ipv4 (s, attr->nexthop.s_addr);
1425 }
1426
1427 /* MED attribute. */
1428 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1429 {
1430 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1431 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1432 stream_putc (s, 4);
1433 stream_putl (s, attr->med);
1434 }
1435
1436 /* Local preference. */
1437 if (peer_sort (peer) == BGP_PEER_IBGP ||
1438 peer_sort (peer) == BGP_PEER_CONFED)
1439 {
1440 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1441 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1442 stream_putc (s, 4);
1443 stream_putl (s, attr->local_pref);
1444 }
1445
1446 /* Atomic aggregate. */
1447 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1448 {
1449 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1450 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1451 stream_putc (s, 0);
1452 }
1453
1454 /* Aggregator. */
1455 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1456 {
1457 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1458 stream_putc (s, BGP_ATTR_AGGREGATOR);
1459 stream_putc (s, 6);
1460 stream_putw (s, attr->aggregator_as);
1461 stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
1462 }
1463
1464 /* Community attribute. */
1465 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1466 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1467 {
1468 if (attr->community->size * 4 > 255)
1469 {
1470 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1471 stream_putc (s, BGP_ATTR_COMMUNITIES);
1472 stream_putw (s, attr->community->size * 4);
1473 }
1474 else
1475 {
1476 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1477 stream_putc (s, BGP_ATTR_COMMUNITIES);
1478 stream_putc (s, attr->community->size * 4);
1479 }
1480 stream_put (s, attr->community->val, attr->community->size * 4);
1481 }
1482
1483 /* Route Reflector. */
1484 if (peer_sort (peer) == BGP_PEER_IBGP
1485 && from
1486 && peer_sort (from) == BGP_PEER_IBGP)
1487 {
1488 /* Originator ID. */
1489 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1490 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
1491 stream_putc (s, 4);
1492
1493 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
1494 stream_put_in_addr (s, &attr->originator_id);
1495 else
1496 {
1497 if (from)
1498 stream_put_in_addr (s, &from->remote_id);
1499 else
1500 stream_put_in_addr (s, &attr->originator_id);
1501 }
1502
1503 /* Cluster list. */
1504 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1505 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
1506
1507 if (attr->cluster)
1508 {
1509 stream_putc (s, attr->cluster->length + 4);
1510 /* If this peer configuration's parent BGP has cluster_id. */
1511 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1512 stream_put_in_addr (s, &bgp->cluster_id);
1513 else
1514 stream_put_in_addr (s, &bgp->router_id);
1515 stream_put (s, attr->cluster->list, attr->cluster->length);
1516 }
1517 else
1518 {
1519 stream_putc (s, 4);
1520 /* If this peer configuration's parent BGP has cluster_id. */
1521 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1522 stream_put_in_addr (s, &bgp->cluster_id);
1523 else
1524 stream_put_in_addr (s, &bgp->router_id);
1525 }
1526 }
1527
1528#ifdef HAVE_IPV6
1529 /* If p is IPv6 address put it into attribute. */
1530 if (p->family == AF_INET6)
1531 {
1532 unsigned long sizep;
718e3744 1533
1534 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1535 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
9985f83c 1536 sizep = stream_get_endp (s);
718e3744 1537 stream_putc (s, 0); /* Length of this attribute. */
1538 stream_putw (s, AFI_IP6); /* AFI */
1539 stream_putc (s, safi); /* SAFI */
1540
1541 stream_putc (s, attr->mp_nexthop_len);
1542
1543 if (attr->mp_nexthop_len == 16)
1544 stream_put (s, &attr->mp_nexthop_global, 16);
1545 else if (attr->mp_nexthop_len == 32)
1546 {
1547 stream_put (s, &attr->mp_nexthop_global, 16);
1548 stream_put (s, &attr->mp_nexthop_local, 16);
1549 }
1550
1551 /* SNPA */
1552 stream_putc (s, 0);
1553
718e3744 1554 /* Prefix write. */
1555 stream_put_prefix (s, p);
1556
1557 /* Set MP attribute length. */
9985f83c 1558 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
718e3744 1559 }
1560#endif /* HAVE_IPV6 */
1561
1562 if (p->family == AF_INET && safi == SAFI_MULTICAST)
1563 {
1564 unsigned long sizep;
718e3744 1565
1566 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1567 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
9985f83c 1568 sizep = stream_get_endp (s);
718e3744 1569 stream_putc (s, 0); /* Length of this attribute. */
1570 stream_putw (s, AFI_IP); /* AFI */
1571 stream_putc (s, SAFI_MULTICAST); /* SAFI */
1572
1573 stream_putc (s, 4);
1574 stream_put_ipv4 (s, attr->nexthop.s_addr);
1575
1576 /* SNPA */
1577 stream_putc (s, 0);
1578
718e3744 1579 /* Prefix write. */
1580 stream_put_prefix (s, p);
1581
1582 /* Set MP attribute length. */
9985f83c 1583 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
718e3744 1584 }
1585
1586 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
1587 {
1588 unsigned long sizep;
718e3744 1589
1590 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1591 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
9985f83c 1592 sizep = stream_get_endp (s);
718e3744 1593 stream_putc (s, 0); /* Length of this attribute. */
1594 stream_putw (s, AFI_IP); /* AFI */
1595 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
1596
1597 stream_putc (s, 12);
1598 stream_putl (s, 0);
1599 stream_putl (s, 0);
1600 stream_put (s, &attr->mp_nexthop_global_in, 4);
1601
1602 /* SNPA */
1603 stream_putc (s, 0);
1604
718e3744 1605 /* Tag, RD, Prefix write. */
1606 stream_putc (s, p->prefixlen + 88);
1607 stream_put (s, tag, 3);
1608 stream_put (s, prd->val, 8);
1609 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
1610
1611 /* Set MP attribute length. */
9985f83c 1612 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
718e3744 1613 }
1614
1615 /* Extended Communities attribute. */
1616 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
1617 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
1618 {
4372df71 1619 if (peer_sort (peer) == BGP_PEER_IBGP || peer_sort (peer) == BGP_PEER_CONFED)
718e3744 1620 {
4372df71 1621 if (attr->ecommunity->size * 8 > 255)
1622 {
1623 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1624 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1625 stream_putw (s, attr->ecommunity->size * 8);
1626 }
1627 else
1628 {
1629 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1630 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1631 stream_putc (s, attr->ecommunity->size * 8);
1632 }
1633 stream_put (s, attr->ecommunity->val, attr->ecommunity->size * 8);
718e3744 1634 }
1635 else
1636 {
5228ad27 1637 u_int8_t *pnt;
4372df71 1638 int tbit;
1639 int ecom_tr_size = 0;
1640 int i;
1641
1642 for (i = 0; i < attr->ecommunity->size; i++)
1643 {
1644 pnt = attr->ecommunity->val + (i * 8);
1645 tbit = *pnt;
1646
1647 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
1648 continue;
1649
1650 ecom_tr_size++;
1651 }
1652
1653 if (ecom_tr_size)
1654 {
1655 if (ecom_tr_size * 8 > 255)
1656 {
1657 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1658 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1659 stream_putw (s, ecom_tr_size * 8);
1660 }
1661 else
1662 {
1663 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1664 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1665 stream_putc (s, ecom_tr_size * 8);
1666 }
1667
1668 for (i = 0; i < attr->ecommunity->size; i++)
1669 {
1670 pnt = attr->ecommunity->val + (i * 8);
1671 tbit = *pnt;
1672
1673 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
1674 continue;
1675
1676 stream_put (s, pnt, 8);
1677 }
1678 }
718e3744 1679 }
718e3744 1680 }
1681
1682 /* Unknown transit attribute. */
1683 if (attr->transit)
1684 stream_put (s, attr->transit->val, attr->transit->length);
1685
1686 /* Return total size of attribute. */
9985f83c 1687 return stream_get_endp (s) - cp;
718e3744 1688}
1689
1690bgp_size_t
1691bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
1692 afi_t afi, safi_t safi, struct prefix_rd *prd,
5228ad27 1693 char *tag)
718e3744 1694{
1695 unsigned long cp;
1696 unsigned long attrlen_pnt;
1697 bgp_size_t size;
1698
9985f83c 1699 cp = stream_get_endp (s);
718e3744 1700
1701 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1702 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
1703
9985f83c 1704 attrlen_pnt = stream_get_endp (s);
718e3744 1705 stream_putc (s, 0); /* Length of this attribute. */
1706
1707 stream_putw (s, family2afi (p->family));
1708
1709 if (safi == SAFI_MPLS_VPN)
1710 {
1711 /* SAFI */
1712 stream_putc (s, BGP_SAFI_VPNV4);
1713
1714 /* prefix. */
1715 stream_putc (s, p->prefixlen + 88);
1716 stream_put (s, tag, 3);
1717 stream_put (s, prd->val, 8);
1718 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
1719 }
1720 else
1721 {
1722 /* SAFI */
1723 stream_putc (s, safi);
1724
1725 /* prefix */
1726 stream_put_prefix (s, p);
1727 }
1728
1729 /* Set MP attribute length. */
9985f83c 1730 size = stream_get_endp (s) - attrlen_pnt - 1;
718e3744 1731 stream_putc_at (s, attrlen_pnt, size);
1732
9985f83c 1733 return stream_get_endp (s) - cp;
718e3744 1734}
1735
1736/* Initialization of attribute. */
1737void
1738bgp_attr_init ()
1739{
1740 void attrhash_init ();
1741
1742 aspath_init ();
1743 attrhash_init ();
1744 community_init ();
1745 ecommunity_init ();
1746 cluster_init ();
1747 transit_init ();
1748}
1749
1750/* Make attribute packet. */
1751void
a384592f 1752bgp_dump_routes_attr (struct stream *s, struct attr *attr,
1753 struct prefix *prefix)
718e3744 1754{
1755 unsigned long cp;
1756 unsigned long len;
1757 struct aspath *aspath;
1758
1759 /* Remember current pointer. */
9985f83c 1760 cp = stream_get_endp (s);
718e3744 1761
1762 /* Place holder of length. */
1763 stream_putw (s, 0);
1764
1765 /* Origin attribute. */
1766 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1767 stream_putc (s, BGP_ATTR_ORIGIN);
1768 stream_putc (s, 1);
1769 stream_putc (s, attr->origin);
1770
1771 aspath = attr->aspath;
1772
1773 if (aspath->length > 255)
1774 {
1775 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1776 stream_putc (s, BGP_ATTR_AS_PATH);
1777 stream_putw (s, aspath->length);
1778 }
1779 else
1780 {
1781 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1782 stream_putc (s, BGP_ATTR_AS_PATH);
1783 stream_putc (s, aspath->length);
1784 }
1785 stream_put (s, aspath->data, aspath->length);
1786
1787 /* Nexthop attribute. */
a384592f 1788 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
1789 if(prefix != NULL
1790#ifdef HAVE_IPV6
1791 && prefix->family != AF_INET6
1792#endif /* HAVE_IPV6 */
1793 )
1794 {
1795 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1796 stream_putc (s, BGP_ATTR_NEXT_HOP);
1797 stream_putc (s, 4);
1798 stream_put_ipv4 (s, attr->nexthop.s_addr);
1799 }
718e3744 1800
1801 /* MED attribute. */
1802 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1803 {
1804 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1805 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1806 stream_putc (s, 4);
1807 stream_putl (s, attr->med);
1808 }
1809
1810 /* Local preference. */
1811 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
1812 {
1813 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1814 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1815 stream_putc (s, 4);
1816 stream_putl (s, attr->local_pref);
1817 }
1818
1819 /* Atomic aggregate. */
1820 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1821 {
1822 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1823 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1824 stream_putc (s, 0);
1825 }
1826
1827 /* Aggregator. */
1828 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1829 {
1830 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1831 stream_putc (s, BGP_ATTR_AGGREGATOR);
1832 stream_putc (s, 6);
1833 stream_putw (s, attr->aggregator_as);
1834 stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
1835 }
1836
1837 /* Community attribute. */
1838 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
1839 {
1840 if (attr->community->size * 4 > 255)
1841 {
1842 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1843 stream_putc (s, BGP_ATTR_COMMUNITIES);
1844 stream_putw (s, attr->community->size * 4);
1845 }
1846 else
1847 {
1848 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1849 stream_putc (s, BGP_ATTR_COMMUNITIES);
1850 stream_putc (s, attr->community->size * 4);
1851 }
1852 stream_put (s, attr->community->val, attr->community->size * 4);
1853 }
1854
a384592f 1855#ifdef HAVE_IPV6
1856 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
1857 if(prefix != NULL && prefix->family == AF_INET6 &&
1858 (attr->mp_nexthop_len == 16 || attr->mp_nexthop_len == 32) )
1859 {
1860 int sizep;
1861
1862 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
1863 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
9985f83c 1864 sizep = stream_get_endp (s);
a384592f 1865
1866 /* MP header */
1867 stream_putc (s, 0); /* Length of this attribute. */
1868 stream_putw(s, AFI_IP6); /* AFI */
1869 stream_putc(s, SAFI_UNICAST); /* SAFI */
1870
1871 /* Next hop */
1872 stream_putc(s, attr->mp_nexthop_len);
1873 stream_put(s, &attr->mp_nexthop_global, 16);
1874 if(attr->mp_nexthop_len == 32)
1875 stream_put(s, &attr->mp_nexthop_local, 16);
1876
1877 /* SNPA */
1878 stream_putc(s, 0);
1879
1880 /* Prefix */
1881 stream_put_prefix(s, prefix);
1882
1883 /* Set MP attribute length. */
9985f83c 1884 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
a384592f 1885 }
1886#endif /* HAVE_IPV6 */
1887
718e3744 1888 /* Return total size of attribute. */
9985f83c 1889 len = stream_get_endp (s) - cp - 2;
718e3744 1890 stream_putw_at (s, cp, len);
1891}