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
34 #include "bgpd/bgpd.h"
35 #include "bgpd/bgp_attr.h"
36 #include "bgpd/bgp_route.h"
37 #include "bgpd/bgp_aspath.h"
38 #include "bgpd/bgp_community.h"
39 #include "bgpd/bgp_debug.h"
40 #include "bgpd/bgp_packet.h"
41 #include "bgpd/bgp_ecommunity.h"
42 #include "bgpd/bgp_updgrp.h"
44 /* Attribute strings for logging. */
45 static const struct message attr_str
[] =
47 { BGP_ATTR_ORIGIN
, "ORIGIN" },
48 { BGP_ATTR_AS_PATH
, "AS_PATH" },
49 { BGP_ATTR_NEXT_HOP
, "NEXT_HOP" },
50 { BGP_ATTR_MULTI_EXIT_DISC
, "MULTI_EXIT_DISC" },
51 { BGP_ATTR_LOCAL_PREF
, "LOCAL_PREF" },
52 { BGP_ATTR_ATOMIC_AGGREGATE
, "ATOMIC_AGGREGATE" },
53 { BGP_ATTR_AGGREGATOR
, "AGGREGATOR" },
54 { BGP_ATTR_COMMUNITIES
, "COMMUNITY" },
55 { BGP_ATTR_ORIGINATOR_ID
, "ORIGINATOR_ID" },
56 { BGP_ATTR_CLUSTER_LIST
, "CLUSTER_LIST" },
57 { BGP_ATTR_DPA
, "DPA" },
58 { BGP_ATTR_ADVERTISER
, "ADVERTISER"} ,
59 { BGP_ATTR_RCID_PATH
, "RCID_PATH" },
60 { BGP_ATTR_MP_REACH_NLRI
, "MP_REACH_NLRI" },
61 { BGP_ATTR_MP_UNREACH_NLRI
, "MP_UNREACH_NLRI" },
62 { BGP_ATTR_EXT_COMMUNITIES
, "EXT_COMMUNITIES" },
63 { BGP_ATTR_AS4_PATH
, "AS4_PATH" },
64 { BGP_ATTR_AS4_AGGREGATOR
, "AS4_AGGREGATOR" },
65 { BGP_ATTR_AS_PATHLIMIT
, "AS_PATHLIMIT" },
67 static const int attr_str_max
= array_size(attr_str
);
69 static const struct message attr_flag_str
[] =
71 { BGP_ATTR_FLAG_OPTIONAL
, "Optional" },
72 { BGP_ATTR_FLAG_TRANS
, "Transitive" },
73 { BGP_ATTR_FLAG_PARTIAL
, "Partial" },
74 /* bgp_attr_flags_diagnose() relies on this bit being last in this list */
75 { BGP_ATTR_FLAG_EXTLEN
, "Extended Length" },
77 static const size_t attr_flag_str_max
= array_size(attr_flag_str
);
79 static struct hash
*cluster_hash
;
82 cluster_hash_alloc (void *p
)
84 struct cluster_list
* val
= (struct cluster_list
*) p
;
85 struct cluster_list
*cluster
;
87 cluster
= XMALLOC (MTYPE_CLUSTER
, sizeof (struct cluster_list
));
88 cluster
->length
= val
->length
;
92 cluster
->list
= XMALLOC (MTYPE_CLUSTER_VAL
, val
->length
);
93 memcpy (cluster
->list
, val
->list
, val
->length
);
103 /* Cluster list related functions. */
104 static struct cluster_list
*
105 cluster_parse (struct in_addr
* pnt
, int length
)
107 struct cluster_list tmp
;
108 struct cluster_list
*cluster
;
113 cluster
= hash_get (cluster_hash
, &tmp
, cluster_hash_alloc
);
119 cluster_loop_check (struct cluster_list
*cluster
, struct in_addr originator
)
123 for (i
= 0; i
< cluster
->length
/ 4; i
++)
124 if (cluster
->list
[i
].s_addr
== originator
.s_addr
)
130 cluster_hash_key_make (void *p
)
132 const struct cluster_list
*cluster
= p
;
134 return jhash(cluster
->list
, cluster
->length
, 0);
138 cluster_hash_cmp (const void *p1
, const void *p2
)
140 const struct cluster_list
* cluster1
= p1
;
141 const struct cluster_list
* cluster2
= p2
;
143 return (cluster1
->length
== cluster2
->length
&&
144 memcmp (cluster1
->list
, cluster2
->list
, cluster1
->length
) == 0);
148 cluster_free (struct cluster_list
*cluster
)
151 XFREE (MTYPE_CLUSTER_VAL
, cluster
->list
);
152 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
);
174 static struct cluster_list
*
175 cluster_intern (struct cluster_list
*cluster
)
177 struct cluster_list
*find
;
179 find
= hash_get (cluster_hash
, cluster
, cluster_hash_alloc
);
186 cluster_unintern (struct cluster_list
*cluster
)
191 if (cluster
->refcnt
== 0)
193 hash_release (cluster_hash
, cluster
);
194 cluster_free (cluster
);
201 cluster_hash
= hash_create (cluster_hash_key_make
, cluster_hash_cmp
);
205 cluster_finish (void)
207 hash_free (cluster_hash
);
211 /* Unknown transit attribute. */
212 static struct hash
*transit_hash
;
215 transit_free (struct transit
*transit
)
218 XFREE (MTYPE_TRANSIT_VAL
, transit
->val
);
219 XFREE (MTYPE_TRANSIT
, transit
);
222 static struct transit
*
223 transit_dup (struct transit
*transit
)
227 new = XCALLOC (MTYPE_TRANSIT
, sizeof (struct transit
));
228 new->length
= transit
->length
;
231 new->val
= XMALLOC (MTYPE_TRANSIT_VAL
, transit
->length
);
232 memcpy (new->val
, transit
->val
, transit
->length
);
241 transit_hash_alloc (void *p
)
243 /* Transit structure is already allocated. */
247 static struct transit
*
248 transit_intern (struct transit
*transit
)
250 struct transit
*find
;
252 find
= hash_get (transit_hash
, transit
, transit_hash_alloc
);
254 transit_free (transit
);
261 transit_unintern (struct transit
*transit
)
266 if (transit
->refcnt
== 0)
268 hash_release (transit_hash
, transit
);
269 transit_free (transit
);
274 transit_hash_key_make (void *p
)
276 const struct transit
* transit
= p
;
278 return jhash(transit
->val
, transit
->length
, 0);
282 transit_hash_cmp (const void *p1
, const void *p2
)
284 const struct transit
* transit1
= p1
;
285 const struct transit
* transit2
= p2
;
287 return (transit1
->length
== transit2
->length
&&
288 memcmp (transit1
->val
, transit2
->val
, transit1
->length
) == 0);
294 transit_hash
= hash_create (transit_hash_key_make
, transit_hash_cmp
);
298 transit_finish (void)
300 hash_free (transit_hash
);
304 /* Attribute hash routines. */
305 static struct hash
*attrhash
;
307 static struct attr_extra
*
308 bgp_attr_extra_new (void)
310 return XCALLOC (MTYPE_ATTR_EXTRA
, sizeof (struct attr_extra
));
314 bgp_attr_extra_free (struct attr
*attr
)
318 XFREE (MTYPE_ATTR_EXTRA
, attr
->extra
);
324 bgp_attr_extra_get (struct attr
*attr
)
327 attr
->extra
= bgp_attr_extra_new();
331 /* Shallow copy of an attribute
332 * Though, not so shallow that it doesn't copy the contents
333 * of the attr_extra pointed to by 'extra'
336 bgp_attr_dup (struct attr
*new, struct attr
*orig
)
338 struct attr_extra
*extra
= new->extra
;
341 /* if caller provided attr_extra space, use it in any case.
343 * This is neccesary even if orig->extra equals NULL, because otherwise
344 * memory may be later allocated on the heap by bgp_attr_extra_get.
346 * That memory would eventually be leaked, because the caller must not
347 * call bgp_attr_extra_free if he provided attr_extra on the stack.
352 memset(new->extra
, 0, sizeof(struct attr_extra
));
354 *new->extra
= *orig
->extra
;
356 else if (orig
->extra
)
358 new->extra
= bgp_attr_extra_new();
359 *new->extra
= *orig
->extra
;
364 bgp_attr_deep_dup (struct attr
*new, struct attr
*orig
)
367 new->aspath
= aspath_dup(orig
->aspath
);
370 new->community
= community_dup(orig
->community
);
374 if (orig
->extra
->ecommunity
)
375 new->extra
->ecommunity
= ecommunity_dup(orig
->extra
->ecommunity
);
376 if (orig
->extra
->cluster
)
377 new->extra
->cluster
= cluster_dup(orig
->extra
->cluster
);
378 if (orig
->extra
->transit
)
379 new->extra
->transit
= transit_dup(orig
->extra
->transit
);
384 bgp_attr_deep_free (struct attr
*attr
)
387 aspath_free(attr
->aspath
);
390 community_free(attr
->community
);
394 if (attr
->extra
->ecommunity
)
395 ecommunity_free(&attr
->extra
->ecommunity
);
396 if (attr
->extra
->cluster
)
397 cluster_free(attr
->extra
->cluster
);
398 if (attr
->extra
->transit
)
399 transit_free(attr
->extra
->transit
);
406 return attrhash
->count
;
410 attr_unknown_count (void)
412 return transit_hash
->count
;
416 attrhash_key_make (void *p
)
418 const struct attr
*attr
= (struct attr
*) p
;
419 const struct attr_extra
*extra
= attr
->extra
;
421 #define MIX(val) key = jhash_1word(val, key)
424 MIX(attr
->nexthop
.s_addr
);
426 MIX(attr
->local_pref
);
429 key
+= attr
->nexthop
.s_addr
;
431 key
+= attr
->local_pref
;
435 MIX(extra
->aggregator_as
);
436 MIX(extra
->aggregator_addr
.s_addr
);
438 MIX(extra
->mp_nexthop_global_in
.s_addr
);
439 MIX(extra
->originator_id
.s_addr
);
444 MIX(aspath_key_make (attr
->aspath
));
446 MIX(community_hash_make (attr
->community
));
450 if (extra
->ecommunity
)
451 MIX(ecommunity_hash_make (extra
->ecommunity
));
453 MIX(cluster_hash_key_make (extra
->cluster
));
455 MIX(transit_hash_key_make (extra
->transit
));
458 MIX(extra
->mp_nexthop_len
);
459 key
= jhash(extra
->mp_nexthop_global
.s6_addr
, IPV6_MAX_BYTELEN
, key
);
460 key
= jhash(extra
->mp_nexthop_local
.s6_addr
, IPV6_MAX_BYTELEN
, key
);
461 #endif /* HAVE_IPV6 */
468 attrhash_cmp (const void *p1
, const void *p2
)
470 const struct attr
* attr1
= p1
;
471 const struct attr
* attr2
= p2
;
473 if (attr1
->flag
== attr2
->flag
474 && attr1
->origin
== attr2
->origin
475 && attr1
->nexthop
.s_addr
== attr2
->nexthop
.s_addr
476 && attr1
->aspath
== attr2
->aspath
477 && attr1
->community
== attr2
->community
478 && attr1
->med
== attr2
->med
479 && attr1
->local_pref
== attr2
->local_pref
480 && attr1
->rmap_change_flags
== attr2
->rmap_change_flags
)
482 const struct attr_extra
*ae1
= attr1
->extra
;
483 const struct attr_extra
*ae2
= attr2
->extra
;
486 && ae1
->aggregator_as
== ae2
->aggregator_as
487 && ae1
->aggregator_addr
.s_addr
== ae2
->aggregator_addr
.s_addr
488 && ae1
->weight
== ae2
->weight
489 && ae1
->tag
== ae2
->tag
491 && ae1
->mp_nexthop_len
== ae2
->mp_nexthop_len
492 && IPV6_ADDR_SAME (&ae1
->mp_nexthop_global
, &ae2
->mp_nexthop_global
)
493 && IPV6_ADDR_SAME (&ae1
->mp_nexthop_local
, &ae2
->mp_nexthop_local
)
494 #endif /* HAVE_IPV6 */
495 && IPV4_ADDR_SAME (&ae1
->mp_nexthop_global_in
, &ae2
->mp_nexthop_global_in
)
496 && ae1
->ecommunity
== ae2
->ecommunity
497 && ae1
->cluster
== ae2
->cluster
498 && ae1
->transit
== ae2
->transit
499 && IPV4_ADDR_SAME (&ae1
->originator_id
, &ae2
->originator_id
))
503 /* neither attribute has extra attributes, so they're same */
513 attrhash
= hash_create (attrhash_key_make
, attrhash_cmp
);
517 attrhash_finish (void)
519 hash_free (attrhash
);
524 attr_show_all_iterator (struct hash_backet
*backet
, struct vty
*vty
)
526 struct attr
*attr
= backet
->data
;
528 vty_out (vty
, "attr[%ld] nexthop %s%s", attr
->refcnt
,
529 inet_ntoa (attr
->nexthop
), VTY_NEWLINE
);
533 attr_show_all (struct vty
*vty
)
535 hash_iterate (attrhash
,
536 (void (*)(struct hash_backet
*, void *))
537 attr_show_all_iterator
,
542 bgp_attr_hash_alloc (void *p
)
544 struct attr
* val
= (struct attr
*) p
;
547 attr
= XMALLOC (MTYPE_ATTR
, sizeof (struct attr
));
551 attr
->extra
= bgp_attr_extra_new ();
552 *attr
->extra
= *val
->extra
;
558 /* Internet argument attribute. */
560 bgp_attr_intern (struct attr
*attr
)
564 /* Intern referenced strucutre. */
567 if (! attr
->aspath
->refcnt
)
568 attr
->aspath
= aspath_intern (attr
->aspath
);
570 attr
->aspath
->refcnt
++;
574 if (! attr
->community
->refcnt
)
575 attr
->community
= community_intern (attr
->community
);
577 attr
->community
->refcnt
++;
581 struct attr_extra
*attre
= attr
->extra
;
583 if (attre
->ecommunity
)
585 if (! attre
->ecommunity
->refcnt
)
586 attre
->ecommunity
= ecommunity_intern (attre
->ecommunity
);
588 attre
->ecommunity
->refcnt
++;
593 if (! attre
->cluster
->refcnt
)
594 attre
->cluster
= cluster_intern (attre
->cluster
);
596 attre
->cluster
->refcnt
++;
600 if (! attre
->transit
->refcnt
)
601 attre
->transit
= transit_intern (attre
->transit
);
603 attre
->transit
->refcnt
++;
607 find
= (struct attr
*) hash_get (attrhash
, attr
, bgp_attr_hash_alloc
);
614 * Increment the refcount on various structures that attr holds.
615 * Note on usage: call _only_ when the 'attr' object has already
616 * been 'intern'ed and exists in 'attrhash' table. The function
617 * serves to hold a reference to that (real) object.
618 * Note also that the caller can safely call bgp_attr_unintern()
619 * after calling bgp_attr_refcount(). That would release the
620 * reference and could result in a free() of the attr object.
623 bgp_attr_refcount (struct attr
*attr
)
625 /* Intern referenced strucutre. */
627 attr
->aspath
->refcnt
++;
630 attr
->community
->refcnt
++;
634 struct attr_extra
*attre
= attr
->extra
;
635 if (attre
->ecommunity
)
636 attre
->ecommunity
->refcnt
++;
639 attre
->cluster
->refcnt
++;
642 attre
->transit
->refcnt
++;
648 /* Make network statement's attribute. */
650 bgp_attr_default_set (struct attr
*attr
, u_char origin
)
652 memset (attr
, 0, sizeof (struct attr
));
653 bgp_attr_extra_get (attr
);
655 attr
->origin
= origin
;
656 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN
);
657 attr
->aspath
= aspath_empty ();
658 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH
);
659 attr
->extra
->weight
= BGP_ATTR_DEFAULT_WEIGHT
;
660 attr
->extra
->tag
= 0;
661 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP
);
663 attr
->extra
->mp_nexthop_len
= IPV6_MAX_BYTELEN
;
670 /* Make network statement's attribute. */
672 bgp_attr_default_intern (u_char origin
)
677 bgp_attr_default_set(&attr
, origin
);
679 new = bgp_attr_intern (&attr
);
680 bgp_attr_extra_free (&attr
);
682 aspath_unintern (&new->aspath
);
686 /* Create the attributes for an aggregate */
688 bgp_attr_aggregate_intern (struct bgp
*bgp
, u_char origin
,
689 struct aspath
*aspath
,
690 struct community
*community
, int as_set
,
691 u_char atomic_aggregate
)
695 struct attr_extra attre
;
697 memset (&attr
, 0, sizeof (struct attr
));
698 memset (&attre
, 0, sizeof (struct attr_extra
));
701 /* Origin attribute. */
702 attr
.origin
= origin
;
703 attr
.flag
|= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN
);
705 /* AS path attribute. */
707 attr
.aspath
= aspath_intern (aspath
);
709 attr
.aspath
= aspath_empty ();
710 attr
.flag
|= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH
);
712 /* Next hop attribute. */
713 attr
.flag
|= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP
);
717 attr
.community
= community
;
718 attr
.flag
|= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES
);
721 attre
.weight
= BGP_ATTR_DEFAULT_WEIGHT
;
723 attre
.mp_nexthop_len
= IPV6_MAX_BYTELEN
;
725 if (! as_set
|| atomic_aggregate
)
726 attr
.flag
|= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE
);
727 attr
.flag
|= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR
);
728 if (CHECK_FLAG (bgp
->config
, BGP_CONFIG_CONFEDERATION
))
729 attre
.aggregator_as
= bgp
->confed_id
;
731 attre
.aggregator_as
= bgp
->as
;
732 attre
.aggregator_addr
= bgp
->router_id
;
734 new = bgp_attr_intern (&attr
);
736 aspath_unintern (&new->aspath
);
740 /* Unintern just the sub-components of the attr, but not the attr */
742 bgp_attr_unintern_sub (struct attr
*attr
)
744 /* aspath refcount shoud be decrement. */
746 aspath_unintern (&attr
->aspath
);
747 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH
));
750 community_unintern (&attr
->community
);
751 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES
));
755 if (attr
->extra
->ecommunity
)
756 ecommunity_unintern (&attr
->extra
->ecommunity
);
757 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES
));
759 if (attr
->extra
->cluster
)
760 cluster_unintern (attr
->extra
->cluster
);
761 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST
));
763 if (attr
->extra
->transit
)
764 transit_unintern (attr
->extra
->transit
);
768 /* Free bgp attribute and aspath. */
770 bgp_attr_unintern (struct attr
**pattr
)
772 struct attr
*attr
= *pattr
;
775 struct attr_extra tmp_extra
;
777 /* Decrement attribute reference. */
784 tmp
.extra
= &tmp_extra
;
785 memcpy (tmp
.extra
, attr
->extra
, sizeof (struct attr_extra
));
788 /* If reference becomes zero then free attribute object. */
789 if (attr
->refcnt
== 0)
791 ret
= hash_release (attrhash
, attr
);
792 assert (ret
!= NULL
);
793 bgp_attr_extra_free (attr
);
794 XFREE (MTYPE_ATTR
, attr
);
798 bgp_attr_unintern_sub (&tmp
);
802 bgp_attr_flush (struct attr
*attr
)
804 if (attr
->aspath
&& ! attr
->aspath
->refcnt
)
805 aspath_free (attr
->aspath
);
806 if (attr
->community
&& ! attr
->community
->refcnt
)
807 community_free (attr
->community
);
810 struct attr_extra
*attre
= attr
->extra
;
812 if (attre
->ecommunity
&& ! attre
->ecommunity
->refcnt
)
813 ecommunity_free (&attre
->ecommunity
);
814 if (attre
->cluster
&& ! attre
->cluster
->refcnt
)
815 cluster_free (attre
->cluster
);
816 if (attre
->transit
&& ! attre
->transit
->refcnt
)
817 transit_free (attre
->transit
);
821 /* Implement draft-scudder-idr-optional-transitive behaviour and
822 * avoid resetting sessions for malformed attributes which are
823 * are partial/optional and hence where the error likely was not
824 * introduced by the sending neighbour.
826 static bgp_attr_parse_ret_t
827 bgp_attr_malformed (struct bgp_attr_parser_args
*args
, u_char subcode
,
830 struct peer
*const peer
= args
->peer
;
831 const u_int8_t flags
= args
->flags
;
832 /* startp and length must be special-cased, as whether or not to
833 * send the attribute data with the NOTIFY depends on the error,
834 * the caller therefore signals this with the seperate length argument
836 u_char
*notify_datap
= (length
> 0 ? args
->startp
: NULL
);
838 /* Only relax error handling for eBGP peers */
839 if (peer
->sort
!= BGP_PEER_EBGP
)
841 bgp_notify_send_with_data (peer
, BGP_NOTIFY_UPDATE_ERR
, subcode
,
842 notify_datap
, length
);
843 return BGP_ATTR_PARSE_ERROR
;
847 /* Adjust the stream getp to the end of the attribute, in case we can
848 * still proceed but the caller hasn't read all the attribute.
850 stream_set_getp (BGP_INPUT (peer
),
851 (args
->startp
- STREAM_DATA (BGP_INPUT (peer
)))
854 switch (args
->type
) {
855 /* where an attribute is relatively inconsequential, e.g. it does not
856 * affect route selection, and can be safely ignored, then any such
857 * attributes which are malformed should just be ignored and the route
858 * processed as normal.
860 case BGP_ATTR_AS4_AGGREGATOR
:
861 case BGP_ATTR_AGGREGATOR
:
862 case BGP_ATTR_ATOMIC_AGGREGATE
:
863 return BGP_ATTR_PARSE_PROCEED
;
865 /* Core attributes, particularly ones which may influence route
866 * selection, should always cause session resets
868 case BGP_ATTR_ORIGIN
:
869 case BGP_ATTR_AS_PATH
:
870 case BGP_ATTR_NEXT_HOP
:
871 case BGP_ATTR_MULTI_EXIT_DISC
:
872 case BGP_ATTR_LOCAL_PREF
:
873 case BGP_ATTR_COMMUNITIES
:
874 case BGP_ATTR_ORIGINATOR_ID
:
875 case BGP_ATTR_CLUSTER_LIST
:
876 case BGP_ATTR_MP_REACH_NLRI
:
877 case BGP_ATTR_MP_UNREACH_NLRI
:
878 case BGP_ATTR_EXT_COMMUNITIES
:
879 bgp_notify_send_with_data (peer
, BGP_NOTIFY_UPDATE_ERR
, subcode
,
880 notify_datap
, length
);
881 return BGP_ATTR_PARSE_ERROR
;
884 /* Partial optional attributes that are malformed should not cause
885 * the whole session to be reset. Instead treat it as a withdrawal
886 * of the routes, if possible.
888 if (CHECK_FLAG (flags
, BGP_ATTR_FLAG_TRANS
)
889 && CHECK_FLAG (flags
, BGP_ATTR_FLAG_OPTIONAL
)
890 && CHECK_FLAG (flags
, BGP_ATTR_FLAG_PARTIAL
))
891 return BGP_ATTR_PARSE_WITHDRAW
;
893 /* default to reset */
894 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
897 /* Find out what is wrong with the path attribute flag bits and log the error.
898 "Flag bits" here stand for Optional, Transitive and Partial, but not for
899 Extended Length. Checking O/T/P bits at once implies, that the attribute
900 being diagnosed is defined by RFC as either a "well-known" or an "optional,
901 non-transitive" attribute. */
903 bgp_attr_flags_diagnose (struct bgp_attr_parser_args
*args
,
904 u_int8_t desired_flags
/* how RFC says it must be */
908 u_char real_flags
= args
->flags
;
909 const u_int8_t attr_code
= args
->type
;
911 desired_flags
&= ~BGP_ATTR_FLAG_EXTLEN
;
912 real_flags
&= ~BGP_ATTR_FLAG_EXTLEN
;
913 for (i
= 0; i
<= 2; i
++) /* O,T,P, but not E */
916 CHECK_FLAG (desired_flags
, attr_flag_str
[i
].key
) !=
917 CHECK_FLAG (real_flags
, attr_flag_str
[i
].key
)
920 zlog_err ("%s attribute must%s be flagged as \"%s\"",
921 LOOKUP (attr_str
, attr_code
),
922 CHECK_FLAG (desired_flags
, attr_flag_str
[i
].key
) ? "" : " not",
923 attr_flag_str
[i
].str
);
928 zlog_debug ("Strange, %s called for attr %s, but no problem found with flags"
929 " (real flags 0x%x, desired 0x%x)",
930 __func__
, LOOKUP (attr_str
, attr_code
),
931 real_flags
, desired_flags
);
935 /* Required flags for attributes. EXTLEN will be masked off when testing,
936 * as will PARTIAL for optional+transitive attributes.
938 const u_int8_t attr_flags_values
[] = {
939 [BGP_ATTR_ORIGIN
] = BGP_ATTR_FLAG_TRANS
,
940 [BGP_ATTR_AS_PATH
] = BGP_ATTR_FLAG_TRANS
,
941 [BGP_ATTR_NEXT_HOP
] = BGP_ATTR_FLAG_TRANS
,
942 [BGP_ATTR_MULTI_EXIT_DISC
] = BGP_ATTR_FLAG_OPTIONAL
,
943 [BGP_ATTR_LOCAL_PREF
] = BGP_ATTR_FLAG_TRANS
,
944 [BGP_ATTR_ATOMIC_AGGREGATE
] = BGP_ATTR_FLAG_TRANS
,
945 [BGP_ATTR_AGGREGATOR
] = BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
,
946 [BGP_ATTR_COMMUNITIES
] = BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
,
947 [BGP_ATTR_ORIGINATOR_ID
] = BGP_ATTR_FLAG_OPTIONAL
,
948 [BGP_ATTR_CLUSTER_LIST
] = BGP_ATTR_FLAG_OPTIONAL
,
949 [BGP_ATTR_MP_REACH_NLRI
] = BGP_ATTR_FLAG_OPTIONAL
,
950 [BGP_ATTR_MP_UNREACH_NLRI
] = BGP_ATTR_FLAG_OPTIONAL
,
951 [BGP_ATTR_EXT_COMMUNITIES
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
952 [BGP_ATTR_AS4_PATH
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
953 [BGP_ATTR_AS4_AGGREGATOR
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
955 static const size_t attr_flags_values_max
=
956 sizeof (attr_flags_values
) / sizeof (attr_flags_values
[0]);
959 bgp_attr_flag_invalid (struct bgp_attr_parser_args
*args
)
961 u_int8_t mask
= BGP_ATTR_FLAG_EXTLEN
;
962 const u_int8_t flags
= args
->flags
;
963 const u_int8_t attr_code
= args
->type
;
964 struct peer
*const peer
= args
->peer
;
966 /* there may be attributes we don't know about */
967 if (attr_code
> attr_flags_values_max
)
969 if (attr_flags_values
[attr_code
] == 0)
972 /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
975 if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL
, flags
)
976 && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS
, flags
))
978 zlog_err ("%s well-known attributes must have transitive flag set (%x)",
979 LOOKUP (attr_str
, attr_code
), flags
);
983 /* "For well-known attributes and for optional non-transitive attributes,
984 * the Partial bit MUST be set to 0."
986 if (CHECK_FLAG (flags
, BGP_ATTR_FLAG_PARTIAL
))
988 if (!CHECK_FLAG (flags
, BGP_ATTR_FLAG_OPTIONAL
))
990 zlog_err ("%s well-known attribute "
991 "must NOT have the partial flag set (%x)",
992 LOOKUP (attr_str
, attr_code
), flags
);
995 if (CHECK_FLAG (flags
, BGP_ATTR_FLAG_OPTIONAL
)
996 && !CHECK_FLAG (flags
, BGP_ATTR_FLAG_TRANS
))
998 zlog_err ("%s optional + transitive attribute "
999 "must NOT have the partial flag set (%x)",
1000 LOOKUP (attr_str
, attr_code
), flags
);
1005 /* Optional transitive attributes may go through speakers that don't
1006 * reocgnise them and set the Partial bit.
1008 if (CHECK_FLAG (flags
, BGP_ATTR_FLAG_OPTIONAL
)
1009 && CHECK_FLAG (flags
, BGP_ATTR_FLAG_TRANS
))
1010 SET_FLAG (mask
, BGP_ATTR_FLAG_PARTIAL
);
1013 == attr_flags_values
[attr_code
])
1016 bgp_attr_flags_diagnose (args
, attr_flags_values
[attr_code
]);
1020 /* Get origin attribute of the update message. */
1021 static bgp_attr_parse_ret_t
1022 bgp_attr_origin (struct bgp_attr_parser_args
*args
)
1024 struct peer
*const peer
= args
->peer
;
1025 struct attr
*const attr
= args
->attr
;
1026 const bgp_size_t length
= args
->length
;
1028 /* If any recognized attribute has Attribute Length that conflicts
1029 with the expected length (based on the attribute type code), then
1030 the Error Subcode is set to Attribute Length Error. The Data
1031 field contains the erroneous attribute (type, length and
1035 zlog_err ("Origin attribute length is not one %d", length
);
1036 return bgp_attr_malformed (args
,
1037 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1041 /* Fetch origin attribute. */
1042 attr
->origin
= stream_getc (BGP_INPUT (peer
));
1044 /* If the ORIGIN attribute has an undefined value, then the Error
1045 Subcode is set to Invalid Origin Attribute. The Data field
1046 contains the unrecognized attribute (type, length and value). */
1047 if ((attr
->origin
!= BGP_ORIGIN_IGP
)
1048 && (attr
->origin
!= BGP_ORIGIN_EGP
)
1049 && (attr
->origin
!= BGP_ORIGIN_INCOMPLETE
))
1051 zlog_err ("Origin attribute value is invalid %d", attr
->origin
);
1052 return bgp_attr_malformed (args
,
1053 BGP_NOTIFY_UPDATE_INVAL_ORIGIN
,
1057 /* Set oring attribute flag. */
1058 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN
);
1063 /* Parse AS path information. This function is wrapper of
1066 bgp_attr_aspath (struct bgp_attr_parser_args
*args
)
1068 struct attr
*const attr
= args
->attr
;
1069 struct peer
*const peer
= args
->peer
;
1070 const bgp_size_t length
= args
->length
;
1073 * peer with AS4 => will get 4Byte ASnums
1074 * otherwise, will get 16 Bit
1076 attr
->aspath
= aspath_parse (peer
->ibuf
, length
,
1077 CHECK_FLAG (peer
->cap
, PEER_CAP_AS4_RCV
));
1079 /* In case of IBGP, length will be zero. */
1082 zlog_err ("Malformed AS path from %s, length is %d", peer
->host
, length
);
1083 return bgp_attr_malformed (args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
, 0);
1086 /* Set aspath attribute flag. */
1087 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH
);
1089 return BGP_ATTR_PARSE_PROCEED
;
1092 static bgp_attr_parse_ret_t
1093 bgp_attr_aspath_check (struct peer
*const peer
, struct attr
*const attr
)
1095 /* These checks were part of bgp_attr_aspath, but with
1096 * as4 we should to check aspath things when
1097 * aspath synthesizing with as4_path has already taken place.
1098 * Otherwise we check ASPATH and use the synthesized thing, and that is
1100 * So do the checks later, i.e. here
1102 struct bgp
*bgp
= peer
->bgp
;
1103 struct aspath
*aspath
;
1105 /* Confederation sanity check. */
1106 if ((peer
->sort
== BGP_PEER_CONFED
&& ! aspath_left_confed_check (attr
->aspath
)) ||
1107 (peer
->sort
== BGP_PEER_EBGP
&& aspath_confed_check (attr
->aspath
)))
1109 zlog_err ("Malformed AS path from %s", peer
->host
);
1110 bgp_notify_send (peer
, BGP_NOTIFY_UPDATE_ERR
,
1111 BGP_NOTIFY_UPDATE_MAL_AS_PATH
);
1112 return BGP_ATTR_PARSE_ERROR
;
1115 /* First AS check for EBGP. */
1116 if (bgp
!= NULL
&& bgp_flag_check (bgp
, BGP_FLAG_ENFORCE_FIRST_AS
))
1118 if (peer
->sort
== BGP_PEER_EBGP
1119 && ! aspath_firstas_check (attr
->aspath
, peer
->as
))
1121 zlog_err ("%s incorrect first AS (must be %u)", peer
->host
, peer
->as
);
1122 bgp_notify_send (peer
, BGP_NOTIFY_UPDATE_ERR
,
1123 BGP_NOTIFY_UPDATE_MAL_AS_PATH
);
1124 return BGP_ATTR_PARSE_ERROR
;
1128 /* local-as prepend */
1129 if (peer
->change_local_as
&&
1130 ! CHECK_FLAG (peer
->flags
, PEER_FLAG_LOCAL_AS_NO_PREPEND
))
1132 aspath
= aspath_dup (attr
->aspath
);
1133 aspath
= aspath_add_seq (aspath
, peer
->change_local_as
);
1134 aspath_unintern (&attr
->aspath
);
1135 attr
->aspath
= aspath_intern (aspath
);
1138 return BGP_ATTR_PARSE_PROCEED
;
1141 /* Parse AS4 path information. This function is another wrapper of
1144 bgp_attr_as4_path (struct bgp_attr_parser_args
*args
, struct aspath
**as4_path
)
1146 struct peer
*const peer
= args
->peer
;
1147 struct attr
*const attr
= args
->attr
;
1148 const bgp_size_t length
= args
->length
;
1150 *as4_path
= aspath_parse (peer
->ibuf
, length
, 1);
1152 /* In case of IBGP, length will be zero. */
1155 zlog_err ("Malformed AS4 path from %s, length is %d", peer
->host
, length
);
1156 return bgp_attr_malformed (args
,
1157 BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1161 /* Set aspath attribute flag. */
1163 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH
);
1165 return BGP_ATTR_PARSE_PROCEED
;
1168 /* Nexthop attribute. */
1169 static bgp_attr_parse_ret_t
1170 bgp_attr_nexthop (struct bgp_attr_parser_args
*args
)
1172 struct peer
*const peer
= args
->peer
;
1173 struct attr
*const attr
= args
->attr
;
1174 const bgp_size_t length
= args
->length
;
1176 in_addr_t nexthop_h
, nexthop_n
;
1178 /* Check nexthop attribute length. */
1181 zlog_err ("Nexthop attribute length isn't four [%d]", length
);
1183 return bgp_attr_malformed (args
,
1184 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1188 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1189 attribute must result in a NOTIFICATION message (this is implemented below).
1190 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1191 logged locally (this is implemented somewhere else). The UPDATE message
1192 gets ignored in any of these cases. */
1193 nexthop_n
= stream_get_ipv4 (peer
->ibuf
);
1194 nexthop_h
= ntohl (nexthop_n
);
1195 if (IPV4_NET0 (nexthop_h
) || IPV4_NET127 (nexthop_h
) || IPV4_CLASS_DE (nexthop_h
))
1197 char buf
[INET_ADDRSTRLEN
];
1198 inet_ntop (AF_INET
, &nexthop_n
, buf
, INET_ADDRSTRLEN
);
1199 zlog_err ("Martian nexthop %s", buf
);
1200 return bgp_attr_malformed (args
,
1201 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP
,
1205 attr
->nexthop
.s_addr
= nexthop_n
;
1206 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP
);
1208 return BGP_ATTR_PARSE_PROCEED
;
1211 /* MED atrribute. */
1212 static bgp_attr_parse_ret_t
1213 bgp_attr_med (struct bgp_attr_parser_args
*args
)
1215 struct peer
*const peer
= args
->peer
;
1216 struct attr
*const attr
= args
->attr
;
1217 const bgp_size_t length
= args
->length
;
1222 zlog_err ("MED attribute length isn't four [%d]", length
);
1224 return bgp_attr_malformed (args
,
1225 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1229 attr
->med
= stream_getl (peer
->ibuf
);
1231 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC
);
1233 return BGP_ATTR_PARSE_PROCEED
;
1236 /* Local preference attribute. */
1237 static bgp_attr_parse_ret_t
1238 bgp_attr_local_pref (struct bgp_attr_parser_args
*args
)
1240 struct peer
*const peer
= args
->peer
;
1241 struct attr
*const attr
= args
->attr
;
1242 const bgp_size_t length
= args
->length
;
1247 zlog_err ("LOCAL_PREF attribute length isn't 4 [%u]", length
);
1248 return bgp_attr_malformed (args
,
1249 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1253 /* If it is contained in an UPDATE message that is received from an
1254 external peer, then this attribute MUST be ignored by the
1255 receiving speaker. */
1256 if (peer
->sort
== BGP_PEER_EBGP
)
1258 stream_forward_getp (peer
->ibuf
, length
);
1259 return BGP_ATTR_PARSE_PROCEED
;
1262 attr
->local_pref
= stream_getl (peer
->ibuf
);
1264 /* Set atomic aggregate flag. */
1265 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF
);
1267 return BGP_ATTR_PARSE_PROCEED
;
1270 /* Atomic aggregate. */
1272 bgp_attr_atomic (struct bgp_attr_parser_args
*args
)
1274 struct peer
*const peer
= args
->peer
;
1275 struct attr
*const attr
= args
->attr
;
1276 const bgp_size_t length
= args
->length
;
1281 zlog_err ("ATOMIC_AGGREGATE attribute length isn't 0 [%u]", length
);
1282 return bgp_attr_malformed (args
,
1283 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1287 /* Set atomic aggregate flag. */
1288 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE
);
1290 return BGP_ATTR_PARSE_PROCEED
;
1293 /* Aggregator attribute */
1295 bgp_attr_aggregator (struct bgp_attr_parser_args
*args
)
1297 struct peer
*const peer
= args
->peer
;
1298 struct attr
*const attr
= args
->attr
;
1299 const bgp_size_t length
= args
->length
;
1302 struct attr_extra
*attre
= bgp_attr_extra_get (attr
);
1304 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1305 if (CHECK_FLAG (peer
->cap
, PEER_CAP_AS4_RCV
))
1308 if (length
!= wantedlen
)
1310 zlog_err ("AGGREGATOR attribute length isn't %u [%u]", wantedlen
, length
);
1311 return bgp_attr_malformed (args
,
1312 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1316 if ( CHECK_FLAG (peer
->cap
, PEER_CAP_AS4_RCV
) )
1317 attre
->aggregator_as
= stream_getl (peer
->ibuf
);
1319 attre
->aggregator_as
= stream_getw (peer
->ibuf
);
1320 attre
->aggregator_addr
.s_addr
= stream_get_ipv4 (peer
->ibuf
);
1322 /* Set atomic aggregate flag. */
1323 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR
);
1325 return BGP_ATTR_PARSE_PROCEED
;
1328 /* New Aggregator attribute */
1329 static bgp_attr_parse_ret_t
1330 bgp_attr_as4_aggregator (struct bgp_attr_parser_args
*args
,
1331 as_t
*as4_aggregator_as
,
1332 struct in_addr
*as4_aggregator_addr
)
1334 struct peer
*const peer
= args
->peer
;
1335 struct attr
*const attr
= args
->attr
;
1336 const bgp_size_t length
= args
->length
;
1340 zlog_err ("New Aggregator length is not 8 [%d]", length
);
1341 return bgp_attr_malformed (args
,
1342 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1346 *as4_aggregator_as
= stream_getl (peer
->ibuf
);
1347 as4_aggregator_addr
->s_addr
= stream_get_ipv4 (peer
->ibuf
);
1349 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR
);
1351 return BGP_ATTR_PARSE_PROCEED
;
1354 /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1356 static bgp_attr_parse_ret_t
1357 bgp_attr_munge_as4_attrs (struct peer
*const peer
,
1358 struct attr
*const attr
,
1359 struct aspath
*as4_path
, as_t as4_aggregator
,
1360 struct in_addr
*as4_aggregator_addr
)
1362 int ignore_as4_path
= 0;
1363 struct aspath
*newpath
;
1364 struct attr_extra
*attre
= attr
->extra
;
1366 if (CHECK_FLAG (peer
->cap
, PEER_CAP_AS4_RCV
))
1368 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1370 * It is worth a warning though, because the peer really
1371 * should not send them
1373 if (BGP_DEBUG(as4
, AS4
))
1375 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
)))
1376 zlog_debug ("[AS4] %s %s AS4_PATH",
1377 peer
->host
, "AS4 capable peer, yet it sent");
1379 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
)))
1380 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1381 peer
->host
, "AS4 capable peer, yet it sent");
1384 return BGP_ATTR_PARSE_PROCEED
;
1387 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1388 * because that may override AS4_PATH
1390 if (attr
->flag
& (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR
) ) )
1392 if (attr
->flag
& (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR
) ) )
1397 * if the as_number in aggregator is not AS_TRANS,
1398 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1399 * and the Aggregator shall be taken as
1400 * info on the aggregating node, and the AS_PATH
1401 * shall be taken as the AS_PATH
1403 * the Aggregator shall be ignored and the
1404 * AS4_AGGREGATOR shall be taken as the
1405 * Aggregating node and the AS_PATH is to be
1406 * constructed "as in all other cases"
1408 if (attre
->aggregator_as
!= BGP_AS_TRANS
)
1411 if ( BGP_DEBUG(as4
, AS4
))
1412 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1413 " send AGGREGATOR != AS_TRANS and"
1414 " AS4_AGGREGATOR, so ignore"
1415 " AS4_AGGREGATOR and AS4_PATH", peer
->host
);
1416 ignore_as4_path
= 1;
1420 /* "New_aggregator shall be taken as aggregator" */
1421 attre
->aggregator_as
= as4_aggregator
;
1422 attre
->aggregator_addr
.s_addr
= as4_aggregator_addr
->s_addr
;
1427 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1428 * That is bogus - but reading the conditions
1429 * we have to handle AS4_AGGREGATOR as if it were
1430 * AGGREGATOR in that case
1432 if ( BGP_DEBUG(as4
, AS4
))
1433 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1434 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1435 " it as if AGGREGATOR with AS_TRANS had been there", peer
->host
);
1436 (attre
= bgp_attr_extra_get (attr
))->aggregator_as
= as4_aggregator
;
1437 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1438 attr
->flag
|= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR
));
1442 /* need to reconcile NEW_AS_PATH and AS_PATH */
1443 if (!ignore_as4_path
&& (attr
->flag
& (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH
))))
1446 return BGP_ATTR_PARSE_PROCEED
;
1448 newpath
= aspath_reconcile_as4 (attr
->aspath
, as4_path
);
1449 aspath_unintern (&attr
->aspath
);
1450 attr
->aspath
= aspath_intern (newpath
);
1452 return BGP_ATTR_PARSE_PROCEED
;
1455 /* Community attribute. */
1456 static bgp_attr_parse_ret_t
1457 bgp_attr_community (struct bgp_attr_parser_args
*args
)
1459 struct peer
*const peer
= args
->peer
;
1460 struct attr
*const attr
= args
->attr
;
1461 const bgp_size_t length
= args
->length
;
1465 attr
->community
= NULL
;
1466 return BGP_ATTR_PARSE_PROCEED
;
1470 community_parse ((u_int32_t
*)stream_pnt (peer
->ibuf
), length
);
1472 /* XXX: fix community_parse to use stream API and remove this */
1473 stream_forward_getp (peer
->ibuf
, length
);
1475 if (!attr
->community
)
1476 return bgp_attr_malformed (args
,
1477 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
1480 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES
);
1482 return BGP_ATTR_PARSE_PROCEED
;
1485 /* Originator ID attribute. */
1486 static bgp_attr_parse_ret_t
1487 bgp_attr_originator_id (struct bgp_attr_parser_args
*args
)
1489 struct peer
*const peer
= args
->peer
;
1490 struct attr
*const attr
= args
->attr
;
1491 const bgp_size_t length
= args
->length
;
1496 zlog_err ("Bad originator ID length %d", length
);
1498 return bgp_attr_malformed (args
,
1499 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1503 (bgp_attr_extra_get (attr
))->originator_id
.s_addr
1504 = stream_get_ipv4 (peer
->ibuf
);
1506 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID
);
1508 return BGP_ATTR_PARSE_PROCEED
;
1511 /* Cluster list attribute. */
1512 static bgp_attr_parse_ret_t
1513 bgp_attr_cluster_list (struct bgp_attr_parser_args
*args
)
1515 struct peer
*const peer
= args
->peer
;
1516 struct attr
*const attr
= args
->attr
;
1517 const bgp_size_t length
= args
->length
;
1522 zlog_err ("Bad cluster list length %d", length
);
1524 return bgp_attr_malformed (args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1528 (bgp_attr_extra_get (attr
))->cluster
1529 = cluster_parse ((struct in_addr
*)stream_pnt (peer
->ibuf
), length
);
1531 /* XXX: Fix cluster_parse to use stream API and then remove this */
1532 stream_forward_getp (peer
->ibuf
, length
);
1534 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST
);
1536 return BGP_ATTR_PARSE_PROCEED
;
1539 /* Multiprotocol reachability information parse. */
1541 bgp_mp_reach_parse (struct bgp_attr_parser_args
*args
,
1542 struct bgp_nlri
*mp_update
)
1546 bgp_size_t nlri_len
;
1551 struct peer
*const peer
= args
->peer
;
1552 struct attr
*const attr
= args
->attr
;
1553 const bgp_size_t length
= args
->length
;
1554 struct attr_extra
*attre
= bgp_attr_extra_get(attr
);
1556 /* Set end of packet. */
1557 s
= BGP_INPUT(peer
);
1558 start
= stream_get_getp(s
);
1560 /* safe to read statically sized header? */
1561 #define BGP_MP_REACH_MIN_SIZE 5
1562 #define LEN_LEFT (length - (stream_get_getp(s) - start))
1563 if ((length
> STREAM_READABLE(s
)) || (length
< BGP_MP_REACH_MIN_SIZE
))
1565 zlog_info ("%s: %s sent invalid length, %lu",
1566 __func__
, peer
->host
, (unsigned long)length
);
1567 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
1570 /* Load AFI, SAFI. */
1571 afi
= stream_getw (s
);
1572 safi
= stream_getc (s
);
1574 /* Get nexthop length. */
1575 attre
->mp_nexthop_len
= stream_getc (s
);
1577 if (LEN_LEFT
< attre
->mp_nexthop_len
)
1579 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1580 __func__
, peer
->host
, attre
->mp_nexthop_len
);
1581 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
1584 /* Nexthop length check. */
1585 switch (attre
->mp_nexthop_len
)
1587 case BGP_ATTR_NHLEN_IPV4
:
1588 stream_get (&attre
->mp_nexthop_global_in
, s
, IPV4_MAX_BYTELEN
);
1589 /* Probably needed for RFC 2283 */
1590 if (attr
->nexthop
.s_addr
== 0)
1591 memcpy(&attr
->nexthop
.s_addr
, &attre
->mp_nexthop_global_in
, IPV4_MAX_BYTELEN
);
1593 case BGP_ATTR_NHLEN_VPNV4
:
1594 stream_getl (s
); /* RD high */
1595 stream_getl (s
); /* RD low */
1596 stream_get (&attre
->mp_nexthop_global_in
, s
, IPV4_MAX_BYTELEN
);
1599 case BGP_ATTR_NHLEN_IPV6_GLOBAL
:
1600 stream_get (&attre
->mp_nexthop_global
, s
, IPV6_MAX_BYTELEN
);
1602 case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
:
1603 stream_get (&attre
->mp_nexthop_global
, s
, IPV6_MAX_BYTELEN
);
1604 stream_get (&attre
->mp_nexthop_local
, s
, IPV6_MAX_BYTELEN
);
1605 if (! IN6_IS_ADDR_LINKLOCAL (&attre
->mp_nexthop_local
))
1607 char buf1
[INET6_ADDRSTRLEN
];
1608 char buf2
[INET6_ADDRSTRLEN
];
1610 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
1611 zlog_debug ("%s sent two nexthops %s %s but second one is not a link-local nexthop", peer
->host
,
1612 inet_ntop (AF_INET6
, &attre
->mp_nexthop_global
,
1613 buf1
, INET6_ADDRSTRLEN
),
1614 inet_ntop (AF_INET6
, &attre
->mp_nexthop_local
,
1615 buf2
, INET6_ADDRSTRLEN
));
1617 attre
->mp_nexthop_len
= IPV6_MAX_BYTELEN
;
1620 #endif /* HAVE_IPV6 */
1622 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1623 __func__
, peer
->host
, attre
->mp_nexthop_len
);
1624 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
1629 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1630 __func__
, peer
->host
);
1631 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
1636 if ((val
= stream_getc (s
)))
1637 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1641 /* must have nrli_len, what is left of the attribute */
1642 nlri_len
= LEN_LEFT
;
1643 if ((!nlri_len
) || (nlri_len
> STREAM_READABLE(s
)))
1645 zlog_info ("%s: (%s) Failed to read NLRI",
1646 __func__
, peer
->host
);
1647 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
1650 if (safi
!= SAFI_MPLS_LABELED_VPN
)
1652 ret
= bgp_nlri_sanity_check (peer
, afi
, safi
, stream_pnt (s
),
1653 nlri_len
, &num_mp_pfx
);
1656 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1657 __func__
, peer
->host
);
1658 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
1662 mp_update
->afi
= afi
;
1663 mp_update
->safi
= safi
;
1664 mp_update
->nlri
= stream_pnt (s
);
1665 mp_update
->length
= nlri_len
;
1667 stream_forward_getp (s
, nlri_len
);
1669 return BGP_ATTR_PARSE_PROCEED
;
1673 /* Multiprotocol unreachable parse */
1675 bgp_mp_unreach_parse (struct bgp_attr_parser_args
*args
,
1676 struct bgp_nlri
*mp_withdraw
)
1681 u_int16_t withdraw_len
;
1684 struct peer
*const peer
= args
->peer
;
1685 const bgp_size_t length
= args
->length
;
1689 #define BGP_MP_UNREACH_MIN_SIZE 3
1690 if ((length
> STREAM_READABLE(s
)) || (length
< BGP_MP_UNREACH_MIN_SIZE
))
1691 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
1693 afi
= stream_getw (s
);
1694 safi
= stream_getc (s
);
1696 withdraw_len
= length
- BGP_MP_UNREACH_MIN_SIZE
;
1698 if (safi
!= SAFI_MPLS_LABELED_VPN
)
1700 ret
= bgp_nlri_sanity_check (peer
, afi
, safi
, stream_pnt (s
),
1701 withdraw_len
, &num_mp_pfx
);
1703 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS
;
1706 mp_withdraw
->afi
= afi
;
1707 mp_withdraw
->safi
= safi
;
1708 mp_withdraw
->nlri
= stream_pnt (s
);
1709 mp_withdraw
->length
= withdraw_len
;
1711 stream_forward_getp (s
, withdraw_len
);
1713 return BGP_ATTR_PARSE_PROCEED
;
1716 /* Extended Community attribute. */
1717 static bgp_attr_parse_ret_t
1718 bgp_attr_ext_communities (struct bgp_attr_parser_args
*args
)
1720 struct peer
*const peer
= args
->peer
;
1721 struct attr
*const attr
= args
->attr
;
1722 const bgp_size_t length
= args
->length
;
1727 attr
->extra
->ecommunity
= NULL
;
1728 /* Empty extcomm doesn't seem to be invalid per se */
1729 return BGP_ATTR_PARSE_PROCEED
;
1732 (bgp_attr_extra_get (attr
))->ecommunity
=
1733 ecommunity_parse ((u_int8_t
*)stream_pnt (peer
->ibuf
), length
);
1734 /* XXX: fix ecommunity_parse to use stream API */
1735 stream_forward_getp (peer
->ibuf
, length
);
1737 if (!attr
->extra
->ecommunity
)
1738 return bgp_attr_malformed (args
,
1739 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
1742 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES
);
1744 return BGP_ATTR_PARSE_PROCEED
;
1747 /* BGP unknown attribute treatment. */
1748 static bgp_attr_parse_ret_t
1749 bgp_attr_unknown (struct bgp_attr_parser_args
*args
)
1751 bgp_size_t total
= args
->total
;
1752 struct transit
*transit
;
1753 struct attr_extra
*attre
;
1754 struct peer
*const peer
= args
->peer
;
1755 struct attr
*const attr
= args
->attr
;
1756 u_char
*const startp
= args
->startp
;
1757 const u_char type
= args
->type
;
1758 const u_char flag
= args
->flags
;
1759 const bgp_size_t length
= args
->length
;
1761 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
1762 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1763 peer
->host
, type
, length
);
1765 /* Forward read pointer of input stream. */
1766 stream_forward_getp (peer
->ibuf
, length
);
1768 /* If any of the mandatory well-known attributes are not recognized,
1769 then the Error Subcode is set to Unrecognized Well-known
1770 Attribute. The Data field contains the unrecognized attribute
1771 (type, length and value). */
1772 if (!CHECK_FLAG (flag
, BGP_ATTR_FLAG_OPTIONAL
))
1774 return bgp_attr_malformed (args
,
1775 BGP_NOTIFY_UPDATE_UNREC_ATTR
,
1779 /* Unrecognized non-transitive optional attributes must be quietly
1780 ignored and not passed along to other BGP peers. */
1781 if (! CHECK_FLAG (flag
, BGP_ATTR_FLAG_TRANS
))
1782 return BGP_ATTR_PARSE_PROCEED
;
1784 /* If a path with recognized transitive optional attribute is
1785 accepted and passed along to other BGP peers and the Partial bit
1786 in the Attribute Flags octet is set to 1 by some previous AS, it
1787 is not set back to 0 by the current AS. */
1788 SET_FLAG (*startp
, BGP_ATTR_FLAG_PARTIAL
);
1790 /* Store transitive attribute to the end of attr->transit. */
1791 if (! ((attre
= bgp_attr_extra_get(attr
))->transit
) )
1792 attre
->transit
= XCALLOC (MTYPE_TRANSIT
, sizeof (struct transit
));
1794 transit
= attre
->transit
;
1797 transit
->val
= XREALLOC (MTYPE_TRANSIT_VAL
, transit
->val
,
1798 transit
->length
+ total
);
1800 transit
->val
= XMALLOC (MTYPE_TRANSIT_VAL
, total
);
1802 memcpy (transit
->val
+ transit
->length
, startp
, total
);
1803 transit
->length
+= total
;
1805 return BGP_ATTR_PARSE_PROCEED
;
1808 /* Read attribute of update packet. This function is called from
1809 bgp_update_receive() in bgp_packet.c. */
1810 bgp_attr_parse_ret_t
1811 bgp_attr_parse (struct peer
*peer
, struct attr
*attr
, bgp_size_t size
,
1812 struct bgp_nlri
*mp_update
, struct bgp_nlri
*mp_withdraw
)
1818 u_char
*startp
, *endp
;
1820 u_char seen
[BGP_ATTR_BITMAP_SIZE
];
1821 /* we need the as4_path only until we have synthesized the as_path with it */
1822 /* same goes for as4_aggregator */
1823 struct aspath
*as4_path
= NULL
;
1824 as_t as4_aggregator
= 0;
1825 struct in_addr as4_aggregator_addr
= { 0 };
1827 /* Initialize bitmap. */
1828 memset (seen
, 0, BGP_ATTR_BITMAP_SIZE
);
1830 /* End pointer of BGP attribute. */
1831 endp
= BGP_INPUT_PNT (peer
) + size
;
1833 /* Get attributes to the end of attribute length. */
1834 while (BGP_INPUT_PNT (peer
) < endp
)
1836 /* Check remaining length check.*/
1837 if (endp
- BGP_INPUT_PNT (peer
) < BGP_ATTR_MIN_LEN
)
1839 /* XXX warning: long int format, int arg (arg 5) */
1840 zlog_warn ("%s: error BGP attribute length %lu is smaller than min len",
1842 (unsigned long) (endp
- STREAM_PNT (BGP_INPUT (peer
))));
1844 bgp_notify_send (peer
,
1845 BGP_NOTIFY_UPDATE_ERR
,
1846 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
1847 return BGP_ATTR_PARSE_ERROR
;
1850 /* Fetch attribute flag and type. */
1851 startp
= BGP_INPUT_PNT (peer
);
1852 /* "The lower-order four bits of the Attribute Flags octet are
1853 unused. They MUST be zero when sent and MUST be ignored when
1855 flag
= 0xF0 & stream_getc (BGP_INPUT (peer
));
1856 type
= stream_getc (BGP_INPUT (peer
));
1858 /* Check whether Extended-Length applies and is in bounds */
1859 if (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
)
1860 && ((endp
- startp
) < (BGP_ATTR_MIN_LEN
+ 1)))
1862 zlog_warn ("%s: Extended length set, but just %lu bytes of attr header",
1864 (unsigned long) (endp
- STREAM_PNT (BGP_INPUT (peer
))));
1866 bgp_notify_send (peer
,
1867 BGP_NOTIFY_UPDATE_ERR
,
1868 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
1869 return BGP_ATTR_PARSE_ERROR
;
1872 /* Check extended attribue length bit. */
1873 if (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
))
1874 length
= stream_getw (BGP_INPUT (peer
));
1876 length
= stream_getc (BGP_INPUT (peer
));
1878 /* If any attribute appears more than once in the UPDATE
1879 message, then the Error Subcode is set to Malformed Attribute
1882 if (CHECK_BITMAP (seen
, type
))
1884 zlog_warn ("%s: error BGP attribute type %d appears twice in a message",
1887 bgp_notify_send (peer
,
1888 BGP_NOTIFY_UPDATE_ERR
,
1889 BGP_NOTIFY_UPDATE_MAL_ATTR
);
1890 return BGP_ATTR_PARSE_ERROR
;
1893 /* Set type to bitmap to check duplicate attribute. `type' is
1894 unsigned char so it never overflow bitmap range. */
1896 SET_BITMAP (seen
, type
);
1898 /* Overflow check. */
1899 attr_endp
= BGP_INPUT_PNT (peer
) + length
;
1901 if (attr_endp
> endp
)
1903 zlog_warn ("%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p", peer
->host
, type
, length
, size
, attr_endp
, endp
);
1904 bgp_notify_send_with_data (peer
,
1905 BGP_NOTIFY_UPDATE_ERR
,
1906 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1907 startp
, attr_endp
- startp
);
1908 return BGP_ATTR_PARSE_ERROR
;
1911 struct bgp_attr_parser_args attr_args
= {
1918 .total
= attr_endp
- startp
,
1922 /* If any recognized attribute has Attribute Flags that conflict
1923 with the Attribute Type Code, then the Error Subcode is set to
1924 Attribute Flags Error. The Data field contains the erroneous
1925 attribute (type, length and value). */
1926 if (bgp_attr_flag_invalid (&attr_args
))
1928 bgp_attr_parse_ret_t ret
;
1929 ret
= bgp_attr_malformed (&attr_args
,
1930 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
1932 if (ret
== BGP_ATTR_PARSE_PROCEED
)
1937 /* OK check attribute and store it's value. */
1940 case BGP_ATTR_ORIGIN
:
1941 ret
= bgp_attr_origin (&attr_args
);
1943 case BGP_ATTR_AS_PATH
:
1944 ret
= bgp_attr_aspath (&attr_args
);
1946 case BGP_ATTR_AS4_PATH
:
1947 ret
= bgp_attr_as4_path (&attr_args
, &as4_path
);
1949 case BGP_ATTR_NEXT_HOP
:
1950 ret
= bgp_attr_nexthop (&attr_args
);
1952 case BGP_ATTR_MULTI_EXIT_DISC
:
1953 ret
= bgp_attr_med (&attr_args
);
1955 case BGP_ATTR_LOCAL_PREF
:
1956 ret
= bgp_attr_local_pref (&attr_args
);
1958 case BGP_ATTR_ATOMIC_AGGREGATE
:
1959 ret
= bgp_attr_atomic (&attr_args
);
1961 case BGP_ATTR_AGGREGATOR
:
1962 ret
= bgp_attr_aggregator (&attr_args
);
1964 case BGP_ATTR_AS4_AGGREGATOR
:
1965 ret
= bgp_attr_as4_aggregator (&attr_args
,
1967 &as4_aggregator_addr
);
1969 case BGP_ATTR_COMMUNITIES
:
1970 ret
= bgp_attr_community (&attr_args
);
1972 case BGP_ATTR_ORIGINATOR_ID
:
1973 ret
= bgp_attr_originator_id (&attr_args
);
1975 case BGP_ATTR_CLUSTER_LIST
:
1976 ret
= bgp_attr_cluster_list (&attr_args
);
1978 case BGP_ATTR_MP_REACH_NLRI
:
1979 ret
= bgp_mp_reach_parse (&attr_args
, mp_update
);
1981 case BGP_ATTR_MP_UNREACH_NLRI
:
1982 ret
= bgp_mp_unreach_parse (&attr_args
, mp_withdraw
);
1984 case BGP_ATTR_EXT_COMMUNITIES
:
1985 ret
= bgp_attr_ext_communities (&attr_args
);
1988 ret
= bgp_attr_unknown (&attr_args
);
1992 if (ret
== BGP_ATTR_PARSE_ERROR_NOTIFYPLS
)
1994 bgp_notify_send (peer
,
1995 BGP_NOTIFY_UPDATE_ERR
,
1996 BGP_NOTIFY_UPDATE_MAL_ATTR
);
1997 ret
= BGP_ATTR_PARSE_ERROR
;
2000 /* If hard error occured immediately return to the caller. */
2001 if (ret
== BGP_ATTR_PARSE_ERROR
)
2003 zlog_warn ("%s: Attribute %s, parse error",
2005 LOOKUP (attr_str
, type
));
2007 aspath_unintern (&as4_path
);
2010 if (ret
== BGP_ATTR_PARSE_WITHDRAW
)
2013 zlog_warn ("%s: Attribute %s, parse error - treating as withdrawal",
2015 LOOKUP (attr_str
, type
));
2017 aspath_unintern (&as4_path
);
2021 /* Check the fetched length. */
2022 if (BGP_INPUT_PNT (peer
) != attr_endp
)
2024 zlog_warn ("%s: BGP attribute %s, fetch error",
2025 peer
->host
, LOOKUP (attr_str
, type
));
2026 bgp_notify_send (peer
,
2027 BGP_NOTIFY_UPDATE_ERR
,
2028 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
2030 aspath_unintern (&as4_path
);
2031 return BGP_ATTR_PARSE_ERROR
;
2035 /* Check final read pointer is same as end pointer. */
2036 if (BGP_INPUT_PNT (peer
) != endp
)
2038 zlog_warn ("%s: BGP attribute %s, length mismatch",
2039 peer
->host
, LOOKUP (attr_str
, type
));
2040 bgp_notify_send (peer
,
2041 BGP_NOTIFY_UPDATE_ERR
,
2042 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
2044 aspath_unintern (&as4_path
);
2045 return BGP_ATTR_PARSE_ERROR
;
2049 * At this place we can see whether we got AS4_PATH and/or
2050 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
2051 * We can not do this before we've read all attributes because
2052 * the as4 handling does not say whether AS4_PATH has to be sent
2053 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
2054 * in relationship to AGGREGATOR.
2055 * So, to be defensive, we are not relying on any order and read
2056 * all attributes first, including these 32bit ones, and now,
2057 * afterwards, we look what and if something is to be done for as4.
2059 /* actually... this doesn't ever return failure currently, but
2060 * better safe than sorry */
2061 if (bgp_attr_munge_as4_attrs (peer
, attr
, as4_path
,
2062 as4_aggregator
, &as4_aggregator_addr
))
2064 bgp_notify_send (peer
,
2065 BGP_NOTIFY_UPDATE_ERR
,
2066 BGP_NOTIFY_UPDATE_MAL_ATTR
);
2068 aspath_unintern (&as4_path
);
2069 return BGP_ATTR_PARSE_ERROR
;
2072 /* At this stage, we have done all fiddling with as4, and the
2073 * resulting info is in attr->aggregator resp. attr->aspath
2074 * so we can chuck as4_aggregator and as4_path alltogether in
2075 * order to save memory
2079 aspath_unintern (&as4_path
); /* unintern - it is in the hash */
2080 /* The flag that we got this is still there, but that does not
2085 * The "rest" of the code does nothing with as4_aggregator.
2086 * there is no memory attached specifically which is not part
2088 * so ignoring just means do nothing.
2091 * Finally do the checks on the aspath we did not do yet
2092 * because we waited for a potentially synthesized aspath.
2094 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
)))
2096 ret
= bgp_attr_aspath_check (peer
, attr
);
2097 if (ret
!= BGP_ATTR_PARSE_PROCEED
)
2101 /* Finally intern unknown attribute. */
2102 if (attr
->extra
&& attr
->extra
->transit
)
2103 attr
->extra
->transit
= transit_intern (attr
->extra
->transit
);
2105 return BGP_ATTR_PARSE_PROCEED
;
2108 /* Well-known attribute check. */
2110 bgp_attr_check (struct peer
*peer
, struct attr
*attr
)
2114 if (! CHECK_FLAG (attr
->flag
, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN
)))
2115 type
= BGP_ATTR_ORIGIN
;
2117 if (! CHECK_FLAG (attr
->flag
, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH
)))
2118 type
= BGP_ATTR_AS_PATH
;
2120 if (! CHECK_FLAG (attr
->flag
, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP
)))
2121 type
= BGP_ATTR_NEXT_HOP
;
2123 if (peer
->sort
== BGP_PEER_IBGP
2124 && ! CHECK_FLAG (attr
->flag
, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF
)))
2125 type
= BGP_ATTR_LOCAL_PREF
;
2129 zlog_warn ("%s Missing well-known attribute %d.", peer
->host
, type
);
2130 bgp_notify_send_with_data (peer
,
2131 BGP_NOTIFY_UPDATE_ERR
,
2132 BGP_NOTIFY_UPDATE_MISS_ATTR
,
2134 return BGP_ATTR_PARSE_ERROR
;
2136 return BGP_ATTR_PARSE_PROCEED
;
2139 int stream_put_prefix (struct stream
*, struct prefix
*);
2142 bgp_packet_mpattr_start (struct stream
*s
, afi_t afi
, safi_t safi
,
2143 struct bpacket_attr_vec_arr
*vecarr
,
2148 /* Set extended bit always to encode the attribute length as 2 bytes */
2149 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_EXTLEN
);
2150 stream_putc (s
, BGP_ATTR_MP_REACH_NLRI
);
2151 sizep
= stream_get_endp (s
);
2152 stream_putw (s
, 0); /* Marker: Attribute length. */
2153 stream_putw (s
, afi
); /* AFI */
2154 stream_putc (s
, safi
); /* SAFI */
2163 case SAFI_MULTICAST
:
2164 bpacket_attr_vec_arr_set_vec (vecarr
, BGP_ATTR_VEC_NH
, s
, attr
);
2166 stream_put_ipv4 (s
, attr
->nexthop
.s_addr
);
2169 bpacket_attr_vec_arr_set_vec (vecarr
, BGP_ATTR_VEC_NH
, s
, attr
);
2170 stream_putc (s
, 12);
2173 stream_put (s
, &attr
->extra
->mp_nexthop_global_in
, 4);
2184 case SAFI_MULTICAST
:
2186 unsigned long sizep
;
2187 struct attr_extra
*attre
= attr
->extra
;
2189 assert (attr
->extra
);
2190 bpacket_attr_vec_arr_set_vec (vecarr
, BGP_ATTR_VEC_NH
, s
, attr
);
2191 stream_putc (s
, attre
->mp_nexthop_len
);
2192 stream_put (s
, &attre
->mp_nexthop_global
, IPV6_MAX_BYTELEN
);
2193 if (attre
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
)
2194 stream_put (s
, &attre
->mp_nexthop_local
, IPV6_MAX_BYTELEN
);
2200 #endif /*HAVE_IPV6*/
2211 bgp_packet_mpattr_prefix (struct stream
*s
, afi_t afi
, safi_t safi
,
2212 struct prefix
*p
, struct prefix_rd
*prd
,
2218 /* Tag, RD, Prefix write. */
2219 stream_putc (s
, p
->prefixlen
+ 88);
2220 stream_put (s
, tag
, 3);
2221 stream_put (s
, prd
->val
, 8);
2222 stream_put (s
, &p
->u
.prefix
, PSIZE (p
->prefixlen
));
2226 stream_put_prefix (s
, p
);
2232 bgp_packet_mpattr_end (struct stream
*s
, size_t sizep
)
2234 /* Set MP attribute length. Don't count the (2) bytes used to encode
2236 stream_putw_at (s
, sizep
, (stream_get_endp (s
) - sizep
) - 2);
2239 /* Make attribute packet. */
2241 bgp_packet_attribute (struct bgp
*bgp
, struct peer
*peer
,
2242 struct stream
*s
, struct attr
*attr
,
2243 struct bpacket_attr_vec_arr
*vecarr
,
2244 struct prefix
*p
, afi_t afi
, safi_t safi
,
2245 struct peer
*from
, struct prefix_rd
*prd
, u_char
*tag
)
2248 size_t aspath_sizep
;
2249 struct aspath
*aspath
;
2250 int send_as4_path
= 0;
2251 int send_as4_aggregator
= 0;
2253 int use32bit
= (CHECK_FLAG (peer
->cap
, PEER_CAP_AS4_RCV
)) ? 1 : 0;
2254 size_t mpattrlen_pos
= 0;
2259 /* Remember current pointer. */
2260 cp
= stream_get_endp (s
);
2262 if (p
&& !(afi
== AFI_IP
&& safi
== SAFI_UNICAST
))
2264 mpattrlen_pos
= bgp_packet_mpattr_start(s
, afi
, safi
, vecarr
, attr
);
2265 bgp_packet_mpattr_prefix(s
, afi
, safi
, p
, prd
, tag
);
2266 bgp_packet_mpattr_end(s
, mpattrlen_pos
);
2269 /* Origin attribute. */
2270 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2271 stream_putc (s
, BGP_ATTR_ORIGIN
);
2273 stream_putc (s
, attr
->origin
);
2275 /* AS path attribute. */
2277 /* If remote-peer is EBGP */
2278 if (peer
->sort
== BGP_PEER_EBGP
2279 && (! CHECK_FLAG (peer
->af_flags
[afi
][safi
], PEER_FLAG_AS_PATH_UNCHANGED
)
2280 || attr
->aspath
->segments
== NULL
)
2281 && (! CHECK_FLAG (peer
->af_flags
[afi
][safi
], PEER_FLAG_RSERVER_CLIENT
)))
2283 aspath
= aspath_dup (attr
->aspath
);
2285 if (CHECK_FLAG(bgp
->config
, BGP_CONFIG_CONFEDERATION
))
2287 /* Strip the confed info, and then stuff our path CONFED_ID
2289 aspath
= aspath_delete_confed_seq (aspath
);
2290 aspath
= aspath_add_seq (aspath
, bgp
->confed_id
);
2294 if (peer
->change_local_as
) {
2295 /* If replace-as is specified, we only use the change_local_as when
2296 advertising routes. */
2297 if( ! CHECK_FLAG (peer
->flags
, PEER_FLAG_LOCAL_AS_REPLACE_AS
) ) {
2298 aspath
= aspath_add_seq (aspath
, peer
->local_as
);
2300 aspath
= aspath_add_seq (aspath
, peer
->change_local_as
);
2302 aspath
= aspath_add_seq (aspath
, peer
->local_as
);
2306 else if (peer
->sort
== BGP_PEER_CONFED
)
2308 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2309 aspath
= aspath_dup (attr
->aspath
);
2310 aspath
= aspath_add_confed_seq (aspath
, peer
->local_as
);
2313 aspath
= attr
->aspath
;
2315 /* If peer is not AS4 capable, then:
2316 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2317 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2318 * types are in it (i.e. exclude them if they are there)
2319 * AND do this only if there is at least one asnum > 65535 in the path!
2320 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2321 * all ASnums > 65535 to BGP_AS_TRANS
2324 stream_putc (s
, BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_EXTLEN
);
2325 stream_putc (s
, BGP_ATTR_AS_PATH
);
2326 aspath_sizep
= stream_get_endp (s
);
2328 stream_putw_at (s
, aspath_sizep
, aspath_put (s
, aspath
, use32bit
));
2330 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2333 if (!use32bit
&& aspath_has_as4 (aspath
))
2334 send_as4_path
= 1; /* we'll do this later, at the correct place */
2336 /* Nexthop attribute. */
2337 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP
) && afi
== AFI_IP
)
2339 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2340 stream_putc (s
, BGP_ATTR_NEXT_HOP
);
2341 bpacket_attr_vec_arr_set_vec (vecarr
, BGP_ATTR_VEC_NH
, s
, attr
);
2343 stream_put_ipv4 (s
, attr
->nexthop
.s_addr
);
2346 /* MED attribute. */
2347 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC
) ||
2350 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
);
2351 stream_putc (s
, BGP_ATTR_MULTI_EXIT_DISC
);
2353 stream_putl (s
, (bgp
->maxmed_active
? bgp
->maxmed_value
: attr
->med
));
2356 /* Local preference. */
2357 if (peer
->sort
== BGP_PEER_IBGP
||
2358 peer
->sort
== BGP_PEER_CONFED
)
2360 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2361 stream_putc (s
, BGP_ATTR_LOCAL_PREF
);
2363 stream_putl (s
, attr
->local_pref
);
2366 /* Atomic aggregate. */
2367 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE
))
2369 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2370 stream_putc (s
, BGP_ATTR_ATOMIC_AGGREGATE
);
2375 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR
))
2377 assert (attr
->extra
);
2379 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
2380 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2381 stream_putc (s
, BGP_ATTR_AGGREGATOR
);
2385 /* AS4 capable peer */
2387 stream_putl (s
, attr
->extra
->aggregator_as
);
2391 /* 2-byte AS peer */
2394 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2395 if ( attr
->extra
->aggregator_as
> 65535 )
2397 stream_putw (s
, BGP_AS_TRANS
);
2399 /* we have to send AS4_AGGREGATOR, too.
2400 * we'll do that later in order to send attributes in ascending
2403 send_as4_aggregator
= 1;
2406 stream_putw (s
, (u_int16_t
) attr
->extra
->aggregator_as
);
2408 stream_put_ipv4 (s
, attr
->extra
->aggregator_addr
.s_addr
);
2411 /* Community attribute. */
2412 if (CHECK_FLAG (peer
->af_flags
[afi
][safi
], PEER_FLAG_SEND_COMMUNITY
)
2413 && (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES
)))
2415 if (attr
->community
->size
* 4 > 255)
2417 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_EXTLEN
);
2418 stream_putc (s
, BGP_ATTR_COMMUNITIES
);
2419 stream_putw (s
, attr
->community
->size
* 4);
2423 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2424 stream_putc (s
, BGP_ATTR_COMMUNITIES
);
2425 stream_putc (s
, attr
->community
->size
* 4);
2427 stream_put (s
, attr
->community
->val
, attr
->community
->size
* 4);
2430 /* Route Reflector. */
2431 if (peer
->sort
== BGP_PEER_IBGP
2433 && from
->sort
== BGP_PEER_IBGP
)
2435 /* Originator ID. */
2436 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
);
2437 stream_putc (s
, BGP_ATTR_ORIGINATOR_ID
);
2440 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
))
2441 stream_put_in_addr (s
, &attr
->extra
->originator_id
);
2443 stream_put_in_addr (s
, &from
->remote_id
);
2446 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
);
2447 stream_putc (s
, BGP_ATTR_CLUSTER_LIST
);
2449 if (attr
->extra
&& attr
->extra
->cluster
)
2451 stream_putc (s
, attr
->extra
->cluster
->length
+ 4);
2452 /* If this peer configuration's parent BGP has cluster_id. */
2453 if (bgp
->config
& BGP_CONFIG_CLUSTER_ID
)
2454 stream_put_in_addr (s
, &bgp
->cluster_id
);
2456 stream_put_in_addr (s
, &bgp
->router_id
);
2457 stream_put (s
, attr
->extra
->cluster
->list
,
2458 attr
->extra
->cluster
->length
);
2463 /* If this peer configuration's parent BGP has cluster_id. */
2464 if (bgp
->config
& BGP_CONFIG_CLUSTER_ID
)
2465 stream_put_in_addr (s
, &bgp
->cluster_id
);
2467 stream_put_in_addr (s
, &bgp
->router_id
);
2471 /* Extended Communities attribute. */
2472 if (CHECK_FLAG (peer
->af_flags
[afi
][safi
], PEER_FLAG_SEND_EXT_COMMUNITY
)
2473 && (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES
)))
2475 struct attr_extra
*attre
= attr
->extra
;
2479 if (peer
->sort
== BGP_PEER_IBGP
2480 || peer
->sort
== BGP_PEER_CONFED
)
2482 if (attre
->ecommunity
->size
* 8 > 255)
2484 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_EXTLEN
);
2485 stream_putc (s
, BGP_ATTR_EXT_COMMUNITIES
);
2486 stream_putw (s
, attre
->ecommunity
->size
* 8);
2490 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2491 stream_putc (s
, BGP_ATTR_EXT_COMMUNITIES
);
2492 stream_putc (s
, attre
->ecommunity
->size
* 8);
2494 stream_put (s
, attre
->ecommunity
->val
, attre
->ecommunity
->size
* 8);
2500 int ecom_tr_size
= 0;
2503 for (i
= 0; i
< attre
->ecommunity
->size
; i
++)
2505 pnt
= attre
->ecommunity
->val
+ (i
* 8);
2508 if (CHECK_FLAG (tbit
, ECOMMUNITY_FLAG_NON_TRANSITIVE
))
2516 if (ecom_tr_size
* 8 > 255)
2518 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_EXTLEN
);
2519 stream_putc (s
, BGP_ATTR_EXT_COMMUNITIES
);
2520 stream_putw (s
, ecom_tr_size
* 8);
2524 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2525 stream_putc (s
, BGP_ATTR_EXT_COMMUNITIES
);
2526 stream_putc (s
, ecom_tr_size
* 8);
2529 for (i
= 0; i
< attre
->ecommunity
->size
; i
++)
2531 pnt
= attre
->ecommunity
->val
+ (i
* 8);
2534 if (CHECK_FLAG (tbit
, ECOMMUNITY_FLAG_NON_TRANSITIVE
))
2537 stream_put (s
, pnt
, 8);
2543 if ( send_as4_path
)
2545 /* If the peer is NOT As4 capable, AND */
2546 /* there are ASnums > 65535 in path THEN
2547 * give out AS4_PATH */
2549 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2551 * Hm, I wonder... confederation things *should* only be at
2552 * the beginning of an aspath, right? Then we should use
2553 * aspath_delete_confed_seq for this, because it is already
2555 * Folks, talk to me: what is reasonable here!?
2557 aspath
= aspath_delete_confed_seq (aspath
);
2559 stream_putc (s
, BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_EXTLEN
);
2560 stream_putc (s
, BGP_ATTR_AS4_PATH
);
2561 aspath_sizep
= stream_get_endp (s
);
2563 stream_putw_at (s
, aspath_sizep
, aspath_put (s
, aspath
, 1));
2566 if (aspath
!= attr
->aspath
)
2567 aspath_free (aspath
);
2569 if ( send_as4_aggregator
)
2571 assert (attr
->extra
);
2573 /* send AS4_AGGREGATOR, at this place */
2574 /* this section of code moved here in order to ensure the correct
2575 * *ascending* order of attributes
2577 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2578 stream_putc (s
, BGP_ATTR_AS4_AGGREGATOR
);
2580 stream_putl (s
, attr
->extra
->aggregator_as
);
2581 stream_put_ipv4 (s
, attr
->extra
->aggregator_addr
.s_addr
);
2584 /* Unknown transit attribute. */
2585 if (attr
->extra
&& attr
->extra
->transit
)
2586 stream_put (s
, attr
->extra
->transit
->val
, attr
->extra
->transit
->length
);
2588 /* Return total size of attribute. */
2589 return stream_get_endp (s
) - cp
;
2593 bgp_packet_mpunreach_start (struct stream
*s
, afi_t afi
, safi_t safi
)
2595 unsigned long attrlen_pnt
;
2597 /* Set extended bit always to encode the attribute length as 2 bytes */
2598 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_EXTLEN
);
2599 stream_putc (s
, BGP_ATTR_MP_UNREACH_NLRI
);
2601 attrlen_pnt
= stream_get_endp (s
);
2602 stream_putw (s
, 0); /* Length of this attribute. */
2604 stream_putw (s
, afi
);
2605 safi
= (safi
== SAFI_MPLS_VPN
) ? SAFI_MPLS_LABELED_VPN
: safi
;
2606 stream_putc (s
, safi
);
2611 bgp_packet_mpunreach_prefix (struct stream
*s
, struct prefix
*p
,
2612 afi_t afi
, safi_t safi
, struct prefix_rd
*prd
,
2615 if (safi
== SAFI_MPLS_VPN
)
2617 stream_putc (s
, p
->prefixlen
+ 88);
2618 stream_put (s
, tag
, 3);
2619 stream_put (s
, prd
->val
, 8);
2620 stream_put (s
, &p
->u
.prefix
, PSIZE (p
->prefixlen
));
2623 stream_put_prefix (s
, p
);
2627 bgp_packet_mpunreach_end (struct stream
*s
, size_t attrlen_pnt
)
2631 /* Set MP attribute length. Don't count the (2) bytes used to encode
2633 size
= stream_get_endp (s
) - attrlen_pnt
- 2;
2634 stream_putw_at (s
, attrlen_pnt
, size
);
2637 /* Initialization of attribute. */
2639 bgp_attr_init (void)
2650 bgp_attr_finish (void)
2654 community_finish ();
2655 ecommunity_finish ();
2660 /* Make attribute packet. */
2662 bgp_dump_routes_attr (struct stream
*s
, struct attr
*attr
,
2663 struct prefix
*prefix
)
2668 struct aspath
*aspath
;
2670 /* Remember current pointer. */
2671 cp
= stream_get_endp (s
);
2673 /* Place holder of length. */
2676 /* Origin attribute. */
2677 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2678 stream_putc (s
, BGP_ATTR_ORIGIN
);
2680 stream_putc (s
, attr
->origin
);
2682 aspath
= attr
->aspath
;
2684 stream_putc (s
, BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_EXTLEN
);
2685 stream_putc (s
, BGP_ATTR_AS_PATH
);
2686 aspath_lenp
= stream_get_endp (s
);
2689 stream_putw_at (s
, aspath_lenp
, aspath_put (s
, aspath
, 1));
2691 /* Nexthop attribute. */
2692 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2695 && prefix
->family
!= AF_INET6
2696 #endif /* HAVE_IPV6 */
2699 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2700 stream_putc (s
, BGP_ATTR_NEXT_HOP
);
2702 stream_put_ipv4 (s
, attr
->nexthop
.s_addr
);
2705 /* MED attribute. */
2706 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC
))
2708 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
);
2709 stream_putc (s
, BGP_ATTR_MULTI_EXIT_DISC
);
2711 stream_putl (s
, attr
->med
);
2714 /* Local preference. */
2715 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF
))
2717 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2718 stream_putc (s
, BGP_ATTR_LOCAL_PREF
);
2720 stream_putl (s
, attr
->local_pref
);
2723 /* Atomic aggregate. */
2724 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE
))
2726 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2727 stream_putc (s
, BGP_ATTR_ATOMIC_AGGREGATE
);
2732 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR
))
2734 assert (attr
->extra
);
2735 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2736 stream_putc (s
, BGP_ATTR_AGGREGATOR
);
2738 stream_putl (s
, attr
->extra
->aggregator_as
);
2739 stream_put_ipv4 (s
, attr
->extra
->aggregator_addr
.s_addr
);
2742 /* Community attribute. */
2743 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES
))
2745 if (attr
->community
->size
* 4 > 255)
2747 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_EXTLEN
);
2748 stream_putc (s
, BGP_ATTR_COMMUNITIES
);
2749 stream_putw (s
, attr
->community
->size
* 4);
2753 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2754 stream_putc (s
, BGP_ATTR_COMMUNITIES
);
2755 stream_putc (s
, attr
->community
->size
* 4);
2757 stream_put (s
, attr
->community
->val
, attr
->community
->size
* 4);
2761 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
2762 if (prefix
!= NULL
&& prefix
->family
== AF_INET6
&& attr
->extra
&&
2763 (attr
->extra
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL
||
2764 attr
->extra
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
) )
2767 struct attr_extra
*attre
= attr
->extra
;
2769 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
2770 stream_putc(s
, BGP_ATTR_MP_REACH_NLRI
);
2771 sizep
= stream_get_endp (s
);
2774 stream_putc (s
, 0); /* Marker: Attribute length. */
2775 stream_putw(s
, AFI_IP6
); /* AFI */
2776 stream_putc(s
, SAFI_UNICAST
); /* SAFI */
2779 stream_putc(s
, attre
->mp_nexthop_len
);
2780 stream_put(s
, &attre
->mp_nexthop_global
, IPV6_MAX_BYTELEN
);
2781 if (attre
->mp_nexthop_len
== BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
)
2782 stream_put(s
, &attre
->mp_nexthop_local
, IPV6_MAX_BYTELEN
);
2788 stream_put_prefix(s
, prefix
);
2790 /* Set MP attribute length. */
2791 stream_putc_at (s
, sizep
, (stream_get_endp (s
) - sizep
) - 1);
2793 #endif /* HAVE_IPV6 */
2795 /* Return total size of attribute. */
2796 len
= stream_get_endp (s
) - cp
- 2;
2797 stream_putw_at (s
, cp
, len
);