1 /* BGP attributes management routines.
2 Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
4 This file is part of GNU Zebra.
6 GNU Zebra is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 GNU Zebra is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Zebra; see the file COPYING. If not, write to the Free
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
33 #include "bgpd/bgpd.h"
34 #include "bgpd/bgp_attr.h"
35 #include "bgpd/bgp_route.h"
36 #include "bgpd/bgp_aspath.h"
37 #include "bgpd/bgp_community.h"
38 #include "bgpd/bgp_debug.h"
39 #include "bgpd/bgp_packet.h"
40 #include "bgpd/bgp_ecommunity.h"
42 /* Attribute strings for logging. */
43 static const struct message attr_str
[] =
45 { BGP_ATTR_ORIGIN
, "ORIGIN" },
46 { BGP_ATTR_AS_PATH
, "AS_PATH" },
47 { BGP_ATTR_NEXT_HOP
, "NEXT_HOP" },
48 { BGP_ATTR_MULTI_EXIT_DISC
, "MULTI_EXIT_DISC" },
49 { BGP_ATTR_LOCAL_PREF
, "LOCAL_PREF" },
50 { BGP_ATTR_ATOMIC_AGGREGATE
, "ATOMIC_AGGREGATE" },
51 { BGP_ATTR_AGGREGATOR
, "AGGREGATOR" },
52 { BGP_ATTR_COMMUNITIES
, "COMMUNITY" },
53 { BGP_ATTR_ORIGINATOR_ID
, "ORIGINATOR_ID" },
54 { BGP_ATTR_CLUSTER_LIST
, "CLUSTER_LIST" },
55 { BGP_ATTR_DPA
, "DPA" },
56 { BGP_ATTR_ADVERTISER
, "ADVERTISER"} ,
57 { BGP_ATTR_RCID_PATH
, "RCID_PATH" },
58 { BGP_ATTR_MP_REACH_NLRI
, "MP_REACH_NLRI" },
59 { BGP_ATTR_MP_UNREACH_NLRI
, "MP_UNREACH_NLRI" },
60 { BGP_ATTR_EXT_COMMUNITIES
, "EXT_COMMUNITIES" },
61 { BGP_ATTR_AS4_PATH
, "AS4_PATH" },
62 { BGP_ATTR_AS4_AGGREGATOR
, "AS4_AGGREGATOR" },
63 { BGP_ATTR_AS_PATHLIMIT
, "AS_PATHLIMIT" },
65 static const int attr_str_max
= sizeof(attr_str
)/sizeof(attr_str
[0]);
67 static const struct message attr_flag_str
[] =
69 { BGP_ATTR_FLAG_OPTIONAL
, "Optional" },
70 { BGP_ATTR_FLAG_TRANS
, "Transitive" },
71 { BGP_ATTR_FLAG_PARTIAL
, "Partial" },
72 /* bgp_attr_flags_diagnose() relies on this bit being last in this list */
73 { BGP_ATTR_FLAG_EXTLEN
, "Extended Length" },
75 static const size_t attr_flag_str_max
=
76 sizeof (attr_flag_str
) / sizeof (attr_flag_str
[0]);
78 static struct hash
*cluster_hash
;
81 cluster_hash_alloc (void *p
)
83 struct cluster_list
* val
= (struct cluster_list
*) p
;
84 struct cluster_list
*cluster
;
86 cluster
= XMALLOC (MTYPE_CLUSTER
, sizeof (struct cluster_list
));
87 cluster
->length
= val
->length
;
91 cluster
->list
= XMALLOC (MTYPE_CLUSTER_VAL
, val
->length
);
92 memcpy (cluster
->list
, val
->list
, val
->length
);
102 /* Cluster list related functions. */
103 static struct cluster_list
*
104 cluster_parse (struct in_addr
* pnt
, int length
)
106 struct cluster_list tmp
;
107 struct cluster_list
*cluster
;
112 cluster
= hash_get (cluster_hash
, &tmp
, cluster_hash_alloc
);
118 cluster_loop_check (struct cluster_list
*cluster
, struct in_addr originator
)
122 for (i
= 0; i
< cluster
->length
/ 4; i
++)
123 if (cluster
->list
[i
].s_addr
== originator
.s_addr
)
129 cluster_hash_key_make (void *p
)
131 const struct cluster_list
*cluster
= p
;
133 return jhash(cluster
->list
, cluster
->length
, 0);
137 cluster_hash_cmp (const void *p1
, const void *p2
)
139 const struct cluster_list
* cluster1
= p1
;
140 const struct cluster_list
* cluster2
= p2
;
142 return (cluster1
->length
== cluster2
->length
&&
143 memcmp (cluster1
->list
, cluster2
->list
, cluster1
->length
) == 0);
147 cluster_free (struct cluster_list
*cluster
)
150 XFREE (MTYPE_CLUSTER_VAL
, cluster
->list
);
151 XFREE (MTYPE_CLUSTER
, cluster
);
155 static struct cluster_list
*
156 cluster_dup (struct cluster_list
*cluster
)
158 struct cluster_list
*new;
160 new = XCALLOC (MTYPE_CLUSTER
, sizeof (struct cluster_list
));
161 new->length
= cluster
->length
;
165 new->list
= XMALLOC (MTYPE_CLUSTER_VAL
, cluster
->length
);
166 memcpy (new->list
, cluster
->list
, cluster
->length
);
175 static struct cluster_list
*
176 cluster_intern (struct cluster_list
*cluster
)
178 struct cluster_list
*find
;
180 find
= hash_get (cluster_hash
, cluster
, cluster_hash_alloc
);
187 cluster_unintern (struct cluster_list
*cluster
)
192 if (cluster
->refcnt
== 0)
194 hash_release (cluster_hash
, cluster
);
195 cluster_free (cluster
);
202 cluster_hash
= hash_create (cluster_hash_key_make
, cluster_hash_cmp
);
206 cluster_finish (void)
208 hash_free (cluster_hash
);
212 /* Unknown transit attribute. */
213 static struct hash
*transit_hash
;
216 transit_free (struct transit
*transit
)
219 XFREE (MTYPE_TRANSIT_VAL
, transit
->val
);
220 XFREE (MTYPE_TRANSIT
, transit
);
225 transit_hash_alloc (void *p
)
227 /* Transit structure is already allocated. */
231 static struct transit
*
232 transit_intern (struct transit
*transit
)
234 struct transit
*find
;
236 find
= hash_get (transit_hash
, transit
, transit_hash_alloc
);
238 transit_free (transit
);
245 transit_unintern (struct transit
*transit
)
250 if (transit
->refcnt
== 0)
252 hash_release (transit_hash
, transit
);
253 transit_free (transit
);
258 transit_hash_key_make (void *p
)
260 const struct transit
* transit
= p
;
262 return jhash(transit
->val
, transit
->length
, 0);
266 transit_hash_cmp (const void *p1
, const void *p2
)
268 const struct transit
* transit1
= p1
;
269 const struct transit
* transit2
= p2
;
271 return (transit1
->length
== transit2
->length
&&
272 memcmp (transit1
->val
, transit2
->val
, transit1
->length
) == 0);
278 transit_hash
= hash_create (transit_hash_key_make
, transit_hash_cmp
);
282 transit_finish (void)
284 hash_free (transit_hash
);
288 /* Attribute hash routines. */
289 static struct hash
*attrhash
;
291 static struct attr_extra
*
292 bgp_attr_extra_new (void)
294 return XCALLOC (MTYPE_ATTR_EXTRA
, sizeof (struct attr_extra
));
298 bgp_attr_extra_free (struct attr
*attr
)
302 XFREE (MTYPE_ATTR_EXTRA
, attr
->extra
);
308 bgp_attr_extra_get (struct attr
*attr
)
311 attr
->extra
= bgp_attr_extra_new();
315 /* Shallow copy of an attribute
316 * Though, not so shallow that it doesn't copy the contents
317 * of the attr_extra pointed to by 'extra'
320 bgp_attr_dup (struct attr
*new, struct attr
*orig
)
325 new->extra
= bgp_attr_extra_new();
326 *new->extra
= *orig
->extra
;
333 return attrhash
->count
;
337 attr_unknown_count (void)
339 return transit_hash
->count
;
343 attrhash_key_make (void *p
)
345 const struct attr
* attr
= (struct attr
*) p
;
347 #define MIX(val) key = jhash_1word(val, key)
350 MIX(attr
->nexthop
.s_addr
);
352 MIX(attr
->local_pref
);
355 key
+= attr
->nexthop
.s_addr
;
357 key
+= attr
->local_pref
;
361 MIX(attr
->extra
->aggregator_as
);
362 MIX(attr
->extra
->aggregator_addr
.s_addr
);
363 MIX(attr
->extra
->weight
);
364 MIX(attr
->extra
->mp_nexthop_global_in
.s_addr
);
368 MIX(aspath_key_make (attr
->aspath
));
370 MIX(community_hash_make (attr
->community
));
374 if (attr
->extra
->ecommunity
)
375 MIX(ecommunity_hash_make (attr
->extra
->ecommunity
));
376 if (attr
->extra
->cluster
)
377 MIX(cluster_hash_key_make (attr
->extra
->cluster
));
378 if (attr
->extra
->transit
)
379 MIX(transit_hash_key_make (attr
->extra
->transit
));
382 MIX(attr
->extra
->mp_nexthop_len
);
383 key
= jhash(attr
->extra
->mp_nexthop_global
.s6_addr
, 16, key
);
384 key
= jhash(attr
->extra
->mp_nexthop_local
.s6_addr
, 16, key
);
385 #endif /* HAVE_IPV6 */
392 attrhash_cmp (const void *p1
, const void *p2
)
394 const struct attr
* attr1
= p1
;
395 const struct attr
* attr2
= p2
;
397 if (attr1
->flag
== attr2
->flag
398 && attr1
->origin
== attr2
->origin
399 && attr1
->nexthop
.s_addr
== attr2
->nexthop
.s_addr
400 && attr1
->aspath
== attr2
->aspath
401 && attr1
->community
== attr2
->community
402 && attr1
->med
== attr2
->med
403 && attr1
->local_pref
== attr2
->local_pref
)
405 const struct attr_extra
*ae1
= attr1
->extra
;
406 const struct attr_extra
*ae2
= attr2
->extra
;
409 && ae1
->aggregator_as
== ae2
->aggregator_as
410 && ae1
->aggregator_addr
.s_addr
== ae2
->aggregator_addr
.s_addr
411 && ae1
->weight
== ae2
->weight
413 && ae1
->mp_nexthop_len
== ae2
->mp_nexthop_len
414 && IPV6_ADDR_SAME (&ae1
->mp_nexthop_global
, &ae2
->mp_nexthop_global
)
415 && IPV6_ADDR_SAME (&ae1
->mp_nexthop_local
, &ae2
->mp_nexthop_local
)
416 #endif /* HAVE_IPV6 */
417 && IPV4_ADDR_SAME (&ae1
->mp_nexthop_global_in
, &ae2
->mp_nexthop_global_in
)
418 && ae1
->ecommunity
== ae2
->ecommunity
419 && ae1
->cluster
== ae2
->cluster
420 && ae1
->transit
== ae2
->transit
)
424 /* neither attribute has extra attributes, so they're same */
434 attrhash
= hash_create (attrhash_key_make
, attrhash_cmp
);
438 attrhash_finish (void)
440 hash_free (attrhash
);
445 attr_show_all_iterator (struct hash_backet
*backet
, struct vty
*vty
)
447 struct attr
*attr
= backet
->data
;
449 vty_out (vty
, "attr[%ld] nexthop %s%s", attr
->refcnt
,
450 inet_ntoa (attr
->nexthop
), VTY_NEWLINE
);
454 attr_show_all (struct vty
*vty
)
456 hash_iterate (attrhash
,
457 (void (*)(struct hash_backet
*, void *))
458 attr_show_all_iterator
,
463 bgp_attr_hash_alloc (void *p
)
465 struct attr
* val
= (struct attr
*) p
;
468 attr
= XMALLOC (MTYPE_ATTR
, sizeof (struct attr
));
472 attr
->extra
= bgp_attr_extra_new ();
473 *attr
->extra
= *val
->extra
;
479 /* Internet argument attribute. */
481 bgp_attr_intern (struct attr
*attr
)
485 /* Intern referenced strucutre. */
488 if (! attr
->aspath
->refcnt
)
489 attr
->aspath
= aspath_intern (attr
->aspath
);
491 attr
->aspath
->refcnt
++;
495 if (! attr
->community
->refcnt
)
496 attr
->community
= community_intern (attr
->community
);
498 attr
->community
->refcnt
++;
502 struct attr_extra
*attre
= attr
->extra
;
504 if (attre
->ecommunity
)
506 if (! attre
->ecommunity
->refcnt
)
507 attre
->ecommunity
= ecommunity_intern (attre
->ecommunity
);
509 attre
->ecommunity
->refcnt
++;
514 if (! attre
->cluster
->refcnt
)
515 attre
->cluster
= cluster_intern (attre
->cluster
);
517 attre
->cluster
->refcnt
++;
521 if (! attre
->transit
->refcnt
)
522 attre
->transit
= transit_intern (attre
->transit
);
524 attre
->transit
->refcnt
++;
528 find
= (struct attr
*) hash_get (attrhash
, attr
, bgp_attr_hash_alloc
);
535 /* Make network statement's attribute. */
537 bgp_attr_default_set (struct attr
*attr
, u_char origin
)
539 memset (attr
, 0, sizeof (struct attr
));
540 bgp_attr_extra_get (attr
);
542 attr
->origin
= origin
;
543 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN
);
544 attr
->aspath
= aspath_empty ();
545 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH
);
546 attr
->extra
->weight
= BGP_ATTR_DEFAULT_WEIGHT
;
547 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP
);
549 attr
->extra
->mp_nexthop_len
= IPV6_MAX_BYTELEN
;
556 /* Make network statement's attribute. */
558 bgp_attr_default_intern (u_char origin
)
563 memset (&attr
, 0, sizeof (struct attr
));
564 bgp_attr_extra_get (&attr
);
566 bgp_attr_default_set(&attr
, origin
);
568 new = bgp_attr_intern (&attr
);
569 bgp_attr_extra_free (&attr
);
571 aspath_unintern (&new->aspath
);
576 bgp_attr_aggregate_intern (struct bgp
*bgp
, u_char origin
,
577 struct aspath
*aspath
,
578 struct community
*community
, int as_set
)
582 struct attr_extra
*attre
;
584 memset (&attr
, 0, sizeof (struct attr
));
585 attre
= bgp_attr_extra_get (&attr
);
587 /* Origin attribute. */
588 attr
.origin
= origin
;
589 attr
.flag
|= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN
);
591 /* AS path attribute. */
593 attr
.aspath
= aspath_intern (aspath
);
595 attr
.aspath
= aspath_empty ();
596 attr
.flag
|= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH
);
598 /* Next hop attribute. */
599 attr
.flag
|= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP
);
603 attr
.community
= community
;
604 attr
.flag
|= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES
);
607 attre
->weight
= BGP_ATTR_DEFAULT_WEIGHT
;
609 attre
->mp_nexthop_len
= IPV6_MAX_BYTELEN
;
612 attr
.flag
|= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE
);
613 attr
.flag
|= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR
);
614 if (CHECK_FLAG (bgp
->config
, BGP_CONFIG_CONFEDERATION
))
615 attre
->aggregator_as
= bgp
->confed_id
;
617 attre
->aggregator_as
= bgp
->as
;
618 attre
->aggregator_addr
= bgp
->router_id
;
620 new = bgp_attr_intern (&attr
);
621 bgp_attr_extra_free (&attr
);
623 aspath_unintern (&new->aspath
);
627 /* Unintern just the sub-components of the attr, but not the attr */
629 bgp_attr_unintern_sub (struct attr
*attr
)
631 /* aspath refcount shoud be decrement. */
633 aspath_unintern (&attr
->aspath
);
634 UNSET_FLAG(attr
->flag
, BGP_ATTR_AS_PATH
);
637 community_unintern (&attr
->community
);
638 UNSET_FLAG(attr
->flag
, BGP_ATTR_COMMUNITIES
);
642 if (attr
->extra
->ecommunity
)
643 ecommunity_unintern (&attr
->extra
->ecommunity
);
644 UNSET_FLAG(attr
->flag
, BGP_ATTR_EXT_COMMUNITIES
);
646 if (attr
->extra
->cluster
)
647 cluster_unintern (attr
->extra
->cluster
);
648 UNSET_FLAG(attr
->flag
, BGP_ATTR_CLUSTER_LIST
);
650 if (attr
->extra
->transit
)
651 transit_unintern (attr
->extra
->transit
);
655 /* Free bgp attribute and aspath. */
657 bgp_attr_unintern (struct attr
**attr
)
662 /* Decrement attribute reference. */
669 tmp
.extra
= bgp_attr_extra_new ();
670 memcpy (tmp
.extra
, (*attr
)->extra
, sizeof (struct attr_extra
));
673 /* If reference becomes zero then free attribute object. */
674 if ((*attr
)->refcnt
== 0)
676 ret
= hash_release (attrhash
, *attr
);
677 assert (ret
!= NULL
);
678 bgp_attr_extra_free (*attr
);
679 XFREE (MTYPE_ATTR
, *attr
);
683 bgp_attr_unintern_sub (&tmp
);
684 bgp_attr_extra_free (&tmp
);
688 bgp_attr_flush (struct attr
*attr
)
690 if (attr
->aspath
&& ! attr
->aspath
->refcnt
)
691 aspath_free (attr
->aspath
);
692 if (attr
->community
&& ! attr
->community
->refcnt
)
693 community_free (attr
->community
);
696 struct attr_extra
*attre
= attr
->extra
;
698 if (attre
->ecommunity
&& ! attre
->ecommunity
->refcnt
)
699 ecommunity_free (&attre
->ecommunity
);
700 if (attre
->cluster
&& ! attre
->cluster
->refcnt
)
701 cluster_free (attre
->cluster
);
702 if (attre
->transit
&& ! attre
->transit
->refcnt
)
703 transit_free (attre
->transit
);
707 /* Implement draft-scudder-idr-optional-transitive behaviour and
708 * avoid resetting sessions for malformed attributes which are
709 * are partial/optional and hence where the error likely was not
710 * introduced by the sending neighbour.
712 static bgp_attr_parse_ret_t
713 bgp_attr_malformed (struct peer
*peer
, u_char type
, u_char flag
,
714 u_char subcode
, u_char
*startp
, bgp_size_t length
)
716 /* Only relax error handling for eBGP peers */
717 if (peer_sort (peer
) != BGP_PEER_EBGP
)
719 bgp_notify_send_with_data (peer
, BGP_NOTIFY_UPDATE_ERR
, subcode
,
721 return BGP_ATTR_PARSE_ERROR
;
726 /* where an optional attribute is inconsequential, e.g. it does not affect
727 * route selection, and can be safely ignored then any such attributes
728 * which are malformed should just be ignored and the route processed as
731 case BGP_ATTR_AS4_AGGREGATOR
:
732 case BGP_ATTR_AGGREGATOR
:
733 case BGP_ATTR_ATOMIC_AGGREGATE
:
734 return BGP_ATTR_PARSE_PROCEED
;
736 /* Core attributes, particularly ones which may influence route
737 * selection should always cause session resets
739 case BGP_ATTR_ORIGIN
:
740 case BGP_ATTR_AS_PATH
:
741 case BGP_ATTR_NEXT_HOP
:
742 case BGP_ATTR_MULTI_EXIT_DISC
:
743 case BGP_ATTR_LOCAL_PREF
:
744 case BGP_ATTR_COMMUNITIES
:
745 case BGP_ATTR_ORIGINATOR_ID
:
746 case BGP_ATTR_CLUSTER_LIST
:
747 case BGP_ATTR_MP_REACH_NLRI
:
748 case BGP_ATTR_MP_UNREACH_NLRI
:
749 case BGP_ATTR_EXT_COMMUNITIES
:
750 bgp_notify_send_with_data (peer
, BGP_NOTIFY_UPDATE_ERR
, subcode
,
752 return BGP_ATTR_PARSE_ERROR
;
755 /* Partial optional attributes that are malformed should not cause
756 * the whole session to be reset. Instead treat it as a withdrawal
757 * of the routes, if possible.
759 if (CHECK_FLAG (flag
, BGP_ATTR_FLAG_TRANS
)
760 && CHECK_FLAG (flag
, BGP_ATTR_FLAG_OPTIONAL
)
761 && CHECK_FLAG (flag
, BGP_ATTR_FLAG_PARTIAL
))
762 return BGP_ATTR_PARSE_WITHDRAW
;
764 /* default to reset */
765 return BGP_ATTR_PARSE_ERROR
;
768 /* Find out what is wrong with the path attribute flag bits and log the error.
769 "Flag bits" here stand for Optional, Transitive and Partial, but not for
770 Extended Length. Checking O/T/P bits at once implies, that the attribute
771 being diagnosed is defined by RFC as either a "well-known" or an "optional,
772 non-transitive" attribute. */
774 bgp_attr_flags_diagnose
777 const u_int8_t attr_code
,
778 u_int8_t desired_flags
, /* how RFC says it must be */
779 u_int8_t real_flags
/* on wire */
784 desired_flags
&= ~BGP_ATTR_FLAG_EXTLEN
;
785 real_flags
&= ~BGP_ATTR_FLAG_EXTLEN
;
786 for (i
= 0; i
<= 2; i
++) /* O,T,P, but not E */
789 CHECK_FLAG (desired_flags
, attr_flag_str
[i
].key
) !=
790 CHECK_FLAG (real_flags
, attr_flag_str
[i
].key
)
793 zlog (peer
->log
, LOG_ERR
, "%s attribute must%s be flagged as \"%s\"",
794 LOOKUP (attr_str
, attr_code
),
795 CHECK_FLAG (desired_flags
, attr_flag_str
[i
].key
) ? "" : " not",
796 attr_flag_str
[i
].str
);
802 /* Get origin attribute of the update message. */
803 static bgp_attr_parse_ret_t
804 bgp_attr_origin (struct peer
*peer
, bgp_size_t length
,
805 struct attr
*attr
, u_char flag
, u_char
*startp
)
809 /* total is entire attribute length include Attribute Flags (1),
810 Attribute Type code (1) and Attribute length (1 or 2). */
811 total
= length
+ (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
813 /* If any recognized attribute has Attribute Flags that conflict
814 with the Attribute Type Code, then the Error Subcode is set to
815 Attribute Flags Error. The Data field contains the erroneous
816 attribute (type, length and value). */
817 if ((flag
& ~BGP_ATTR_FLAG_EXTLEN
) != BGP_ATTR_FLAG_TRANS
)
819 bgp_attr_flags_diagnose (peer
, BGP_ATTR_ORIGIN
, BGP_ATTR_FLAG_TRANS
, flag
);
820 return bgp_attr_malformed (peer
, BGP_ATTR_ORIGIN
, flag
, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
, startp
, total
);
823 /* If any recognized attribute has Attribute Length that conflicts
824 with the expected length (based on the attribute type code), then
825 the Error Subcode is set to Attribute Length Error. The Data
826 field contains the erroneous attribute (type, length and
830 zlog (peer
->log
, LOG_ERR
, "Origin attribute length is not one %d",
832 return bgp_attr_malformed (peer
, BGP_ATTR_ORIGIN
, flag
,
833 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
837 /* Fetch origin attribute. */
838 attr
->origin
= stream_getc (BGP_INPUT (peer
));
840 /* If the ORIGIN attribute has an undefined value, then the Error
841 Subcode is set to Invalid Origin Attribute. The Data field
842 contains the unrecognized attribute (type, length and value). */
843 if ((attr
->origin
!= BGP_ORIGIN_IGP
)
844 && (attr
->origin
!= BGP_ORIGIN_EGP
)
845 && (attr
->origin
!= BGP_ORIGIN_INCOMPLETE
))
847 zlog (peer
->log
, LOG_ERR
, "Origin attribute value is invalid %d",
849 return bgp_attr_malformed (peer
, BGP_ATTR_ORIGIN
, flag
,
850 BGP_NOTIFY_UPDATE_INVAL_ORIGIN
,
854 /* Set oring attribute flag. */
855 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN
);
860 /* Parse AS path information. This function is wrapper of
863 bgp_attr_aspath (struct peer
*peer
, bgp_size_t length
,
864 struct attr
*attr
, u_char flag
, u_char
*startp
)
868 total
= length
+ (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
871 if (CHECK_FLAG (flag
, BGP_ATTR_FLAG_PARTIAL
))
873 zlog (peer
->log
, LOG_ERR
,
874 "AS_PATH attribute must not be flagged as \"partial\" (%u)", flag
);
875 return bgp_attr_malformed (peer
, BGP_ATTR_ORIGIN
, flag
,
876 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
880 if (CHECK_FLAG (flag
, BGP_ATTR_FLAG_OPTIONAL
)
881 || ! CHECK_FLAG (flag
, BGP_ATTR_FLAG_TRANS
))
883 zlog (peer
->log
, LOG_ERR
,
884 "As-Path attribute flag isn't transitive %d", flag
);
885 return bgp_attr_malformed (peer
, BGP_ATTR_AS_PATH
, flag
,
886 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
891 * peer with AS4 => will get 4Byte ASnums
892 * otherwise, will get 16 Bit
894 attr
->aspath
= aspath_parse (peer
->ibuf
, length
,
895 CHECK_FLAG (peer
->cap
, PEER_CAP_AS4_RCV
));
897 /* In case of IBGP, length will be zero. */
900 zlog (peer
->log
, LOG_ERR
,
901 "Malformed AS path from %s, length is %d",
903 return bgp_attr_malformed (peer
, BGP_ATTR_AS_PATH
, flag
,
904 BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
908 /* Set aspath attribute flag. */
909 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH
);
911 return BGP_ATTR_PARSE_PROCEED
;
914 static bgp_attr_parse_ret_t
915 bgp_attr_aspath_check (struct peer
*peer
, struct attr
*attr
, u_char flag
)
917 /* These checks were part of bgp_attr_aspath, but with
918 * as4 we should to check aspath things when
919 * aspath synthesizing with as4_path has already taken place.
920 * Otherwise we check ASPATH and use the synthesized thing, and that is
922 * So do the checks later, i.e. here
924 struct bgp
*bgp
= peer
->bgp
;
925 struct aspath
*aspath
;
929 /* Confederation sanity check. */
930 if ((peer_sort (peer
) == BGP_PEER_CONFED
&& ! aspath_left_confed_check (attr
->aspath
)) ||
931 (peer_sort (peer
) == BGP_PEER_EBGP
&& aspath_confed_check (attr
->aspath
)))
933 zlog (peer
->log
, LOG_ERR
, "Malformed AS path from %s", peer
->host
);
934 return bgp_attr_malformed (peer
, BGP_ATTR_AS_PATH
, flag
,
935 BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
939 /* First AS check for EBGP. */
940 if (bgp
!= NULL
&& bgp_flag_check (bgp
, BGP_FLAG_ENFORCE_FIRST_AS
))
942 if (peer_sort (peer
) == BGP_PEER_EBGP
943 && ! aspath_firstas_check (attr
->aspath
, peer
->as
))
945 zlog (peer
->log
, LOG_ERR
,
946 "%s incorrect first AS (must be %u)", peer
->host
, peer
->as
);
947 return bgp_attr_malformed (peer
, BGP_ATTR_AS_PATH
, flag
,
948 BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
953 /* local-as prepend */
954 if (peer
->change_local_as
&&
955 ! CHECK_FLAG (peer
->flags
, PEER_FLAG_LOCAL_AS_NO_PREPEND
))
957 aspath
= aspath_dup (attr
->aspath
);
958 aspath
= aspath_add_seq (aspath
, peer
->change_local_as
);
959 aspath_unintern (&attr
->aspath
);
960 attr
->aspath
= aspath_intern (aspath
);
963 return BGP_ATTR_PARSE_PROCEED
;
966 /* Parse AS4 path information. This function is another wrapper of
969 bgp_attr_as4_path (struct peer
*peer
, bgp_size_t length
,
970 struct attr
*attr
, u_char flag
, u_char
*startp
,
971 struct aspath
**as4_path
)
975 total
= length
+ (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
978 if (!CHECK_FLAG (flag
, BGP_ATTR_FLAG_OPTIONAL
)
979 || !CHECK_FLAG (flag
, BGP_ATTR_FLAG_TRANS
))
981 zlog (peer
->log
, LOG_ERR
,
982 "As4-Path attribute flag isn't optional/transitive %d", flag
);
983 return bgp_attr_malformed (peer
, BGP_ATTR_AS_PATH
, flag
,
984 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
988 *as4_path
= aspath_parse (peer
->ibuf
, length
, 1);
990 /* In case of IBGP, length will be zero. */
993 zlog (peer
->log
, LOG_ERR
,
994 "Malformed AS4 path from %s, length is %d",
996 return bgp_attr_malformed (peer
, BGP_ATTR_AS4_PATH
, flag
,
997 BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1001 /* Set aspath attribute flag. */
1003 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH
);
1005 return BGP_ATTR_PARSE_PROCEED
;
1008 /* Nexthop attribute. */
1009 static bgp_attr_parse_ret_t
1010 bgp_attr_nexthop (struct peer
*peer
, bgp_size_t length
,
1011 struct attr
*attr
, u_char flag
, u_char
*startp
)
1014 in_addr_t nexthop_h
, nexthop_n
;
1016 total
= length
+ (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
1019 if ((flag
& ~BGP_ATTR_FLAG_EXTLEN
) != BGP_ATTR_FLAG_TRANS
)
1021 bgp_attr_flags_diagnose (peer
, BGP_ATTR_NEXT_HOP
, BGP_ATTR_FLAG_TRANS
, flag
);
1022 return bgp_attr_malformed (peer
, BGP_ATTR_NEXT_HOP
, flag
, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
, startp
, total
);
1025 /* Check nexthop attribute length. */
1028 zlog (peer
->log
, LOG_ERR
, "Nexthop attribute length isn't four [%d]",
1031 return bgp_attr_malformed (peer
, BGP_ATTR_NEXT_HOP
, flag
,
1032 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1036 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1037 attribute must result in a NOTIFICATION message (this is implemented below).
1038 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1039 logged locally (this is implemented somewhere else). The UPDATE message
1040 gets ignored in any of these cases. */
1041 nexthop_n
= stream_get_ipv4 (peer
->ibuf
);
1042 nexthop_h
= ntohl (nexthop_n
);
1043 if (IPV4_NET0 (nexthop_h
) || IPV4_NET127 (nexthop_h
) || IPV4_CLASS_DE (nexthop_h
))
1045 char buf
[INET_ADDRSTRLEN
];
1046 inet_ntop (AF_INET
, &nexthop_h
, buf
, INET_ADDRSTRLEN
);
1047 zlog (peer
->log
, LOG_ERR
, "Martian nexthop %s", buf
);
1048 return bgp_attr_malformed (peer
, BGP_ATTR_NEXT_HOP
, flag
,
1049 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP
,
1053 attr
->nexthop
.s_addr
= nexthop_n
;
1054 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP
);
1056 return BGP_ATTR_PARSE_PROCEED
;
1059 /* MED atrribute. */
1060 static bgp_attr_parse_ret_t
1061 bgp_attr_med (struct peer
*peer
, bgp_size_t length
,
1062 struct attr
*attr
, u_char flag
, u_char
*startp
)
1066 total
= length
+ (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
1069 if ((flag
& ~BGP_ATTR_FLAG_EXTLEN
) != BGP_ATTR_FLAG_OPTIONAL
)
1071 bgp_attr_flags_diagnose (peer
, BGP_ATTR_MULTI_EXIT_DISC
, BGP_ATTR_FLAG_OPTIONAL
, flag
);
1072 return bgp_attr_malformed (peer
, BGP_ATTR_MULTI_EXIT_DISC
, flag
,
1073 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
1080 zlog (peer
->log
, LOG_ERR
,
1081 "MED attribute length isn't four [%d]", length
);
1083 return bgp_attr_malformed (peer
, BGP_ATTR_MULTI_EXIT_DISC
, flag
,
1084 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1088 attr
->med
= stream_getl (peer
->ibuf
);
1090 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC
);
1092 return BGP_ATTR_PARSE_PROCEED
;
1095 /* Local preference attribute. */
1096 static bgp_attr_parse_ret_t
1097 bgp_attr_local_pref (struct peer
*peer
, bgp_size_t length
,
1098 struct attr
*attr
, u_char flag
, u_char
*startp
)
1102 total
= length
+ (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
1104 if ((flag
& ~BGP_ATTR_FLAG_EXTLEN
) != BGP_ATTR_FLAG_TRANS
)
1106 bgp_attr_flags_diagnose (peer
, BGP_ATTR_LOCAL_PREF
, BGP_ATTR_FLAG_TRANS
, flag
);
1107 return bgp_attr_malformed (peer
, BGP_ATTR_LOCAL_PREF
, flag
,
1108 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
1114 zlog (peer
->log
, LOG_ERR
, "LOCAL_PREF attribute length isn't 4 [%u]", length
);
1115 return bgp_attr_malformed (peer
, BGP_ATTR_LOCAL_PREF
, flag
,
1116 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1120 /* If it is contained in an UPDATE message that is received from an
1121 external peer, then this attribute MUST be ignored by the
1122 receiving speaker. */
1123 if (peer_sort (peer
) == BGP_PEER_EBGP
)
1125 stream_forward_getp (peer
->ibuf
, length
);
1126 return BGP_ATTR_PARSE_PROCEED
;
1129 attr
->local_pref
= stream_getl (peer
->ibuf
);
1131 /* Set atomic aggregate flag. */
1132 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF
);
1134 return BGP_ATTR_PARSE_PROCEED
;
1137 /* Atomic aggregate. */
1139 bgp_attr_atomic (struct peer
*peer
, bgp_size_t length
,
1140 struct attr
*attr
, u_char flag
, u_char
*startp
)
1144 total
= length
+ (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
1146 if ((flag
& ~BGP_ATTR_FLAG_EXTLEN
) != BGP_ATTR_FLAG_TRANS
)
1148 bgp_attr_flags_diagnose (peer
, BGP_ATTR_ATOMIC_AGGREGATE
, BGP_ATTR_FLAG_TRANS
, flag
);
1149 return bgp_attr_malformed (peer
, BGP_ATTR_ATOMIC_AGGREGATE
, flag
,
1150 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
1157 zlog (peer
->log
, LOG_ERR
, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]", length
);
1158 return bgp_attr_malformed (peer
, BGP_ATTR_ATOMIC_AGGREGATE
, flag
,
1159 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1163 /* Set atomic aggregate flag. */
1164 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE
);
1166 return BGP_ATTR_PARSE_PROCEED
;
1169 /* Aggregator attribute */
1171 bgp_attr_aggregator (struct peer
*peer
, bgp_size_t length
,
1172 struct attr
*attr
, u_char flag
, u_char
*startp
)
1175 struct attr_extra
*attre
= bgp_attr_extra_get (attr
);
1178 total
= length
+ (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
1180 if (! CHECK_FLAG (flag
, BGP_ATTR_FLAG_OPTIONAL
))
1182 zlog (peer
->log
, LOG_ERR
,
1183 "AGGREGATOR attribute must be flagged as \"optional\" (%u)", flag
);
1184 return bgp_attr_malformed (peer
, BGP_ATTR_AGGREGATOR
, flag
,
1185 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
1188 if (! CHECK_FLAG (flag
, BGP_ATTR_FLAG_TRANS
))
1190 zlog (peer
->log
, LOG_ERR
,
1191 "AGGREGATOR attribute must be flagged as \"transitive\" (%u)", flag
);
1192 return bgp_attr_malformed (peer
, BGP_ATTR_AGGREGATOR
, flag
,
1193 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
1196 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1197 if (CHECK_FLAG (peer
->cap
, PEER_CAP_AS4_RCV
))
1200 if (length
!= wantedlen
)
1202 zlog (peer
->log
, LOG_ERR
, "AGGREGATOR attribute length isn't %u [%u]", wantedlen
, length
);
1203 return bgp_attr_malformed (peer
, BGP_ATTR_AGGREGATOR
, flag
,
1204 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1208 if ( CHECK_FLAG (peer
->cap
, PEER_CAP_AS4_RCV
) )
1209 attre
->aggregator_as
= stream_getl (peer
->ibuf
);
1211 attre
->aggregator_as
= stream_getw (peer
->ibuf
);
1212 attre
->aggregator_addr
.s_addr
= stream_get_ipv4 (peer
->ibuf
);
1214 /* Set atomic aggregate flag. */
1215 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR
);
1217 return BGP_ATTR_PARSE_PROCEED
;
1220 /* New Aggregator attribute */
1221 static bgp_attr_parse_ret_t
1222 bgp_attr_as4_aggregator (struct peer
*peer
, bgp_size_t length
,
1223 struct attr
*attr
, u_char flag
,
1224 as_t
*as4_aggregator_as
,
1225 struct in_addr
*as4_aggregator_addr
)
1229 zlog (peer
->log
, LOG_ERR
, "New Aggregator length is not 8 [%d]", length
);
1230 return bgp_attr_malformed (peer
, BGP_ATTR_AS4_AGGREGATOR
, flag
,
1231 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1234 *as4_aggregator_as
= stream_getl (peer
->ibuf
);
1235 as4_aggregator_addr
->s_addr
= stream_get_ipv4 (peer
->ibuf
);
1237 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR
);
1239 return BGP_ATTR_PARSE_PROCEED
;
1242 /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1244 static bgp_attr_parse_ret_t
1245 bgp_attr_munge_as4_attrs (struct peer
*peer
, struct attr
*attr
, u_char flag
,
1246 struct aspath
*as4_path
, as_t as4_aggregator
,
1247 struct in_addr
*as4_aggregator_addr
)
1249 int ignore_as4_path
= 0;
1250 struct aspath
*newpath
;
1251 struct attr_extra
*attre
= attr
->extra
;
1253 if (CHECK_FLAG (peer
->cap
, PEER_CAP_AS4_RCV
))
1255 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1257 * It is worth a warning though, because the peer really
1258 * should not send them
1260 if (BGP_DEBUG(as4
, AS4
))
1262 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
)))
1263 zlog_debug ("[AS4] %s %s AS4_PATH",
1264 peer
->host
, "AS4 capable peer, yet it sent");
1266 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
)))
1267 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1268 peer
->host
, "AS4 capable peer, yet it sent");
1271 return BGP_ATTR_PARSE_PROCEED
;
1274 if (attr
->flag
& (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH
))
1275 && !(attr
->flag
& (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH
))))
1277 /* Hu? This is not supposed to happen at all!
1278 * got as4_path and no aspath,
1279 * This should already
1280 * have been handled by 'well known attributes missing'
1281 * But... yeah, paranoia
1282 * Take this as a "malformed attribute"
1284 zlog (peer
->log
, LOG_ERR
,
1285 "%s BGP not AS4 capable peer sent AS4_PATH but"
1286 " no AS_PATH, cant do anything here", peer
->host
);
1287 return bgp_attr_malformed (peer
, BGP_ATTR_AS_PATH
, flag
,
1288 BGP_NOTIFY_UPDATE_MAL_ATTR
,
1292 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1293 * because that may override AS4_PATH
1295 if (attr
->flag
& (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR
) ) )
1297 if (attr
->flag
& (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR
) ) )
1302 * if the as_number in aggregator is not AS_TRANS,
1303 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1304 * and the Aggregator shall be taken as
1305 * info on the aggregating node, and the AS_PATH
1306 * shall be taken as the AS_PATH
1308 * the Aggregator shall be ignored and the
1309 * AS4_AGGREGATOR shall be taken as the
1310 * Aggregating node and the AS_PATH is to be
1311 * constructed "as in all other cases"
1313 if (attre
->aggregator_as
!= BGP_AS_TRANS
)
1316 if ( BGP_DEBUG(as4
, AS4
))
1317 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1318 " send AGGREGATOR != AS_TRANS and"
1319 " AS4_AGGREGATOR, so ignore"
1320 " AS4_AGGREGATOR and AS4_PATH", peer
->host
);
1321 ignore_as4_path
= 1;
1325 /* "New_aggregator shall be taken as aggregator" */
1326 attre
->aggregator_as
= as4_aggregator
;
1327 attre
->aggregator_addr
.s_addr
= as4_aggregator_addr
->s_addr
;
1332 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1333 * That is bogus - but reading the conditions
1334 * we have to handle AS4_AGGREGATOR as if it were
1335 * AGGREGATOR in that case
1337 if ( BGP_DEBUG(as4
, AS4
))
1338 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1339 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1340 " it as if AGGREGATOR with AS_TRANS had been there", peer
->host
);
1341 (attre
= bgp_attr_extra_get (attr
))->aggregator_as
= as4_aggregator
;
1342 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1343 attr
->flag
|= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR
));
1347 /* need to reconcile NEW_AS_PATH and AS_PATH */
1348 if (!ignore_as4_path
&& (attr
->flag
& (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH
))))
1350 newpath
= aspath_reconcile_as4 (attr
->aspath
, as4_path
);
1351 aspath_unintern (&attr
->aspath
);
1352 attr
->aspath
= aspath_intern (newpath
);
1354 return BGP_ATTR_PARSE_PROCEED
;
1357 /* Community attribute. */
1358 static bgp_attr_parse_ret_t
1359 bgp_attr_community (struct peer
*peer
, bgp_size_t length
,
1360 struct attr
*attr
, u_char flag
, u_char
*startp
)
1363 = length
+ (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
1367 attr
->community
= NULL
;
1368 return BGP_ATTR_PARSE_PROCEED
;
1372 community_parse ((u_int32_t
*)stream_pnt (peer
->ibuf
), length
);
1374 /* XXX: fix community_parse to use stream API and remove this */
1375 stream_forward_getp (peer
->ibuf
, length
);
1377 if (!attr
->community
)
1378 return bgp_attr_malformed (peer
, BGP_ATTR_COMMUNITIES
, flag
,
1379 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
1382 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES
);
1384 return BGP_ATTR_PARSE_PROCEED
;
1387 /* Originator ID attribute. */
1388 static bgp_attr_parse_ret_t
1389 bgp_attr_originator_id (struct peer
*peer
, bgp_size_t length
,
1390 struct attr
*attr
, u_char flag
, u_char
*startp
)
1394 total
= length
+ (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
1396 if ((flag
& ~BGP_ATTR_FLAG_EXTLEN
) != BGP_ATTR_FLAG_OPTIONAL
)
1398 bgp_attr_flags_diagnose (peer
, BGP_ATTR_ORIGINATOR_ID
, BGP_ATTR_FLAG_OPTIONAL
, flag
);
1399 return bgp_attr_malformed (peer
, BGP_ATTR_ORIGINATOR_ID
, flag
,
1400 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
1406 zlog (peer
->log
, LOG_ERR
, "Bad originator ID length %d", length
);
1408 return bgp_attr_malformed (peer
, BGP_ATTR_ORIGINATOR_ID
, flag
,
1409 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1413 (bgp_attr_extra_get (attr
))->originator_id
.s_addr
1414 = stream_get_ipv4 (peer
->ibuf
);
1416 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID
);
1418 return BGP_ATTR_PARSE_PROCEED
;
1421 /* Cluster list attribute. */
1422 static bgp_attr_parse_ret_t
1423 bgp_attr_cluster_list (struct peer
*peer
, bgp_size_t length
,
1424 struct attr
*attr
, u_char flag
, u_char
*startp
)
1428 total
= length
+ (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
1430 if ((flag
& ~BGP_ATTR_FLAG_EXTLEN
) != BGP_ATTR_FLAG_OPTIONAL
)
1432 bgp_attr_flags_diagnose (peer
, BGP_ATTR_CLUSTER_LIST
, BGP_ATTR_FLAG_OPTIONAL
, flag
);
1433 return bgp_attr_malformed (peer
, BGP_ATTR_CLUSTER_LIST
, flag
,
1434 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
1440 zlog (peer
->log
, LOG_ERR
, "Bad cluster list length %d", length
);
1442 return bgp_attr_malformed (peer
, BGP_ATTR_CLUSTER_LIST
, flag
,
1443 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1447 (bgp_attr_extra_get (attr
))->cluster
1448 = cluster_parse ((struct in_addr
*)stream_pnt (peer
->ibuf
), length
);
1450 /* XXX: Fix cluster_parse to use stream API and then remove this */
1451 stream_forward_getp (peer
->ibuf
, length
);
1453 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST
);
1455 return BGP_ATTR_PARSE_PROCEED
;
1458 /* Multiprotocol reachability information parse. */
1460 bgp_mp_reach_parse (struct peer
*peer
, const bgp_size_t length
,
1461 struct attr
*attr
, const u_char flag
, u_char
*startp
, struct bgp_nlri
*mp_update
)
1465 bgp_size_t nlri_len
;
1469 struct attr_extra
*attre
= bgp_attr_extra_get(attr
);
1472 total
= length
+ (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
1474 if ((flag
& ~BGP_ATTR_FLAG_EXTLEN
) != BGP_ATTR_FLAG_OPTIONAL
)
1476 bgp_attr_flags_diagnose (peer
, BGP_ATTR_MP_REACH_NLRI
, BGP_ATTR_FLAG_OPTIONAL
, flag
);
1477 return bgp_attr_malformed (peer
, BGP_ATTR_MP_REACH_NLRI
, flag
,
1478 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
1481 /* Set end of packet. */
1482 s
= BGP_INPUT(peer
);
1483 start
= stream_get_getp(s
);
1485 /* safe to read statically sized header? */
1486 #define BGP_MP_REACH_MIN_SIZE 5
1487 #define LEN_LEFT (length - (stream_get_getp(s) - start))
1488 if ((length
> STREAM_READABLE(s
)) || (length
< BGP_MP_REACH_MIN_SIZE
))
1490 zlog_info ("%s: %s sent invalid length, %lu",
1491 __func__
, peer
->host
, (unsigned long)length
);
1492 return BGP_ATTR_PARSE_ERROR
;
1495 /* Load AFI, SAFI. */
1496 afi
= stream_getw (s
);
1497 safi
= stream_getc (s
);
1499 /* Get nexthop length. */
1500 attre
->mp_nexthop_len
= stream_getc (s
);
1502 if (LEN_LEFT
< attre
->mp_nexthop_len
)
1504 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1505 __func__
, peer
->host
, attre
->mp_nexthop_len
);
1506 return BGP_ATTR_PARSE_ERROR
;
1509 /* Nexthop length check. */
1510 switch (attre
->mp_nexthop_len
)
1513 stream_get (&attre
->mp_nexthop_global_in
, s
, 4);
1514 /* Probably needed for RFC 2283 */
1515 if (attr
->nexthop
.s_addr
== 0)
1516 memcpy(&attr
->nexthop
.s_addr
, &attre
->mp_nexthop_global_in
, 4);
1519 stream_getl (s
); /* RD high */
1520 stream_getl (s
); /* RD low */
1521 stream_get (&attre
->mp_nexthop_global_in
, s
, 4);
1525 stream_get (&attre
->mp_nexthop_global
, s
, 16);
1528 stream_get (&attre
->mp_nexthop_global
, s
, 16);
1529 stream_get (&attre
->mp_nexthop_local
, s
, 16);
1530 if (! IN6_IS_ADDR_LINKLOCAL (&attre
->mp_nexthop_local
))
1532 char buf1
[INET6_ADDRSTRLEN
];
1533 char buf2
[INET6_ADDRSTRLEN
];
1535 if (BGP_DEBUG (update
, UPDATE_IN
))
1536 zlog_debug ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer
->host
,
1537 inet_ntop (AF_INET6
, &attre
->mp_nexthop_global
,
1538 buf1
, INET6_ADDRSTRLEN
),
1539 inet_ntop (AF_INET6
, &attre
->mp_nexthop_local
,
1540 buf2
, INET6_ADDRSTRLEN
));
1542 attre
->mp_nexthop_len
= 16;
1545 #endif /* HAVE_IPV6 */
1547 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1548 __func__
, peer
->host
, attre
->mp_nexthop_len
);
1549 return BGP_ATTR_PARSE_ERROR
;
1554 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1555 __func__
, peer
->host
);
1556 return BGP_ATTR_PARSE_ERROR
;
1561 if ((val
= stream_getc (s
)))
1562 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1566 /* must have nrli_len, what is left of the attribute */
1567 nlri_len
= LEN_LEFT
;
1568 if ((!nlri_len
) || (nlri_len
> STREAM_READABLE(s
)))
1570 zlog_info ("%s: (%s) Failed to read NLRI",
1571 __func__
, peer
->host
);
1572 return BGP_ATTR_PARSE_ERROR
;
1575 if (safi
!= SAFI_MPLS_LABELED_VPN
)
1577 ret
= bgp_nlri_sanity_check (peer
, afi
, stream_pnt (s
), nlri_len
);
1580 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1581 __func__
, peer
->host
);
1582 return BGP_ATTR_PARSE_ERROR
;
1586 mp_update
->afi
= afi
;
1587 mp_update
->safi
= safi
;
1588 mp_update
->nlri
= stream_pnt (s
);
1589 mp_update
->length
= nlri_len
;
1591 stream_forward_getp (s
, nlri_len
);
1593 return BGP_ATTR_PARSE_PROCEED
;
1597 /* Multiprotocol unreachable parse */
1599 bgp_mp_unreach_parse (struct peer
*peer
, const bgp_size_t length
,
1600 const u_char flag
, u_char
*startp
,
1601 struct bgp_nlri
*mp_withdraw
)
1606 u_int16_t withdraw_len
;
1610 total
= length
+ (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
1612 if ((flag
& ~BGP_ATTR_FLAG_EXTLEN
) != BGP_ATTR_FLAG_OPTIONAL
)
1614 bgp_attr_flags_diagnose (peer
, BGP_ATTR_MP_UNREACH_NLRI
, BGP_ATTR_FLAG_OPTIONAL
, flag
);
1615 return bgp_attr_malformed (peer
, BGP_ATTR_MP_UNREACH_NLRI
, flag
,
1616 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
1622 #define BGP_MP_UNREACH_MIN_SIZE 3
1623 if ((length
> STREAM_READABLE(s
)) || (length
< BGP_MP_UNREACH_MIN_SIZE
))
1624 return BGP_ATTR_PARSE_ERROR
;
1626 afi
= stream_getw (s
);
1627 safi
= stream_getc (s
);
1629 withdraw_len
= length
- BGP_MP_UNREACH_MIN_SIZE
;
1631 if (safi
!= SAFI_MPLS_LABELED_VPN
)
1633 ret
= bgp_nlri_sanity_check (peer
, afi
, stream_pnt (s
), withdraw_len
);
1635 return BGP_ATTR_PARSE_ERROR
;
1638 mp_withdraw
->afi
= afi
;
1639 mp_withdraw
->safi
= safi
;
1640 mp_withdraw
->nlri
= stream_pnt (s
);
1641 mp_withdraw
->length
= withdraw_len
;
1643 stream_forward_getp (s
, withdraw_len
);
1645 return BGP_ATTR_PARSE_PROCEED
;
1648 /* Extended Community attribute. */
1649 static bgp_attr_parse_ret_t
1650 bgp_attr_ext_communities (struct peer
*peer
, bgp_size_t length
,
1651 struct attr
*attr
, u_char flag
, u_char
*startp
)
1654 = length
+ (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
1659 attr
->extra
->ecommunity
= NULL
;
1660 /* Empty extcomm doesn't seem to be invalid per se */
1661 return BGP_ATTR_PARSE_PROCEED
;
1664 (bgp_attr_extra_get (attr
))->ecommunity
=
1665 ecommunity_parse ((u_int8_t
*)stream_pnt (peer
->ibuf
), length
);
1666 /* XXX: fix ecommunity_parse to use stream API */
1667 stream_forward_getp (peer
->ibuf
, length
);
1669 if (!attr
->extra
->ecommunity
)
1670 return bgp_attr_malformed (peer
, BGP_ATTR_EXT_COMMUNITIES
,
1671 flag
, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
1674 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES
);
1676 return BGP_ATTR_PARSE_PROCEED
;
1679 /* BGP unknown attribute treatment. */
1680 static bgp_attr_parse_ret_t
1681 bgp_attr_unknown (struct peer
*peer
, struct attr
*attr
, u_char flag
,
1682 u_char type
, bgp_size_t length
, u_char
*startp
)
1685 struct transit
*transit
;
1686 struct attr_extra
*attre
;
1688 if (BGP_DEBUG (normal
, NORMAL
))
1689 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1690 peer
->host
, type
, length
);
1692 if (BGP_DEBUG (events
, EVENTS
))
1693 zlog (peer
->log
, LOG_DEBUG
,
1694 "Unknown attribute type %d length %d is received", type
, length
);
1696 /* Forward read pointer of input stream. */
1697 stream_forward_getp (peer
->ibuf
, length
);
1699 /* Adjest total length to include type and length. */
1700 total
= length
+ (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
) ? 4 : 3);
1702 /* If any of the mandatory well-known attributes are not recognized,
1703 then the Error Subcode is set to Unrecognized Well-known
1704 Attribute. The Data field contains the unrecognized attribute
1705 (type, length and value). */
1706 if (!CHECK_FLAG (flag
, BGP_ATTR_FLAG_OPTIONAL
))
1708 return bgp_attr_malformed (peer
, type
, flag
,
1709 BGP_NOTIFY_UPDATE_UNREC_ATTR
,
1713 /* Unrecognized non-transitive optional attributes must be quietly
1714 ignored and not passed along to other BGP peers. */
1715 if (! CHECK_FLAG (flag
, BGP_ATTR_FLAG_TRANS
))
1716 return BGP_ATTR_PARSE_PROCEED
;
1718 /* If a path with recognized transitive optional attribute is
1719 accepted and passed along to other BGP peers and the Partial bit
1720 in the Attribute Flags octet is set to 1 by some previous AS, it
1721 is not set back to 0 by the current AS. */
1722 SET_FLAG (*startp
, BGP_ATTR_FLAG_PARTIAL
);
1724 /* Store transitive attribute to the end of attr->transit. */
1725 if (! ((attre
= bgp_attr_extra_get(attr
))->transit
) )
1726 attre
->transit
= XCALLOC (MTYPE_TRANSIT
, sizeof (struct transit
));
1728 transit
= attre
->transit
;
1731 transit
->val
= XREALLOC (MTYPE_TRANSIT_VAL
, transit
->val
,
1732 transit
->length
+ total
);
1734 transit
->val
= XMALLOC (MTYPE_TRANSIT_VAL
, total
);
1736 memcpy (transit
->val
+ transit
->length
, startp
, total
);
1737 transit
->length
+= total
;
1739 return BGP_ATTR_PARSE_PROCEED
;
1742 /* Read attribute of update packet. This function is called from
1743 bgp_update() in bgpd.c. */
1744 bgp_attr_parse_ret_t
1745 bgp_attr_parse (struct peer
*peer
, struct attr
*attr
, bgp_size_t size
,
1746 struct bgp_nlri
*mp_update
, struct bgp_nlri
*mp_withdraw
)
1752 u_char
*startp
, *endp
;
1754 u_char seen
[BGP_ATTR_BITMAP_SIZE
];
1755 /* we need the as4_path only until we have synthesized the as_path with it */
1756 /* same goes for as4_aggregator */
1757 struct aspath
*as4_path
= NULL
;
1758 as_t as4_aggregator
= 0;
1759 struct in_addr as4_aggregator_addr
= { 0 };
1761 /* Initialize bitmap. */
1762 memset (seen
, 0, BGP_ATTR_BITMAP_SIZE
);
1764 /* End pointer of BGP attribute. */
1765 endp
= BGP_INPUT_PNT (peer
) + size
;
1767 /* Get attributes to the end of attribute length. */
1768 while (BGP_INPUT_PNT (peer
) < endp
)
1770 /* Check remaining length check.*/
1771 if (endp
- BGP_INPUT_PNT (peer
) < BGP_ATTR_MIN_LEN
)
1773 /* XXX warning: long int format, int arg (arg 5) */
1774 zlog (peer
->log
, LOG_WARNING
,
1775 "%s: error BGP attribute length %lu is smaller than min len",
1777 (unsigned long) (endp
- STREAM_PNT (BGP_INPUT (peer
))));
1779 bgp_notify_send (peer
,
1780 BGP_NOTIFY_UPDATE_ERR
,
1781 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
1782 return BGP_ATTR_PARSE_ERROR
;
1785 /* Fetch attribute flag and type. */
1786 startp
= BGP_INPUT_PNT (peer
);
1787 /* "The lower-order four bits of the Attribute Flags octet are
1788 unused. They MUST be zero when sent and MUST be ignored when
1790 flag
= 0xF0 & stream_getc (BGP_INPUT (peer
));
1791 type
= stream_getc (BGP_INPUT (peer
));
1793 /* Check whether Extended-Length applies and is in bounds */
1794 if (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
)
1795 && ((endp
- startp
) < (BGP_ATTR_MIN_LEN
+ 1)))
1797 zlog (peer
->log
, LOG_WARNING
,
1798 "%s: Extended length set, but just %lu bytes of attr header",
1800 (unsigned long) (endp
- STREAM_PNT (BGP_INPUT (peer
))));
1802 bgp_notify_send (peer
,
1803 BGP_NOTIFY_UPDATE_ERR
,
1804 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
1805 return BGP_ATTR_PARSE_ERROR
;
1808 /* Check extended attribue length bit. */
1809 if (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
))
1810 length
= stream_getw (BGP_INPUT (peer
));
1812 length
= stream_getc (BGP_INPUT (peer
));
1814 /* If any attribute appears more than once in the UPDATE
1815 message, then the Error Subcode is set to Malformed Attribute
1818 if (CHECK_BITMAP (seen
, type
))
1820 zlog (peer
->log
, LOG_WARNING
,
1821 "%s: error BGP attribute type %d appears twice in a message",
1824 bgp_notify_send (peer
,
1825 BGP_NOTIFY_UPDATE_ERR
,
1826 BGP_NOTIFY_UPDATE_MAL_ATTR
);
1827 return BGP_ATTR_PARSE_ERROR
;
1830 /* Set type to bitmap to check duplicate attribute. `type' is
1831 unsigned char so it never overflow bitmap range. */
1833 SET_BITMAP (seen
, type
);
1835 /* Overflow check. */
1836 attr_endp
= BGP_INPUT_PNT (peer
) + length
;
1838 if (attr_endp
> endp
)
1840 zlog (peer
->log
, LOG_WARNING
,
1841 "%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
);
1842 bgp_notify_send (peer
,
1843 BGP_NOTIFY_UPDATE_ERR
,
1844 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
1845 return BGP_ATTR_PARSE_ERROR
;
1848 /* OK check attribute and store it's value. */
1851 case BGP_ATTR_ORIGIN
:
1852 ret
= bgp_attr_origin (peer
, length
, attr
, flag
, startp
);
1854 case BGP_ATTR_AS_PATH
:
1855 ret
= bgp_attr_aspath (peer
, length
, attr
, flag
, startp
);
1857 case BGP_ATTR_AS4_PATH
:
1858 ret
= bgp_attr_as4_path (peer
, length
, attr
, flag
, startp
, &as4_path
);
1860 case BGP_ATTR_NEXT_HOP
:
1861 ret
= bgp_attr_nexthop (peer
, length
, attr
, flag
, startp
);
1863 case BGP_ATTR_MULTI_EXIT_DISC
:
1864 ret
= bgp_attr_med (peer
, length
, attr
, flag
, startp
);
1866 case BGP_ATTR_LOCAL_PREF
:
1867 ret
= bgp_attr_local_pref (peer
, length
, attr
, flag
, startp
);
1869 case BGP_ATTR_ATOMIC_AGGREGATE
:
1870 ret
= bgp_attr_atomic (peer
, length
, attr
, flag
, startp
);
1872 case BGP_ATTR_AGGREGATOR
:
1873 ret
= bgp_attr_aggregator (peer
, length
, attr
, flag
, startp
);
1875 case BGP_ATTR_AS4_AGGREGATOR
:
1876 ret
= bgp_attr_as4_aggregator (peer
, length
, attr
, flag
,
1878 &as4_aggregator_addr
);
1880 case BGP_ATTR_COMMUNITIES
:
1881 ret
= bgp_attr_community (peer
, length
, attr
, flag
, startp
);
1883 case BGP_ATTR_ORIGINATOR_ID
:
1884 ret
= bgp_attr_originator_id (peer
, length
, attr
, flag
, startp
);
1886 case BGP_ATTR_CLUSTER_LIST
:
1887 ret
= bgp_attr_cluster_list (peer
, length
, attr
, flag
, startp
);
1889 case BGP_ATTR_MP_REACH_NLRI
:
1890 ret
= bgp_mp_reach_parse (peer
, length
, attr
, flag
, startp
, mp_update
);
1892 case BGP_ATTR_MP_UNREACH_NLRI
:
1893 ret
= bgp_mp_unreach_parse (peer
, length
, flag
, startp
, mp_withdraw
);
1895 case BGP_ATTR_EXT_COMMUNITIES
:
1896 ret
= bgp_attr_ext_communities (peer
, length
, attr
, flag
, startp
);
1899 ret
= bgp_attr_unknown (peer
, attr
, flag
, type
, length
, startp
);
1903 /* If hard error occured immediately return to the caller. */
1904 if (ret
== BGP_ATTR_PARSE_ERROR
)
1906 zlog (peer
->log
, LOG_WARNING
,
1907 "%s: Attribute %s, parse error",
1909 LOOKUP (attr_str
, type
));
1910 bgp_notify_send (peer
,
1911 BGP_NOTIFY_UPDATE_ERR
,
1912 BGP_NOTIFY_UPDATE_MAL_ATTR
);
1914 aspath_unintern (&as4_path
);
1917 if (ret
== BGP_ATTR_PARSE_WITHDRAW
)
1920 zlog (peer
->log
, LOG_WARNING
,
1921 "%s: Attribute %s, parse error - treating as withdrawal",
1923 LOOKUP (attr_str
, type
));
1925 aspath_unintern (&as4_path
);
1929 /* Check the fetched length. */
1930 if (BGP_INPUT_PNT (peer
) != attr_endp
)
1932 zlog (peer
->log
, LOG_WARNING
,
1933 "%s: BGP attribute %s, fetch error",
1934 peer
->host
, LOOKUP (attr_str
, type
));
1935 bgp_notify_send (peer
,
1936 BGP_NOTIFY_UPDATE_ERR
,
1937 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
1939 aspath_unintern (&as4_path
);
1940 return BGP_ATTR_PARSE_ERROR
;
1944 /* Check final read pointer is same as end pointer. */
1945 if (BGP_INPUT_PNT (peer
) != endp
)
1947 zlog (peer
->log
, LOG_WARNING
,
1948 "%s: BGP attribute %s, length mismatch",
1949 peer
->host
, LOOKUP (attr_str
, type
));
1950 bgp_notify_send (peer
,
1951 BGP_NOTIFY_UPDATE_ERR
,
1952 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
1954 aspath_unintern (&as4_path
);
1955 return BGP_ATTR_PARSE_ERROR
;
1959 * At this place we can see whether we got AS4_PATH and/or
1960 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1961 * We can not do this before we've read all attributes because
1962 * the as4 handling does not say whether AS4_PATH has to be sent
1963 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1964 * in relationship to AGGREGATOR.
1965 * So, to be defensive, we are not relying on any order and read
1966 * all attributes first, including these 32bit ones, and now,
1967 * afterwards, we look what and if something is to be done for as4.
1969 if (bgp_attr_munge_as4_attrs (peer
, attr
, flag
, as4_path
,
1970 as4_aggregator
, &as4_aggregator_addr
))
1973 aspath_unintern (&as4_path
);
1974 return BGP_ATTR_PARSE_ERROR
;
1977 /* At this stage, we have done all fiddling with as4, and the
1978 * resulting info is in attr->aggregator resp. attr->aspath
1979 * so we can chuck as4_aggregator and as4_path alltogether in
1980 * order to save memory
1984 aspath_unintern (&as4_path
); /* unintern - it is in the hash */
1985 /* The flag that we got this is still there, but that does not
1990 * The "rest" of the code does nothing with as4_aggregator.
1991 * there is no memory attached specifically which is not part
1993 * so ignoring just means do nothing.
1996 * Finally do the checks on the aspath we did not do yet
1997 * because we waited for a potentially synthesized aspath.
1999 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
)))
2001 ret
= bgp_attr_aspath_check (peer
, attr
, flag
);
2002 if (ret
!= BGP_ATTR_PARSE_PROCEED
)
2006 /* Finally intern unknown attribute. */
2007 if (attr
->extra
&& attr
->extra
->transit
)
2008 attr
->extra
->transit
= transit_intern (attr
->extra
->transit
);
2010 return BGP_ATTR_PARSE_PROCEED
;
2013 /* Well-known attribute check. */
2015 bgp_attr_check (struct peer
*peer
, struct attr
*attr
)
2019 if (! CHECK_FLAG (attr
->flag
, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN
)))
2020 type
= BGP_ATTR_ORIGIN
;
2022 if (! CHECK_FLAG (attr
->flag
, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH
)))
2023 type
= BGP_ATTR_AS_PATH
;
2025 if (! CHECK_FLAG (attr
->flag
, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP
)))
2026 type
= BGP_ATTR_NEXT_HOP
;
2028 if (peer_sort (peer
) == BGP_PEER_IBGP
2029 && ! CHECK_FLAG (attr
->flag
, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF
)))
2030 type
= BGP_ATTR_LOCAL_PREF
;
2034 zlog (peer
->log
, LOG_WARNING
,
2035 "%s Missing well-known attribute %d.",
2037 bgp_notify_send_with_data (peer
,
2038 BGP_NOTIFY_UPDATE_ERR
,
2039 BGP_NOTIFY_UPDATE_MISS_ATTR
,
2041 return BGP_ATTR_PARSE_ERROR
;
2043 return BGP_ATTR_PARSE_PROCEED
;
2046 int stream_put_prefix (struct stream
*, struct prefix
*);
2048 /* Make attribute packet. */
2050 bgp_packet_attribute (struct bgp
*bgp
, struct peer
*peer
,
2051 struct stream
*s
, struct attr
*attr
, struct prefix
*p
,
2052 afi_t afi
, safi_t safi
, struct peer
*from
,
2053 struct prefix_rd
*prd
, u_char
*tag
)
2056 size_t aspath_sizep
;
2057 struct aspath
*aspath
;
2058 int send_as4_path
= 0;
2059 int send_as4_aggregator
= 0;
2060 int use32bit
= (CHECK_FLAG (peer
->cap
, PEER_CAP_AS4_RCV
)) ? 1 : 0;
2063 bgp
= bgp_get_default ();
2065 /* Remember current pointer. */
2066 cp
= stream_get_endp (s
);
2068 /* Origin attribute. */
2069 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2070 stream_putc (s
, BGP_ATTR_ORIGIN
);
2072 stream_putc (s
, attr
->origin
);
2074 /* AS path attribute. */
2076 /* If remote-peer is EBGP */
2077 if (peer_sort (peer
) == BGP_PEER_EBGP
2078 && (! CHECK_FLAG (peer
->af_flags
[afi
][safi
], PEER_FLAG_AS_PATH_UNCHANGED
)
2079 || attr
->aspath
->segments
== NULL
)
2080 && (! CHECK_FLAG (peer
->af_flags
[afi
][safi
], PEER_FLAG_RSERVER_CLIENT
)))
2082 aspath
= aspath_dup (attr
->aspath
);
2084 if (CHECK_FLAG(bgp
->config
, BGP_CONFIG_CONFEDERATION
))
2086 /* Strip the confed info, and then stuff our path CONFED_ID
2088 aspath
= aspath_delete_confed_seq (aspath
);
2089 aspath
= aspath_add_seq (aspath
, bgp
->confed_id
);
2093 aspath
= aspath_add_seq (aspath
, peer
->local_as
);
2094 if (peer
->change_local_as
)
2095 aspath
= aspath_add_seq (aspath
, peer
->change_local_as
);
2098 else if (peer_sort (peer
) == BGP_PEER_CONFED
)
2100 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2101 aspath
= aspath_dup (attr
->aspath
);
2102 aspath
= aspath_add_confed_seq (aspath
, peer
->local_as
);
2105 aspath
= attr
->aspath
;
2107 /* If peer is not AS4 capable, then:
2108 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2109 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2110 * types are in it (i.e. exclude them if they are there)
2111 * AND do this only if there is at least one asnum > 65535 in the path!
2112 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2113 * all ASnums > 65535 to BGP_AS_TRANS
2116 stream_putc (s
, BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_EXTLEN
);
2117 stream_putc (s
, BGP_ATTR_AS_PATH
);
2118 aspath_sizep
= stream_get_endp (s
);
2120 stream_putw_at (s
, aspath_sizep
, aspath_put (s
, aspath
, use32bit
));
2122 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2125 if (!use32bit
&& aspath_has_as4 (aspath
))
2126 send_as4_path
= 1; /* we'll do this later, at the correct place */
2128 /* Nexthop attribute. */
2129 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP
) && afi
== AFI_IP
)
2131 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2132 stream_putc (s
, BGP_ATTR_NEXT_HOP
);
2134 if (safi
== SAFI_MPLS_VPN
)
2136 if (attr
->nexthop
.s_addr
== 0)
2137 stream_put_ipv4 (s
, peer
->nexthop
.v4
.s_addr
);
2139 stream_put_ipv4 (s
, attr
->nexthop
.s_addr
);
2142 stream_put_ipv4 (s
, attr
->nexthop
.s_addr
);
2145 /* MED attribute. */
2146 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC
))
2148 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
);
2149 stream_putc (s
, BGP_ATTR_MULTI_EXIT_DISC
);
2151 stream_putl (s
, attr
->med
);
2154 /* Local preference. */
2155 if (peer_sort (peer
) == BGP_PEER_IBGP
||
2156 peer_sort (peer
) == BGP_PEER_CONFED
)
2158 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2159 stream_putc (s
, BGP_ATTR_LOCAL_PREF
);
2161 stream_putl (s
, attr
->local_pref
);
2164 /* Atomic aggregate. */
2165 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE
))
2167 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2168 stream_putc (s
, BGP_ATTR_ATOMIC_AGGREGATE
);
2173 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR
))
2175 assert (attr
->extra
);
2177 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
2178 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2179 stream_putc (s
, BGP_ATTR_AGGREGATOR
);
2183 /* AS4 capable peer */
2185 stream_putl (s
, attr
->extra
->aggregator_as
);
2189 /* 2-byte AS peer */
2192 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2193 if ( attr
->extra
->aggregator_as
> 65535 )
2195 stream_putw (s
, BGP_AS_TRANS
);
2197 /* we have to send AS4_AGGREGATOR, too.
2198 * we'll do that later in order to send attributes in ascending
2201 send_as4_aggregator
= 1;
2204 stream_putw (s
, (u_int16_t
) attr
->extra
->aggregator_as
);
2206 stream_put_ipv4 (s
, attr
->extra
->aggregator_addr
.s_addr
);
2209 /* Community attribute. */
2210 if (CHECK_FLAG (peer
->af_flags
[afi
][safi
], PEER_FLAG_SEND_COMMUNITY
)
2211 && (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES
)))
2213 if (attr
->community
->size
* 4 > 255)
2215 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_EXTLEN
);
2216 stream_putc (s
, BGP_ATTR_COMMUNITIES
);
2217 stream_putw (s
, attr
->community
->size
* 4);
2221 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2222 stream_putc (s
, BGP_ATTR_COMMUNITIES
);
2223 stream_putc (s
, attr
->community
->size
* 4);
2225 stream_put (s
, attr
->community
->val
, attr
->community
->size
* 4);
2228 /* Route Reflector. */
2229 if (peer_sort (peer
) == BGP_PEER_IBGP
2231 && peer_sort (from
) == BGP_PEER_IBGP
)
2233 /* Originator ID. */
2234 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
);
2235 stream_putc (s
, BGP_ATTR_ORIGINATOR_ID
);
2238 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
))
2239 stream_put_in_addr (s
, &attr
->extra
->originator_id
);
2241 stream_put_in_addr (s
, &from
->remote_id
);
2244 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
);
2245 stream_putc (s
, BGP_ATTR_CLUSTER_LIST
);
2247 if (attr
->extra
&& attr
->extra
->cluster
)
2249 stream_putc (s
, attr
->extra
->cluster
->length
+ 4);
2250 /* If this peer configuration's parent BGP has cluster_id. */
2251 if (bgp
->config
& BGP_CONFIG_CLUSTER_ID
)
2252 stream_put_in_addr (s
, &bgp
->cluster_id
);
2254 stream_put_in_addr (s
, &bgp
->router_id
);
2255 stream_put (s
, attr
->extra
->cluster
->list
,
2256 attr
->extra
->cluster
->length
);
2261 /* If this peer configuration's parent BGP has cluster_id. */
2262 if (bgp
->config
& BGP_CONFIG_CLUSTER_ID
)
2263 stream_put_in_addr (s
, &bgp
->cluster_id
);
2265 stream_put_in_addr (s
, &bgp
->router_id
);
2270 /* If p is IPv6 address put it into attribute. */
2271 if (p
->family
== AF_INET6
)
2273 unsigned long sizep
;
2274 struct attr_extra
*attre
= attr
->extra
;
2276 assert (attr
->extra
);
2278 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
);
2279 stream_putc (s
, BGP_ATTR_MP_REACH_NLRI
);
2280 sizep
= stream_get_endp (s
);
2281 stream_putc (s
, 0); /* Marker: Attribute length. */
2282 stream_putw (s
, AFI_IP6
); /* AFI */
2283 stream_putc (s
, safi
); /* SAFI */
2285 stream_putc (s
, attre
->mp_nexthop_len
);
2287 if (attre
->mp_nexthop_len
== 16)
2288 stream_put (s
, &attre
->mp_nexthop_global
, 16);
2289 else if (attre
->mp_nexthop_len
== 32)
2291 stream_put (s
, &attre
->mp_nexthop_global
, 16);
2292 stream_put (s
, &attre
->mp_nexthop_local
, 16);
2299 stream_put_prefix (s
, p
);
2301 /* Set MP attribute length. */
2302 stream_putc_at (s
, sizep
, (stream_get_endp (s
) - sizep
) - 1);
2304 #endif /* HAVE_IPV6 */
2306 if (p
->family
== AF_INET
&& safi
== SAFI_MULTICAST
)
2308 unsigned long sizep
;
2310 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
);
2311 stream_putc (s
, BGP_ATTR_MP_REACH_NLRI
);
2312 sizep
= stream_get_endp (s
);
2313 stream_putc (s
, 0); /* Marker: Attribute Length. */
2314 stream_putw (s
, AFI_IP
); /* AFI */
2315 stream_putc (s
, SAFI_MULTICAST
); /* SAFI */
2318 stream_put_ipv4 (s
, attr
->nexthop
.s_addr
);
2324 stream_put_prefix (s
, p
);
2326 /* Set MP attribute length. */
2327 stream_putc_at (s
, sizep
, (stream_get_endp (s
) - sizep
) - 1);
2330 if (p
->family
== AF_INET
&& safi
== SAFI_MPLS_VPN
)
2332 unsigned long sizep
;
2334 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
);
2335 stream_putc (s
, BGP_ATTR_MP_REACH_NLRI
);
2336 sizep
= stream_get_endp (s
);
2337 stream_putc (s
, 0); /* Length of this attribute. */
2338 stream_putw (s
, AFI_IP
); /* AFI */
2339 stream_putc (s
, SAFI_MPLS_LABELED_VPN
); /* SAFI */
2341 stream_putc (s
, 12);
2344 stream_put (s
, &attr
->extra
->mp_nexthop_global_in
, 4);
2349 /* Tag, RD, Prefix write. */
2350 stream_putc (s
, p
->prefixlen
+ 88);
2351 stream_put (s
, tag
, 3);
2352 stream_put (s
, prd
->val
, 8);
2353 stream_put (s
, &p
->u
.prefix
, PSIZE (p
->prefixlen
));
2355 /* Set MP attribute length. */
2356 stream_putc_at (s
, sizep
, (stream_get_endp (s
) - sizep
) - 1);
2359 /* Extended Communities attribute. */
2360 if (CHECK_FLAG (peer
->af_flags
[afi
][safi
], PEER_FLAG_SEND_EXT_COMMUNITY
)
2361 && (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES
)))
2363 struct attr_extra
*attre
= attr
->extra
;
2367 if (peer_sort (peer
) == BGP_PEER_IBGP
2368 || peer_sort (peer
) == BGP_PEER_CONFED
)
2370 if (attre
->ecommunity
->size
* 8 > 255)
2372 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_EXTLEN
);
2373 stream_putc (s
, BGP_ATTR_EXT_COMMUNITIES
);
2374 stream_putw (s
, attre
->ecommunity
->size
* 8);
2378 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2379 stream_putc (s
, BGP_ATTR_EXT_COMMUNITIES
);
2380 stream_putc (s
, attre
->ecommunity
->size
* 8);
2382 stream_put (s
, attre
->ecommunity
->val
, attre
->ecommunity
->size
* 8);
2388 int ecom_tr_size
= 0;
2391 for (i
= 0; i
< attre
->ecommunity
->size
; i
++)
2393 pnt
= attre
->ecommunity
->val
+ (i
* 8);
2396 if (CHECK_FLAG (tbit
, ECOMMUNITY_FLAG_NON_TRANSITIVE
))
2404 if (ecom_tr_size
* 8 > 255)
2406 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_EXTLEN
);
2407 stream_putc (s
, BGP_ATTR_EXT_COMMUNITIES
);
2408 stream_putw (s
, ecom_tr_size
* 8);
2412 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2413 stream_putc (s
, BGP_ATTR_EXT_COMMUNITIES
);
2414 stream_putc (s
, ecom_tr_size
* 8);
2417 for (i
= 0; i
< attre
->ecommunity
->size
; i
++)
2419 pnt
= attre
->ecommunity
->val
+ (i
* 8);
2422 if (CHECK_FLAG (tbit
, ECOMMUNITY_FLAG_NON_TRANSITIVE
))
2425 stream_put (s
, pnt
, 8);
2431 if ( send_as4_path
)
2433 /* If the peer is NOT As4 capable, AND */
2434 /* there are ASnums > 65535 in path THEN
2435 * give out AS4_PATH */
2437 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2439 * Hm, I wonder... confederation things *should* only be at
2440 * the beginning of an aspath, right? Then we should use
2441 * aspath_delete_confed_seq for this, because it is already
2443 * Folks, talk to me: what is reasonable here!?
2445 aspath
= aspath_delete_confed_seq (aspath
);
2447 stream_putc (s
, BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_EXTLEN
);
2448 stream_putc (s
, BGP_ATTR_AS4_PATH
);
2449 aspath_sizep
= stream_get_endp (s
);
2451 stream_putw_at (s
, aspath_sizep
, aspath_put (s
, aspath
, 1));
2454 if (aspath
!= attr
->aspath
)
2455 aspath_free (aspath
);
2457 if ( send_as4_aggregator
)
2459 assert (attr
->extra
);
2461 /* send AS4_AGGREGATOR, at this place */
2462 /* this section of code moved here in order to ensure the correct
2463 * *ascending* order of attributes
2465 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2466 stream_putc (s
, BGP_ATTR_AS4_AGGREGATOR
);
2468 stream_putl (s
, attr
->extra
->aggregator_as
);
2469 stream_put_ipv4 (s
, attr
->extra
->aggregator_addr
.s_addr
);
2472 /* Unknown transit attribute. */
2473 if (attr
->extra
&& attr
->extra
->transit
)
2474 stream_put (s
, attr
->extra
->transit
->val
, attr
->extra
->transit
->length
);
2476 /* Return total size of attribute. */
2477 return stream_get_endp (s
) - cp
;
2481 bgp_packet_withdraw (struct peer
*peer
, struct stream
*s
, struct prefix
*p
,
2482 afi_t afi
, safi_t safi
, struct prefix_rd
*prd
,
2486 unsigned long attrlen_pnt
;
2489 cp
= stream_get_endp (s
);
2491 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
);
2492 stream_putc (s
, BGP_ATTR_MP_UNREACH_NLRI
);
2494 attrlen_pnt
= stream_get_endp (s
);
2495 stream_putc (s
, 0); /* Length of this attribute. */
2497 stream_putw (s
, family2afi (p
->family
));
2499 if (safi
== SAFI_MPLS_VPN
)
2502 stream_putc (s
, SAFI_MPLS_LABELED_VPN
);
2505 stream_putc (s
, p
->prefixlen
+ 88);
2506 stream_put (s
, tag
, 3);
2507 stream_put (s
, prd
->val
, 8);
2508 stream_put (s
, &p
->u
.prefix
, PSIZE (p
->prefixlen
));
2513 stream_putc (s
, safi
);
2516 stream_put_prefix (s
, p
);
2519 /* Set MP attribute length. */
2520 size
= stream_get_endp (s
) - attrlen_pnt
- 1;
2521 stream_putc_at (s
, attrlen_pnt
, size
);
2523 return stream_get_endp (s
) - cp
;
2526 /* Initialization of attribute. */
2528 bgp_attr_init (void)
2539 bgp_attr_finish (void)
2543 community_finish ();
2544 ecommunity_finish ();
2549 /* Make attribute packet. */
2551 bgp_dump_routes_attr (struct stream
*s
, struct attr
*attr
,
2552 struct prefix
*prefix
)
2557 struct aspath
*aspath
;
2559 /* Remember current pointer. */
2560 cp
= stream_get_endp (s
);
2562 /* Place holder of length. */
2565 /* Origin attribute. */
2566 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2567 stream_putc (s
, BGP_ATTR_ORIGIN
);
2569 stream_putc (s
, attr
->origin
);
2571 aspath
= attr
->aspath
;
2573 stream_putc (s
, BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_EXTLEN
);
2574 stream_putc (s
, BGP_ATTR_AS_PATH
);
2575 aspath_lenp
= stream_get_endp (s
);
2578 stream_putw_at (s
, aspath_lenp
, aspath_put (s
, aspath
, 1));
2580 /* Nexthop attribute. */
2581 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2584 && prefix
->family
!= AF_INET6
2585 #endif /* HAVE_IPV6 */
2588 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2589 stream_putc (s
, BGP_ATTR_NEXT_HOP
);
2591 stream_put_ipv4 (s
, attr
->nexthop
.s_addr
);
2594 /* MED attribute. */
2595 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC
))
2597 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
);
2598 stream_putc (s
, BGP_ATTR_MULTI_EXIT_DISC
);
2600 stream_putl (s
, attr
->med
);
2603 /* Local preference. */
2604 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF
))
2606 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2607 stream_putc (s
, BGP_ATTR_LOCAL_PREF
);
2609 stream_putl (s
, attr
->local_pref
);
2612 /* Atomic aggregate. */
2613 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE
))
2615 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2616 stream_putc (s
, BGP_ATTR_ATOMIC_AGGREGATE
);
2621 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR
))
2623 assert (attr
->extra
);
2624 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2625 stream_putc (s
, BGP_ATTR_AGGREGATOR
);
2627 stream_putl (s
, attr
->extra
->aggregator_as
);
2628 stream_put_ipv4 (s
, attr
->extra
->aggregator_addr
.s_addr
);
2631 /* Community attribute. */
2632 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES
))
2634 if (attr
->community
->size
* 4 > 255)
2636 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_EXTLEN
);
2637 stream_putc (s
, BGP_ATTR_COMMUNITIES
);
2638 stream_putw (s
, attr
->community
->size
* 4);
2642 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2643 stream_putc (s
, BGP_ATTR_COMMUNITIES
);
2644 stream_putc (s
, attr
->community
->size
* 4);
2646 stream_put (s
, attr
->community
->val
, attr
->community
->size
* 4);
2650 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
2651 if (prefix
!= NULL
&& prefix
->family
== AF_INET6
&& attr
->extra
&&
2652 (attr
->extra
->mp_nexthop_len
== 16 || attr
->extra
->mp_nexthop_len
== 32) )
2655 struct attr_extra
*attre
= attr
->extra
;
2657 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
2658 stream_putc(s
, BGP_ATTR_MP_REACH_NLRI
);
2659 sizep
= stream_get_endp (s
);
2662 stream_putc (s
, 0); /* Marker: Attribute length. */
2663 stream_putw(s
, AFI_IP6
); /* AFI */
2664 stream_putc(s
, SAFI_UNICAST
); /* SAFI */
2667 stream_putc(s
, attre
->mp_nexthop_len
);
2668 stream_put(s
, &attre
->mp_nexthop_global
, 16);
2669 if (attre
->mp_nexthop_len
== 32)
2670 stream_put(s
, &attre
->mp_nexthop_local
, 16);
2676 stream_put_prefix(s
, prefix
);
2678 /* Set MP attribute length. */
2679 stream_putc_at (s
, sizep
, (stream_get_endp (s
) - sizep
) - 1);
2681 #endif /* HAVE_IPV6 */
2683 /* Return total size of attribute. */
2684 len
= stream_get_endp (s
) - cp
- 2;
2685 stream_putw_at (s
, cp
, len
);