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
= array_size(attr_str
);
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
= array_size(attr_flag_str
);
77 static struct hash
*cluster_hash
;
80 cluster_hash_alloc (void *p
)
82 struct cluster_list
* val
= (struct cluster_list
*) p
;
83 struct cluster_list
*cluster
;
85 cluster
= XMALLOC (MTYPE_CLUSTER
, sizeof (struct cluster_list
));
86 cluster
->length
= val
->length
;
90 cluster
->list
= XMALLOC (MTYPE_CLUSTER_VAL
, val
->length
);
91 memcpy (cluster
->list
, val
->list
, val
->length
);
101 /* Cluster list related functions. */
102 static struct cluster_list
*
103 cluster_parse (struct in_addr
* pnt
, int length
)
105 struct cluster_list tmp
;
106 struct cluster_list
*cluster
;
111 cluster
= hash_get (cluster_hash
, &tmp
, cluster_hash_alloc
);
117 cluster_loop_check (struct cluster_list
*cluster
, struct in_addr originator
)
121 for (i
= 0; i
< cluster
->length
/ 4; i
++)
122 if (cluster
->list
[i
].s_addr
== originator
.s_addr
)
128 cluster_hash_key_make (void *p
)
130 const struct cluster_list
*cluster
= p
;
132 return jhash(cluster
->list
, cluster
->length
, 0);
136 cluster_hash_cmp (const void *p1
, const void *p2
)
138 const struct cluster_list
* cluster1
= p1
;
139 const struct cluster_list
* cluster2
= p2
;
141 return (cluster1
->length
== cluster2
->length
&&
142 memcmp (cluster1
->list
, cluster2
->list
, cluster1
->length
) == 0);
146 cluster_free (struct cluster_list
*cluster
)
149 XFREE (MTYPE_CLUSTER_VAL
, cluster
->list
);
150 XFREE (MTYPE_CLUSTER
, cluster
);
154 static struct cluster_list
*
155 cluster_dup (struct cluster_list
*cluster
)
157 struct cluster_list
*new;
159 new = XCALLOC (MTYPE_CLUSTER
, sizeof (struct cluster_list
));
160 new->length
= cluster
->length
;
164 new->list
= XMALLOC (MTYPE_CLUSTER_VAL
, cluster
->length
);
165 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
);
224 transit_hash_alloc (void *p
)
226 /* Transit structure is already allocated. */
230 static struct transit
*
231 transit_intern (struct transit
*transit
)
233 struct transit
*find
;
235 find
= hash_get (transit_hash
, transit
, transit_hash_alloc
);
237 transit_free (transit
);
244 transit_unintern (struct transit
*transit
)
249 if (transit
->refcnt
== 0)
251 hash_release (transit_hash
, transit
);
252 transit_free (transit
);
257 transit_hash_key_make (void *p
)
259 const struct transit
* transit
= p
;
261 return jhash(transit
->val
, transit
->length
, 0);
265 transit_hash_cmp (const void *p1
, const void *p2
)
267 const struct transit
* transit1
= p1
;
268 const struct transit
* transit2
= p2
;
270 return (transit1
->length
== transit2
->length
&&
271 memcmp (transit1
->val
, transit2
->val
, transit1
->length
) == 0);
277 transit_hash
= hash_create (transit_hash_key_make
, transit_hash_cmp
);
281 transit_finish (void)
283 hash_free (transit_hash
);
287 /* Attribute hash routines. */
288 static struct hash
*attrhash
;
290 static struct attr_extra
*
291 bgp_attr_extra_new (void)
293 return XCALLOC (MTYPE_ATTR_EXTRA
, sizeof (struct attr_extra
));
297 bgp_attr_extra_free (struct attr
*attr
)
301 XFREE (MTYPE_ATTR_EXTRA
, attr
->extra
);
307 bgp_attr_extra_get (struct attr
*attr
)
310 attr
->extra
= bgp_attr_extra_new();
314 /* Shallow copy of an attribute
315 * Though, not so shallow that it doesn't copy the contents
316 * of the attr_extra pointed to by 'extra'
319 bgp_attr_dup (struct attr
*new, struct attr
*orig
)
321 struct attr_extra
*extra
= new->extra
;
324 /* if caller provided attr_extra space, use it in any case.
326 * This is neccesary even if orig->extra equals NULL, because otherwise
327 * memory may be later allocated on the heap by bgp_attr_extra_get.
329 * That memory would eventually be leaked, because the caller must not
330 * call bgp_attr_extra_free if he provided attr_extra on the stack.
335 memset(new->extra
, 0, sizeof(struct attr_extra
));
337 *new->extra
= *orig
->extra
;
339 else if (orig
->extra
)
341 new->extra
= bgp_attr_extra_new();
342 *new->extra
= *orig
->extra
;
349 return attrhash
->count
;
353 attr_unknown_count (void)
355 return transit_hash
->count
;
359 attrhash_key_make (void *p
)
361 const struct attr
*attr
= (struct attr
*) p
;
362 const struct attr_extra
*extra
= attr
->extra
;
364 #define MIX(val) key = jhash_1word(val, key)
367 MIX(attr
->nexthop
.s_addr
);
369 MIX(attr
->local_pref
);
372 key
+= attr
->nexthop
.s_addr
;
374 key
+= attr
->local_pref
;
378 MIX(extra
->aggregator_as
);
379 MIX(extra
->aggregator_addr
.s_addr
);
381 MIX(extra
->mp_nexthop_global_in
.s_addr
);
382 MIX(extra
->originator_id
.s_addr
);
386 MIX(aspath_key_make (attr
->aspath
));
388 MIX(community_hash_make (attr
->community
));
392 if (extra
->ecommunity
)
393 MIX(ecommunity_hash_make (extra
->ecommunity
));
395 MIX(cluster_hash_key_make (extra
->cluster
));
397 MIX(transit_hash_key_make (extra
->transit
));
400 MIX(extra
->mp_nexthop_len
);
401 key
= jhash(extra
->mp_nexthop_global
.s6_addr
, 16, key
);
402 key
= jhash(extra
->mp_nexthop_local
.s6_addr
, 16, key
);
403 #endif /* HAVE_IPV6 */
410 attrhash_cmp (const void *p1
, const void *p2
)
412 const struct attr
* attr1
= p1
;
413 const struct attr
* attr2
= p2
;
415 if (attr1
->flag
== attr2
->flag
416 && attr1
->origin
== attr2
->origin
417 && attr1
->nexthop
.s_addr
== attr2
->nexthop
.s_addr
418 && attr1
->aspath
== attr2
->aspath
419 && attr1
->community
== attr2
->community
420 && attr1
->med
== attr2
->med
421 && attr1
->local_pref
== attr2
->local_pref
)
423 const struct attr_extra
*ae1
= attr1
->extra
;
424 const struct attr_extra
*ae2
= attr2
->extra
;
427 && ae1
->aggregator_as
== ae2
->aggregator_as
428 && ae1
->aggregator_addr
.s_addr
== ae2
->aggregator_addr
.s_addr
429 && ae1
->weight
== ae2
->weight
431 && ae1
->mp_nexthop_len
== ae2
->mp_nexthop_len
432 && IPV6_ADDR_SAME (&ae1
->mp_nexthop_global
, &ae2
->mp_nexthop_global
)
433 && IPV6_ADDR_SAME (&ae1
->mp_nexthop_local
, &ae2
->mp_nexthop_local
)
434 #endif /* HAVE_IPV6 */
435 && IPV4_ADDR_SAME (&ae1
->mp_nexthop_global_in
, &ae2
->mp_nexthop_global_in
)
436 && ae1
->ecommunity
== ae2
->ecommunity
437 && ae1
->cluster
== ae2
->cluster
438 && ae1
->transit
== ae2
->transit
439 && IPV4_ADDR_SAME (&ae1
->originator_id
, &ae2
->originator_id
))
443 /* neither attribute has extra attributes, so they're same */
453 attrhash
= hash_create (attrhash_key_make
, attrhash_cmp
);
457 attrhash_finish (void)
459 hash_free (attrhash
);
464 attr_show_all_iterator (struct hash_backet
*backet
, struct vty
*vty
)
466 struct attr
*attr
= backet
->data
;
468 vty_out (vty
, "attr[%ld] nexthop %s%s", attr
->refcnt
,
469 inet_ntoa (attr
->nexthop
), VTY_NEWLINE
);
473 attr_show_all (struct vty
*vty
)
475 hash_iterate (attrhash
,
476 (void (*)(struct hash_backet
*, void *))
477 attr_show_all_iterator
,
482 bgp_attr_hash_alloc (void *p
)
484 struct attr
* val
= (struct attr
*) p
;
487 attr
= XMALLOC (MTYPE_ATTR
, sizeof (struct attr
));
491 attr
->extra
= bgp_attr_extra_new ();
492 *attr
->extra
= *val
->extra
;
498 /* Internet argument attribute. */
500 bgp_attr_intern (struct attr
*attr
)
504 /* Intern referenced strucutre. */
507 if (! attr
->aspath
->refcnt
)
508 attr
->aspath
= aspath_intern (attr
->aspath
);
510 attr
->aspath
->refcnt
++;
514 if (! attr
->community
->refcnt
)
515 attr
->community
= community_intern (attr
->community
);
517 attr
->community
->refcnt
++;
521 struct attr_extra
*attre
= attr
->extra
;
523 if (attre
->ecommunity
)
525 if (! attre
->ecommunity
->refcnt
)
526 attre
->ecommunity
= ecommunity_intern (attre
->ecommunity
);
528 attre
->ecommunity
->refcnt
++;
533 if (! attre
->cluster
->refcnt
)
534 attre
->cluster
= cluster_intern (attre
->cluster
);
536 attre
->cluster
->refcnt
++;
540 if (! attre
->transit
->refcnt
)
541 attre
->transit
= transit_intern (attre
->transit
);
543 attre
->transit
->refcnt
++;
547 find
= (struct attr
*) hash_get (attrhash
, attr
, bgp_attr_hash_alloc
);
554 /* Make network statement's attribute. */
556 bgp_attr_default_set (struct attr
*attr
, u_char origin
)
558 memset (attr
, 0, sizeof (struct attr
));
559 bgp_attr_extra_get (attr
);
561 attr
->origin
= origin
;
562 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN
);
563 attr
->aspath
= aspath_empty ();
564 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH
);
565 attr
->extra
->weight
= BGP_ATTR_DEFAULT_WEIGHT
;
566 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP
);
568 attr
->extra
->mp_nexthop_len
= IPV6_MAX_BYTELEN
;
575 /* Make network statement's attribute. */
577 bgp_attr_default_intern (u_char origin
)
582 bgp_attr_default_set(&attr
, origin
);
584 new = bgp_attr_intern (&attr
);
585 bgp_attr_extra_free (&attr
);
587 aspath_unintern (&new->aspath
);
592 bgp_attr_aggregate_intern (struct bgp
*bgp
, u_char origin
,
593 struct aspath
*aspath
,
594 struct community
*community
, int as_set
)
598 struct attr_extra attre
;
600 memset (&attr
, 0, sizeof (struct attr
));
601 memset (&attre
, 0, sizeof (struct attr_extra
));
604 /* Origin attribute. */
605 attr
.origin
= origin
;
606 attr
.flag
|= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN
);
608 /* AS path attribute. */
610 attr
.aspath
= aspath_intern (aspath
);
612 attr
.aspath
= aspath_empty ();
613 attr
.flag
|= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH
);
615 /* Next hop attribute. */
616 attr
.flag
|= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP
);
620 attr
.community
= community
;
621 attr
.flag
|= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES
);
624 attre
.weight
= BGP_ATTR_DEFAULT_WEIGHT
;
626 attre
.mp_nexthop_len
= IPV6_MAX_BYTELEN
;
629 attr
.flag
|= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE
);
630 attr
.flag
|= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR
);
631 if (CHECK_FLAG (bgp
->config
, BGP_CONFIG_CONFEDERATION
))
632 attre
.aggregator_as
= bgp
->confed_id
;
634 attre
.aggregator_as
= bgp
->as
;
635 attre
.aggregator_addr
= bgp
->router_id
;
637 new = bgp_attr_intern (&attr
);
639 aspath_unintern (&new->aspath
);
643 /* Unintern just the sub-components of the attr, but not the attr */
645 bgp_attr_unintern_sub (struct attr
*attr
)
647 /* aspath refcount shoud be decrement. */
649 aspath_unintern (&attr
->aspath
);
650 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH
));
653 community_unintern (&attr
->community
);
654 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES
));
658 if (attr
->extra
->ecommunity
)
659 ecommunity_unintern (&attr
->extra
->ecommunity
);
660 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES
));
662 if (attr
->extra
->cluster
)
663 cluster_unintern (attr
->extra
->cluster
);
664 UNSET_FLAG(attr
->flag
, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST
));
666 if (attr
->extra
->transit
)
667 transit_unintern (attr
->extra
->transit
);
671 /* Free bgp attribute and aspath. */
673 bgp_attr_unintern (struct attr
**pattr
)
675 struct attr
*attr
= *pattr
;
678 struct attr_extra tmp_extra
;
680 /* Decrement attribute reference. */
687 tmp
.extra
= &tmp_extra
;
688 memcpy (tmp
.extra
, attr
->extra
, sizeof (struct attr_extra
));
691 /* If reference becomes zero then free attribute object. */
692 if (attr
->refcnt
== 0)
694 ret
= hash_release (attrhash
, attr
);
695 assert (ret
!= NULL
);
696 bgp_attr_extra_free (attr
);
697 XFREE (MTYPE_ATTR
, attr
);
701 bgp_attr_unintern_sub (&tmp
);
705 bgp_attr_flush (struct attr
*attr
)
707 if (attr
->aspath
&& ! attr
->aspath
->refcnt
)
708 aspath_free (attr
->aspath
);
709 if (attr
->community
&& ! attr
->community
->refcnt
)
710 community_free (attr
->community
);
713 struct attr_extra
*attre
= attr
->extra
;
715 if (attre
->ecommunity
&& ! attre
->ecommunity
->refcnt
)
716 ecommunity_free (&attre
->ecommunity
);
717 if (attre
->cluster
&& ! attre
->cluster
->refcnt
)
718 cluster_free (attre
->cluster
);
719 if (attre
->transit
&& ! attre
->transit
->refcnt
)
720 transit_free (attre
->transit
);
724 /* Implement draft-scudder-idr-optional-transitive behaviour and
725 * avoid resetting sessions for malformed attributes which are
726 * are partial/optional and hence where the error likely was not
727 * introduced by the sending neighbour.
729 static bgp_attr_parse_ret_t
730 bgp_attr_malformed (struct bgp_attr_parser_args
*args
, u_char subcode
,
733 struct peer
*const peer
= args
->peer
;
734 const u_int8_t flags
= args
->flags
;
735 /* startp and length must be special-cased, as whether or not to
736 * send the attribute data with the NOTIFY depends on the error,
737 * the caller therefore signals this with the seperate length argument
739 u_char
*notify_datap
= (length
> 0 ? args
->startp
: NULL
);
741 /* Only relax error handling for eBGP peers */
742 if (peer
->sort
!= BGP_PEER_EBGP
)
744 bgp_notify_send_with_data (peer
, BGP_NOTIFY_UPDATE_ERR
, subcode
,
745 notify_datap
, length
);
746 return BGP_ATTR_PARSE_ERROR
;
750 /* Adjust the stream getp to the end of the attribute, in case we can
751 * still proceed but the caller hasn't read all the attribute.
753 stream_set_getp (BGP_INPUT (peer
),
754 (args
->startp
- STREAM_DATA (BGP_INPUT (peer
)))
757 switch (args
->type
) {
758 /* where an attribute is relatively inconsequential, e.g. it does not
759 * affect route selection, and can be safely ignored, then any such
760 * attributes which are malformed should just be ignored and the route
761 * processed as normal.
763 case BGP_ATTR_AS4_AGGREGATOR
:
764 case BGP_ATTR_AGGREGATOR
:
765 case BGP_ATTR_ATOMIC_AGGREGATE
:
766 return BGP_ATTR_PARSE_PROCEED
;
768 /* Core attributes, particularly ones which may influence route
769 * selection, should always cause session resets
771 case BGP_ATTR_ORIGIN
:
772 case BGP_ATTR_AS_PATH
:
773 case BGP_ATTR_NEXT_HOP
:
774 case BGP_ATTR_MULTI_EXIT_DISC
:
775 case BGP_ATTR_LOCAL_PREF
:
776 case BGP_ATTR_COMMUNITIES
:
777 case BGP_ATTR_ORIGINATOR_ID
:
778 case BGP_ATTR_CLUSTER_LIST
:
779 case BGP_ATTR_MP_REACH_NLRI
:
780 case BGP_ATTR_MP_UNREACH_NLRI
:
781 case BGP_ATTR_EXT_COMMUNITIES
:
782 bgp_notify_send_with_data (peer
, BGP_NOTIFY_UPDATE_ERR
, subcode
,
783 notify_datap
, length
);
784 return BGP_ATTR_PARSE_ERROR
;
787 /* Partial optional attributes that are malformed should not cause
788 * the whole session to be reset. Instead treat it as a withdrawal
789 * of the routes, if possible.
791 if (CHECK_FLAG (flags
, BGP_ATTR_FLAG_TRANS
)
792 && CHECK_FLAG (flags
, BGP_ATTR_FLAG_OPTIONAL
)
793 && CHECK_FLAG (flags
, BGP_ATTR_FLAG_PARTIAL
))
794 return BGP_ATTR_PARSE_WITHDRAW
;
796 /* default to reset */
797 return BGP_ATTR_PARSE_ERROR
;
800 /* Find out what is wrong with the path attribute flag bits and log the error.
801 "Flag bits" here stand for Optional, Transitive and Partial, but not for
802 Extended Length. Checking O/T/P bits at once implies, that the attribute
803 being diagnosed is defined by RFC as either a "well-known" or an "optional,
804 non-transitive" attribute. */
806 bgp_attr_flags_diagnose (struct bgp_attr_parser_args
*args
,
807 u_int8_t desired_flags
/* how RFC says it must be */
811 u_char real_flags
= args
->flags
;
812 const u_int8_t attr_code
= args
->type
;
814 desired_flags
&= ~BGP_ATTR_FLAG_EXTLEN
;
815 real_flags
&= ~BGP_ATTR_FLAG_EXTLEN
;
816 for (i
= 0; i
<= 2; i
++) /* O,T,P, but not E */
819 CHECK_FLAG (desired_flags
, attr_flag_str
[i
].key
) !=
820 CHECK_FLAG (real_flags
, attr_flag_str
[i
].key
)
823 zlog (args
->peer
->log
, LOG_ERR
, "%s attribute must%s be flagged as \"%s\"",
824 LOOKUP (attr_str
, attr_code
),
825 CHECK_FLAG (desired_flags
, attr_flag_str
[i
].key
) ? "" : " not",
826 attr_flag_str
[i
].str
);
831 zlog (args
->peer
->log
, LOG_DEBUG
,
832 "Strange, %s called for attr %s, but no problem found with flags"
833 " (real flags 0x%x, desired 0x%x)",
834 __func__
, LOOKUP (attr_str
, attr_code
),
835 real_flags
, desired_flags
);
839 /* Required flags for attributes. EXTLEN will be masked off when testing,
840 * as will PARTIAL for optional+transitive attributes.
842 const u_int8_t attr_flags_values
[] = {
843 [BGP_ATTR_ORIGIN
] = BGP_ATTR_FLAG_TRANS
,
844 [BGP_ATTR_AS_PATH
] = BGP_ATTR_FLAG_TRANS
,
845 [BGP_ATTR_NEXT_HOP
] = BGP_ATTR_FLAG_TRANS
,
846 [BGP_ATTR_MULTI_EXIT_DISC
] = BGP_ATTR_FLAG_OPTIONAL
,
847 [BGP_ATTR_LOCAL_PREF
] = BGP_ATTR_FLAG_TRANS
,
848 [BGP_ATTR_ATOMIC_AGGREGATE
] = BGP_ATTR_FLAG_TRANS
,
849 [BGP_ATTR_AGGREGATOR
] = BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
,
850 [BGP_ATTR_COMMUNITIES
] = BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_OPTIONAL
,
851 [BGP_ATTR_ORIGINATOR_ID
] = BGP_ATTR_FLAG_OPTIONAL
,
852 [BGP_ATTR_CLUSTER_LIST
] = BGP_ATTR_FLAG_OPTIONAL
,
853 [BGP_ATTR_MP_REACH_NLRI
] = BGP_ATTR_FLAG_OPTIONAL
,
854 [BGP_ATTR_MP_UNREACH_NLRI
] = BGP_ATTR_FLAG_OPTIONAL
,
855 [BGP_ATTR_EXT_COMMUNITIES
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
856 [BGP_ATTR_AS4_PATH
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
857 [BGP_ATTR_AS4_AGGREGATOR
] = BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS
,
859 static const size_t attr_flags_values_max
=
860 sizeof (attr_flags_values
) / sizeof (attr_flags_values
[0]);
863 bgp_attr_flag_invalid (struct bgp_attr_parser_args
*args
)
865 u_int8_t mask
= BGP_ATTR_FLAG_EXTLEN
;
866 const u_int8_t flags
= args
->flags
;
867 const u_int8_t attr_code
= args
->type
;
868 struct peer
*const peer
= args
->peer
;
870 /* there may be attributes we don't know about */
871 if (attr_code
> attr_flags_values_max
)
873 if (attr_flags_values
[attr_code
] == 0)
876 /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
879 if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL
, flags
)
880 && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS
, flags
))
882 zlog (peer
->log
, LOG_ERR
,
883 "%s well-known attributes must have transitive flag set (%x)",
884 LOOKUP (attr_str
, attr_code
), flags
);
888 /* "For well-known attributes and for optional non-transitive attributes,
889 * the Partial bit MUST be set to 0."
891 if (CHECK_FLAG (flags
, BGP_ATTR_FLAG_PARTIAL
))
893 if (!CHECK_FLAG (flags
, BGP_ATTR_FLAG_OPTIONAL
))
895 zlog (peer
->log
, LOG_ERR
,
896 "%s well-known attribute "
897 "must NOT have the partial flag set (%x)",
898 LOOKUP (attr_str
, attr_code
), flags
);
901 if (CHECK_FLAG (flags
, BGP_ATTR_FLAG_OPTIONAL
)
902 && !CHECK_FLAG (flags
, BGP_ATTR_FLAG_TRANS
))
904 zlog (peer
->log
, LOG_ERR
,
905 "%s optional + transitive attribute "
906 "must NOT have the partial flag set (%x)",
907 LOOKUP (attr_str
, attr_code
), flags
);
912 /* Optional transitive attributes may go through speakers that don't
913 * reocgnise them and set the Partial bit.
915 if (CHECK_FLAG (flags
, BGP_ATTR_FLAG_OPTIONAL
)
916 && CHECK_FLAG (flags
, BGP_ATTR_FLAG_TRANS
))
917 SET_FLAG (mask
, BGP_ATTR_FLAG_PARTIAL
);
920 == attr_flags_values
[attr_code
])
923 bgp_attr_flags_diagnose (args
, attr_flags_values
[attr_code
]);
927 /* Get origin attribute of the update message. */
928 static bgp_attr_parse_ret_t
929 bgp_attr_origin (struct bgp_attr_parser_args
*args
)
931 struct peer
*const peer
= args
->peer
;
932 struct attr
*const attr
= args
->attr
;
933 const bgp_size_t length
= args
->length
;
935 /* If any recognized attribute has Attribute Length that conflicts
936 with the expected length (based on the attribute type code), then
937 the Error Subcode is set to Attribute Length Error. The Data
938 field contains the erroneous attribute (type, length and
942 zlog (peer
->log
, LOG_ERR
, "Origin attribute length is not one %d",
944 return bgp_attr_malformed (args
,
945 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
949 /* Fetch origin attribute. */
950 attr
->origin
= stream_getc (BGP_INPUT (peer
));
952 /* If the ORIGIN attribute has an undefined value, then the Error
953 Subcode is set to Invalid Origin Attribute. The Data field
954 contains the unrecognized attribute (type, length and value). */
955 if ((attr
->origin
!= BGP_ORIGIN_IGP
)
956 && (attr
->origin
!= BGP_ORIGIN_EGP
)
957 && (attr
->origin
!= BGP_ORIGIN_INCOMPLETE
))
959 zlog (peer
->log
, LOG_ERR
, "Origin attribute value is invalid %d",
961 return bgp_attr_malformed (args
,
962 BGP_NOTIFY_UPDATE_INVAL_ORIGIN
,
966 /* Set oring attribute flag. */
967 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN
);
972 /* Parse AS path information. This function is wrapper of
975 bgp_attr_aspath (struct bgp_attr_parser_args
*args
)
977 struct attr
*const attr
= args
->attr
;
978 struct peer
*const peer
= args
->peer
;
979 const bgp_size_t length
= args
->length
;
982 * peer with AS4 => will get 4Byte ASnums
983 * otherwise, will get 16 Bit
985 attr
->aspath
= aspath_parse (peer
->ibuf
, length
,
986 CHECK_FLAG (peer
->cap
, PEER_CAP_AS4_RCV
));
988 /* In case of IBGP, length will be zero. */
991 zlog (peer
->log
, LOG_ERR
,
992 "Malformed AS path from %s, length is %d",
994 return bgp_attr_malformed (args
, BGP_NOTIFY_UPDATE_MAL_AS_PATH
, 0);
997 /* Set aspath attribute flag. */
998 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH
);
1000 return BGP_ATTR_PARSE_PROCEED
;
1003 static bgp_attr_parse_ret_t
1004 bgp_attr_aspath_check (struct peer
*const peer
, struct attr
*const attr
)
1006 /* These checks were part of bgp_attr_aspath, but with
1007 * as4 we should to check aspath things when
1008 * aspath synthesizing with as4_path has already taken place.
1009 * Otherwise we check ASPATH and use the synthesized thing, and that is
1011 * So do the checks later, i.e. here
1013 struct bgp
*bgp
= peer
->bgp
;
1014 struct aspath
*aspath
;
1016 /* Confederation sanity check. */
1017 if ((peer
->sort
== BGP_PEER_CONFED
&& ! aspath_left_confed_check (attr
->aspath
)) ||
1018 (peer
->sort
== BGP_PEER_EBGP
&& aspath_confed_check (attr
->aspath
)))
1020 zlog (peer
->log
, LOG_ERR
, "Malformed AS path from %s", peer
->host
);
1021 bgp_notify_send (peer
, BGP_NOTIFY_UPDATE_ERR
,
1022 BGP_NOTIFY_UPDATE_MAL_AS_PATH
);
1023 return BGP_ATTR_PARSE_ERROR
;
1026 /* First AS check for EBGP. */
1027 if (bgp
!= NULL
&& bgp_flag_check (bgp
, BGP_FLAG_ENFORCE_FIRST_AS
))
1029 if (peer
->sort
== BGP_PEER_EBGP
1030 && ! aspath_firstas_check (attr
->aspath
, peer
->as
))
1032 zlog (peer
->log
, LOG_ERR
,
1033 "%s incorrect first AS (must be %u)", peer
->host
, peer
->as
);
1034 bgp_notify_send (peer
, BGP_NOTIFY_UPDATE_ERR
,
1035 BGP_NOTIFY_UPDATE_MAL_AS_PATH
);
1036 return BGP_ATTR_PARSE_ERROR
;
1040 /* local-as prepend */
1041 if (peer
->change_local_as
&&
1042 ! CHECK_FLAG (peer
->flags
, PEER_FLAG_LOCAL_AS_NO_PREPEND
))
1044 aspath
= aspath_dup (attr
->aspath
);
1045 aspath
= aspath_add_seq (aspath
, peer
->change_local_as
);
1046 aspath_unintern (&attr
->aspath
);
1047 attr
->aspath
= aspath_intern (aspath
);
1050 return BGP_ATTR_PARSE_PROCEED
;
1053 /* Parse AS4 path information. This function is another wrapper of
1056 bgp_attr_as4_path (struct bgp_attr_parser_args
*args
, struct aspath
**as4_path
)
1058 struct peer
*const peer
= args
->peer
;
1059 struct attr
*const attr
= args
->attr
;
1060 const bgp_size_t length
= args
->length
;
1062 *as4_path
= aspath_parse (peer
->ibuf
, length
, 1);
1064 /* In case of IBGP, length will be zero. */
1067 zlog (peer
->log
, LOG_ERR
,
1068 "Malformed AS4 path from %s, length is %d",
1069 peer
->host
, length
);
1070 return bgp_attr_malformed (args
,
1071 BGP_NOTIFY_UPDATE_MAL_AS_PATH
,
1075 /* Set aspath attribute flag. */
1077 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH
);
1079 return BGP_ATTR_PARSE_PROCEED
;
1082 /* Nexthop attribute. */
1083 static bgp_attr_parse_ret_t
1084 bgp_attr_nexthop (struct bgp_attr_parser_args
*args
)
1086 struct peer
*const peer
= args
->peer
;
1087 struct attr
*const attr
= args
->attr
;
1088 const bgp_size_t length
= args
->length
;
1090 in_addr_t nexthop_h
, nexthop_n
;
1092 /* Check nexthop attribute length. */
1095 zlog (peer
->log
, LOG_ERR
, "Nexthop attribute length isn't four [%d]",
1098 return bgp_attr_malformed (args
,
1099 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1103 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1104 attribute must result in a NOTIFICATION message (this is implemented below).
1105 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1106 logged locally (this is implemented somewhere else). The UPDATE message
1107 gets ignored in any of these cases. */
1108 nexthop_n
= stream_get_ipv4 (peer
->ibuf
);
1109 nexthop_h
= ntohl (nexthop_n
);
1110 if (IPV4_NET0 (nexthop_h
) || IPV4_NET127 (nexthop_h
) || IPV4_CLASS_DE (nexthop_h
))
1112 char buf
[INET_ADDRSTRLEN
];
1113 inet_ntop (AF_INET
, &nexthop_h
, buf
, INET_ADDRSTRLEN
);
1114 zlog (peer
->log
, LOG_ERR
, "Martian nexthop %s", buf
);
1115 return bgp_attr_malformed (args
,
1116 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP
,
1120 attr
->nexthop
.s_addr
= nexthop_n
;
1121 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP
);
1123 return BGP_ATTR_PARSE_PROCEED
;
1126 /* MED atrribute. */
1127 static bgp_attr_parse_ret_t
1128 bgp_attr_med (struct bgp_attr_parser_args
*args
)
1130 struct peer
*const peer
= args
->peer
;
1131 struct attr
*const attr
= args
->attr
;
1132 const bgp_size_t length
= args
->length
;
1137 zlog (peer
->log
, LOG_ERR
,
1138 "MED attribute length isn't four [%d]", length
);
1140 return bgp_attr_malformed (args
,
1141 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1145 attr
->med
= stream_getl (peer
->ibuf
);
1147 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC
);
1149 return BGP_ATTR_PARSE_PROCEED
;
1152 /* Local preference attribute. */
1153 static bgp_attr_parse_ret_t
1154 bgp_attr_local_pref (struct bgp_attr_parser_args
*args
)
1156 struct peer
*const peer
= args
->peer
;
1157 struct attr
*const attr
= args
->attr
;
1158 const bgp_size_t length
= args
->length
;
1163 zlog (peer
->log
, LOG_ERR
, "LOCAL_PREF attribute length isn't 4 [%u]",
1165 return bgp_attr_malformed (args
,
1166 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1170 /* If it is contained in an UPDATE message that is received from an
1171 external peer, then this attribute MUST be ignored by the
1172 receiving speaker. */
1173 if (peer
->sort
== BGP_PEER_EBGP
)
1175 stream_forward_getp (peer
->ibuf
, length
);
1176 return BGP_ATTR_PARSE_PROCEED
;
1179 attr
->local_pref
= stream_getl (peer
->ibuf
);
1181 /* Set atomic aggregate flag. */
1182 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF
);
1184 return BGP_ATTR_PARSE_PROCEED
;
1187 /* Atomic aggregate. */
1189 bgp_attr_atomic (struct bgp_attr_parser_args
*args
)
1191 struct peer
*const peer
= args
->peer
;
1192 struct attr
*const attr
= args
->attr
;
1193 const bgp_size_t length
= args
->length
;
1198 zlog (peer
->log
, LOG_ERR
, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
1200 return bgp_attr_malformed (args
,
1201 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1205 /* Set atomic aggregate flag. */
1206 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE
);
1208 return BGP_ATTR_PARSE_PROCEED
;
1211 /* Aggregator attribute */
1213 bgp_attr_aggregator (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
;
1220 struct attr_extra
*attre
= bgp_attr_extra_get (attr
);
1222 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1223 if (CHECK_FLAG (peer
->cap
, PEER_CAP_AS4_RCV
))
1226 if (length
!= wantedlen
)
1228 zlog (peer
->log
, LOG_ERR
, "AGGREGATOR attribute length isn't %u [%u]",
1230 return bgp_attr_malformed (args
,
1231 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1235 if ( CHECK_FLAG (peer
->cap
, PEER_CAP_AS4_RCV
) )
1236 attre
->aggregator_as
= stream_getl (peer
->ibuf
);
1238 attre
->aggregator_as
= stream_getw (peer
->ibuf
);
1239 attre
->aggregator_addr
.s_addr
= stream_get_ipv4 (peer
->ibuf
);
1241 /* Set atomic aggregate flag. */
1242 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR
);
1244 return BGP_ATTR_PARSE_PROCEED
;
1247 /* New Aggregator attribute */
1248 static bgp_attr_parse_ret_t
1249 bgp_attr_as4_aggregator (struct bgp_attr_parser_args
*args
,
1250 as_t
*as4_aggregator_as
,
1251 struct in_addr
*as4_aggregator_addr
)
1253 struct peer
*const peer
= args
->peer
;
1254 struct attr
*const attr
= args
->attr
;
1255 const bgp_size_t length
= args
->length
;
1259 zlog (peer
->log
, LOG_ERR
, "New Aggregator length is not 8 [%d]",
1261 return bgp_attr_malformed (args
,
1262 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1266 *as4_aggregator_as
= stream_getl (peer
->ibuf
);
1267 as4_aggregator_addr
->s_addr
= stream_get_ipv4 (peer
->ibuf
);
1269 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR
);
1271 return BGP_ATTR_PARSE_PROCEED
;
1274 /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1276 static bgp_attr_parse_ret_t
1277 bgp_attr_munge_as4_attrs (struct peer
*const peer
,
1278 struct attr
*const attr
,
1279 struct aspath
*as4_path
, as_t as4_aggregator
,
1280 struct in_addr
*as4_aggregator_addr
)
1282 int ignore_as4_path
= 0;
1283 struct aspath
*newpath
;
1284 struct attr_extra
*attre
= attr
->extra
;
1286 if (CHECK_FLAG (peer
->cap
, PEER_CAP_AS4_RCV
))
1288 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1290 * It is worth a warning though, because the peer really
1291 * should not send them
1293 if (BGP_DEBUG(as4
, AS4
))
1295 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH
)))
1296 zlog_debug ("[AS4] %s %s AS4_PATH",
1297 peer
->host
, "AS4 capable peer, yet it sent");
1299 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR
)))
1300 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1301 peer
->host
, "AS4 capable peer, yet it sent");
1304 return BGP_ATTR_PARSE_PROCEED
;
1307 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1308 * because that may override AS4_PATH
1310 if (attr
->flag
& (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR
) ) )
1312 if (attr
->flag
& (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR
) ) )
1317 * if the as_number in aggregator is not AS_TRANS,
1318 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1319 * and the Aggregator shall be taken as
1320 * info on the aggregating node, and the AS_PATH
1321 * shall be taken as the AS_PATH
1323 * the Aggregator shall be ignored and the
1324 * AS4_AGGREGATOR shall be taken as the
1325 * Aggregating node and the AS_PATH is to be
1326 * constructed "as in all other cases"
1328 if (attre
->aggregator_as
!= BGP_AS_TRANS
)
1331 if ( BGP_DEBUG(as4
, AS4
))
1332 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1333 " send AGGREGATOR != AS_TRANS and"
1334 " AS4_AGGREGATOR, so ignore"
1335 " AS4_AGGREGATOR and AS4_PATH", peer
->host
);
1336 ignore_as4_path
= 1;
1340 /* "New_aggregator shall be taken as aggregator" */
1341 attre
->aggregator_as
= as4_aggregator
;
1342 attre
->aggregator_addr
.s_addr
= as4_aggregator_addr
->s_addr
;
1347 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1348 * That is bogus - but reading the conditions
1349 * we have to handle AS4_AGGREGATOR as if it were
1350 * AGGREGATOR in that case
1352 if ( BGP_DEBUG(as4
, AS4
))
1353 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1354 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1355 " it as if AGGREGATOR with AS_TRANS had been there", peer
->host
);
1356 (attre
= bgp_attr_extra_get (attr
))->aggregator_as
= as4_aggregator
;
1357 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1358 attr
->flag
|= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR
));
1362 /* need to reconcile NEW_AS_PATH and AS_PATH */
1363 if (!ignore_as4_path
&& (attr
->flag
& (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH
))))
1366 return BGP_ATTR_PARSE_PROCEED
;
1368 newpath
= aspath_reconcile_as4 (attr
->aspath
, as4_path
);
1369 aspath_unintern (&attr
->aspath
);
1370 attr
->aspath
= aspath_intern (newpath
);
1372 return BGP_ATTR_PARSE_PROCEED
;
1375 /* Community attribute. */
1376 static bgp_attr_parse_ret_t
1377 bgp_attr_community (struct bgp_attr_parser_args
*args
)
1379 struct peer
*const peer
= args
->peer
;
1380 struct attr
*const attr
= args
->attr
;
1381 const bgp_size_t length
= args
->length
;
1385 attr
->community
= NULL
;
1386 return BGP_ATTR_PARSE_PROCEED
;
1390 community_parse ((u_int32_t
*)stream_pnt (peer
->ibuf
), length
);
1392 /* XXX: fix community_parse to use stream API and remove this */
1393 stream_forward_getp (peer
->ibuf
, length
);
1395 if (!attr
->community
)
1396 return bgp_attr_malformed (args
,
1397 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
1400 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES
);
1402 return BGP_ATTR_PARSE_PROCEED
;
1405 /* Originator ID attribute. */
1406 static bgp_attr_parse_ret_t
1407 bgp_attr_originator_id (struct bgp_attr_parser_args
*args
)
1409 struct peer
*const peer
= args
->peer
;
1410 struct attr
*const attr
= args
->attr
;
1411 const bgp_size_t length
= args
->length
;
1416 zlog (peer
->log
, LOG_ERR
, "Bad originator ID length %d", length
);
1418 return bgp_attr_malformed (args
,
1419 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1423 (bgp_attr_extra_get (attr
))->originator_id
.s_addr
1424 = stream_get_ipv4 (peer
->ibuf
);
1426 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID
);
1428 return BGP_ATTR_PARSE_PROCEED
;
1431 /* Cluster list attribute. */
1432 static bgp_attr_parse_ret_t
1433 bgp_attr_cluster_list (struct bgp_attr_parser_args
*args
)
1435 struct peer
*const peer
= args
->peer
;
1436 struct attr
*const attr
= args
->attr
;
1437 const bgp_size_t length
= args
->length
;
1442 zlog (peer
->log
, LOG_ERR
, "Bad cluster list length %d", length
);
1444 return bgp_attr_malformed (args
, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
,
1448 (bgp_attr_extra_get (attr
))->cluster
1449 = cluster_parse ((struct in_addr
*)stream_pnt (peer
->ibuf
), length
);
1451 /* XXX: Fix cluster_parse to use stream API and then remove this */
1452 stream_forward_getp (peer
->ibuf
, length
);
1454 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST
);
1456 return BGP_ATTR_PARSE_PROCEED
;
1459 /* Multiprotocol reachability information parse. */
1461 bgp_mp_reach_parse (struct bgp_attr_parser_args
*args
,
1462 struct bgp_nlri
*mp_update
)
1466 bgp_size_t nlri_len
;
1470 struct peer
*const peer
= args
->peer
;
1471 struct attr
*const attr
= args
->attr
;
1472 const bgp_size_t length
= args
->length
;
1473 struct attr_extra
*attre
= bgp_attr_extra_get(attr
);
1475 /* Set end of packet. */
1476 s
= BGP_INPUT(peer
);
1477 start
= stream_get_getp(s
);
1479 /* safe to read statically sized header? */
1480 #define BGP_MP_REACH_MIN_SIZE 5
1481 #define LEN_LEFT (length - (stream_get_getp(s) - start))
1482 if ((length
> STREAM_READABLE(s
)) || (length
< BGP_MP_REACH_MIN_SIZE
))
1484 zlog_info ("%s: %s sent invalid length, %lu",
1485 __func__
, peer
->host
, (unsigned long)length
);
1486 return BGP_ATTR_PARSE_ERROR
;
1489 /* Load AFI, SAFI. */
1490 afi
= stream_getw (s
);
1491 safi
= stream_getc (s
);
1493 /* Get nexthop length. */
1494 attre
->mp_nexthop_len
= stream_getc (s
);
1496 if (LEN_LEFT
< attre
->mp_nexthop_len
)
1498 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1499 __func__
, peer
->host
, attre
->mp_nexthop_len
);
1500 return BGP_ATTR_PARSE_ERROR
;
1503 /* Nexthop length check. */
1504 switch (attre
->mp_nexthop_len
)
1507 stream_get (&attre
->mp_nexthop_global_in
, s
, 4);
1508 /* Probably needed for RFC 2283 */
1509 if (attr
->nexthop
.s_addr
== 0)
1510 memcpy(&attr
->nexthop
.s_addr
, &attre
->mp_nexthop_global_in
, 4);
1513 stream_getl (s
); /* RD high */
1514 stream_getl (s
); /* RD low */
1515 stream_get (&attre
->mp_nexthop_global_in
, s
, 4);
1519 stream_get (&attre
->mp_nexthop_global
, s
, 16);
1522 stream_get (&attre
->mp_nexthop_global
, s
, 16);
1523 stream_get (&attre
->mp_nexthop_local
, s
, 16);
1524 if (! IN6_IS_ADDR_LINKLOCAL (&attre
->mp_nexthop_local
))
1526 char buf1
[INET6_ADDRSTRLEN
];
1527 char buf2
[INET6_ADDRSTRLEN
];
1529 if (BGP_DEBUG (update
, UPDATE_IN
))
1530 zlog_debug ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer
->host
,
1531 inet_ntop (AF_INET6
, &attre
->mp_nexthop_global
,
1532 buf1
, INET6_ADDRSTRLEN
),
1533 inet_ntop (AF_INET6
, &attre
->mp_nexthop_local
,
1534 buf2
, INET6_ADDRSTRLEN
));
1536 attre
->mp_nexthop_len
= 16;
1539 #endif /* HAVE_IPV6 */
1541 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1542 __func__
, peer
->host
, attre
->mp_nexthop_len
);
1543 return BGP_ATTR_PARSE_ERROR
;
1548 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1549 __func__
, peer
->host
);
1550 return BGP_ATTR_PARSE_ERROR
;
1555 if ((val
= stream_getc (s
)))
1556 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1560 /* must have nrli_len, what is left of the attribute */
1561 nlri_len
= LEN_LEFT
;
1562 if ((!nlri_len
) || (nlri_len
> STREAM_READABLE(s
)))
1564 zlog_info ("%s: (%s) Failed to read NLRI",
1565 __func__
, peer
->host
);
1566 return BGP_ATTR_PARSE_ERROR
;
1569 if (safi
!= SAFI_MPLS_LABELED_VPN
)
1571 ret
= bgp_nlri_sanity_check (peer
, afi
, stream_pnt (s
), nlri_len
);
1574 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1575 __func__
, peer
->host
);
1576 return BGP_ATTR_PARSE_ERROR
;
1580 mp_update
->afi
= afi
;
1581 mp_update
->safi
= safi
;
1582 mp_update
->nlri
= stream_pnt (s
);
1583 mp_update
->length
= nlri_len
;
1585 stream_forward_getp (s
, nlri_len
);
1587 return BGP_ATTR_PARSE_PROCEED
;
1591 /* Multiprotocol unreachable parse */
1593 bgp_mp_unreach_parse (struct bgp_attr_parser_args
*args
,
1594 struct bgp_nlri
*mp_withdraw
)
1599 u_int16_t withdraw_len
;
1601 struct peer
*const peer
= args
->peer
;
1602 const bgp_size_t length
= args
->length
;
1606 #define BGP_MP_UNREACH_MIN_SIZE 3
1607 if ((length
> STREAM_READABLE(s
)) || (length
< BGP_MP_UNREACH_MIN_SIZE
))
1608 return BGP_ATTR_PARSE_ERROR
;
1610 afi
= stream_getw (s
);
1611 safi
= stream_getc (s
);
1613 withdraw_len
= length
- BGP_MP_UNREACH_MIN_SIZE
;
1615 if (safi
!= SAFI_MPLS_LABELED_VPN
)
1617 ret
= bgp_nlri_sanity_check (peer
, afi
, stream_pnt (s
), withdraw_len
);
1619 return BGP_ATTR_PARSE_ERROR
;
1622 mp_withdraw
->afi
= afi
;
1623 mp_withdraw
->safi
= safi
;
1624 mp_withdraw
->nlri
= stream_pnt (s
);
1625 mp_withdraw
->length
= withdraw_len
;
1627 stream_forward_getp (s
, withdraw_len
);
1629 return BGP_ATTR_PARSE_PROCEED
;
1632 /* Extended Community attribute. */
1633 static bgp_attr_parse_ret_t
1634 bgp_attr_ext_communities (struct bgp_attr_parser_args
*args
)
1636 struct peer
*const peer
= args
->peer
;
1637 struct attr
*const attr
= args
->attr
;
1638 const bgp_size_t length
= args
->length
;
1643 attr
->extra
->ecommunity
= NULL
;
1644 /* Empty extcomm doesn't seem to be invalid per se */
1645 return BGP_ATTR_PARSE_PROCEED
;
1648 (bgp_attr_extra_get (attr
))->ecommunity
=
1649 ecommunity_parse ((u_int8_t
*)stream_pnt (peer
->ibuf
), length
);
1650 /* XXX: fix ecommunity_parse to use stream API */
1651 stream_forward_getp (peer
->ibuf
, length
);
1653 if (!attr
->extra
->ecommunity
)
1654 return bgp_attr_malformed (args
,
1655 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR
,
1658 attr
->flag
|= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES
);
1660 return BGP_ATTR_PARSE_PROCEED
;
1663 /* BGP unknown attribute treatment. */
1664 static bgp_attr_parse_ret_t
1665 bgp_attr_unknown (struct bgp_attr_parser_args
*args
)
1667 bgp_size_t total
= args
->total
;
1668 struct transit
*transit
;
1669 struct attr_extra
*attre
;
1670 struct peer
*const peer
= args
->peer
;
1671 struct attr
*const attr
= args
->attr
;
1672 u_char
*const startp
= args
->startp
;
1673 const u_char type
= args
->type
;
1674 const u_char flag
= args
->flags
;
1675 const bgp_size_t length
= args
->length
;
1678 if (BGP_DEBUG (normal
, NORMAL
))
1679 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1680 peer
->host
, type
, length
);
1682 if (BGP_DEBUG (events
, EVENTS
))
1683 zlog (peer
->log
, LOG_DEBUG
,
1684 "Unknown attribute type %d length %d is received", type
, length
);
1686 /* Forward read pointer of input stream. */
1687 stream_forward_getp (peer
->ibuf
, length
);
1689 /* If any of the mandatory well-known attributes are not recognized,
1690 then the Error Subcode is set to Unrecognized Well-known
1691 Attribute. The Data field contains the unrecognized attribute
1692 (type, length and value). */
1693 if (!CHECK_FLAG (flag
, BGP_ATTR_FLAG_OPTIONAL
))
1695 return bgp_attr_malformed (args
,
1696 BGP_NOTIFY_UPDATE_UNREC_ATTR
,
1700 /* Unrecognized non-transitive optional attributes must be quietly
1701 ignored and not passed along to other BGP peers. */
1702 if (! CHECK_FLAG (flag
, BGP_ATTR_FLAG_TRANS
))
1703 return BGP_ATTR_PARSE_PROCEED
;
1705 /* If a path with recognized transitive optional attribute is
1706 accepted and passed along to other BGP peers and the Partial bit
1707 in the Attribute Flags octet is set to 1 by some previous AS, it
1708 is not set back to 0 by the current AS. */
1709 SET_FLAG (*startp
, BGP_ATTR_FLAG_PARTIAL
);
1711 /* Store transitive attribute to the end of attr->transit. */
1712 if (! ((attre
= bgp_attr_extra_get(attr
))->transit
) )
1713 attre
->transit
= XCALLOC (MTYPE_TRANSIT
, sizeof (struct transit
));
1715 transit
= attre
->transit
;
1718 transit
->val
= XREALLOC (MTYPE_TRANSIT_VAL
, transit
->val
,
1719 transit
->length
+ total
);
1721 transit
->val
= XMALLOC (MTYPE_TRANSIT_VAL
, total
);
1723 memcpy (transit
->val
+ transit
->length
, startp
, total
);
1724 transit
->length
+= total
;
1726 return BGP_ATTR_PARSE_PROCEED
;
1729 /* Read attribute of update packet. This function is called from
1730 bgp_update_receive() in bgp_packet.c. */
1731 bgp_attr_parse_ret_t
1732 bgp_attr_parse (struct peer
*peer
, struct attr
*attr
, bgp_size_t size
,
1733 struct bgp_nlri
*mp_update
, struct bgp_nlri
*mp_withdraw
)
1739 u_char
*startp
, *endp
;
1741 u_char seen
[BGP_ATTR_BITMAP_SIZE
];
1742 /* we need the as4_path only until we have synthesized the as_path with it */
1743 /* same goes for as4_aggregator */
1744 struct aspath
*as4_path
= NULL
;
1745 as_t as4_aggregator
= 0;
1746 struct in_addr as4_aggregator_addr
= { 0 };
1748 /* Initialize bitmap. */
1749 memset (seen
, 0, BGP_ATTR_BITMAP_SIZE
);
1751 /* End pointer of BGP attribute. */
1752 endp
= BGP_INPUT_PNT (peer
) + size
;
1754 /* Get attributes to the end of attribute length. */
1755 while (BGP_INPUT_PNT (peer
) < endp
)
1757 /* Check remaining length check.*/
1758 if (endp
- BGP_INPUT_PNT (peer
) < BGP_ATTR_MIN_LEN
)
1760 /* XXX warning: long int format, int arg (arg 5) */
1761 zlog (peer
->log
, LOG_WARNING
,
1762 "%s: error BGP attribute length %lu is smaller than min len",
1764 (unsigned long) (endp
- STREAM_PNT (BGP_INPUT (peer
))));
1766 bgp_notify_send (peer
,
1767 BGP_NOTIFY_UPDATE_ERR
,
1768 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
1769 return BGP_ATTR_PARSE_ERROR
;
1772 /* Fetch attribute flag and type. */
1773 startp
= BGP_INPUT_PNT (peer
);
1774 /* "The lower-order four bits of the Attribute Flags octet are
1775 unused. They MUST be zero when sent and MUST be ignored when
1777 flag
= 0xF0 & stream_getc (BGP_INPUT (peer
));
1778 type
= stream_getc (BGP_INPUT (peer
));
1780 /* Check whether Extended-Length applies and is in bounds */
1781 if (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
)
1782 && ((endp
- startp
) < (BGP_ATTR_MIN_LEN
+ 1)))
1784 zlog (peer
->log
, LOG_WARNING
,
1785 "%s: Extended length set, but just %lu bytes of attr header",
1787 (unsigned long) (endp
- STREAM_PNT (BGP_INPUT (peer
))));
1789 bgp_notify_send (peer
,
1790 BGP_NOTIFY_UPDATE_ERR
,
1791 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
1792 return BGP_ATTR_PARSE_ERROR
;
1795 /* Check extended attribue length bit. */
1796 if (CHECK_FLAG (flag
, BGP_ATTR_FLAG_EXTLEN
))
1797 length
= stream_getw (BGP_INPUT (peer
));
1799 length
= stream_getc (BGP_INPUT (peer
));
1801 /* If any attribute appears more than once in the UPDATE
1802 message, then the Error Subcode is set to Malformed Attribute
1805 if (CHECK_BITMAP (seen
, type
))
1807 zlog (peer
->log
, LOG_WARNING
,
1808 "%s: error BGP attribute type %d appears twice in a message",
1811 bgp_notify_send (peer
,
1812 BGP_NOTIFY_UPDATE_ERR
,
1813 BGP_NOTIFY_UPDATE_MAL_ATTR
);
1814 return BGP_ATTR_PARSE_ERROR
;
1817 /* Set type to bitmap to check duplicate attribute. `type' is
1818 unsigned char so it never overflow bitmap range. */
1820 SET_BITMAP (seen
, type
);
1822 /* Overflow check. */
1823 attr_endp
= BGP_INPUT_PNT (peer
) + length
;
1825 if (attr_endp
> endp
)
1827 zlog (peer
->log
, LOG_WARNING
,
1828 "%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
);
1829 bgp_notify_send (peer
,
1830 BGP_NOTIFY_UPDATE_ERR
,
1831 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
1832 return BGP_ATTR_PARSE_ERROR
;
1835 struct bgp_attr_parser_args attr_args
= {
1842 .total
= attr_endp
- startp
,
1846 /* If any recognized attribute has Attribute Flags that conflict
1847 with the Attribute Type Code, then the Error Subcode is set to
1848 Attribute Flags Error. The Data field contains the erroneous
1849 attribute (type, length and value). */
1850 if (bgp_attr_flag_invalid (&attr_args
))
1852 bgp_attr_parse_ret_t ret
;
1853 ret
= bgp_attr_malformed (&attr_args
,
1854 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR
,
1856 if (ret
== BGP_ATTR_PARSE_PROCEED
)
1861 /* OK check attribute and store it's value. */
1864 case BGP_ATTR_ORIGIN
:
1865 ret
= bgp_attr_origin (&attr_args
);
1867 case BGP_ATTR_AS_PATH
:
1868 ret
= bgp_attr_aspath (&attr_args
);
1870 case BGP_ATTR_AS4_PATH
:
1871 ret
= bgp_attr_as4_path (&attr_args
, &as4_path
);
1873 case BGP_ATTR_NEXT_HOP
:
1874 ret
= bgp_attr_nexthop (&attr_args
);
1876 case BGP_ATTR_MULTI_EXIT_DISC
:
1877 ret
= bgp_attr_med (&attr_args
);
1879 case BGP_ATTR_LOCAL_PREF
:
1880 ret
= bgp_attr_local_pref (&attr_args
);
1882 case BGP_ATTR_ATOMIC_AGGREGATE
:
1883 ret
= bgp_attr_atomic (&attr_args
);
1885 case BGP_ATTR_AGGREGATOR
:
1886 ret
= bgp_attr_aggregator (&attr_args
);
1888 case BGP_ATTR_AS4_AGGREGATOR
:
1889 ret
= bgp_attr_as4_aggregator (&attr_args
,
1891 &as4_aggregator_addr
);
1893 case BGP_ATTR_COMMUNITIES
:
1894 ret
= bgp_attr_community (&attr_args
);
1896 case BGP_ATTR_ORIGINATOR_ID
:
1897 ret
= bgp_attr_originator_id (&attr_args
);
1899 case BGP_ATTR_CLUSTER_LIST
:
1900 ret
= bgp_attr_cluster_list (&attr_args
);
1902 case BGP_ATTR_MP_REACH_NLRI
:
1903 ret
= bgp_mp_reach_parse (&attr_args
, mp_update
);
1905 case BGP_ATTR_MP_UNREACH_NLRI
:
1906 ret
= bgp_mp_unreach_parse (&attr_args
, mp_withdraw
);
1908 case BGP_ATTR_EXT_COMMUNITIES
:
1909 ret
= bgp_attr_ext_communities (&attr_args
);
1912 ret
= bgp_attr_unknown (&attr_args
);
1916 /* If hard error occured immediately return to the caller. */
1917 if (ret
== BGP_ATTR_PARSE_ERROR
)
1919 zlog (peer
->log
, LOG_WARNING
,
1920 "%s: Attribute %s, parse error",
1922 LOOKUP (attr_str
, type
));
1923 bgp_notify_send (peer
,
1924 BGP_NOTIFY_UPDATE_ERR
,
1925 BGP_NOTIFY_UPDATE_MAL_ATTR
);
1927 aspath_unintern (&as4_path
);
1930 if (ret
== BGP_ATTR_PARSE_WITHDRAW
)
1933 zlog (peer
->log
, LOG_WARNING
,
1934 "%s: Attribute %s, parse error - treating as withdrawal",
1936 LOOKUP (attr_str
, type
));
1938 aspath_unintern (&as4_path
);
1942 /* Check the fetched length. */
1943 if (BGP_INPUT_PNT (peer
) != attr_endp
)
1945 zlog (peer
->log
, LOG_WARNING
,
1946 "%s: BGP attribute %s, fetch error",
1947 peer
->host
, LOOKUP (attr_str
, type
));
1948 bgp_notify_send (peer
,
1949 BGP_NOTIFY_UPDATE_ERR
,
1950 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
1952 aspath_unintern (&as4_path
);
1953 return BGP_ATTR_PARSE_ERROR
;
1957 /* Check final read pointer is same as end pointer. */
1958 if (BGP_INPUT_PNT (peer
) != endp
)
1960 zlog (peer
->log
, LOG_WARNING
,
1961 "%s: BGP attribute %s, length mismatch",
1962 peer
->host
, LOOKUP (attr_str
, type
));
1963 bgp_notify_send (peer
,
1964 BGP_NOTIFY_UPDATE_ERR
,
1965 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR
);
1967 aspath_unintern (&as4_path
);
1968 return BGP_ATTR_PARSE_ERROR
;
1972 * At this place we can see whether we got AS4_PATH and/or
1973 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1974 * We can not do this before we've read all attributes because
1975 * the as4 handling does not say whether AS4_PATH has to be sent
1976 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1977 * in relationship to AGGREGATOR.
1978 * So, to be defensive, we are not relying on any order and read
1979 * all attributes first, including these 32bit ones, and now,
1980 * afterwards, we look what and if something is to be done for as4.
1982 if (bgp_attr_munge_as4_attrs (peer
, attr
, as4_path
,
1983 as4_aggregator
, &as4_aggregator_addr
))
1986 aspath_unintern (&as4_path
);
1987 return BGP_ATTR_PARSE_ERROR
;
1990 /* At this stage, we have done all fiddling with as4, and the
1991 * resulting info is in attr->aggregator resp. attr->aspath
1992 * so we can chuck as4_aggregator and as4_path alltogether in
1993 * order to save memory
1997 aspath_unintern (&as4_path
); /* unintern - it is in the hash */
1998 /* The flag that we got this is still there, but that does not
2003 * The "rest" of the code does nothing with as4_aggregator.
2004 * there is no memory attached specifically which is not part
2006 * so ignoring just means do nothing.
2009 * Finally do the checks on the aspath we did not do yet
2010 * because we waited for a potentially synthesized aspath.
2012 if (attr
->flag
& (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH
)))
2014 ret
= bgp_attr_aspath_check (peer
, attr
);
2015 if (ret
!= BGP_ATTR_PARSE_PROCEED
)
2019 /* Finally intern unknown attribute. */
2020 if (attr
->extra
&& attr
->extra
->transit
)
2021 attr
->extra
->transit
= transit_intern (attr
->extra
->transit
);
2023 return BGP_ATTR_PARSE_PROCEED
;
2026 /* Well-known attribute check. */
2028 bgp_attr_check (struct peer
*peer
, struct attr
*attr
)
2032 if (! CHECK_FLAG (attr
->flag
, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN
)))
2033 type
= BGP_ATTR_ORIGIN
;
2035 if (! CHECK_FLAG (attr
->flag
, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH
)))
2036 type
= BGP_ATTR_AS_PATH
;
2038 if (! CHECK_FLAG (attr
->flag
, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP
)))
2039 type
= BGP_ATTR_NEXT_HOP
;
2041 if (peer
->sort
== BGP_PEER_IBGP
2042 && ! CHECK_FLAG (attr
->flag
, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF
)))
2043 type
= BGP_ATTR_LOCAL_PREF
;
2047 zlog (peer
->log
, LOG_WARNING
,
2048 "%s Missing well-known attribute %d.",
2050 bgp_notify_send_with_data (peer
,
2051 BGP_NOTIFY_UPDATE_ERR
,
2052 BGP_NOTIFY_UPDATE_MISS_ATTR
,
2054 return BGP_ATTR_PARSE_ERROR
;
2056 return BGP_ATTR_PARSE_PROCEED
;
2059 int stream_put_prefix (struct stream
*, struct prefix
*);
2062 bgp_packet_mpattr_start (struct stream
*s
, afi_t afi
, safi_t safi
,
2067 /* Set extended bit always to encode the attribute length as 2 bytes */
2068 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_EXTLEN
);
2069 stream_putc (s
, BGP_ATTR_MP_REACH_NLRI
);
2070 sizep
= stream_get_endp (s
);
2071 stream_putw (s
, 0); /* Marker: Attribute length. */
2072 stream_putw (s
, afi
); /* AFI */
2073 stream_putc (s
, safi
); /* SAFI */
2082 case SAFI_MULTICAST
:
2084 stream_put_ipv4 (s
, attr
->nexthop
.s_addr
);
2087 stream_putc (s
, 12);
2090 stream_put (s
, &attr
->extra
->mp_nexthop_global_in
, 4);
2101 case SAFI_MULTICAST
:
2103 unsigned long sizep
;
2104 struct attr_extra
*attre
= attr
->extra
;
2106 assert (attr
->extra
);
2107 stream_putc (s
, attre
->mp_nexthop_len
);
2108 stream_put (s
, &attre
->mp_nexthop_global
, 16);
2109 if (attre
->mp_nexthop_len
== 32)
2110 stream_put (s
, &attre
->mp_nexthop_local
, 16);
2116 #endif /*HAVE_IPV6*/
2127 bgp_packet_mpattr_prefix (struct stream
*s
, afi_t afi
, safi_t safi
,
2128 struct prefix
*p
, struct prefix_rd
*prd
,
2134 /* Tag, RD, Prefix write. */
2135 stream_putc (s
, p
->prefixlen
+ 88);
2136 stream_put (s
, tag
, 3);
2137 stream_put (s
, prd
->val
, 8);
2138 stream_put (s
, &p
->u
.prefix
, PSIZE (p
->prefixlen
));
2142 stream_put_prefix (s
, p
);
2148 bgp_packet_mpattr_end (struct stream
*s
, size_t sizep
)
2150 /* Set MP attribute length. Don't count the (2) bytes used to encode
2152 stream_putw_at (s
, sizep
, (stream_get_endp (s
) - sizep
) - 2);
2155 /* Make attribute packet. */
2157 bgp_packet_attribute (struct bgp
*bgp
, struct peer
*peer
,
2158 struct stream
*s
, struct attr
*attr
,
2159 struct prefix
*p
, afi_t afi
, safi_t safi
,
2160 struct peer
*from
, struct prefix_rd
*prd
, u_char
*tag
)
2163 size_t aspath_sizep
;
2164 struct aspath
*aspath
;
2165 int send_as4_path
= 0;
2166 int send_as4_aggregator
= 0;
2167 int use32bit
= (CHECK_FLAG (peer
->cap
, PEER_CAP_AS4_RCV
)) ? 1 : 0;
2168 size_t mpattrlen_pos
= 0;
2171 bgp
= bgp_get_default ();
2173 /* Remember current pointer. */
2174 cp
= stream_get_endp (s
);
2176 if (p
&& !(afi
== AFI_IP
&& safi
== SAFI_UNICAST
))
2178 mpattrlen_pos
= bgp_packet_mpattr_start(s
, afi
, safi
, attr
);
2179 bgp_packet_mpattr_prefix(s
, afi
, safi
, p
, prd
, tag
);
2180 bgp_packet_mpattr_end(s
, mpattrlen_pos
);
2183 /* Origin attribute. */
2184 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2185 stream_putc (s
, BGP_ATTR_ORIGIN
);
2187 stream_putc (s
, attr
->origin
);
2189 /* AS path attribute. */
2191 /* If remote-peer is EBGP */
2192 if (peer
->sort
== BGP_PEER_EBGP
2193 && (! CHECK_FLAG (peer
->af_flags
[afi
][safi
], PEER_FLAG_AS_PATH_UNCHANGED
)
2194 || attr
->aspath
->segments
== NULL
)
2195 && (! CHECK_FLAG (peer
->af_flags
[afi
][safi
], PEER_FLAG_RSERVER_CLIENT
)))
2197 aspath
= aspath_dup (attr
->aspath
);
2199 if (CHECK_FLAG(bgp
->config
, BGP_CONFIG_CONFEDERATION
))
2201 /* Strip the confed info, and then stuff our path CONFED_ID
2203 aspath
= aspath_delete_confed_seq (aspath
);
2204 aspath
= aspath_add_seq (aspath
, bgp
->confed_id
);
2208 if (peer
->change_local_as
) {
2209 /* If replace-as is specified, we only use the change_local_as when
2210 advertising routes. */
2211 if( ! CHECK_FLAG (peer
->flags
, PEER_FLAG_LOCAL_AS_REPLACE_AS
) ) {
2212 aspath
= aspath_add_seq (aspath
, peer
->local_as
);
2214 aspath
= aspath_add_seq (aspath
, peer
->change_local_as
);
2216 aspath
= aspath_add_seq (aspath
, peer
->local_as
);
2220 else if (peer
->sort
== BGP_PEER_CONFED
)
2222 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2223 aspath
= aspath_dup (attr
->aspath
);
2224 aspath
= aspath_add_confed_seq (aspath
, peer
->local_as
);
2227 aspath
= attr
->aspath
;
2229 /* If peer is not AS4 capable, then:
2230 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2231 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2232 * types are in it (i.e. exclude them if they are there)
2233 * AND do this only if there is at least one asnum > 65535 in the path!
2234 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2235 * all ASnums > 65535 to BGP_AS_TRANS
2238 stream_putc (s
, BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_EXTLEN
);
2239 stream_putc (s
, BGP_ATTR_AS_PATH
);
2240 aspath_sizep
= stream_get_endp (s
);
2242 stream_putw_at (s
, aspath_sizep
, aspath_put (s
, aspath
, use32bit
));
2244 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2247 if (!use32bit
&& aspath_has_as4 (aspath
))
2248 send_as4_path
= 1; /* we'll do this later, at the correct place */
2250 /* Nexthop attribute. */
2251 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP
) && afi
== AFI_IP
)
2253 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2254 stream_putc (s
, BGP_ATTR_NEXT_HOP
);
2256 if (safi
== SAFI_MPLS_VPN
)
2258 if (attr
->nexthop
.s_addr
== 0)
2259 stream_put_ipv4 (s
, peer
->nexthop
.v4
.s_addr
);
2261 stream_put_ipv4 (s
, attr
->nexthop
.s_addr
);
2264 stream_put_ipv4 (s
, attr
->nexthop
.s_addr
);
2267 /* MED attribute. */
2268 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC
))
2270 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
);
2271 stream_putc (s
, BGP_ATTR_MULTI_EXIT_DISC
);
2273 stream_putl (s
, attr
->med
);
2276 /* Local preference. */
2277 if (peer
->sort
== BGP_PEER_IBGP
||
2278 peer
->sort
== BGP_PEER_CONFED
)
2280 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2281 stream_putc (s
, BGP_ATTR_LOCAL_PREF
);
2283 stream_putl (s
, attr
->local_pref
);
2286 /* Atomic aggregate. */
2287 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE
))
2289 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2290 stream_putc (s
, BGP_ATTR_ATOMIC_AGGREGATE
);
2295 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR
))
2297 assert (attr
->extra
);
2299 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
2300 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2301 stream_putc (s
, BGP_ATTR_AGGREGATOR
);
2305 /* AS4 capable peer */
2307 stream_putl (s
, attr
->extra
->aggregator_as
);
2311 /* 2-byte AS peer */
2314 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2315 if ( attr
->extra
->aggregator_as
> 65535 )
2317 stream_putw (s
, BGP_AS_TRANS
);
2319 /* we have to send AS4_AGGREGATOR, too.
2320 * we'll do that later in order to send attributes in ascending
2323 send_as4_aggregator
= 1;
2326 stream_putw (s
, (u_int16_t
) attr
->extra
->aggregator_as
);
2328 stream_put_ipv4 (s
, attr
->extra
->aggregator_addr
.s_addr
);
2331 /* Community attribute. */
2332 if (CHECK_FLAG (peer
->af_flags
[afi
][safi
], PEER_FLAG_SEND_COMMUNITY
)
2333 && (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES
)))
2335 if (attr
->community
->size
* 4 > 255)
2337 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_EXTLEN
);
2338 stream_putc (s
, BGP_ATTR_COMMUNITIES
);
2339 stream_putw (s
, attr
->community
->size
* 4);
2343 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2344 stream_putc (s
, BGP_ATTR_COMMUNITIES
);
2345 stream_putc (s
, attr
->community
->size
* 4);
2347 stream_put (s
, attr
->community
->val
, attr
->community
->size
* 4);
2350 /* Route Reflector. */
2351 if (peer
->sort
== BGP_PEER_IBGP
2353 && from
->sort
== BGP_PEER_IBGP
)
2355 /* Originator ID. */
2356 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
);
2357 stream_putc (s
, BGP_ATTR_ORIGINATOR_ID
);
2360 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID
))
2361 stream_put_in_addr (s
, &attr
->extra
->originator_id
);
2363 stream_put_in_addr (s
, &from
->remote_id
);
2366 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
);
2367 stream_putc (s
, BGP_ATTR_CLUSTER_LIST
);
2369 if (attr
->extra
&& attr
->extra
->cluster
)
2371 stream_putc (s
, attr
->extra
->cluster
->length
+ 4);
2372 /* If this peer configuration's parent BGP has cluster_id. */
2373 if (bgp
->config
& BGP_CONFIG_CLUSTER_ID
)
2374 stream_put_in_addr (s
, &bgp
->cluster_id
);
2376 stream_put_in_addr (s
, &bgp
->router_id
);
2377 stream_put (s
, attr
->extra
->cluster
->list
,
2378 attr
->extra
->cluster
->length
);
2383 /* If this peer configuration's parent BGP has cluster_id. */
2384 if (bgp
->config
& BGP_CONFIG_CLUSTER_ID
)
2385 stream_put_in_addr (s
, &bgp
->cluster_id
);
2387 stream_put_in_addr (s
, &bgp
->router_id
);
2391 /* Extended Communities attribute. */
2392 if (CHECK_FLAG (peer
->af_flags
[afi
][safi
], PEER_FLAG_SEND_EXT_COMMUNITY
)
2393 && (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES
)))
2395 struct attr_extra
*attre
= attr
->extra
;
2399 if (peer
->sort
== BGP_PEER_IBGP
2400 || peer
->sort
== BGP_PEER_CONFED
)
2402 if (attre
->ecommunity
->size
* 8 > 255)
2404 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_EXTLEN
);
2405 stream_putc (s
, BGP_ATTR_EXT_COMMUNITIES
);
2406 stream_putw (s
, attre
->ecommunity
->size
* 8);
2410 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2411 stream_putc (s
, BGP_ATTR_EXT_COMMUNITIES
);
2412 stream_putc (s
, attre
->ecommunity
->size
* 8);
2414 stream_put (s
, attre
->ecommunity
->val
, attre
->ecommunity
->size
* 8);
2420 int ecom_tr_size
= 0;
2423 for (i
= 0; i
< attre
->ecommunity
->size
; i
++)
2425 pnt
= attre
->ecommunity
->val
+ (i
* 8);
2428 if (CHECK_FLAG (tbit
, ECOMMUNITY_FLAG_NON_TRANSITIVE
))
2436 if (ecom_tr_size
* 8 > 255)
2438 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_EXTLEN
);
2439 stream_putc (s
, BGP_ATTR_EXT_COMMUNITIES
);
2440 stream_putw (s
, ecom_tr_size
* 8);
2444 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2445 stream_putc (s
, BGP_ATTR_EXT_COMMUNITIES
);
2446 stream_putc (s
, ecom_tr_size
* 8);
2449 for (i
= 0; i
< attre
->ecommunity
->size
; i
++)
2451 pnt
= attre
->ecommunity
->val
+ (i
* 8);
2454 if (CHECK_FLAG (tbit
, ECOMMUNITY_FLAG_NON_TRANSITIVE
))
2457 stream_put (s
, pnt
, 8);
2463 if ( send_as4_path
)
2465 /* If the peer is NOT As4 capable, AND */
2466 /* there are ASnums > 65535 in path THEN
2467 * give out AS4_PATH */
2469 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2471 * Hm, I wonder... confederation things *should* only be at
2472 * the beginning of an aspath, right? Then we should use
2473 * aspath_delete_confed_seq for this, because it is already
2475 * Folks, talk to me: what is reasonable here!?
2477 aspath
= aspath_delete_confed_seq (aspath
);
2479 stream_putc (s
, BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_EXTLEN
);
2480 stream_putc (s
, BGP_ATTR_AS4_PATH
);
2481 aspath_sizep
= stream_get_endp (s
);
2483 stream_putw_at (s
, aspath_sizep
, aspath_put (s
, aspath
, 1));
2486 if (aspath
!= attr
->aspath
)
2487 aspath_free (aspath
);
2489 if ( send_as4_aggregator
)
2491 assert (attr
->extra
);
2493 /* send AS4_AGGREGATOR, at this place */
2494 /* this section of code moved here in order to ensure the correct
2495 * *ascending* order of attributes
2497 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2498 stream_putc (s
, BGP_ATTR_AS4_AGGREGATOR
);
2500 stream_putl (s
, attr
->extra
->aggregator_as
);
2501 stream_put_ipv4 (s
, attr
->extra
->aggregator_addr
.s_addr
);
2504 /* Unknown transit attribute. */
2505 if (attr
->extra
&& attr
->extra
->transit
)
2506 stream_put (s
, attr
->extra
->transit
->val
, attr
->extra
->transit
->length
);
2508 /* Return total size of attribute. */
2509 return stream_get_endp (s
) - cp
;
2513 bgp_packet_mpunreach_start (struct stream
*s
, afi_t afi
, safi_t safi
)
2515 unsigned long attrlen_pnt
;
2517 /* Set extended bit always to encode the attribute length as 2 bytes */
2518 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_EXTLEN
);
2519 stream_putc (s
, BGP_ATTR_MP_UNREACH_NLRI
);
2521 attrlen_pnt
= stream_get_endp (s
);
2522 stream_putw (s
, 0); /* Length of this attribute. */
2524 stream_putw (s
, afi
);
2525 safi
= (safi
== SAFI_MPLS_VPN
) ? SAFI_MPLS_LABELED_VPN
: safi
;
2526 stream_putc (s
, safi
);
2531 bgp_packet_mpunreach_prefix (struct stream
*s
, struct prefix
*p
,
2532 afi_t afi
, safi_t safi
, struct prefix_rd
*prd
,
2535 if (safi
== SAFI_MPLS_VPN
)
2537 stream_putc (s
, p
->prefixlen
+ 88);
2538 stream_put (s
, tag
, 3);
2539 stream_put (s
, prd
->val
, 8);
2540 stream_put (s
, &p
->u
.prefix
, PSIZE (p
->prefixlen
));
2543 stream_put_prefix (s
, p
);
2547 bgp_packet_mpunreach_end (struct stream
*s
, size_t attrlen_pnt
)
2551 /* Set MP attribute length. Don't count the (2) bytes used to encode
2553 size
= stream_get_endp (s
) - attrlen_pnt
- 2;
2554 stream_putw_at (s
, attrlen_pnt
, size
);
2557 /* Initialization of attribute. */
2559 bgp_attr_init (void)
2570 bgp_attr_finish (void)
2574 community_finish ();
2575 ecommunity_finish ();
2580 /* Make attribute packet. */
2582 bgp_dump_routes_attr (struct stream
*s
, struct attr
*attr
,
2583 struct prefix
*prefix
)
2588 struct aspath
*aspath
;
2590 /* Remember current pointer. */
2591 cp
= stream_get_endp (s
);
2593 /* Place holder of length. */
2596 /* Origin attribute. */
2597 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2598 stream_putc (s
, BGP_ATTR_ORIGIN
);
2600 stream_putc (s
, attr
->origin
);
2602 aspath
= attr
->aspath
;
2604 stream_putc (s
, BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_EXTLEN
);
2605 stream_putc (s
, BGP_ATTR_AS_PATH
);
2606 aspath_lenp
= stream_get_endp (s
);
2609 stream_putw_at (s
, aspath_lenp
, aspath_put (s
, aspath
, 1));
2611 /* Nexthop attribute. */
2612 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2615 && prefix
->family
!= AF_INET6
2616 #endif /* HAVE_IPV6 */
2619 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2620 stream_putc (s
, BGP_ATTR_NEXT_HOP
);
2622 stream_put_ipv4 (s
, attr
->nexthop
.s_addr
);
2625 /* MED attribute. */
2626 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC
))
2628 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
);
2629 stream_putc (s
, BGP_ATTR_MULTI_EXIT_DISC
);
2631 stream_putl (s
, attr
->med
);
2634 /* Local preference. */
2635 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF
))
2637 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2638 stream_putc (s
, BGP_ATTR_LOCAL_PREF
);
2640 stream_putl (s
, attr
->local_pref
);
2643 /* Atomic aggregate. */
2644 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE
))
2646 stream_putc (s
, BGP_ATTR_FLAG_TRANS
);
2647 stream_putc (s
, BGP_ATTR_ATOMIC_AGGREGATE
);
2652 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR
))
2654 assert (attr
->extra
);
2655 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2656 stream_putc (s
, BGP_ATTR_AGGREGATOR
);
2658 stream_putl (s
, attr
->extra
->aggregator_as
);
2659 stream_put_ipv4 (s
, attr
->extra
->aggregator_addr
.s_addr
);
2662 /* Community attribute. */
2663 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES
))
2665 if (attr
->community
->size
* 4 > 255)
2667 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
|BGP_ATTR_FLAG_EXTLEN
);
2668 stream_putc (s
, BGP_ATTR_COMMUNITIES
);
2669 stream_putw (s
, attr
->community
->size
* 4);
2673 stream_putc (s
, BGP_ATTR_FLAG_OPTIONAL
|BGP_ATTR_FLAG_TRANS
);
2674 stream_putc (s
, BGP_ATTR_COMMUNITIES
);
2675 stream_putc (s
, attr
->community
->size
* 4);
2677 stream_put (s
, attr
->community
->val
, attr
->community
->size
* 4);
2681 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
2682 if (prefix
!= NULL
&& prefix
->family
== AF_INET6
&& attr
->extra
&&
2683 (attr
->extra
->mp_nexthop_len
== 16 || attr
->extra
->mp_nexthop_len
== 32) )
2686 struct attr_extra
*attre
= attr
->extra
;
2688 stream_putc(s
, BGP_ATTR_FLAG_OPTIONAL
);
2689 stream_putc(s
, BGP_ATTR_MP_REACH_NLRI
);
2690 sizep
= stream_get_endp (s
);
2693 stream_putc (s
, 0); /* Marker: Attribute length. */
2694 stream_putw(s
, AFI_IP6
); /* AFI */
2695 stream_putc(s
, SAFI_UNICAST
); /* SAFI */
2698 stream_putc(s
, attre
->mp_nexthop_len
);
2699 stream_put(s
, &attre
->mp_nexthop_global
, 16);
2700 if (attre
->mp_nexthop_len
== 32)
2701 stream_put(s
, &attre
->mp_nexthop_local
, 16);
2707 stream_put_prefix(s
, prefix
);
2709 /* Set MP attribute length. */
2710 stream_putc_at (s
, sizep
, (stream_get_endp (s
) - sizep
) - 1);
2712 #endif /* HAVE_IPV6 */
2714 /* Return total size of attribute. */
2715 len
= stream_get_endp (s
) - cp
- 2;
2716 stream_putw_at (s
, cp
, len
);