version 1.1.1.1, 2012/02/21 17:26:12
|
version 1.1.1.4, 2016/11/02 10:09:10
|
Line 29 Software Foundation, Inc., 59 Temple Place - Suite 330
|
Line 29 Software Foundation, Inc., 59 Temple Place - Suite 330
|
#include "log.h" |
#include "log.h" |
#include "hash.h" |
#include "hash.h" |
#include "jhash.h" |
#include "jhash.h" |
|
#include "filter.h" |
|
|
#include "bgpd/bgpd.h" |
#include "bgpd/bgpd.h" |
#include "bgpd/bgp_attr.h" |
#include "bgpd/bgp_attr.h" |
Line 38 Software Foundation, Inc., 59 Temple Place - Suite 330
|
Line 39 Software Foundation, Inc., 59 Temple Place - Suite 330
|
#include "bgpd/bgp_debug.h" |
#include "bgpd/bgp_debug.h" |
#include "bgpd/bgp_packet.h" |
#include "bgpd/bgp_packet.h" |
#include "bgpd/bgp_ecommunity.h" |
#include "bgpd/bgp_ecommunity.h" |
| #include "table.h" |
| #include "bgp_encap_types.h" |
| |
/* Attribute strings for logging. */ |
/* Attribute strings for logging. */ |
static const struct message attr_str [] = |
static const struct message attr_str [] = |
{ |
{ |
Line 51 static const struct message attr_str [] =
|
Line 54 static const struct message attr_str [] =
|
{ BGP_ATTR_AGGREGATOR, "AGGREGATOR" }, |
{ BGP_ATTR_AGGREGATOR, "AGGREGATOR" }, |
{ BGP_ATTR_COMMUNITIES, "COMMUNITY" }, |
{ BGP_ATTR_COMMUNITIES, "COMMUNITY" }, |
{ BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" }, |
{ BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" }, |
{ BGP_ATTR_CLUSTER_LIST, "CLUSTERLIST" }, | { BGP_ATTR_CLUSTER_LIST, "CLUSTER_LIST" }, |
{ BGP_ATTR_DPA, "DPA" }, |
{ BGP_ATTR_DPA, "DPA" }, |
{ BGP_ATTR_ADVERTISER, "ADVERTISER"} , |
{ BGP_ATTR_ADVERTISER, "ADVERTISER"} , |
{ BGP_ATTR_RCID_PATH, "RCID_PATH" }, |
{ BGP_ATTR_RCID_PATH, "RCID_PATH" }, |
Line 61 static const struct message attr_str [] =
|
Line 64 static const struct message attr_str [] =
|
{ BGP_ATTR_AS4_PATH, "AS4_PATH" }, |
{ BGP_ATTR_AS4_PATH, "AS4_PATH" }, |
{ BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" }, |
{ BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" }, |
{ BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" }, |
{ BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" }, |
|
{ BGP_ATTR_ENCAP, "ENCAP" }, |
}; |
}; |
static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]); | static const int attr_str_max = array_size(attr_str); |
| |
| static const struct message attr_flag_str[] = |
| { |
| { BGP_ATTR_FLAG_OPTIONAL, "Optional" }, |
| { BGP_ATTR_FLAG_TRANS, "Transitive" }, |
| { BGP_ATTR_FLAG_PARTIAL, "Partial" }, |
| /* bgp_attr_flags_diagnose() relies on this bit being last in this list */ |
| { BGP_ATTR_FLAG_EXTLEN, "Extended Length" }, |
| }; |
| |
static struct hash *cluster_hash; |
static struct hash *cluster_hash; |
|
|
static void * |
static void * |
Line 175 cluster_intern (struct cluster_list *cluster)
|
Line 188 cluster_intern (struct cluster_list *cluster)
|
void |
void |
cluster_unintern (struct cluster_list *cluster) |
cluster_unintern (struct cluster_list *cluster) |
{ |
{ |
struct cluster_list *ret; |
|
|
|
if (cluster->refcnt) |
if (cluster->refcnt) |
cluster->refcnt--; |
cluster->refcnt--; |
|
|
if (cluster->refcnt == 0) |
if (cluster->refcnt == 0) |
{ |
{ |
ret = hash_release (cluster_hash, cluster); | hash_release (cluster_hash, cluster); |
cluster_free (cluster); |
cluster_free (cluster); |
} |
} |
} |
} |
Line 196 cluster_init (void)
|
Line 207 cluster_init (void)
|
static void |
static void |
cluster_finish (void) |
cluster_finish (void) |
{ |
{ |
|
hash_clean (cluster_hash, (void (*)(void *))cluster_free); |
hash_free (cluster_hash); |
hash_free (cluster_hash); |
cluster_hash = NULL; |
cluster_hash = NULL; |
} |
} |
| |
| struct bgp_attr_encap_subtlv * |
| encap_tlv_dup(struct bgp_attr_encap_subtlv *orig) |
| { |
| struct bgp_attr_encap_subtlv *new; |
| struct bgp_attr_encap_subtlv *tail; |
| struct bgp_attr_encap_subtlv *p; |
| |
| for (p = orig, tail = new = NULL; p; p = p->next) { |
| int size = sizeof(struct bgp_attr_encap_subtlv) - 1 + p->length; |
| if (tail) { |
| tail->next = XCALLOC(MTYPE_ENCAP_TLV, size); |
| tail = tail->next; |
| } else { |
| tail = new = XCALLOC(MTYPE_ENCAP_TLV, size); |
| } |
| assert(tail); |
| memcpy(tail, p, size); |
| tail->next = NULL; |
| } |
| |
| return new; |
| } |
| |
| static void |
| encap_free(struct bgp_attr_encap_subtlv *p) |
| { |
| struct bgp_attr_encap_subtlv *next; |
| while (p) { |
| next = p->next; |
| p->next = NULL; |
| XFREE(MTYPE_ENCAP_TLV, p); |
| p = next; |
| } |
| } |
| |
| void |
| bgp_attr_flush_encap(struct attr *attr) |
| { |
| if (!attr || !attr->extra) |
| return; |
| |
| if (attr->extra->encap_subtlvs) { |
| encap_free(attr->extra->encap_subtlvs); |
| attr->extra->encap_subtlvs = NULL; |
| } |
| } |
| |
| /* |
| * Compare encap sub-tlv chains |
| * |
| * 1 = equivalent |
| * 0 = not equivalent |
| * |
| * This algorithm could be made faster if needed |
| */ |
| static int |
| encap_same(struct bgp_attr_encap_subtlv *h1, struct bgp_attr_encap_subtlv *h2) |
| { |
| struct bgp_attr_encap_subtlv *p; |
| struct bgp_attr_encap_subtlv *q; |
| |
| if (!h1 && !h2) |
| return 1; |
| if (h1 && !h2) |
| return 0; |
| if (!h1 && h2) |
| return 0; |
| if (h1 == h2) |
| return 1; |
| |
| for (p = h1; p; p = p->next) { |
| for (q = h2; q; q = q->next) { |
| if ((p->type == q->type) && |
| (p->length == q->length) && |
| !memcmp(p->value, q->value, p->length)) { |
| |
| break; |
| } |
| } |
| if (!q) |
| return 0; |
| } |
| |
| for (p = h2; p; p = p->next) { |
| for (q = h1; q; q = q->next) { |
| if ((p->type == q->type) && |
| (p->length == q->length) && |
| !memcmp(p->value, q->value, p->length)) { |
| |
| break; |
| } |
| } |
| if (!q) |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
/* Unknown transit attribute. */ |
/* Unknown transit attribute. */ |
static struct hash *transit_hash; |
static struct hash *transit_hash; |
|
|
Line 235 transit_intern (struct transit *transit)
|
Line 346 transit_intern (struct transit *transit)
|
void |
void |
transit_unintern (struct transit *transit) |
transit_unintern (struct transit *transit) |
{ |
{ |
struct transit *ret; |
|
|
|
if (transit->refcnt) |
if (transit->refcnt) |
transit->refcnt--; |
transit->refcnt--; |
|
|
if (transit->refcnt == 0) |
if (transit->refcnt == 0) |
{ |
{ |
ret = hash_release (transit_hash, transit); | hash_release (transit_hash, transit); |
transit_free (transit); |
transit_free (transit); |
} |
} |
} |
} |
Line 274 transit_init (void)
|
Line 383 transit_init (void)
|
static void |
static void |
transit_finish (void) |
transit_finish (void) |
{ |
{ |
|
hash_clean (transit_hash, (void (*)(void *))transit_free); |
hash_free (transit_hash); |
hash_free (transit_hash); |
transit_hash = NULL; |
transit_hash = NULL; |
} |
} |
| |
/* Attribute hash routines. */ |
/* Attribute hash routines. */ |
static struct hash *attrhash; |
static struct hash *attrhash; |
|
|
Line 292 bgp_attr_extra_free (struct attr *attr)
|
Line 402 bgp_attr_extra_free (struct attr *attr)
|
{ |
{ |
if (attr->extra) |
if (attr->extra) |
{ |
{ |
|
if (attr->extra->encap_subtlvs) { |
|
encap_free(attr->extra->encap_subtlvs); |
|
attr->extra->encap_subtlvs = NULL; |
|
} |
XFREE (MTYPE_ATTR_EXTRA, attr->extra); |
XFREE (MTYPE_ATTR_EXTRA, attr->extra); |
attr->extra = NULL; |
attr->extra = NULL; |
} |
} |
Line 312 bgp_attr_extra_get (struct attr *attr)
|
Line 426 bgp_attr_extra_get (struct attr *attr)
|
void |
void |
bgp_attr_dup (struct attr *new, struct attr *orig) |
bgp_attr_dup (struct attr *new, struct attr *orig) |
{ |
{ |
|
struct attr_extra *extra = new->extra; |
|
|
*new = *orig; |
*new = *orig; |
if (orig->extra) | /* if caller provided attr_extra space, use it in any case. |
| * |
| * This is neccesary even if orig->extra equals NULL, because otherwise |
| * memory may be later allocated on the heap by bgp_attr_extra_get. |
| * |
| * That memory would eventually be leaked, because the caller must not |
| * call bgp_attr_extra_free if he provided attr_extra on the stack. |
| */ |
| if (extra) |
{ |
{ |
|
new->extra = extra; |
|
memset(new->extra, 0, sizeof(struct attr_extra)); |
|
if (orig->extra) { |
|
*new->extra = *orig->extra; |
|
if (orig->extra->encap_subtlvs) { |
|
new->extra->encap_subtlvs = encap_tlv_dup(orig->extra->encap_subtlvs); |
|
} |
|
} |
|
} |
|
else if (orig->extra) |
|
{ |
new->extra = bgp_attr_extra_new(); |
new->extra = bgp_attr_extra_new(); |
*new->extra = *orig->extra; |
*new->extra = *orig->extra; |
|
if (orig->extra->encap_subtlvs) { |
|
new->extra->encap_subtlvs = encap_tlv_dup(orig->extra->encap_subtlvs); |
|
} |
} |
} |
} |
} |
|
|
Line 335 attr_unknown_count (void)
|
Line 473 attr_unknown_count (void)
|
unsigned int |
unsigned int |
attrhash_key_make (void *p) |
attrhash_key_make (void *p) |
{ |
{ |
const struct attr * attr = (struct attr *) p; | const struct attr *attr = (struct attr *) p; |
| const struct attr_extra *extra = attr->extra; |
uint32_t key = 0; |
uint32_t key = 0; |
#define MIX(val) key = jhash_1word(val, key) |
#define MIX(val) key = jhash_1word(val, key) |
|
|
Line 349 attrhash_key_make (void *p)
|
Line 488 attrhash_key_make (void *p)
|
key += attr->med; |
key += attr->med; |
key += attr->local_pref; |
key += attr->local_pref; |
|
|
if (attr->extra) | if (extra) |
{ |
{ |
MIX(attr->extra->aggregator_as); | MIX(extra->aggregator_as); |
MIX(attr->extra->aggregator_addr.s_addr); | MIX(extra->aggregator_addr.s_addr); |
MIX(attr->extra->weight); | MIX(extra->weight); |
MIX(attr->extra->mp_nexthop_global_in.s_addr); | MIX(extra->mp_nexthop_global_in.s_addr); |
| MIX(extra->originator_id.s_addr); |
} |
} |
|
|
if (attr->aspath) |
if (attr->aspath) |
Line 362 attrhash_key_make (void *p)
|
Line 502 attrhash_key_make (void *p)
|
if (attr->community) |
if (attr->community) |
MIX(community_hash_make (attr->community)); |
MIX(community_hash_make (attr->community)); |
|
|
if (attr->extra) | if (extra) |
{ |
{ |
if (attr->extra->ecommunity) | if (extra->ecommunity) |
MIX(ecommunity_hash_make (attr->extra->ecommunity)); | MIX(ecommunity_hash_make (extra->ecommunity)); |
if (attr->extra->cluster) | if (extra->cluster) |
MIX(cluster_hash_key_make (attr->extra->cluster)); | MIX(cluster_hash_key_make (extra->cluster)); |
if (attr->extra->transit) | if (extra->transit) |
MIX(transit_hash_key_make (attr->extra->transit)); | MIX(transit_hash_key_make (extra->transit)); |
|
|
#ifdef HAVE_IPV6 | MIX(extra->mp_nexthop_len); |
MIX(attr->extra->mp_nexthop_len); | key = jhash(extra->mp_nexthop_global.s6_addr, 16, key); |
key = jhash(attr->extra->mp_nexthop_global.s6_addr, 16, key); | key = jhash(extra->mp_nexthop_local.s6_addr, 16, key); |
key = jhash(attr->extra->mp_nexthop_local.s6_addr, 16, key); | |
#endif /* HAVE_IPV6 */ | |
} |
} |
|
|
return key; |
return key; |
Line 402 attrhash_cmp (const void *p1, const void *p2)
|
Line 540 attrhash_cmp (const void *p1, const void *p2)
|
&& ae1->aggregator_as == ae2->aggregator_as |
&& ae1->aggregator_as == ae2->aggregator_as |
&& ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr |
&& ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr |
&& ae1->weight == ae2->weight |
&& ae1->weight == ae2->weight |
#ifdef HAVE_IPV6 |
|
&& ae1->mp_nexthop_len == ae2->mp_nexthop_len |
&& ae1->mp_nexthop_len == ae2->mp_nexthop_len |
&& IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global) |
&& IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global) |
&& IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local) |
&& IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local) |
#endif /* HAVE_IPV6 */ |
|
&& IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in) |
&& IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in) |
&& ae1->ecommunity == ae2->ecommunity |
&& ae1->ecommunity == ae2->ecommunity |
&& ae1->cluster == ae2->cluster |
&& ae1->cluster == ae2->cluster |
&& ae1->transit == ae2->transit) | && ae1->transit == ae2->transit |
| && (ae1->encap_tunneltype == ae2->encap_tunneltype) |
| && encap_same(ae1->encap_subtlvs, ae2->encap_subtlvs) |
| && IPV4_ADDR_SAME (&ae1->originator_id, &ae2->originator_id)) |
return 1; |
return 1; |
else if (ae1 || ae2) |
else if (ae1 || ae2) |
return 0; |
return 0; |
Line 427 attrhash_init (void)
|
Line 566 attrhash_init (void)
|
attrhash = hash_create (attrhash_key_make, attrhash_cmp); |
attrhash = hash_create (attrhash_key_make, attrhash_cmp); |
} |
} |
|
|
|
/* |
|
* special for hash_clean below |
|
*/ |
static void |
static void |
|
attr_vfree (void *attr) |
|
{ |
|
bgp_attr_extra_free ((struct attr *)attr); |
|
XFREE (MTYPE_ATTR, attr); |
|
} |
|
|
|
static void |
attrhash_finish (void) |
attrhash_finish (void) |
{ |
{ |
|
hash_clean(attrhash, attr_vfree); |
hash_free (attrhash); |
hash_free (attrhash); |
attrhash = NULL; |
attrhash = NULL; |
} |
} |
Line 464 bgp_attr_hash_alloc (void *p)
|
Line 614 bgp_attr_hash_alloc (void *p)
|
{ |
{ |
attr->extra = bgp_attr_extra_new (); |
attr->extra = bgp_attr_extra_new (); |
*attr->extra = *val->extra; |
*attr->extra = *val->extra; |
|
|
|
if (attr->extra->encap_subtlvs) { |
|
attr->extra->encap_subtlvs = encap_tlv_dup(attr->extra->encap_subtlvs); |
|
} |
} |
} |
attr->refcnt = 0; |
attr->refcnt = 0; |
return attr; |
return attr; |
Line 538 bgp_attr_default_set (struct attr *attr, u_char origin
|
Line 692 bgp_attr_default_set (struct attr *attr, u_char origin
|
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); |
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); |
attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT; |
attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT; |
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); |
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); |
#ifdef HAVE_IPV6 |
|
attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN; |
attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN; |
#endif |
|
|
|
return attr; |
return attr; |
} |
} |
Line 552 bgp_attr_default_intern (u_char origin)
|
Line 704 bgp_attr_default_intern (u_char origin)
|
{ |
{ |
struct attr attr; |
struct attr attr; |
struct attr *new; |
struct attr *new; |
struct attr_extra *attre; | |
| |
memset (&attr, 0, sizeof (struct attr)); |
memset (&attr, 0, sizeof (struct attr)); |
attre = bgp_attr_extra_get (&attr); | bgp_attr_extra_get (&attr); |
| |
bgp_attr_default_set(&attr, origin); |
bgp_attr_default_set(&attr, origin); |
|
|
new = bgp_attr_intern (&attr); |
new = bgp_attr_intern (&attr); |
Line 573 bgp_attr_aggregate_intern (struct bgp *bgp, u_char ori
|
Line 724 bgp_attr_aggregate_intern (struct bgp *bgp, u_char ori
|
{ |
{ |
struct attr attr; |
struct attr attr; |
struct attr *new; |
struct attr *new; |
struct attr_extra *attre; | struct attr_extra attre; |
|
|
memset (&attr, 0, sizeof (struct attr)); |
memset (&attr, 0, sizeof (struct attr)); |
attre = bgp_attr_extra_get (&attr); | memset (&attre, 0, sizeof (struct attr_extra)); |
| attr.extra = &attre; |
| |
/* Origin attribute. */ |
/* Origin attribute. */ |
attr.origin = origin; |
attr.origin = origin; |
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN); |
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN); |
Line 598 bgp_attr_aggregate_intern (struct bgp *bgp, u_char ori
|
Line 750 bgp_attr_aggregate_intern (struct bgp *bgp, u_char ori
|
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); |
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); |
} |
} |
|
|
attre->weight = BGP_ATTR_DEFAULT_WEIGHT; | attre.weight = BGP_ATTR_DEFAULT_WEIGHT; |
#ifdef HAVE_IPV6 | attre.mp_nexthop_len = IPV6_MAX_BYTELEN; |
attre->mp_nexthop_len = IPV6_MAX_BYTELEN; | |
#endif | |
if (! as_set) |
if (! as_set) |
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); |
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); |
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); |
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); |
if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION)) |
if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION)) |
attre->aggregator_as = bgp->confed_id; | attre.aggregator_as = bgp->confed_id; |
else |
else |
attre->aggregator_as = bgp->as; | attre.aggregator_as = bgp->as; |
attre->aggregator_addr = bgp->router_id; | attre.aggregator_addr = bgp->router_id; |
|
|
new = bgp_attr_intern (&attr); |
new = bgp_attr_intern (&attr); |
bgp_attr_extra_free (&attr); | |
| |
aspath_unintern (&new->aspath); |
aspath_unintern (&new->aspath); |
return new; |
return new; |
} |
} |
Line 625 bgp_attr_unintern_sub (struct attr *attr)
|
Line 775 bgp_attr_unintern_sub (struct attr *attr)
|
/* aspath refcount shoud be decrement. */ |
/* aspath refcount shoud be decrement. */ |
if (attr->aspath) |
if (attr->aspath) |
aspath_unintern (&attr->aspath); |
aspath_unintern (&attr->aspath); |
UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH); | UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)); |
|
|
if (attr->community) |
if (attr->community) |
community_unintern (&attr->community); |
community_unintern (&attr->community); |
UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES); | UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)); |
|
|
if (attr->extra) |
if (attr->extra) |
{ |
{ |
if (attr->extra->ecommunity) |
if (attr->extra->ecommunity) |
ecommunity_unintern (&attr->extra->ecommunity); |
ecommunity_unintern (&attr->extra->ecommunity); |
UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES); | UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)); |
|
|
if (attr->extra->cluster) |
if (attr->extra->cluster) |
cluster_unintern (attr->extra->cluster); |
cluster_unintern (attr->extra->cluster); |
UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST); | UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST)); |
|
|
if (attr->extra->transit) |
if (attr->extra->transit) |
transit_unintern (attr->extra->transit); |
transit_unintern (attr->extra->transit); |
Line 648 bgp_attr_unintern_sub (struct attr *attr)
|
Line 798 bgp_attr_unintern_sub (struct attr *attr)
|
|
|
/* Free bgp attribute and aspath. */ |
/* Free bgp attribute and aspath. */ |
void |
void |
bgp_attr_unintern (struct attr **attr) | bgp_attr_unintern (struct attr **pattr) |
{ |
{ |
|
struct attr *attr = *pattr; |
struct attr *ret; |
struct attr *ret; |
struct attr tmp; |
struct attr tmp; |
|
struct attr_extra tmp_extra; |
|
|
/* Decrement attribute reference. */ |
/* Decrement attribute reference. */ |
(*attr)->refcnt--; | attr->refcnt--; |
|
|
tmp = *(*attr); | tmp = *attr; |
|
|
if ((*attr)->extra) | if (attr->extra) |
{ |
{ |
tmp.extra = bgp_attr_extra_new (); | tmp.extra = &tmp_extra; |
memcpy (tmp.extra, (*attr)->extra, sizeof (struct attr_extra)); | memcpy (tmp.extra, attr->extra, sizeof (struct attr_extra)); |
} |
} |
|
|
/* If reference becomes zero then free attribute object. */ |
/* If reference becomes zero then free attribute object. */ |
if ((*attr)->refcnt == 0) | if (attr->refcnt == 0) |
{ | { |
ret = hash_release (attrhash, *attr); | ret = hash_release (attrhash, attr); |
assert (ret != NULL); |
assert (ret != NULL); |
bgp_attr_extra_free (*attr); | bgp_attr_extra_free (attr); |
XFREE (MTYPE_ATTR, *attr); | XFREE (MTYPE_ATTR, attr); |
*attr = NULL; | *pattr = NULL; |
} |
} |
|
|
bgp_attr_unintern_sub (&tmp); |
bgp_attr_unintern_sub (&tmp); |
Line 681 void
|
Line 833 void
|
bgp_attr_flush (struct attr *attr) |
bgp_attr_flush (struct attr *attr) |
{ |
{ |
if (attr->aspath && ! attr->aspath->refcnt) |
if (attr->aspath && ! attr->aspath->refcnt) |
aspath_free (attr->aspath); | { |
| aspath_free (attr->aspath); |
| attr->aspath = NULL; |
| } |
if (attr->community && ! attr->community->refcnt) |
if (attr->community && ! attr->community->refcnt) |
community_free (attr->community); | { |
| community_free (attr->community); |
| attr->community = NULL; |
| } |
if (attr->extra) |
if (attr->extra) |
{ |
{ |
struct attr_extra *attre = attr->extra; |
struct attr_extra *attre = attr->extra; |
Line 691 bgp_attr_flush (struct attr *attr)
|
Line 849 bgp_attr_flush (struct attr *attr)
|
if (attre->ecommunity && ! attre->ecommunity->refcnt) |
if (attre->ecommunity && ! attre->ecommunity->refcnt) |
ecommunity_free (&attre->ecommunity); |
ecommunity_free (&attre->ecommunity); |
if (attre->cluster && ! attre->cluster->refcnt) |
if (attre->cluster && ! attre->cluster->refcnt) |
cluster_free (attre->cluster); | { |
| cluster_free (attre->cluster); |
| attre->cluster = NULL; |
| } |
if (attre->transit && ! attre->transit->refcnt) |
if (attre->transit && ! attre->transit->refcnt) |
transit_free (attre->transit); | { |
| transit_free (attre->transit); |
| attre->transit = NULL; |
| } |
| encap_free(attre->encap_subtlvs); |
| attre->encap_subtlvs = NULL; |
} |
} |
} |
} |
|
|
Line 703 bgp_attr_flush (struct attr *attr)
|
Line 869 bgp_attr_flush (struct attr *attr)
|
* introduced by the sending neighbour. |
* introduced by the sending neighbour. |
*/ |
*/ |
static bgp_attr_parse_ret_t |
static bgp_attr_parse_ret_t |
bgp_attr_malformed (struct peer *peer, u_char type, u_char flag, | bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode, |
u_char subcode, u_char *startp, bgp_size_t length) | bgp_size_t length) |
{ |
{ |
|
struct peer *const peer = args->peer; |
|
const u_int8_t flags = args->flags; |
|
/* startp and length must be special-cased, as whether or not to |
|
* send the attribute data with the NOTIFY depends on the error, |
|
* the caller therefore signals this with the seperate length argument |
|
*/ |
|
u_char *notify_datap = (length > 0 ? args->startp : NULL); |
|
|
/* Only relax error handling for eBGP peers */ |
/* Only relax error handling for eBGP peers */ |
if (peer_sort (peer) != BGP_PEER_EBGP) | if (peer->sort != BGP_PEER_EBGP) |
{ |
{ |
bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode, |
bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode, |
startp, length); | notify_datap, length); |
return BGP_ATTR_PARSE_ERROR; |
return BGP_ATTR_PARSE_ERROR; |
|
|
} |
} |
|
|
switch (type) { | /* Adjust the stream getp to the end of the attribute, in case we can |
/* where an optional attribute is inconsequential, e.g. it does not affect | * still proceed but the caller hasn't read all the attribute. |
* route selection, and can be safely ignored then any such attributes | */ |
* which are malformed should just be ignored and the route processed as | stream_set_getp (BGP_INPUT (peer), |
* normal. | (args->startp - STREAM_DATA (BGP_INPUT (peer))) |
| + args->total); |
| |
| switch (args->type) { |
| /* where an attribute is relatively inconsequential, e.g. it does not |
| * affect route selection, and can be safely ignored, then any such |
| * attributes which are malformed should just be ignored and the route |
| * processed as normal. |
*/ |
*/ |
case BGP_ATTR_AS4_AGGREGATOR: |
case BGP_ATTR_AS4_AGGREGATOR: |
case BGP_ATTR_AGGREGATOR: |
case BGP_ATTR_AGGREGATOR: |
Line 727 bgp_attr_malformed (struct peer *peer, u_char type, u_
|
Line 908 bgp_attr_malformed (struct peer *peer, u_char type, u_
|
return BGP_ATTR_PARSE_PROCEED; |
return BGP_ATTR_PARSE_PROCEED; |
|
|
/* Core attributes, particularly ones which may influence route |
/* Core attributes, particularly ones which may influence route |
* selection should always cause session resets | * selection, should always cause session resets |
*/ |
*/ |
case BGP_ATTR_ORIGIN: |
case BGP_ATTR_ORIGIN: |
case BGP_ATTR_AS_PATH: |
case BGP_ATTR_AS_PATH: |
Line 741 bgp_attr_malformed (struct peer *peer, u_char type, u_
|
Line 922 bgp_attr_malformed (struct peer *peer, u_char type, u_
|
case BGP_ATTR_MP_UNREACH_NLRI: |
case BGP_ATTR_MP_UNREACH_NLRI: |
case BGP_ATTR_EXT_COMMUNITIES: |
case BGP_ATTR_EXT_COMMUNITIES: |
bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode, |
bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode, |
startp, length); | notify_datap, length); |
return BGP_ATTR_PARSE_ERROR; |
return BGP_ATTR_PARSE_ERROR; |
} |
} |
|
|
Line 749 bgp_attr_malformed (struct peer *peer, u_char type, u_
|
Line 930 bgp_attr_malformed (struct peer *peer, u_char type, u_
|
* the whole session to be reset. Instead treat it as a withdrawal |
* the whole session to be reset. Instead treat it as a withdrawal |
* of the routes, if possible. |
* of the routes, if possible. |
*/ |
*/ |
if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS) | if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS) |
&& CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) | && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL) |
&& CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) | && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL)) |
return BGP_ATTR_PARSE_WITHDRAW; |
return BGP_ATTR_PARSE_WITHDRAW; |
|
|
/* default to reset */ |
/* default to reset */ |
return BGP_ATTR_PARSE_ERROR; | return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; |
} |
} |
|
|
/* Get origin attribute of the update message. */ | /* Find out what is wrong with the path attribute flag bits and log the error. |
static bgp_attr_parse_ret_t | "Flag bits" here stand for Optional, Transitive and Partial, but not for |
bgp_attr_origin (struct peer *peer, bgp_size_t length, | Extended Length. Checking O/T/P bits at once implies, that the attribute |
struct attr *attr, u_char flag, u_char *startp) | being diagnosed is defined by RFC as either a "well-known" or an "optional, |
| non-transitive" attribute. */ |
| static void |
| bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args, |
| u_int8_t desired_flags /* how RFC says it must be */ |
| ) |
{ |
{ |
bgp_size_t total; | u_char seen = 0, i; |
| u_char real_flags = args->flags; |
| const u_int8_t attr_code = args->type; |
| |
| desired_flags &= ~BGP_ATTR_FLAG_EXTLEN; |
| real_flags &= ~BGP_ATTR_FLAG_EXTLEN; |
| for (i = 0; i <= 2; i++) /* O,T,P, but not E */ |
| if |
| ( |
| CHECK_FLAG (desired_flags, attr_flag_str[i].key) != |
| CHECK_FLAG (real_flags, attr_flag_str[i].key) |
| ) |
| { |
| zlog (args->peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"", |
| LOOKUP (attr_str, attr_code), |
| CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not", |
| attr_flag_str[i].str); |
| seen = 1; |
| } |
| if (!seen) |
| { |
| zlog (args->peer->log, LOG_DEBUG, |
| "Strange, %s called for attr %s, but no problem found with flags" |
| " (real flags 0x%x, desired 0x%x)", |
| __func__, LOOKUP (attr_str, attr_code), |
| real_flags, desired_flags); |
| } |
| } |
|
|
/* total is entire attribute length include Attribute Flags (1), | /* Required flags for attributes. EXTLEN will be masked off when testing, |
Attribute Type code (1) and Attribute length (1 or 2). */ | * as will PARTIAL for optional+transitive attributes. |
total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); | */ |
| const u_int8_t attr_flags_values [] = { |
| [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS, |
| [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS, |
| [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS, |
| [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL, |
| [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS, |
| [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS, |
| [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL, |
| [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL, |
| [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL, |
| [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL, |
| [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL, |
| [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL, |
| [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, |
| [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, |
| [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, |
| }; |
| static const size_t attr_flags_values_max = |
| sizeof (attr_flags_values) / sizeof (attr_flags_values[0]); |
|
|
/* If any recognized attribute has Attribute Flags that conflict | static int |
with the Attribute Type Code, then the Error Subcode is set to | bgp_attr_flag_invalid (struct bgp_attr_parser_args *args) |
Attribute Flags Error. The Data field contains the erroneous | { |
attribute (type, length and value). */ | u_int8_t mask = BGP_ATTR_FLAG_EXTLEN; |
if (flag != BGP_ATTR_FLAG_TRANS) | const u_int8_t flags = args->flags; |
| const u_int8_t attr_code = args->type; |
| struct peer *const peer = args->peer; |
| |
| /* there may be attributes we don't know about */ |
| if (attr_code > attr_flags_values_max) |
| return 0; |
| if (attr_flags_values[attr_code] == 0) |
| return 0; |
| |
| /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to |
| * 1." |
| */ |
| if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags) |
| && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags)) |
{ |
{ |
zlog (peer->log, LOG_ERR, | zlog (peer->log, LOG_ERR, |
"Origin attribute flag isn't transitive %d", flag); | "%s well-known attributes must have transitive flag set (%x)", |
return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, | LOOKUP (attr_str, attr_code), flags); |
BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, | return 1; |
startp, total); | |
} |
} |
|
|
|
/* "For well-known attributes and for optional non-transitive attributes, |
|
* the Partial bit MUST be set to 0." |
|
*/ |
|
if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL)) |
|
{ |
|
if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)) |
|
{ |
|
zlog (peer->log, LOG_ERR, |
|
"%s well-known attribute " |
|
"must NOT have the partial flag set (%x)", |
|
LOOKUP (attr_str, attr_code), flags); |
|
return 1; |
|
} |
|
if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL) |
|
&& !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)) |
|
{ |
|
zlog (peer->log, LOG_ERR, |
|
"%s optional + transitive attribute " |
|
"must NOT have the partial flag set (%x)", |
|
LOOKUP (attr_str, attr_code), flags); |
|
return 1; |
|
} |
|
} |
|
|
|
/* Optional transitive attributes may go through speakers that don't |
|
* reocgnise them and set the Partial bit. |
|
*/ |
|
if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL) |
|
&& CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)) |
|
SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL); |
|
|
|
if ((flags & ~mask) |
|
== attr_flags_values[attr_code]) |
|
return 0; |
|
|
|
bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]); |
|
return 1; |
|
} |
|
|
|
/* Get origin attribute of the update message. */ |
|
static bgp_attr_parse_ret_t |
|
bgp_attr_origin (struct bgp_attr_parser_args *args) |
|
{ |
|
struct peer *const peer = args->peer; |
|
struct attr *const attr = args->attr; |
|
const bgp_size_t length = args->length; |
|
|
/* If any recognized attribute has Attribute Length that conflicts |
/* If any recognized attribute has Attribute Length that conflicts |
with the expected length (based on the attribute type code), then |
with the expected length (based on the attribute type code), then |
the Error Subcode is set to Attribute Length Error. The Data |
the Error Subcode is set to Attribute Length Error. The Data |
Line 791 bgp_attr_origin (struct peer *peer, bgp_size_t length,
|
Line 1083 bgp_attr_origin (struct peer *peer, bgp_size_t length,
|
{ |
{ |
zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d", |
zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d", |
length); |
length); |
return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, | return bgp_attr_malformed (args, |
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, |
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, |
startp, total); | args->total); |
} |
} |
|
|
/* Fetch origin attribute. */ |
/* Fetch origin attribute. */ |
Line 808 bgp_attr_origin (struct peer *peer, bgp_size_t length,
|
Line 1100 bgp_attr_origin (struct peer *peer, bgp_size_t length,
|
{ |
{ |
zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d", |
zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d", |
attr->origin); |
attr->origin); |
return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, | return bgp_attr_malformed (args, |
BGP_NOTIFY_UPDATE_INVAL_ORIGIN, |
BGP_NOTIFY_UPDATE_INVAL_ORIGIN, |
startp, total); | args->total); |
} |
} |
|
|
/* Set oring attribute flag. */ |
/* Set oring attribute flag. */ |
Line 822 bgp_attr_origin (struct peer *peer, bgp_size_t length,
|
Line 1114 bgp_attr_origin (struct peer *peer, bgp_size_t length,
|
/* Parse AS path information. This function is wrapper of |
/* Parse AS path information. This function is wrapper of |
aspath_parse. */ |
aspath_parse. */ |
static int |
static int |
bgp_attr_aspath (struct peer *peer, bgp_size_t length, | bgp_attr_aspath (struct bgp_attr_parser_args *args) |
struct attr *attr, u_char flag, u_char *startp) | |
{ |
{ |
bgp_size_t total; | struct attr *const attr = args->attr; |
| struct peer *const peer = args->peer; |
total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); | const bgp_size_t length = args->length; |
| |
/* Flag check. */ | |
if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) | |
|| ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) | |
{ | |
zlog (peer->log, LOG_ERR, | |
"As-Path attribute flag isn't transitive %d", flag); | |
return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, | |
BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, | |
startp, total); | |
} | |
| |
/* |
/* |
* peer with AS4 => will get 4Byte ASnums |
* peer with AS4 => will get 4Byte ASnums |
* otherwise, will get 16 Bit |
* otherwise, will get 16 Bit |
Line 853 bgp_attr_aspath (struct peer *peer, bgp_size_t length,
|
Line 1133 bgp_attr_aspath (struct peer *peer, bgp_size_t length,
|
zlog (peer->log, LOG_ERR, |
zlog (peer->log, LOG_ERR, |
"Malformed AS path from %s, length is %d", |
"Malformed AS path from %s, length is %d", |
peer->host, length); |
peer->host, length); |
return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, | return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0); |
BGP_NOTIFY_UPDATE_MAL_AS_PATH, | |
NULL, 0); | |
} |
} |
|
|
/* Set aspath attribute flag. */ |
/* Set aspath attribute flag. */ |
Line 865 bgp_attr_aspath (struct peer *peer, bgp_size_t length,
|
Line 1143 bgp_attr_aspath (struct peer *peer, bgp_size_t length,
|
} |
} |
|
|
static bgp_attr_parse_ret_t |
static bgp_attr_parse_ret_t |
bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag) | bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr) |
{ |
{ |
/* These checks were part of bgp_attr_aspath, but with |
/* These checks were part of bgp_attr_aspath, but with |
* as4 we should to check aspath things when |
* as4 we should to check aspath things when |
Line 877 bgp_attr_aspath_check (struct peer *peer, struct attr
|
Line 1155 bgp_attr_aspath_check (struct peer *peer, struct attr
|
struct bgp *bgp = peer->bgp; |
struct bgp *bgp = peer->bgp; |
struct aspath *aspath; |
struct aspath *aspath; |
|
|
bgp = peer->bgp; |
|
|
|
/* Confederation sanity check. */ |
/* Confederation sanity check. */ |
if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) || | if ((peer->sort == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) || |
(peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath))) | (peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath))) |
{ |
{ |
zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host); |
zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host); |
return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, | bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, |
BGP_NOTIFY_UPDATE_MAL_AS_PATH, | BGP_NOTIFY_UPDATE_MAL_AS_PATH); |
NULL, 0); | return BGP_ATTR_PARSE_ERROR; |
} |
} |
|
|
/* First AS check for EBGP. */ |
/* First AS check for EBGP. */ |
if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS)) |
if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS)) |
{ |
{ |
if (peer_sort (peer) == BGP_PEER_EBGP | if (peer->sort == BGP_PEER_EBGP |
&& ! aspath_firstas_check (attr->aspath, peer->as)) |
&& ! aspath_firstas_check (attr->aspath, peer->as)) |
{ |
{ |
zlog (peer->log, LOG_ERR, |
zlog (peer->log, LOG_ERR, |
"%s incorrect first AS (must be %u)", peer->host, peer->as); |
"%s incorrect first AS (must be %u)", peer->host, peer->as); |
return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, | bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, |
BGP_NOTIFY_UPDATE_MAL_AS_PATH, | BGP_NOTIFY_UPDATE_MAL_AS_PATH); |
NULL, 0); | return BGP_ATTR_PARSE_ERROR; |
} |
} |
} |
} |
|
|
Line 919 bgp_attr_aspath_check (struct peer *peer, struct attr
|
Line 1195 bgp_attr_aspath_check (struct peer *peer, struct attr
|
/* Parse AS4 path information. This function is another wrapper of |
/* Parse AS4 path information. This function is another wrapper of |
aspath_parse. */ |
aspath_parse. */ |
static int |
static int |
bgp_attr_as4_path (struct peer *peer, bgp_size_t length, | bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path) |
struct attr *attr, u_char flag, u_char *startp, | |
struct aspath **as4_path) | |
{ |
{ |
bgp_size_t total; | struct peer *const peer = args->peer; |
| struct attr *const attr = args->attr; |
total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); | const bgp_size_t length = args->length; |
| |
/* Flag check. */ | |
if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) | |
|| !CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) | |
{ | |
zlog (peer->log, LOG_ERR, | |
"As4-Path attribute flag isn't optional/transitive %d", flag); | |
return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, | |
BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, | |
startp, total); | |
} | |
| |
*as4_path = aspath_parse (peer->ibuf, length, 1); |
*as4_path = aspath_parse (peer->ibuf, length, 1); |
|
|
/* In case of IBGP, length will be zero. */ |
/* In case of IBGP, length will be zero. */ |
Line 946 bgp_attr_as4_path (struct peer *peer, bgp_size_t lengt
|
Line 1209 bgp_attr_as4_path (struct peer *peer, bgp_size_t lengt
|
zlog (peer->log, LOG_ERR, |
zlog (peer->log, LOG_ERR, |
"Malformed AS4 path from %s, length is %d", |
"Malformed AS4 path from %s, length is %d", |
peer->host, length); |
peer->host, length); |
return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag, | return bgp_attr_malformed (args, |
BGP_NOTIFY_UPDATE_MAL_AS_PATH, |
BGP_NOTIFY_UPDATE_MAL_AS_PATH, |
NULL, 0); | 0); |
} |
} |
|
|
/* Set aspath attribute flag. */ |
/* Set aspath attribute flag. */ |
Line 960 bgp_attr_as4_path (struct peer *peer, bgp_size_t lengt
|
Line 1223 bgp_attr_as4_path (struct peer *peer, bgp_size_t lengt
|
|
|
/* Nexthop attribute. */ |
/* Nexthop attribute. */ |
static bgp_attr_parse_ret_t |
static bgp_attr_parse_ret_t |
bgp_attr_nexthop (struct peer *peer, bgp_size_t length, | bgp_attr_nexthop (struct bgp_attr_parser_args *args) |
struct attr *attr, u_char flag, u_char *startp) | |
{ |
{ |
bgp_size_t total; | struct peer *const peer = args->peer; |
| struct attr *const attr = args->attr; |
| const bgp_size_t length = args->length; |
| |
| in_addr_t nexthop_h, nexthop_n; |
|
|
total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); |
|
|
|
/* Flag check. */ |
|
if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) |
|
|| ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) |
|
{ |
|
zlog (peer->log, LOG_ERR, |
|
"Origin attribute flag isn't transitive %d", flag); |
|
return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, |
|
BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, |
|
startp, total); |
|
} |
|
|
|
/* Check nexthop attribute length. */ |
/* Check nexthop attribute length. */ |
if (length != 4) |
if (length != 4) |
{ |
{ |
zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]", |
zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]", |
length); |
length); |
|
|
return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, | return bgp_attr_malformed (args, |
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, |
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, |
startp, total); | args->total); |
} |
} |
|
|
attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf); | /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP |
| attribute must result in a NOTIFICATION message (this is implemented below). |
| At the same time, semantically incorrect NEXT_HOP is more likely to be just |
| logged locally (this is implemented somewhere else). The UPDATE message |
| gets ignored in any of these cases. */ |
| nexthop_n = stream_get_ipv4 (peer->ibuf); |
| nexthop_h = ntohl (nexthop_n); |
| if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h)) |
| { |
| char buf[INET_ADDRSTRLEN]; |
| inet_ntop (AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN); |
| zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf); |
| return bgp_attr_malformed (args, |
| BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, |
| args->total); |
| } |
| |
| attr->nexthop.s_addr = nexthop_n; |
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); |
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); |
|
|
return BGP_ATTR_PARSE_PROCEED; |
return BGP_ATTR_PARSE_PROCEED; |
Line 997 bgp_attr_nexthop (struct peer *peer, bgp_size_t length
|
Line 1267 bgp_attr_nexthop (struct peer *peer, bgp_size_t length
|
|
|
/* MED atrribute. */ |
/* MED atrribute. */ |
static bgp_attr_parse_ret_t |
static bgp_attr_parse_ret_t |
bgp_attr_med (struct peer *peer, bgp_size_t length, | bgp_attr_med (struct bgp_attr_parser_args *args) |
struct attr *attr, u_char flag, u_char *startp) | |
{ |
{ |
bgp_size_t total; | struct peer *const peer = args->peer; |
| struct attr *const attr = args->attr; |
total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); | const bgp_size_t length = args->length; |
| |
/* Flag checks. */ | |
if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) | |
{ | |
zlog (peer->log, LOG_ERR, | |
"MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag); | |
bgp_notify_send_with_data (peer, | |
BGP_NOTIFY_UPDATE_ERR, | |
BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, | |
startp, total); | |
return -1; | |
} | |
if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) | |
{ | |
zlog (peer->log, LOG_ERR, | |
"MULTI_EXIT_DISC attribute must not be flagged as \"transitive\" (%u)", flag); | |
bgp_notify_send_with_data (peer, | |
BGP_NOTIFY_UPDATE_ERR, | |
BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, | |
startp, total); | |
return -1; | |
} | |
if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) | |
{ | |
zlog (peer->log, LOG_ERR, | |
"MULTI_EXIT_DISC attribute must not be flagged as \"partial\" (%u)", flag); | |
bgp_notify_send_with_data (peer, | |
BGP_NOTIFY_UPDATE_ERR, | |
BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, | |
startp, total); | |
return -1; | |
} | |
| |
/* Length check. */ |
/* Length check. */ |
if (length != 4) |
if (length != 4) |
{ |
{ |
zlog (peer->log, LOG_ERR, |
zlog (peer->log, LOG_ERR, |
"MED attribute length isn't four [%d]", length); |
"MED attribute length isn't four [%d]", length); |
|
|
return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag, | return bgp_attr_malformed (args, |
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, |
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, |
startp, total); | args->total); |
} |
} |
|
|
attr->med = stream_getl (peer->ibuf); |
attr->med = stream_getl (peer->ibuf); |
Line 1056 bgp_attr_med (struct peer *peer, bgp_size_t length,
|
Line 1293 bgp_attr_med (struct peer *peer, bgp_size_t length,
|
|
|
/* Local preference attribute. */ |
/* Local preference attribute. */ |
static bgp_attr_parse_ret_t |
static bgp_attr_parse_ret_t |
bgp_attr_local_pref (struct peer *peer, bgp_size_t length, | bgp_attr_local_pref (struct bgp_attr_parser_args *args) |
struct attr *attr, u_char flag, u_char *startp) | |
{ |
{ |
bgp_size_t total; | struct peer *const peer = args->peer; |
| struct attr *const attr = args->attr; |
| const bgp_size_t length = args->length; |
| |
| /* Length check. */ |
| if (length != 4) |
| { |
| zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]", |
| length); |
| return bgp_attr_malformed (args, |
| BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, |
| args->total); |
| } |
|
|
total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); |
|
/* Flag checks. */ |
|
if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) |
|
{ |
|
zlog (peer->log, LOG_ERR, |
|
"LOCAL_PREF attribute must be flagged as \"well-known\" (%u)", flag); |
|
bgp_notify_send_with_data (peer, |
|
BGP_NOTIFY_UPDATE_ERR, |
|
BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, |
|
startp, total); |
|
return -1; |
|
} |
|
if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) |
|
{ |
|
zlog (peer->log, LOG_ERR, |
|
"LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag); |
|
bgp_notify_send_with_data (peer, |
|
BGP_NOTIFY_UPDATE_ERR, |
|
BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, |
|
startp, total); |
|
return -1; |
|
} |
|
|
|
/* If it is contained in an UPDATE message that is received from an |
/* If it is contained in an UPDATE message that is received from an |
external peer, then this attribute MUST be ignored by the |
external peer, then this attribute MUST be ignored by the |
receiving speaker. */ |
receiving speaker. */ |
if (peer_sort (peer) == BGP_PEER_EBGP) | if (peer->sort == BGP_PEER_EBGP) |
{ |
{ |
stream_forward_getp (peer->ibuf, length); |
stream_forward_getp (peer->ibuf, length); |
return BGP_ATTR_PARSE_PROCEED; |
return BGP_ATTR_PARSE_PROCEED; |
} |
} |
|
|
if (length == 4) | attr->local_pref = stream_getl (peer->ibuf); |
attr->local_pref = stream_getl (peer->ibuf); | |
else | |
attr->local_pref = 0; | |
|
|
/* Set atomic aggregate flag. */ |
/* Set atomic aggregate flag. */ |
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); |
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); |
Line 1106 bgp_attr_local_pref (struct peer *peer, bgp_size_t len
|
Line 1328 bgp_attr_local_pref (struct peer *peer, bgp_size_t len
|
|
|
/* Atomic aggregate. */ |
/* Atomic aggregate. */ |
static int |
static int |
bgp_attr_atomic (struct peer *peer, bgp_size_t length, | bgp_attr_atomic (struct bgp_attr_parser_args *args) |
struct attr *attr, u_char flag, u_char *startp) | |
{ |
{ |
bgp_size_t total; | struct peer *const peer = args->peer; |
| struct attr *const attr = args->attr; |
total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); | const bgp_size_t length = args->length; |
/* Flag checks. */ | |
if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) | |
{ | |
zlog (peer->log, LOG_ERR, | |
"ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag); | |
bgp_notify_send_with_data (peer, | |
BGP_NOTIFY_UPDATE_ERR, | |
BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, | |
startp, total); | |
return -1; | |
} | |
if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) | |
{ | |
zlog (peer->log, LOG_ERR, | |
"ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag); | |
bgp_notify_send_with_data (peer, | |
BGP_NOTIFY_UPDATE_ERR, | |
BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, | |
startp, total); | |
return -1; | |
} | |
if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) | |
{ | |
zlog (peer->log, LOG_ERR, | |
"ATOMIC_AGGREGATE attribute must not be flagged as \"partial\" (%u)", flag); | |
bgp_notify_send_with_data (peer, | |
BGP_NOTIFY_UPDATE_ERR, | |
BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, | |
startp, total); | |
return -1; | |
} | |
| |
/* Length check. */ |
/* Length check. */ |
if (length != 0) |
if (length != 0) |
{ |
{ |
zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length); | zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]", |
| length); |
return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag, | return bgp_attr_malformed (args, |
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, |
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, |
NULL, 0); | args->total); |
} |
} |
|
|
/* Set atomic aggregate flag. */ |
/* Set atomic aggregate flag. */ |
Line 1162 bgp_attr_atomic (struct peer *peer, bgp_size_t length,
|
Line 1352 bgp_attr_atomic (struct peer *peer, bgp_size_t length,
|
|
|
/* Aggregator attribute */ |
/* Aggregator attribute */ |
static int |
static int |
bgp_attr_aggregator (struct peer *peer, bgp_size_t length, | bgp_attr_aggregator (struct bgp_attr_parser_args *args) |
struct attr *attr, u_char flag) | |
{ |
{ |
|
struct peer *const peer = args->peer; |
|
struct attr *const attr = args->attr; |
|
const bgp_size_t length = args->length; |
|
|
int wantedlen = 6; |
int wantedlen = 6; |
struct attr_extra *attre = bgp_attr_extra_get (attr); |
struct attr_extra *attre = bgp_attr_extra_get (attr); |
|
|
Line 1174 bgp_attr_aggregator (struct peer *peer, bgp_size_t len
|
Line 1367 bgp_attr_aggregator (struct peer *peer, bgp_size_t len
|
|
|
if (length != wantedlen) |
if (length != wantedlen) |
{ |
{ |
zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length); | zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]", |
| wantedlen, length); |
return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag, | return bgp_attr_malformed (args, |
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, |
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, |
NULL, 0); | args->total); |
} |
} |
|
|
if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) ) |
if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) ) |
Line 1195 bgp_attr_aggregator (struct peer *peer, bgp_size_t len
|
Line 1388 bgp_attr_aggregator (struct peer *peer, bgp_size_t len
|
|
|
/* New Aggregator attribute */ |
/* New Aggregator attribute */ |
static bgp_attr_parse_ret_t |
static bgp_attr_parse_ret_t |
bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length, | bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args, |
struct attr *attr, u_char flag, | as_t *as4_aggregator_as, |
as_t *as4_aggregator_as, | struct in_addr *as4_aggregator_addr) |
struct in_addr *as4_aggregator_addr) | |
{ |
{ |
|
struct peer *const peer = args->peer; |
|
struct attr *const attr = args->attr; |
|
const bgp_size_t length = args->length; |
|
|
if (length != 8) |
if (length != 8) |
{ |
{ |
zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length); | zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", |
return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag, | length); |
| return bgp_attr_malformed (args, |
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, |
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, |
NULL, 0); | 0); |
} |
} |
|
|
*as4_aggregator_as = stream_getl (peer->ibuf); |
*as4_aggregator_as = stream_getl (peer->ibuf); |
as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf); |
as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf); |
|
|
Line 1218 bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t
|
Line 1416 bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t
|
/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH. |
/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH. |
*/ |
*/ |
static bgp_attr_parse_ret_t |
static bgp_attr_parse_ret_t |
bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag, | bgp_attr_munge_as4_attrs (struct peer *const peer, |
| struct attr *const attr, |
struct aspath *as4_path, as_t as4_aggregator, |
struct aspath *as4_path, as_t as4_aggregator, |
struct in_addr *as4_aggregator_addr) |
struct in_addr *as4_aggregator_addr) |
{ |
{ |
int ignore_as4_path = 0; |
int ignore_as4_path = 0; |
struct aspath *newpath; |
struct aspath *newpath; |
struct attr_extra *attre = attr->extra; |
struct attr_extra *attre = attr->extra; |
| |
| if (!attr->aspath) |
| { |
| /* NULL aspath shouldn't be possible as bgp_attr_parse should have |
| * checked that all well-known, mandatory attributes were present. |
| * |
| * Can only be a problem with peer itself - hard error |
| */ |
| return BGP_ATTR_PARSE_ERROR; |
| } |
| |
if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) |
if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) |
{ |
{ |
/* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR |
/* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR |
Line 1247 bgp_attr_munge_as4_attrs (struct peer *peer, struct at
|
Line 1456 bgp_attr_munge_as4_attrs (struct peer *peer, struct at
|
return BGP_ATTR_PARSE_PROCEED; |
return BGP_ATTR_PARSE_PROCEED; |
} |
} |
|
|
if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH)) |
|
&& !(attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))) |
|
{ |
|
/* Hu? This is not supposed to happen at all! |
|
* got as4_path and no aspath, |
|
* This should already |
|
* have been handled by 'well known attributes missing' |
|
* But... yeah, paranoia |
|
* Take this as a "malformed attribute" |
|
*/ |
|
zlog (peer->log, LOG_ERR, |
|
"%s BGP not AS4 capable peer sent AS4_PATH but" |
|
" no AS_PATH, cant do anything here", peer->host); |
|
return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, |
|
BGP_NOTIFY_UPDATE_MAL_ATTR, |
|
NULL, 0); |
|
} |
|
|
|
/* We have a asn16 peer. First, look for AS4_AGGREGATOR |
/* We have a asn16 peer. First, look for AS4_AGGREGATOR |
* because that may override AS4_PATH |
* because that may override AS4_PATH |
*/ |
*/ |
Line 1323 bgp_attr_munge_as4_attrs (struct peer *peer, struct at
|
Line 1514 bgp_attr_munge_as4_attrs (struct peer *peer, struct at
|
/* need to reconcile NEW_AS_PATH and AS_PATH */ |
/* need to reconcile NEW_AS_PATH and AS_PATH */ |
if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH)))) |
if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH)))) |
{ |
{ |
newpath = aspath_reconcile_as4 (attr->aspath, as4_path); | newpath = aspath_reconcile_as4 (attr->aspath, as4_path); |
aspath_unintern (&attr->aspath); | aspath_unintern (&attr->aspath); |
attr->aspath = aspath_intern (newpath); | attr->aspath = aspath_intern (newpath); |
} |
} |
return BGP_ATTR_PARSE_PROCEED; |
return BGP_ATTR_PARSE_PROCEED; |
} |
} |
|
|
/* Community attribute. */ |
/* Community attribute. */ |
static bgp_attr_parse_ret_t |
static bgp_attr_parse_ret_t |
bgp_attr_community (struct peer *peer, bgp_size_t length, | bgp_attr_community (struct bgp_attr_parser_args *args) |
struct attr *attr, u_char flag, u_char *startp) | |
{ |
{ |
bgp_size_t total | struct peer *const peer = args->peer; |
= length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); | struct attr *const attr = args->attr; |
| const bgp_size_t length = args->length; |
|
|
if (length == 0) |
if (length == 0) |
{ |
{ |
Line 1351 bgp_attr_community (struct peer *peer, bgp_size_t leng
|
Line 1542 bgp_attr_community (struct peer *peer, bgp_size_t leng
|
stream_forward_getp (peer->ibuf, length); |
stream_forward_getp (peer->ibuf, length); |
|
|
if (!attr->community) |
if (!attr->community) |
return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag, | return bgp_attr_malformed (args, |
BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, |
BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, |
startp, total); | args->total); |
|
|
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); |
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); |
|
|
Line 1362 bgp_attr_community (struct peer *peer, bgp_size_t leng
|
Line 1553 bgp_attr_community (struct peer *peer, bgp_size_t leng
|
|
|
/* Originator ID attribute. */ |
/* Originator ID attribute. */ |
static bgp_attr_parse_ret_t |
static bgp_attr_parse_ret_t |
bgp_attr_originator_id (struct peer *peer, bgp_size_t length, | bgp_attr_originator_id (struct bgp_attr_parser_args *args) |
struct attr *attr, u_char flag) | |
{ |
{ |
|
struct peer *const peer = args->peer; |
|
struct attr *const attr = args->attr; |
|
const bgp_size_t length = args->length; |
|
|
|
/* Length check. */ |
if (length != 4) |
if (length != 4) |
{ |
{ |
zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length); |
zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length); |
|
|
return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag, | return bgp_attr_malformed (args, |
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, |
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, |
NULL, 0); | args->total); |
} |
} |
|
|
(bgp_attr_extra_get (attr))->originator_id.s_addr |
(bgp_attr_extra_get (attr))->originator_id.s_addr |
Line 1384 bgp_attr_originator_id (struct peer *peer, bgp_size_t
|
Line 1579 bgp_attr_originator_id (struct peer *peer, bgp_size_t
|
|
|
/* Cluster list attribute. */ |
/* Cluster list attribute. */ |
static bgp_attr_parse_ret_t |
static bgp_attr_parse_ret_t |
bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, | bgp_attr_cluster_list (struct bgp_attr_parser_args *args) |
struct attr *attr, u_char flag) | |
{ |
{ |
|
struct peer *const peer = args->peer; |
|
struct attr *const attr = args->attr; |
|
const bgp_size_t length = args->length; |
|
|
/* Check length. */ |
/* Check length. */ |
if (length % 4) |
if (length % 4) |
{ |
{ |
zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length); |
zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length); |
|
|
return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag, | return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, |
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, | args->total); |
NULL, 0); | |
} |
} |
|
|
(bgp_attr_extra_get (attr))->cluster |
(bgp_attr_extra_get (attr))->cluster |
Line 1410 bgp_attr_cluster_list (struct peer *peer, bgp_size_t l
|
Line 1607 bgp_attr_cluster_list (struct peer *peer, bgp_size_t l
|
|
|
/* Multiprotocol reachability information parse. */ |
/* Multiprotocol reachability information parse. */ |
int |
int |
bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, | bgp_mp_reach_parse (struct bgp_attr_parser_args *args, |
struct bgp_nlri *mp_update) | struct bgp_nlri *mp_update) |
{ |
{ |
afi_t afi; |
afi_t afi; |
safi_t safi; |
safi_t safi; |
bgp_size_t nlri_len; |
bgp_size_t nlri_len; |
size_t start; |
size_t start; |
int ret; |
|
struct stream *s; |
struct stream *s; |
|
struct peer *const peer = args->peer; |
|
struct attr *const attr = args->attr; |
|
const bgp_size_t length = args->length; |
struct attr_extra *attre = bgp_attr_extra_get(attr); |
struct attr_extra *attre = bgp_attr_extra_get(attr); |
|
|
/* Set end of packet. */ |
/* Set end of packet. */ |
Line 1432 bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
|
Line 1631 bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
|
{ |
{ |
zlog_info ("%s: %s sent invalid length, %lu", |
zlog_info ("%s: %s sent invalid length, %lu", |
__func__, peer->host, (unsigned long)length); |
__func__, peer->host, (unsigned long)length); |
return BGP_ATTR_PARSE_ERROR; | return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; |
} |
} |
|
|
/* Load AFI, SAFI. */ |
/* Load AFI, SAFI. */ |
Line 1446 bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
|
Line 1645 bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
|
{ |
{ |
zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute", |
zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute", |
__func__, peer->host, attre->mp_nexthop_len); |
__func__, peer->host, attre->mp_nexthop_len); |
return BGP_ATTR_PARSE_ERROR; | return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; |
} |
} |
|
|
/* Nexthop length check. */ |
/* Nexthop length check. */ |
Line 1459 bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
|
Line 1658 bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
|
memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4); |
memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4); |
break; |
break; |
case 12: |
case 12: |
|
stream_getl (s); /* RD high */ |
|
stream_getl (s); /* RD low */ |
|
stream_get (&attre->mp_nexthop_global_in, s, 4); |
|
break; |
|
case 24: |
{ |
{ |
u_int32_t rd_high; | u_int32_t rd_high __attribute__((unused)); |
u_int32_t rd_low; | u_int32_t rd_low __attribute__((unused)); |
|
|
rd_high = stream_getl (s); | rd_high = stream_getl (s); |
rd_low = stream_getl (s); | rd_low = stream_getl (s); |
stream_get (&attre->mp_nexthop_global_in, s, 4); | |
} |
} |
break; | /* fall through */ |
#ifdef HAVE_IPV6 | |
case 16: |
case 16: |
stream_get (&attre->mp_nexthop_global, s, 16); |
stream_get (&attre->mp_nexthop_global, s, 16); |
break; |
break; |
case 32: |
case 32: |
|
case 48: |
|
if (attre->mp_nexthop_len == 48) { |
|
u_int32_t rd_high __attribute__((unused)); |
|
u_int32_t rd_low __attribute__((unused)); |
|
|
|
rd_high = stream_getl (s); |
|
rd_low = stream_getl (s); |
|
} |
stream_get (&attre->mp_nexthop_global, s, 16); |
stream_get (&attre->mp_nexthop_global, s, 16); |
|
|
|
if (attre->mp_nexthop_len == 48) { |
|
u_int32_t rd_high __attribute__((unused)); |
|
u_int32_t rd_low __attribute__((unused)); |
|
|
|
rd_high = stream_getl (s); |
|
rd_low = stream_getl (s); |
|
} |
stream_get (&attre->mp_nexthop_local, s, 16); |
stream_get (&attre->mp_nexthop_local, s, 16); |
if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local)) |
if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local)) |
{ |
{ |
Line 1490 bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
|
Line 1708 bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
|
attre->mp_nexthop_len = 16; |
attre->mp_nexthop_len = 16; |
} |
} |
break; |
break; |
#endif /* HAVE_IPV6 */ |
|
default: |
default: |
zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d", |
zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d", |
__func__, peer->host, attre->mp_nexthop_len); |
__func__, peer->host, attre->mp_nexthop_len); |
return BGP_ATTR_PARSE_ERROR; | return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; |
} |
} |
|
|
if (!LEN_LEFT) |
if (!LEN_LEFT) |
{ |
{ |
zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)", |
zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)", |
__func__, peer->host); |
__func__, peer->host); |
return BGP_ATTR_PARSE_ERROR; | return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; |
} |
} |
|
|
{ |
{ |
Line 1517 bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
|
Line 1734 bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
|
{ |
{ |
zlog_info ("%s: (%s) Failed to read NLRI", |
zlog_info ("%s: (%s) Failed to read NLRI", |
__func__, peer->host); |
__func__, peer->host); |
return BGP_ATTR_PARSE_ERROR; | return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; |
} |
} |
| |
if (safi != BGP_SAFI_VPNV4) | |
{ | |
ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len); | |
if (ret < 0) | |
{ | |
zlog_info ("%s: (%s) NLRI doesn't pass sanity check", | |
__func__, peer->host); | |
return BGP_ATTR_PARSE_ERROR; | |
} | |
} | |
| |
mp_update->afi = afi; |
mp_update->afi = afi; |
mp_update->safi = safi; |
mp_update->safi = safi; |
mp_update->nlri = stream_pnt (s); |
mp_update->nlri = stream_pnt (s); |
Line 1538 bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
|
Line 1744 bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
|
|
|
stream_forward_getp (s, nlri_len); |
stream_forward_getp (s, nlri_len); |
|
|
|
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI); |
|
|
return BGP_ATTR_PARSE_PROCEED; |
return BGP_ATTR_PARSE_PROCEED; |
#undef LEN_LEFT |
#undef LEN_LEFT |
} |
} |
|
|
/* Multiprotocol unreachable parse */ |
/* Multiprotocol unreachable parse */ |
int |
int |
bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length, | bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, |
struct bgp_nlri *mp_withdraw) |
struct bgp_nlri *mp_withdraw) |
{ |
{ |
struct stream *s; |
struct stream *s; |
afi_t afi; |
afi_t afi; |
safi_t safi; |
safi_t safi; |
u_int16_t withdraw_len; |
u_int16_t withdraw_len; |
int ret; | struct peer *const peer = args->peer; |
| struct attr *const attr = args->attr; |
| const bgp_size_t length = args->length; |
|
|
s = peer->ibuf; |
s = peer->ibuf; |
|
|
#define BGP_MP_UNREACH_MIN_SIZE 3 |
#define BGP_MP_UNREACH_MIN_SIZE 3 |
if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE)) |
if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE)) |
return BGP_ATTR_PARSE_ERROR; | return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; |
|
|
afi = stream_getw (s); |
afi = stream_getw (s); |
safi = stream_getc (s); |
safi = stream_getc (s); |
|
|
withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE; |
withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE; |
|
|
if (safi != BGP_SAFI_VPNV4) |
|
{ |
|
ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len); |
|
if (ret < 0) |
|
return BGP_ATTR_PARSE_ERROR; |
|
} |
|
|
|
mp_withdraw->afi = afi; |
mp_withdraw->afi = afi; |
mp_withdraw->safi = safi; |
mp_withdraw->safi = safi; |
mp_withdraw->nlri = stream_pnt (s); |
mp_withdraw->nlri = stream_pnt (s); |
Line 1578 bgp_mp_unreach_parse (struct peer *peer, bgp_size_t le
|
Line 1781 bgp_mp_unreach_parse (struct peer *peer, bgp_size_t le
|
|
|
stream_forward_getp (s, withdraw_len); |
stream_forward_getp (s, withdraw_len); |
|
|
|
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI); |
|
|
return BGP_ATTR_PARSE_PROCEED; |
return BGP_ATTR_PARSE_PROCEED; |
} |
} |
|
|
/* Extended Community attribute. */ |
/* Extended Community attribute. */ |
static bgp_attr_parse_ret_t |
static bgp_attr_parse_ret_t |
bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, | bgp_attr_ext_communities (struct bgp_attr_parser_args *args) |
struct attr *attr, u_char flag, u_char *startp) | |
{ |
{ |
bgp_size_t total | struct peer *const peer = args->peer; |
= length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); | struct attr *const attr = args->attr; |
| const bgp_size_t length = args->length; |
|
|
if (length == 0) |
if (length == 0) |
{ |
{ |
Line 1603 bgp_attr_ext_communities (struct peer *peer, bgp_size_
|
Line 1808 bgp_attr_ext_communities (struct peer *peer, bgp_size_
|
stream_forward_getp (peer->ibuf, length); |
stream_forward_getp (peer->ibuf, length); |
|
|
if (!attr->extra->ecommunity) |
if (!attr->extra->ecommunity) |
return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES, | return bgp_attr_malformed (args, |
flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, | BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, |
startp, total); | args->total); |
|
|
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); |
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); |
|
|
return BGP_ATTR_PARSE_PROCEED; |
return BGP_ATTR_PARSE_PROCEED; |
} |
} |
|
|
|
/* Parse Tunnel Encap attribute in an UPDATE */ |
|
static int |
|
bgp_attr_encap( |
|
uint8_t type, |
|
struct peer *peer, /* IN */ |
|
bgp_size_t length, /* IN: attr's length field */ |
|
struct attr *attr, /* IN: caller already allocated */ |
|
u_char flag, /* IN: attr's flags field */ |
|
u_char *startp) |
|
{ |
|
bgp_size_t total; |
|
struct attr_extra *attre = NULL; |
|
struct bgp_attr_encap_subtlv *stlv_last = NULL; |
|
uint16_t tunneltype; |
|
|
|
total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); |
|
|
|
if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS) |
|
|| !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL)) |
|
{ |
|
zlog (peer->log, LOG_ERR, |
|
"Tunnel Encap attribute flag isn't optional and transitive %d", flag); |
|
bgp_notify_send_with_data (peer, |
|
BGP_NOTIFY_UPDATE_ERR, |
|
BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, |
|
startp, total); |
|
return -1; |
|
} |
|
|
|
if (BGP_ATTR_ENCAP == type) { |
|
/* read outer TLV type and length */ |
|
uint16_t tlv_length; |
|
|
|
if (length < 4) { |
|
zlog (peer->log, LOG_ERR, |
|
"Tunnel Encap attribute not long enough to contain outer T,L"); |
|
bgp_notify_send_with_data(peer, |
|
BGP_NOTIFY_UPDATE_ERR, |
|
BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, |
|
startp, total); |
|
return -1; |
|
} |
|
tunneltype = stream_getw (BGP_INPUT (peer)); |
|
tlv_length = stream_getw (BGP_INPUT (peer)); |
|
length -= 4; |
|
|
|
if (tlv_length != length) { |
|
zlog (peer->log, LOG_ERR, "%s: tlv_length(%d) != length(%d)", |
|
__func__, tlv_length, length); |
|
} |
|
} |
|
|
|
while (length >= 4) { |
|
uint16_t subtype; |
|
uint16_t sublength; |
|
struct bgp_attr_encap_subtlv *tlv; |
|
|
|
if (BGP_ATTR_ENCAP == type) { |
|
subtype = stream_getc (BGP_INPUT (peer)); |
|
sublength = stream_getc (BGP_INPUT (peer)); |
|
length -= 2; |
|
} |
|
|
|
if (sublength > length) { |
|
zlog (peer->log, LOG_ERR, |
|
"Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d", |
|
sublength, length); |
|
bgp_notify_send_with_data (peer, |
|
BGP_NOTIFY_UPDATE_ERR, |
|
BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, |
|
startp, total); |
|
return -1; |
|
} |
|
|
|
/* alloc and copy sub-tlv */ |
|
/* TBD make sure these are freed when attributes are released */ |
|
tlv = XCALLOC (MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv)-1+sublength); |
|
tlv->type = subtype; |
|
tlv->length = sublength; |
|
stream_get(tlv->value, peer->ibuf, sublength); |
|
length -= sublength; |
|
|
|
/* attach tlv to encap chain */ |
|
if (!attre) { |
|
attre = bgp_attr_extra_get(attr); |
|
if (BGP_ATTR_ENCAP == type) { |
|
for (stlv_last = attre->encap_subtlvs; stlv_last && stlv_last->next; |
|
stlv_last = stlv_last->next); |
|
if (stlv_last) { |
|
stlv_last->next = tlv; |
|
} else { |
|
attre->encap_subtlvs = tlv; |
|
} |
|
} |
|
} else { |
|
stlv_last->next = tlv; |
|
} |
|
stlv_last = tlv; |
|
} |
|
|
|
if (attre && (BGP_ATTR_ENCAP == type)) { |
|
attre->encap_tunneltype = tunneltype; |
|
} |
|
|
|
if (length) { |
|
/* spurious leftover data */ |
|
zlog (peer->log, LOG_ERR, |
|
"Tunnel Encap attribute length is bad: %d leftover octets", length); |
|
bgp_notify_send_with_data (peer, |
|
BGP_NOTIFY_UPDATE_ERR, |
|
BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, |
|
startp, total); |
|
return -1; |
|
} |
|
|
|
return 0; |
|
} |
|
|
/* BGP unknown attribute treatment. */ |
/* BGP unknown attribute treatment. */ |
static bgp_attr_parse_ret_t |
static bgp_attr_parse_ret_t |
bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag, | bgp_attr_unknown (struct bgp_attr_parser_args *args) |
u_char type, bgp_size_t length, u_char *startp) | |
{ |
{ |
bgp_size_t total; | bgp_size_t total = args->total; |
struct transit *transit; |
struct transit *transit; |
struct attr_extra *attre; |
struct attr_extra *attre; |
|
struct peer *const peer = args->peer; |
|
struct attr *const attr = args->attr; |
|
u_char *const startp = args->startp; |
|
const u_char type = args->type; |
|
const u_char flag = args->flags; |
|
const bgp_size_t length = args->length; |
|
|
|
|
if (BGP_DEBUG (normal, NORMAL)) |
if (BGP_DEBUG (normal, NORMAL)) |
zlog_debug ("%s Unknown attribute is received (type %d, length %d)", |
zlog_debug ("%s Unknown attribute is received (type %d, length %d)", |
Line 1632 bgp_attr_unknown (struct peer *peer, struct attr *attr
|
Line 1961 bgp_attr_unknown (struct peer *peer, struct attr *attr
|
/* Forward read pointer of input stream. */ |
/* Forward read pointer of input stream. */ |
stream_forward_getp (peer->ibuf, length); |
stream_forward_getp (peer->ibuf, length); |
|
|
/* Adjest total length to include type and length. */ |
|
total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); |
|
|
|
/* If any of the mandatory well-known attributes are not recognized, |
/* If any of the mandatory well-known attributes are not recognized, |
then the Error Subcode is set to Unrecognized Well-known |
then the Error Subcode is set to Unrecognized Well-known |
Attribute. The Data field contains the unrecognized attribute |
Attribute. The Data field contains the unrecognized attribute |
(type, length and value). */ |
(type, length and value). */ |
if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) |
if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) |
{ |
{ |
return bgp_attr_malformed (peer, type, flag, | return bgp_attr_malformed (args, |
BGP_NOTIFY_UPDATE_UNREC_ATTR, |
BGP_NOTIFY_UPDATE_UNREC_ATTR, |
startp, total); | args->total); |
} |
} |
|
|
/* Unrecognized non-transitive optional attributes must be quietly |
/* Unrecognized non-transitive optional attributes must be quietly |
Line 1675 bgp_attr_unknown (struct peer *peer, struct attr *attr
|
Line 2001 bgp_attr_unknown (struct peer *peer, struct attr *attr
|
return BGP_ATTR_PARSE_PROCEED; |
return BGP_ATTR_PARSE_PROCEED; |
} |
} |
|
|
|
/* Well-known attribute check. */ |
|
static int |
|
bgp_attr_check (struct peer *peer, struct attr *attr) |
|
{ |
|
u_char type = 0; |
|
|
|
/* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an |
|
* empty UPDATE. */ |
|
if (CHECK_FLAG (peer->cap, PEER_CAP_RESTART_RCV) && !attr->flag) |
|
return BGP_ATTR_PARSE_PROCEED; |
|
|
|
/* "An UPDATE message that contains the MP_UNREACH_NLRI is not required |
|
to carry any other path attributes.", though if MP_REACH_NLRI or NLRI |
|
are present, it should. Check for any other attribute being present |
|
instead. |
|
*/ |
|
if (attr->flag == ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI)) |
|
return BGP_ATTR_PARSE_PROCEED; |
|
|
|
if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN))) |
|
type = BGP_ATTR_ORIGIN; |
|
|
|
if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))) |
|
type = BGP_ATTR_AS_PATH; |
|
|
|
/* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present and |
|
* NLRI is empty. We can't easily check NLRI empty here though. |
|
*/ |
|
if (!CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)) |
|
&& !CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI))) |
|
type = BGP_ATTR_NEXT_HOP; |
|
|
|
if (peer->sort == BGP_PEER_IBGP |
|
&& ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) |
|
type = BGP_ATTR_LOCAL_PREF; |
|
|
|
if (type) |
|
{ |
|
zlog (peer->log, LOG_WARNING, |
|
"%s Missing well-known attribute %d / %s", |
|
peer->host, type, LOOKUP (attr_str, type)); |
|
bgp_notify_send_with_data (peer, |
|
BGP_NOTIFY_UPDATE_ERR, |
|
BGP_NOTIFY_UPDATE_MISS_ATTR, |
|
&type, 1); |
|
return BGP_ATTR_PARSE_ERROR; |
|
} |
|
return BGP_ATTR_PARSE_PROCEED; |
|
} |
|
|
/* Read attribute of update packet. This function is called from |
/* Read attribute of update packet. This function is called from |
bgp_update() in bgpd.c. */ | bgp_update_receive() in bgp_packet.c. */ |
bgp_attr_parse_ret_t |
bgp_attr_parse_ret_t |
bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, |
bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, |
struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw) |
struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw) |
Line 1692 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
Line 2068 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
/* same goes for as4_aggregator */ |
/* same goes for as4_aggregator */ |
struct aspath *as4_path = NULL; |
struct aspath *as4_path = NULL; |
as_t as4_aggregator = 0; |
as_t as4_aggregator = 0; |
struct in_addr as4_aggregator_addr = { 0 }; | struct in_addr as4_aggregator_addr = { .s_addr = 0 }; |
|
|
/* Initialize bitmap. */ |
/* Initialize bitmap. */ |
memset (seen, 0, BGP_ATTR_BITMAP_SIZE); |
memset (seen, 0, BGP_ATTR_BITMAP_SIZE); |
Line 1720 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
Line 2096 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
|
|
/* Fetch attribute flag and type. */ |
/* Fetch attribute flag and type. */ |
startp = BGP_INPUT_PNT (peer); |
startp = BGP_INPUT_PNT (peer); |
flag = stream_getc (BGP_INPUT (peer)); | /* "The lower-order four bits of the Attribute Flags octet are |
| unused. They MUST be zero when sent and MUST be ignored when |
| received." */ |
| flag = 0xF0 & stream_getc (BGP_INPUT (peer)); |
type = stream_getc (BGP_INPUT (peer)); |
type = stream_getc (BGP_INPUT (peer)); |
|
|
/* Check whether Extended-Length applies and is in bounds */ |
/* Check whether Extended-Length applies and is in bounds */ |
Line 1737 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
Line 2116 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); |
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); |
return BGP_ATTR_PARSE_ERROR; |
return BGP_ATTR_PARSE_ERROR; |
} |
} |
| |
/* Check extended attribue length bit. */ |
/* Check extended attribue length bit. */ |
if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)) |
if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)) |
length = stream_getw (BGP_INPUT (peer)); |
length = stream_getw (BGP_INPUT (peer)); |
Line 1777 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
Line 2156 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); |
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); |
return BGP_ATTR_PARSE_ERROR; |
return BGP_ATTR_PARSE_ERROR; |
} |
} |
|
|
|
struct bgp_attr_parser_args attr_args = { |
|
.peer = peer, |
|
.length = length, |
|
.attr = attr, |
|
.type = type, |
|
.flags = flag, |
|
.startp = startp, |
|
.total = attr_endp - startp, |
|
}; |
|
|
|
|
|
/* If any recognized attribute has Attribute Flags that conflict |
|
with the Attribute Type Code, then the Error Subcode is set to |
|
Attribute Flags Error. The Data field contains the erroneous |
|
attribute (type, length and value). */ |
|
if (bgp_attr_flag_invalid (&attr_args)) |
|
{ |
|
bgp_attr_parse_ret_t ret; |
|
ret = bgp_attr_malformed (&attr_args, |
|
BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, |
|
attr_args.total); |
|
if (ret == BGP_ATTR_PARSE_PROCEED) |
|
continue; |
|
return ret; |
|
} |
|
|
/* OK check attribute and store it's value. */ |
/* OK check attribute and store it's value. */ |
switch (type) |
switch (type) |
{ |
{ |
case BGP_ATTR_ORIGIN: |
case BGP_ATTR_ORIGIN: |
ret = bgp_attr_origin (peer, length, attr, flag, startp); | ret = bgp_attr_origin (&attr_args); |
break; |
break; |
case BGP_ATTR_AS_PATH: |
case BGP_ATTR_AS_PATH: |
ret = bgp_attr_aspath (peer, length, attr, flag, startp); | ret = bgp_attr_aspath (&attr_args); |
break; |
break; |
case BGP_ATTR_AS4_PATH: |
case BGP_ATTR_AS4_PATH: |
ret = bgp_attr_as4_path (peer, length, attr, flag, startp, &as4_path); | ret = bgp_attr_as4_path (&attr_args, &as4_path); |
break; |
break; |
case BGP_ATTR_NEXT_HOP: |
case BGP_ATTR_NEXT_HOP: |
ret = bgp_attr_nexthop (peer, length, attr, flag, startp); | ret = bgp_attr_nexthop (&attr_args); |
break; |
break; |
case BGP_ATTR_MULTI_EXIT_DISC: |
case BGP_ATTR_MULTI_EXIT_DISC: |
ret = bgp_attr_med (peer, length, attr, flag, startp); | ret = bgp_attr_med (&attr_args); |
break; |
break; |
case BGP_ATTR_LOCAL_PREF: |
case BGP_ATTR_LOCAL_PREF: |
ret = bgp_attr_local_pref (peer, length, attr, flag, startp); | ret = bgp_attr_local_pref (&attr_args); |
break; |
break; |
case BGP_ATTR_ATOMIC_AGGREGATE: |
case BGP_ATTR_ATOMIC_AGGREGATE: |
ret = bgp_attr_atomic (peer, length, attr, flag, startp); | ret = bgp_attr_atomic (&attr_args); |
break; |
break; |
case BGP_ATTR_AGGREGATOR: |
case BGP_ATTR_AGGREGATOR: |
ret = bgp_attr_aggregator (peer, length, attr, flag); | ret = bgp_attr_aggregator (&attr_args); |
break; |
break; |
case BGP_ATTR_AS4_AGGREGATOR: |
case BGP_ATTR_AS4_AGGREGATOR: |
ret = bgp_attr_as4_aggregator (peer, length, attr, flag, | ret = bgp_attr_as4_aggregator (&attr_args, |
&as4_aggregator, | &as4_aggregator, |
&as4_aggregator_addr); |
&as4_aggregator_addr); |
break; |
break; |
case BGP_ATTR_COMMUNITIES: |
case BGP_ATTR_COMMUNITIES: |
ret = bgp_attr_community (peer, length, attr, flag, startp); | ret = bgp_attr_community (&attr_args); |
break; |
break; |
case BGP_ATTR_ORIGINATOR_ID: |
case BGP_ATTR_ORIGINATOR_ID: |
ret = bgp_attr_originator_id (peer, length, attr, flag); | ret = bgp_attr_originator_id (&attr_args); |
break; |
break; |
case BGP_ATTR_CLUSTER_LIST: |
case BGP_ATTR_CLUSTER_LIST: |
ret = bgp_attr_cluster_list (peer, length, attr, flag); | ret = bgp_attr_cluster_list (&attr_args); |
break; |
break; |
case BGP_ATTR_MP_REACH_NLRI: |
case BGP_ATTR_MP_REACH_NLRI: |
ret = bgp_mp_reach_parse (peer, length, attr, mp_update); | ret = bgp_mp_reach_parse (&attr_args, mp_update); |
break; |
break; |
case BGP_ATTR_MP_UNREACH_NLRI: |
case BGP_ATTR_MP_UNREACH_NLRI: |
ret = bgp_mp_unreach_parse (peer, length, mp_withdraw); | ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw); |
break; |
break; |
case BGP_ATTR_EXT_COMMUNITIES: |
case BGP_ATTR_EXT_COMMUNITIES: |
ret = bgp_attr_ext_communities (peer, length, attr, flag, startp); | ret = bgp_attr_ext_communities (&attr_args); |
break; |
break; |
|
case BGP_ATTR_ENCAP: |
|
ret = bgp_attr_encap (type, peer, length, attr, flag, startp); |
|
break; |
default: |
default: |
ret = bgp_attr_unknown (peer, attr, flag, type, length, startp); | ret = bgp_attr_unknown (&attr_args); |
break; |
break; |
} |
} |
|
|
|
if (ret == BGP_ATTR_PARSE_ERROR_NOTIFYPLS) |
|
{ |
|
bgp_notify_send (peer, |
|
BGP_NOTIFY_UPDATE_ERR, |
|
BGP_NOTIFY_UPDATE_MAL_ATTR); |
|
ret = BGP_ATTR_PARSE_ERROR; |
|
} |
|
|
/* If hard error occured immediately return to the caller. */ |
/* If hard error occured immediately return to the caller. */ |
if (ret == BGP_ATTR_PARSE_ERROR) |
if (ret == BGP_ATTR_PARSE_ERROR) |
{ |
{ |
Line 1840 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
Line 2256 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
"%s: Attribute %s, parse error", |
"%s: Attribute %s, parse error", |
peer->host, |
peer->host, |
LOOKUP (attr_str, type)); |
LOOKUP (attr_str, type)); |
bgp_notify_send (peer, |
|
BGP_NOTIFY_UPDATE_ERR, |
|
BGP_NOTIFY_UPDATE_MAL_ATTR); |
|
if (as4_path) |
if (as4_path) |
aspath_unintern (&as4_path); |
aspath_unintern (&as4_path); |
return ret; |
return ret; |
Line 1873 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
Line 2286 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
return BGP_ATTR_PARSE_ERROR; |
return BGP_ATTR_PARSE_ERROR; |
} |
} |
} |
} |
|
|
/* Check final read pointer is same as end pointer. */ |
/* Check final read pointer is same as end pointer. */ |
if (BGP_INPUT_PNT (peer) != endp) |
if (BGP_INPUT_PNT (peer) != endp) |
{ |
{ |
Line 1887 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
Line 2299 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
aspath_unintern (&as4_path); |
aspath_unintern (&as4_path); |
return BGP_ATTR_PARSE_ERROR; |
return BGP_ATTR_PARSE_ERROR; |
} |
} |
| |
| /* Check all mandatory well-known attributes are present */ |
| { |
| bgp_attr_parse_ret_t ret; |
| if ((ret = bgp_attr_check (peer, attr)) < 0) |
| { |
| if (as4_path) |
| aspath_unintern (&as4_path); |
| return ret; |
| } |
| } |
| |
/* |
/* |
* At this place we can see whether we got AS4_PATH and/or |
* At this place we can see whether we got AS4_PATH and/or |
* AS4_AGGREGATOR from a 16Bit peer and act accordingly. |
* AS4_AGGREGATOR from a 16Bit peer and act accordingly. |
Line 1898 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
Line 2321 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
* So, to be defensive, we are not relying on any order and read |
* So, to be defensive, we are not relying on any order and read |
* all attributes first, including these 32bit ones, and now, |
* all attributes first, including these 32bit ones, and now, |
* afterwards, we look what and if something is to be done for as4. |
* afterwards, we look what and if something is to be done for as4. |
|
* |
|
* It is possible to not have AS_PATH, e.g. GR EoR and sole |
|
* MP_UNREACH_NLRI. |
*/ |
*/ |
if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path, | /* actually... this doesn't ever return failure currently, but |
| * better safe than sorry */ |
| if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)) |
| && bgp_attr_munge_as4_attrs (peer, attr, as4_path, |
as4_aggregator, &as4_aggregator_addr)) |
as4_aggregator, &as4_aggregator_addr)) |
{ |
{ |
|
bgp_notify_send (peer, |
|
BGP_NOTIFY_UPDATE_ERR, |
|
BGP_NOTIFY_UPDATE_MAL_ATTR); |
if (as4_path) |
if (as4_path) |
aspath_unintern (&as4_path); |
aspath_unintern (&as4_path); |
return BGP_ATTR_PARSE_ERROR; |
return BGP_ATTR_PARSE_ERROR; |
Line 1931 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
Line 2363 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
*/ |
*/ |
if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH))) |
if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH))) |
{ |
{ |
ret = bgp_attr_aspath_check (peer, attr, flag); | ret = bgp_attr_aspath_check (peer, attr); |
if (ret != BGP_ATTR_PARSE_PROCEED) |
if (ret != BGP_ATTR_PARSE_PROCEED) |
return ret; |
return ret; |
} |
} |
Line 1943 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
Line 2375 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
return BGP_ATTR_PARSE_PROCEED; |
return BGP_ATTR_PARSE_PROCEED; |
} |
} |
|
|
/* Well-known attribute check. */ | int stream_put_prefix (struct stream *, struct prefix *); |
int | |
bgp_attr_check (struct peer *peer, struct attr *attr) | size_t |
| bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, |
| struct attr *attr) |
{ |
{ |
u_char type = 0; | size_t sizep; |
| |
if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN))) | |
type = BGP_ATTR_ORIGIN; | |
|
|
if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))) | /* Set extended bit always to encode the attribute length as 2 bytes */ |
type = BGP_ATTR_AS_PATH; | stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN); |
| stream_putc (s, BGP_ATTR_MP_REACH_NLRI); |
| sizep = stream_get_endp (s); |
| stream_putw (s, 0); /* Marker: Attribute length. */ |
|
|
if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))) | stream_putw (s, afi); |
type = BGP_ATTR_NEXT_HOP; | stream_putc (s, (safi == SAFI_MPLS_VPN) ? SAFI_MPLS_LABELED_VPN : safi); |
|
|
if (peer_sort (peer) == BGP_PEER_IBGP | /* Nexthop */ |
&& ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) | switch (afi) |
type = BGP_ATTR_LOCAL_PREF; | { |
| case AFI_IP: |
| switch (safi) |
| { |
| case SAFI_MULTICAST: |
| stream_putc (s, 4); |
| stream_put_ipv4 (s, attr->nexthop.s_addr); |
| break; |
| case SAFI_MPLS_VPN: |
| stream_putc (s, 12); |
| stream_putl (s, 0); /* RD = 0, per RFC */ |
| stream_putl (s, 0); |
| stream_put (s, &attr->extra->mp_nexthop_global_in, 4); |
| break; |
| case SAFI_ENCAP: |
| stream_putc (s, 4); |
| stream_put (s, &attr->extra->mp_nexthop_global_in, 4); |
| break; |
| case SAFI_UNICAST: /* invalid for IPv4 */ |
| default: |
| break; |
| } |
| break; |
| case AFI_IP6: |
| switch (safi) |
| { |
| case SAFI_UNICAST: |
| case SAFI_MULTICAST: |
| { |
| struct attr_extra *attre = attr->extra; |
|
|
if (type) | assert (attr->extra); |
| stream_putc (s, attre->mp_nexthop_len); |
| stream_put (s, &attre->mp_nexthop_global, 16); |
| if (attre->mp_nexthop_len == 32) |
| stream_put (s, &attre->mp_nexthop_local, 16); |
| } |
| break; |
| case SAFI_MPLS_VPN: |
| { |
| struct attr_extra *attre = attr->extra; |
| |
| assert (attr->extra); |
| if (attre->mp_nexthop_len == 16) { |
| stream_putc (s, 24); |
| stream_putl (s, 0); /* RD = 0, per RFC */ |
| stream_putl (s, 0); |
| stream_put (s, &attre->mp_nexthop_global, 16); |
| } else if (attre->mp_nexthop_len == 32) { |
| stream_putc (s, 48); |
| stream_putl (s, 0); /* RD = 0, per RFC */ |
| stream_putl (s, 0); |
| stream_put (s, &attre->mp_nexthop_global, 16); |
| stream_putl (s, 0); /* RD = 0, per RFC */ |
| stream_putl (s, 0); |
| stream_put (s, &attre->mp_nexthop_local, 16); |
| } |
| } |
| break; |
| case SAFI_ENCAP: |
| assert (attr->extra); |
| stream_putc (s, 16); |
| stream_put (s, &attr->extra->mp_nexthop_global, 16); |
| break; |
| default: |
| break; |
| } |
| break; |
| default: |
| break; |
| } |
| |
| /* SNPA */ |
| stream_putc (s, 0); |
| return sizep; |
| } |
| |
| void |
| bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi, |
| struct prefix *p, struct prefix_rd *prd, |
| u_char *tag) |
| { |
| if (safi == SAFI_MPLS_VPN) |
{ |
{ |
zlog (peer->log, LOG_WARNING, | /* Tag, RD, Prefix write. */ |
"%s Missing well-known attribute %d.", | stream_putc (s, p->prefixlen + 88); |
peer->host, type); | stream_put (s, tag, 3); |
bgp_notify_send_with_data (peer, | stream_put (s, prd->val, 8); |
BGP_NOTIFY_UPDATE_ERR, | stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); |
BGP_NOTIFY_UPDATE_MISS_ATTR, | |
&type, 1); | |
return BGP_ATTR_PARSE_ERROR; | |
} |
} |
return BGP_ATTR_PARSE_PROCEED; | else |
| stream_put_prefix (s, p); |
} |
} |
|
|
int stream_put_prefix (struct stream *, struct prefix *); |
|
|
|
|
size_t |
|
bgp_packet_mpattr_prefix_size (afi_t afi, safi_t safi, struct prefix *p) |
|
{ |
|
int size = PSIZE (p->prefixlen); |
|
if (safi == SAFI_MPLS_VPN) |
|
size += 88; |
|
return size; |
|
} |
|
|
|
/* |
|
* Encodes the tunnel encapsulation attribute |
|
*/ |
|
static void |
|
bgp_packet_mpattr_tea( |
|
struct bgp *bgp, |
|
struct peer *peer, |
|
struct stream *s, |
|
struct attr *attr, |
|
uint8_t attrtype) |
|
{ |
|
unsigned int attrlenfield = 0; |
|
unsigned int attrhdrlen = 0; |
|
struct bgp_attr_encap_subtlv *subtlvs; |
|
struct bgp_attr_encap_subtlv *st; |
|
const char *attrname; |
|
|
|
if (!attr || !attr->extra) |
|
return; |
|
|
|
switch (attrtype) { |
|
case BGP_ATTR_ENCAP: |
|
attrname = "Tunnel Encap"; |
|
subtlvs = attr->extra->encap_subtlvs; |
|
|
|
/* |
|
* The tunnel encap attr has an "outer" tlv. |
|
* T = tunneltype, |
|
* L = total length of subtlvs, |
|
* V = concatenated subtlvs. |
|
*/ |
|
attrlenfield = 2 + 2; /* T + L */ |
|
attrhdrlen = 1 + 1; /* subTLV T + L */ |
|
break; |
|
|
|
default: |
|
assert(0); |
|
} |
|
|
|
|
|
/* if no tlvs, don't make attr */ |
|
if (subtlvs == NULL) |
|
return; |
|
|
|
/* compute attr length */ |
|
for (st = subtlvs; st; st = st->next) { |
|
attrlenfield += (attrhdrlen + st->length); |
|
} |
|
|
|
if (attrlenfield > 0xffff) { |
|
zlog (peer->log, LOG_ERR, |
|
"%s attribute is too long (length=%d), can't send it", |
|
attrname, |
|
attrlenfield); |
|
return; |
|
} |
|
|
|
if (attrlenfield > 0xff) { |
|
/* 2-octet length field */ |
|
stream_putc (s, |
|
BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN); |
|
stream_putc (s, attrtype); |
|
stream_putw (s, attrlenfield & 0xffff); |
|
} else { |
|
/* 1-octet length field */ |
|
stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL); |
|
stream_putc (s, attrtype); |
|
stream_putc (s, attrlenfield & 0xff); |
|
} |
|
|
|
if (attrtype == BGP_ATTR_ENCAP) { |
|
/* write outer T+L */ |
|
stream_putw(s, attr->extra->encap_tunneltype); |
|
stream_putw(s, attrlenfield - 4); |
|
} |
|
|
|
/* write each sub-tlv */ |
|
for (st = subtlvs; st; st = st->next) { |
|
if (attrtype == BGP_ATTR_ENCAP) { |
|
stream_putc (s, st->type); |
|
stream_putc (s, st->length); |
|
} |
|
stream_put (s, st->value, st->length); |
|
} |
|
} |
|
|
|
void |
|
bgp_packet_mpattr_end (struct stream *s, size_t sizep) |
|
{ |
|
/* Set MP attribute length. Don't count the (2) bytes used to encode |
|
the attr length */ |
|
stream_putw_at (s, sizep, (stream_get_endp (s) - sizep) - 2); |
|
} |
|
|
/* Make attribute packet. */ |
/* Make attribute packet. */ |
bgp_size_t |
bgp_size_t |
bgp_packet_attribute (struct bgp *bgp, struct peer *peer, |
bgp_packet_attribute (struct bgp *bgp, struct peer *peer, |
struct stream *s, struct attr *attr, struct prefix *p, | struct stream *s, struct attr *attr, |
afi_t afi, safi_t safi, struct peer *from, | struct prefix *p, afi_t afi, safi_t safi, |
struct prefix_rd *prd, u_char *tag) | struct peer *from, struct prefix_rd *prd, u_char *tag) |
{ |
{ |
size_t cp; |
size_t cp; |
size_t aspath_sizep; |
size_t aspath_sizep; |
Line 1998 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
Line 2611 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
/* Remember current pointer. */ |
/* Remember current pointer. */ |
cp = stream_get_endp (s); |
cp = stream_get_endp (s); |
|
|
|
if (p && !(afi == AFI_IP && safi == SAFI_UNICAST)) |
|
{ |
|
size_t mpattrlen_pos = 0; |
|
mpattrlen_pos = bgp_packet_mpattr_start(s, afi, safi, attr); |
|
bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag); |
|
bgp_packet_mpattr_end(s, mpattrlen_pos); |
|
} |
|
|
/* Origin attribute. */ |
/* Origin attribute. */ |
stream_putc (s, BGP_ATTR_FLAG_TRANS); |
stream_putc (s, BGP_ATTR_FLAG_TRANS); |
stream_putc (s, BGP_ATTR_ORIGIN); |
stream_putc (s, BGP_ATTR_ORIGIN); |
Line 2007 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
Line 2628 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
/* AS path attribute. */ |
/* AS path attribute. */ |
|
|
/* If remote-peer is EBGP */ |
/* If remote-peer is EBGP */ |
if (peer_sort (peer) == BGP_PEER_EBGP | if (peer->sort == BGP_PEER_EBGP |
&& (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED) |
&& (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED) |
|| attr->aspath->segments == NULL) |
|| attr->aspath->segments == NULL) |
&& (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))) |
&& (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))) |
Line 2023 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
Line 2644 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
} |
} |
else |
else |
{ |
{ |
aspath = aspath_add_seq (aspath, peer->local_as); | if (peer->change_local_as) { |
if (peer->change_local_as) | /* If replace-as is specified, we only use the change_local_as when |
| advertising routes. */ |
| if( ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ) { |
| aspath = aspath_add_seq (aspath, peer->local_as); |
| } |
aspath = aspath_add_seq (aspath, peer->change_local_as); |
aspath = aspath_add_seq (aspath, peer->change_local_as); |
|
} else { |
|
aspath = aspath_add_seq (aspath, peer->local_as); |
|
} |
} |
} |
} |
} |
else if (peer_sort (peer) == BGP_PEER_CONFED) | else if (peer->sort == BGP_PEER_CONFED) |
{ |
{ |
/* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */ |
/* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */ |
aspath = aspath_dup (attr->aspath); |
aspath = aspath_dup (attr->aspath); |
Line 2059 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
Line 2687 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
send_as4_path = 1; /* we'll do this later, at the correct place */ |
send_as4_path = 1; /* we'll do this later, at the correct place */ |
|
|
/* Nexthop attribute. */ |
/* Nexthop attribute. */ |
if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP) | if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP && |
| safi == SAFI_UNICAST) /* only write NH attr for unicast safi */ |
{ |
{ |
stream_putc (s, BGP_ATTR_FLAG_TRANS); |
stream_putc (s, BGP_ATTR_FLAG_TRANS); |
stream_putc (s, BGP_ATTR_NEXT_HOP); |
stream_putc (s, BGP_ATTR_NEXT_HOP); |
Line 2085 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
Line 2714 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
} |
} |
|
|
/* Local preference. */ |
/* Local preference. */ |
if (peer_sort (peer) == BGP_PEER_IBGP || | if (peer->sort == BGP_PEER_IBGP || |
peer_sort (peer) == BGP_PEER_CONFED) | peer->sort == BGP_PEER_CONFED) |
{ |
{ |
stream_putc (s, BGP_ATTR_FLAG_TRANS); |
stream_putc (s, BGP_ATTR_FLAG_TRANS); |
stream_putc (s, BGP_ATTR_LOCAL_PREF); |
stream_putc (s, BGP_ATTR_LOCAL_PREF); |
Line 2159 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
Line 2788 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
} |
} |
|
|
/* Route Reflector. */ |
/* Route Reflector. */ |
if (peer_sort (peer) == BGP_PEER_IBGP | if (peer->sort == BGP_PEER_IBGP |
&& from |
&& from |
&& peer_sort (from) == BGP_PEER_IBGP) | && from->sort == BGP_PEER_IBGP) |
{ |
{ |
/* Originator ID. */ |
/* Originator ID. */ |
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); |
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); |
Line 2199 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
Line 2828 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
} |
} |
} |
} |
|
|
#ifdef HAVE_IPV6 |
|
/* If p is IPv6 address put it into attribute. */ |
|
if (p->family == AF_INET6) |
|
{ |
|
unsigned long sizep; |
|
struct attr_extra *attre = attr->extra; |
|
|
|
assert (attr->extra); |
|
|
|
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); |
|
stream_putc (s, BGP_ATTR_MP_REACH_NLRI); |
|
sizep = stream_get_endp (s); |
|
stream_putc (s, 0); /* Marker: Attribute length. */ |
|
stream_putw (s, AFI_IP6); /* AFI */ |
|
stream_putc (s, safi); /* SAFI */ |
|
|
|
stream_putc (s, attre->mp_nexthop_len); |
|
|
|
if (attre->mp_nexthop_len == 16) |
|
stream_put (s, &attre->mp_nexthop_global, 16); |
|
else if (attre->mp_nexthop_len == 32) |
|
{ |
|
stream_put (s, &attre->mp_nexthop_global, 16); |
|
stream_put (s, &attre->mp_nexthop_local, 16); |
|
} |
|
|
|
/* SNPA */ |
|
stream_putc (s, 0); |
|
|
|
/* Prefix write. */ |
|
stream_put_prefix (s, p); |
|
|
|
/* Set MP attribute length. */ |
|
stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1); |
|
} |
|
#endif /* HAVE_IPV6 */ |
|
|
|
if (p->family == AF_INET && safi == SAFI_MULTICAST) |
|
{ |
|
unsigned long sizep; |
|
|
|
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); |
|
stream_putc (s, BGP_ATTR_MP_REACH_NLRI); |
|
sizep = stream_get_endp (s); |
|
stream_putc (s, 0); /* Marker: Attribute Length. */ |
|
stream_putw (s, AFI_IP); /* AFI */ |
|
stream_putc (s, SAFI_MULTICAST); /* SAFI */ |
|
|
|
stream_putc (s, 4); |
|
stream_put_ipv4 (s, attr->nexthop.s_addr); |
|
|
|
/* SNPA */ |
|
stream_putc (s, 0); |
|
|
|
/* Prefix write. */ |
|
stream_put_prefix (s, p); |
|
|
|
/* Set MP attribute length. */ |
|
stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1); |
|
} |
|
|
|
if (p->family == AF_INET && safi == SAFI_MPLS_VPN) |
|
{ |
|
unsigned long sizep; |
|
|
|
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); |
|
stream_putc (s, BGP_ATTR_MP_REACH_NLRI); |
|
sizep = stream_get_endp (s); |
|
stream_putc (s, 0); /* Length of this attribute. */ |
|
stream_putw (s, AFI_IP); /* AFI */ |
|
stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */ |
|
|
|
stream_putc (s, 12); |
|
stream_putl (s, 0); |
|
stream_putl (s, 0); |
|
stream_put (s, &attr->extra->mp_nexthop_global_in, 4); |
|
|
|
/* SNPA */ |
|
stream_putc (s, 0); |
|
|
|
/* Tag, RD, Prefix write. */ |
|
stream_putc (s, p->prefixlen + 88); |
|
stream_put (s, tag, 3); |
|
stream_put (s, prd->val, 8); |
|
stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); |
|
|
|
/* Set MP attribute length. */ |
|
stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1); |
|
} |
|
|
|
/* Extended Communities attribute. */ |
/* Extended Communities attribute. */ |
if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) |
if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) |
&& (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES))) |
&& (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES))) |
Line 2297 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
Line 2836 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
|
|
assert (attre); |
assert (attre); |
|
|
if (peer_sort (peer) == BGP_PEER_IBGP | if (peer->sort == BGP_PEER_IBGP |
|| peer_sort (peer) == BGP_PEER_CONFED) | || peer->sort == BGP_PEER_CONFED) |
{ |
{ |
if (attre->ecommunity->size * 8 > 255) |
if (attre->ecommunity->size * 8 > 255) |
{ |
{ |
Line 2401 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
Line 2940 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
stream_putl (s, attr->extra->aggregator_as); |
stream_putl (s, attr->extra->aggregator_as); |
stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr); |
stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr); |
} |
} |
| |
| if ((afi == AFI_IP || afi == AFI_IP6) && |
| (safi == SAFI_ENCAP || safi == SAFI_MPLS_VPN)) |
| { |
| /* Tunnel Encap attribute */ |
| bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_ENCAP); |
| } |
| |
/* Unknown transit attribute. */ |
/* Unknown transit attribute. */ |
if (attr->extra && attr->extra->transit) |
if (attr->extra && attr->extra->transit) |
stream_put (s, attr->extra->transit->val, attr->extra->transit->length); |
stream_put (s, attr->extra->transit->val, attr->extra->transit->length); |
Line 2410 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
Line 2956 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
return stream_get_endp (s) - cp; |
return stream_get_endp (s) - cp; |
} |
} |
|
|
bgp_size_t | size_t |
bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p, | bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi) |
afi_t afi, safi_t safi, struct prefix_rd *prd, | |
u_char *tag) | |
{ |
{ |
unsigned long cp; |
|
unsigned long attrlen_pnt; |
unsigned long attrlen_pnt; |
bgp_size_t size; |
|
|
|
cp = stream_get_endp (s); | /* Set extended bit always to encode the attribute length as 2 bytes */ |
| stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN); |
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); | |
stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI); |
stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI); |
|
|
attrlen_pnt = stream_get_endp (s); |
attrlen_pnt = stream_get_endp (s); |
stream_putc (s, 0); /* Length of this attribute. */ | stream_putw (s, 0); /* Length of this attribute. */ |
|
|
stream_putw (s, family2afi (p->family)); | stream_putw (s, afi); |
| stream_putc (s, (safi == SAFI_MPLS_VPN) ? SAFI_MPLS_LABELED_VPN : safi); |
| return attrlen_pnt; |
| } |
|
|
if (safi == SAFI_MPLS_VPN) | void |
{ | bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p, |
/* SAFI */ | afi_t afi, safi_t safi, struct prefix_rd *prd, |
stream_putc (s, BGP_SAFI_VPNV4); | u_char *tag) |
| { |
| bgp_packet_mpattr_prefix (s, afi, safi, p, prd, tag); |
| } |
|
|
/* prefix. */ | void |
stream_putc (s, p->prefixlen + 88); | bgp_packet_mpunreach_end (struct stream *s, size_t attrlen_pnt) |
stream_put (s, tag, 3); | { |
stream_put (s, prd->val, 8); | bgp_packet_mpattr_end (s, attrlen_pnt); |
stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); | |
} | |
else | |
{ | |
/* SAFI */ | |
stream_putc (s, safi); | |
| |
/* prefix */ | |
stream_put_prefix (s, p); | |
} | |
| |
/* Set MP attribute length. */ | |
size = stream_get_endp (s) - attrlen_pnt - 1; | |
stream_putc_at (s, attrlen_pnt, size); | |
| |
return stream_get_endp (s) - cp; | |
} |
} |
|
|
/* Initialization of attribute. */ |
/* Initialization of attribute. */ |
Line 2513 bgp_dump_routes_attr (struct stream *s, struct attr *a
|
Line 3044 bgp_dump_routes_attr (struct stream *s, struct attr *a
|
/* Nexthop attribute. */ |
/* Nexthop attribute. */ |
/* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */ |
/* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */ |
if(prefix != NULL |
if(prefix != NULL |
#ifdef HAVE_IPV6 |
|
&& prefix->family != AF_INET6 |
&& prefix->family != AF_INET6 |
#endif /* HAVE_IPV6 */ |
|
) |
) |
{ |
{ |
stream_putc (s, BGP_ATTR_FLAG_TRANS); |
stream_putc (s, BGP_ATTR_FLAG_TRANS); |
Line 2579 bgp_dump_routes_attr (struct stream *s, struct attr *a
|
Line 3108 bgp_dump_routes_attr (struct stream *s, struct attr *a
|
stream_put (s, attr->community->val, attr->community->size * 4); |
stream_put (s, attr->community->val, attr->community->size * 4); |
} |
} |
|
|
#ifdef HAVE_IPV6 |
|
/* Add a MP_NLRI attribute to dump the IPv6 next hop */ |
/* Add a MP_NLRI attribute to dump the IPv6 next hop */ |
if (prefix != NULL && prefix->family == AF_INET6 && attr->extra && |
if (prefix != NULL && prefix->family == AF_INET6 && attr->extra && |
(attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) ) |
(attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) ) |
Line 2611 bgp_dump_routes_attr (struct stream *s, struct attr *a
|
Line 3139 bgp_dump_routes_attr (struct stream *s, struct attr *a
|
/* Set MP attribute length. */ |
/* Set MP attribute length. */ |
stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1); |
stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1); |
} |
} |
#endif /* HAVE_IPV6 */ |
|
|
|
/* Return total size of attribute. */ |
/* Return total size of attribute. */ |
len = stream_get_endp (s) - cp - 2; |
len = stream_get_endp (s) - cp - 2; |