version 1.1.1.3, 2013/07/21 23:54:37
|
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 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 = array_size(attr_str); |
static const int attr_str_max = array_size(attr_str); |
|
|
Line 72 static const struct message attr_flag_str[] =
|
Line 76 static const struct message attr_flag_str[] =
|
/* bgp_attr_flags_diagnose() relies on this bit being last in this list */ |
/* bgp_attr_flags_diagnose() relies on this bit being last in this list */ |
{ BGP_ATTR_FLAG_EXTLEN, "Extended Length" }, |
{ 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; |
|
|
static void * |
static void * |
Line 204 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 280 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 298 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 333 bgp_attr_dup (struct attr *new, struct attr *orig)
|
Line 441 bgp_attr_dup (struct attr *new, struct attr *orig)
|
{ |
{ |
new->extra = extra; |
new->extra = extra; |
memset(new->extra, 0, sizeof(struct attr_extra)); |
memset(new->extra, 0, sizeof(struct attr_extra)); |
if (orig->extra) | if (orig->extra) { |
*new->extra = *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) |
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 379 attrhash_key_make (void *p)
|
Line 494 attrhash_key_make (void *p)
|
MIX(extra->aggregator_addr.s_addr); |
MIX(extra->aggregator_addr.s_addr); |
MIX(extra->weight); |
MIX(extra->weight); |
MIX(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 395 attrhash_key_make (void *p)
|
Line 511 attrhash_key_make (void *p)
|
if (extra->transit) |
if (extra->transit) |
MIX(transit_hash_key_make (extra->transit)); |
MIX(transit_hash_key_make (extra->transit)); |
|
|
#ifdef HAVE_IPV6 |
|
MIX(extra->mp_nexthop_len); |
MIX(extra->mp_nexthop_len); |
key = jhash(extra->mp_nexthop_global.s6_addr, 16, key); |
key = jhash(extra->mp_nexthop_global.s6_addr, 16, key); |
key = jhash(extra->mp_nexthop_local.s6_addr, 16, key); |
key = jhash(extra->mp_nexthop_local.s6_addr, 16, key); |
#endif /* HAVE_IPV6 */ |
|
} |
} |
|
|
return key; |
return key; |
Line 426 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 451 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 488 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 562 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 577 bgp_attr_default_intern (u_char origin)
|
Line 705 bgp_attr_default_intern (u_char origin)
|
struct attr attr; |
struct attr attr; |
struct attr *new; |
struct attr *new; |
|
|
|
memset (&attr, 0, sizeof (struct 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 620 bgp_attr_aggregate_intern (struct bgp *bgp, u_char ori
|
Line 751 bgp_attr_aggregate_intern (struct bgp *bgp, u_char ori
|
} |
} |
|
|
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); |
Line 645 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 703 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 713 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 792 bgp_attr_malformed (struct bgp_attr_parser_args *args,
|
Line 936 bgp_attr_malformed (struct bgp_attr_parser_args *args,
|
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; |
} |
} |
|
|
/* Find out what is wrong with the path attribute flag bits and log the error. |
/* Find out what is wrong with the path attribute flag bits and log the error. |
Line 1108 bgp_attr_nexthop (struct bgp_attr_parser_args *args)
|
Line 1252 bgp_attr_nexthop (struct bgp_attr_parser_args *args)
|
if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h)) |
if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h)) |
{ |
{ |
char buf[INET_ADDRSTRLEN]; |
char buf[INET_ADDRSTRLEN]; |
inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN); | inet_ntop (AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN); |
zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf); |
zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf); |
return bgp_attr_malformed (args, |
return bgp_attr_malformed (args, |
BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, |
BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, |
Line 1280 bgp_attr_munge_as4_attrs (struct peer *const peer,
|
Line 1424 bgp_attr_munge_as4_attrs (struct peer *const peer,
|
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 1360 bgp_attr_munge_as4_attrs (struct peer *const peer,
|
Line 1514 bgp_attr_munge_as4_attrs (struct peer *const peer,
|
/* 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) | newpath = aspath_reconcile_as4 (attr->aspath, as4_path); |
return BGP_ATTR_PARSE_PROCEED; | aspath_unintern (&attr->aspath); |
| attr->aspath = aspath_intern (newpath); |
newpath = aspath_reconcile_as4 (attr->aspath, as4_path); | |
aspath_unintern (&attr->aspath); | |
attr->aspath = aspath_intern (newpath); | |
} |
} |
return BGP_ATTR_PARSE_PROCEED; |
return BGP_ATTR_PARSE_PROCEED; |
} |
} |
Line 1463 bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
|
Line 1614 bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
|
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 peer *const peer = args->peer; |
struct attr *const attr = args->attr; |
struct attr *const attr = args->attr; |
Line 1481 bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
|
Line 1631 bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
|
{ |
{ |
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 1495 bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
|
Line 1645 bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
|
{ |
{ |
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 1512 bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
|
Line 1662 bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
|
stream_getl (s); /* RD low */ |
stream_getl (s); /* RD low */ |
stream_get (&attre->mp_nexthop_global_in, s, 4); |
stream_get (&attre->mp_nexthop_global_in, s, 4); |
break; |
break; |
#ifdef HAVE_IPV6 | case 24: |
| { |
| u_int32_t rd_high __attribute__((unused)); |
| u_int32_t rd_low __attribute__((unused)); |
| |
| rd_high = stream_getl (s); |
| rd_low = stream_getl (s); |
| } |
| /* fall through */ |
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 1534 bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
|
Line 1708 bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
|
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 1561 bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
|
Line 1734 bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
|
{ |
{ |
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 != SAFI_MPLS_LABELED_VPN) | |
{ | |
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 1582 bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
|
Line 1744 bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
|
|
|
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 |
} |
} |
Line 1595 bgp_mp_unreach_parse (struct bgp_attr_parser_args *arg
|
Line 1759 bgp_mp_unreach_parse (struct bgp_attr_parser_args *arg
|
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 peer *const peer = args->peer; |
|
struct attr *const attr = args->attr; |
const bgp_size_t length = args->length; |
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 != SAFI_MPLS_LABELED_VPN) |
|
{ |
|
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 1624 bgp_mp_unreach_parse (struct bgp_attr_parser_args *arg
|
Line 1781 bgp_mp_unreach_parse (struct bgp_attr_parser_args *arg
|
|
|
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; |
} |
} |
|
|
Line 1658 bgp_attr_ext_communities (struct bgp_attr_parser_args
|
Line 1817 bgp_attr_ext_communities (struct bgp_attr_parser_args
|
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 bgp_attr_parser_args *args) |
bgp_attr_unknown (struct bgp_attr_parser_args *args) |
Line 1724 bgp_attr_unknown (struct bgp_attr_parser_args *args)
|
Line 2001 bgp_attr_unknown (struct bgp_attr_parser_args *args)
|
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_receive() in bgp_packet.c. */ |
bgp_update_receive() in bgp_packet.c. */ |
bgp_attr_parse_ret_t |
bgp_attr_parse_ret_t |
Line 1741 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 1906 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
Line 2233 bgp_attr_parse (struct peer *peer, struct attr *attr,
|
case BGP_ATTR_EXT_COMMUNITIES: |
case BGP_ATTR_EXT_COMMUNITIES: |
ret = bgp_attr_ext_communities (&attr_args); |
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 (&attr_args); |
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 1918 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 1951 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 1965 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 1976 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, 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 2021 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 == 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 2076 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 2144 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 2284 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, SAFI_MPLS_LABELED_VPN); /* 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 2486 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 2495 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, SAFI_MPLS_LABELED_VPN); | 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 2598 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 2664 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 2696 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; |