version 1.1.1.1, 2012/02/21 17:26:12
|
version 1.1.1.3, 2013/07/21 23:54:37
|
Line 51 static const struct message attr_str [] =
|
Line 51 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 62 static const struct message attr_str [] =
|
Line 62 static const struct message attr_str [] =
|
{ BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" }, |
{ BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" }, |
{ BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" }, |
{ BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" }, |
}; |
}; |
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 const size_t attr_flag_str_max = array_size(attr_flag_str); |
|
|
static struct hash *cluster_hash; |
static struct hash *cluster_hash; |
|
|
Line 175 cluster_intern (struct cluster_list *cluster)
|
Line 185 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 235 transit_intern (struct transit *transit)
|
Line 243 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 312 bgp_attr_extra_get (struct attr *attr)
|
Line 318 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; |
|
} |
|
else if (orig->extra) |
|
{ |
new->extra = bgp_attr_extra_new(); |
new->extra = bgp_attr_extra_new(); |
*new->extra = *orig->extra; |
*new->extra = *orig->extra; |
} |
} |
Line 335 attr_unknown_count (void)
|
Line 358 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 373 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); |
} |
} |
|
|
if (attr->aspath) |
if (attr->aspath) |
Line 362 attrhash_key_make (void *p)
|
Line 386 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 |
#ifdef HAVE_IPV6 |
MIX(attr->extra->mp_nexthop_len); | MIX(extra->mp_nexthop_len); |
key = jhash(attr->extra->mp_nexthop_global.s6_addr, 16, key); | key = jhash(extra->mp_nexthop_global.s6_addr, 16, key); |
key = jhash(attr->extra->mp_nexthop_local.s6_addr, 16, key); | key = jhash(extra->mp_nexthop_local.s6_addr, 16, key); |
#endif /* HAVE_IPV6 */ |
#endif /* HAVE_IPV6 */ |
} |
} |
|
|
Line 552 bgp_attr_default_intern (u_char origin)
|
Line 576 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)); | |
attre = 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 593 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 619 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 |
#ifdef HAVE_IPV6 |
attre->mp_nexthop_len = IPV6_MAX_BYTELEN; | attre.mp_nexthop_len = IPV6_MAX_BYTELEN; |
#endif |
#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 648 bgp_attr_unintern_sub (struct attr *attr)
|
Line 668 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 703 bgp_attr_flush (struct attr *attr)
|
Line 725 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 764 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 778 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 786 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; |
} |
} |
|
|
/* 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 939 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 956 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 970 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 989 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 999 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 1011 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 1051 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 1065 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 1079 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_h, 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 1123 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 1149 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 1184 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 1208 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 1223 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 1244 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 1272 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) |
{ |
{ |
Line 1247 bgp_attr_munge_as4_attrs (struct peer *peer, struct at
|
Line 1302 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 1360 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)))) |
{ |
{ |
|
if (!attr->aspath) |
|
return BGP_ATTR_PARSE_PROCEED; |
|
|
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); |
Line 1332 bgp_attr_munge_as4_attrs (struct peer *peer, struct at
|
Line 1372 bgp_attr_munge_as4_attrs (struct peer *peer, struct at
|
|
|
/* 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 1391 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 1402 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 1428 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 1456 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; |
Line 1419 bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
|
Line 1465 bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
|
size_t start; |
size_t start; |
int ret; |
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 1459 bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
|
Line 1508 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 */ |
u_int32_t rd_high; | stream_getl (s); /* RD low */ |
u_int32_t rd_low; | stream_get (&attre->mp_nexthop_global_in, s, 4); |
| |
rd_high = stream_getl (s); | |
rd_low = stream_getl (s); | |
stream_get (&attre->mp_nexthop_global_in, s, 4); | |
} | |
break; |
break; |
#ifdef HAVE_IPV6 |
#ifdef HAVE_IPV6 |
case 16: |
case 16: |
Line 1520 bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
|
Line 1564 bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
|
return BGP_ATTR_PARSE_ERROR; |
return BGP_ATTR_PARSE_ERROR; |
} |
} |
|
|
if (safi != BGP_SAFI_VPNV4) | if (safi != SAFI_MPLS_LABELED_VPN) |
{ |
{ |
ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len); |
ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len); |
if (ret < 0) |
if (ret < 0) |
Line 1544 bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
|
Line 1588 bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
|
|
|
/* 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; |
Line 1552 bgp_mp_unreach_parse (struct peer *peer, bgp_size_t le
|
Line 1596 bgp_mp_unreach_parse (struct peer *peer, bgp_size_t le
|
safi_t safi; |
safi_t safi; |
u_int16_t withdraw_len; |
u_int16_t withdraw_len; |
int ret; |
int ret; |
|
struct peer *const peer = args->peer; |
|
const bgp_size_t length = args->length; |
|
|
s = peer->ibuf; |
s = peer->ibuf; |
|
|
Line 1564 bgp_mp_unreach_parse (struct peer *peer, bgp_size_t le
|
Line 1610 bgp_mp_unreach_parse (struct peer *peer, bgp_size_t le
|
|
|
withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE; |
withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE; |
|
|
if (safi != BGP_SAFI_VPNV4) | if (safi != SAFI_MPLS_LABELED_VPN) |
{ |
{ |
ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len); |
ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len); |
if (ret < 0) |
if (ret < 0) |
Line 1583 bgp_mp_unreach_parse (struct peer *peer, bgp_size_t le
|
Line 1629 bgp_mp_unreach_parse (struct peer *peer, bgp_size_t le
|
|
|
/* 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 1649 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); |
|
|
Line 1614 bgp_attr_ext_communities (struct peer *peer, bgp_size_
|
Line 1660 bgp_attr_ext_communities (struct peer *peer, bgp_size_
|
|
|
/* 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 1684 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 1676 bgp_attr_unknown (struct peer *peer, struct attr *attr
|
Line 1725 bgp_attr_unknown (struct peer *peer, struct attr *attr
|
} |
} |
|
|
/* 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 1720 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
Line 1769 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 1789 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 1829 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; |
default: |
default: |
ret = bgp_attr_unknown (peer, attr, flag, type, length, startp); | ret = bgp_attr_unknown (&attr_args); |
break; |
break; |
} |
} |
|
|
Line 1899 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
Line 1977 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
* 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. |
*/ |
*/ |
if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path, | if (bgp_attr_munge_as4_attrs (peer, attr, as4_path, |
as4_aggregator, &as4_aggregator_addr)) |
as4_aggregator, &as4_aggregator_addr)) |
{ |
{ |
if (as4_path) |
if (as4_path) |
Line 1931 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
Line 2009 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 1958 bgp_attr_check (struct peer *peer, struct attr *attr)
|
Line 2036 bgp_attr_check (struct peer *peer, struct attr *attr)
|
if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))) |
if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))) |
type = BGP_ATTR_NEXT_HOP; |
type = BGP_ATTR_NEXT_HOP; |
|
|
if (peer_sort (peer) == BGP_PEER_IBGP | if (peer->sort == BGP_PEER_IBGP |
&& ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) |
&& ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) |
type = BGP_ATTR_LOCAL_PREF; |
type = BGP_ATTR_LOCAL_PREF; |
|
|
Line 2007 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
Line 2085 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 2101 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 2085 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
Line 2170 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 2244 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 2269 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
Line 2354 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
sizep = stream_get_endp (s); |
sizep = stream_get_endp (s); |
stream_putc (s, 0); /* Length of this attribute. */ |
stream_putc (s, 0); /* Length of this attribute. */ |
stream_putw (s, AFI_IP); /* AFI */ |
stream_putw (s, AFI_IP); /* AFI */ |
stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */ | stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */ |
|
|
stream_putc (s, 12); |
stream_putc (s, 12); |
stream_putl (s, 0); |
stream_putl (s, 0); |
Line 2297 bgp_packet_attribute (struct bgp *bgp, struct peer *pe
|
Line 2382 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 2432 bgp_packet_withdraw (struct peer *peer, struct stream
|
Line 2517 bgp_packet_withdraw (struct peer *peer, struct stream
|
if (safi == SAFI_MPLS_VPN) |
if (safi == SAFI_MPLS_VPN) |
{ |
{ |
/* SAFI */ |
/* SAFI */ |
stream_putc (s, BGP_SAFI_VPNV4); | stream_putc (s, SAFI_MPLS_LABELED_VPN); |
|
|
/* prefix. */ |
/* prefix. */ |
stream_putc (s, p->prefixlen + 88); |
stream_putc (s, p->prefixlen + 88); |