From ab005298526f4b14126cae1a6461ad3d700af29c Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sat, 27 Nov 2010 22:48:34 +0000 Subject: bgpd: Rollback some of the changes made for invalid AS_PATH segment fix Some of the changes made in commit cddb8112b80fa9867156c637d63e6e79eeac67bb don't work particularly well for other changes that need to be made to address BGP attribute error handling problems. In particular, returning a pointer from complex attribute data parsing functions will not suffice to express the require range of return status conditions. * bgp_aspath.c: (assegments_parse) Rollback to a more minimal set of changes to fix the original problem. (aspath_parse) Slightly needless pushing around of code, and taking 2 parameters to say whether ot use 2 or 4 byte encoding seems unnecessary. * bgp_attr.c: (bgp_attr_as{,4}path) Rollback, in preparation for BGP attribute error handling update. --- bgpd/bgp_aspath.c | 131 +++++++++++++++++++++++++----------------------------- bgpd/bgp_aspath.h | 2 +- bgpd/bgp_attr.c | 100 ++++++++++++++++++----------------------- 3 files changed, 105 insertions(+), 128 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 5a73eeff..89a27531 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -671,78 +671,77 @@ aspath_hash_alloc (void *arg) return aspath; } -/* parse as-segment byte stream in struct assegment - * - * Returns NULL if the AS_PATH or AS4_PATH is not valid. - */ +/* parse as-segment byte stream in struct assegment */ static struct assegment * -assegments_parse (struct stream *s, size_t length, int use32bit, int as4_path) +assegments_parse (struct stream *s, size_t length, int use32bit) { struct assegment_header segh; struct assegment *seg, *prev = NULL, *head = NULL; + size_t bytes = 0; - assert (length > 0); /* does not expect empty AS_PATH or AS4_PATH */ + /* empty aspath (ie iBGP or somesuch) */ + if (length == 0) + return NULL; if (BGP_DEBUG (as4, AS4_SEGMENT)) zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu", (unsigned long) length); - - /* double check that length does not exceed stream */ - if (STREAM_READABLE(s) < length) + /* basic checks */ + if ((STREAM_READABLE(s) < length) + || (STREAM_READABLE(s) < AS_HEADER_SIZE) + || (length % AS16_VALUE_SIZE )) return NULL; - /* deal with each segment in turn */ - while (length > 0) + while (bytes < length) { int i; size_t seg_size; - /* softly softly, get the header first on its own */ - if (length >= AS_HEADER_SIZE) + if ((length - bytes) <= AS_HEADER_SIZE) { + if (head) + assegment_free_all (head); + return NULL; + } + + /* softly softly, get the header first on its own */ segh.type = stream_getc (s); segh.length = stream_getc (s); seg_size = ASSEGMENT_SIZE(segh.length, use32bit); - /* includes the header bytes */ if (BGP_DEBUG (as4, AS4_SEGMENT)) zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d", segh.type, segh.length); - switch (segh.type) - { - case AS_SEQUENCE: - case AS_SET: - break ; - - case AS_CONFED_SEQUENCE: - case AS_CONFED_SET: - if (!as4_path) - break ; - /* RFC4893 3: "invalid for the AS4_PATH attribute" */ - /* fall through */ - - default: /* reject unknown or invalid AS_PATH segment types */ - seg_size = 0 ; - } ; - } - else - seg_size = 0 ; - - /* Stop now if segment is not valid (discarding anything collected to date) - * - * RFC4271 4.3, Path Attributes, b) AS_PATH: - * - * "path segment value field contains one or more AS numbers" + /* check it.. */ + if ( ((bytes + seg_size) > length) + /* 1771bis 4.3b: seg length contains one or more */ + || (segh.length == 0) + /* Paranoia in case someone changes type of segment length. + * Shift both values by 0x10 to make the comparison operate + * on more, than 8 bits (otherwise it's a warning, bug #564). */ - if ((seg_size == 0) || (seg_size > length) || (segh.length == 0)) + || ((sizeof segh.length > 1) + && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX))) { + if (head) assegment_free_all (head); return NULL; } - length -= seg_size ; + switch (segh.type) + { + case AS_SEQUENCE: + case AS_SET: + case AS_CONFED_SEQUENCE: + case AS_CONFED_SET: + break; + default: + if (head) + assegment_free_all (head); + return NULL; + } /* now its safe to trust lengths */ seg = assegment_new (segh.type, segh.length); @@ -755,9 +754,11 @@ assegments_parse (struct stream *s, size_t length, int use32bit, int as4_path) for (i = 0; i < segh.length; i++) seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s); + bytes += seg_size; + if (BGP_DEBUG (as4, AS4_SEGMENT)) - zlog_debug ("[AS4SEG] Parse aspath segment: length left: %lu", - (unsigned long) length); + zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu", + (unsigned long) bytes); prev = seg; } @@ -765,42 +766,30 @@ assegments_parse (struct stream *s, size_t length, int use32bit, int as4_path) return assegment_normalise (head); } -/* AS path parse function -- parses AS_PATH and AS4_PATH attributes - * - * Requires: s -- stream, currently positioned before first segment - * of AS_PATH or AS4_PATH (ie after attribute header) - * length -- length of the value of the AS_PATH or AS4_PATH - * use32bit -- true <=> 4Byte ASN, otherwise 2Byte ASN - * as4_path -- true <=> AS4_PATH, otherwise AS_PATH - * - * Returns: if valid: address of struct aspath in the hash of known aspaths, - * with reference count incremented. - * else: NULL - * - * NB: empty AS path (length == 0) is valid. The returned struct aspath will - * have segments == NULL and str == zero length string (unique). - */ +/* AS path parse function. pnt is a pointer to byte stream and length + is length of byte stream. If there is same AS path in the the AS + path hash then return it else make new AS path structure. */ struct aspath * -aspath_parse (struct stream *s, size_t length, int use32bit, int as4_path) +aspath_parse (struct stream *s, size_t length, int use32bit) { struct aspath as; struct aspath *find; - /* Parse each segment and construct normalised list of struct assegment */ - memset (&as, 0, sizeof (struct aspath)); - if (length != 0) - { - as.segments = assegments_parse (s, length, use32bit, as4_path); + /* If length is odd it's malformed AS path. */ + /* Nit-picking: if (use32bit == 0) it is malformed if odd, + * otherwise its malformed when length is larger than 2 and (length-2) + * is not dividable by 4. + * But... this time we're lazy + */ + if (length % AS16_VALUE_SIZE ) + return NULL; - if (as.segments == NULL) - return NULL ; /* Invalid AS_PATH or AS4_PATH */ - } ; + memset (&as, 0, sizeof (struct aspath)); + as.segments = assegments_parse (s, length, use32bit); /* If already same aspath exist then return it. */ find = hash_get (ashash, &as, aspath_hash_alloc); - assert(find) ; /* valid aspath, so must find or create */ - /* aspath_hash_alloc dupes segments too. that probably could be * optimised out. */ @@ -808,6 +797,8 @@ aspath_parse (struct stream *s, size_t length, int use32bit, int as4_path) if (as.str) XFREE (MTYPE_AS_STR, as.str); + if (! find) + return NULL; find->refcnt++; return find; @@ -1631,7 +1622,7 @@ aspath_segment_add (struct aspath *as, int type) struct aspath * aspath_empty (void) { - return aspath_parse (NULL, 0, 1, 0); /* 32Bit ;-) not AS4_PATH */ + return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */ } struct aspath * diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index d63b914c..b8a5dfab 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -65,7 +65,7 @@ struct aspath /* Prototypes. */ extern void aspath_init (void); extern void aspath_finish (void); -extern struct aspath *aspath_parse (struct stream *, size_t, int, int); +extern struct aspath *aspath_parse (struct stream *, size_t, int); extern struct aspath *aspath_dup (struct aspath *); extern struct aspath *aspath_aggregate (struct aspath *, struct aspath *); extern struct aspath *aspath_prepend (struct aspath *, struct aspath *); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index e2b6054b..7a0ab560 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -746,78 +746,51 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, return 0; } -/* Parse AS path information. This function is wrapper of aspath_parse. - * - * Parses AS_PATH or AS4_PATH. - * - * Returns: if valid: address of struct aspath in the hash of known aspaths, - * with reference count incremented. - * else: NULL - * - * NB: empty AS path (length == 0) is valid. The returned struct aspath will - * have segments == NULL and str == zero length string (unique). - */ -static struct aspath * + +/* Parse AS path information. This function is wrapper of + aspath_parse. */ +static int bgp_attr_aspath (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp, int as4_path) + struct attr *attr, u_char flag, u_char *startp) { - u_char require ; - struct aspath *asp ; + bgp_size_t total; - /* Check the attribute flags */ - require = as4_path ? BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS - : BGP_ATTR_FLAG_TRANS ; + total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - if ((flag & (BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS)) != require) + /* Flag check. */ + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) + || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) { - const char* path_type ; - bgp_size_t total; - - path_type = as4_path ? "AS4_PATH" : "AS_PATH" ; - - if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)) zlog (peer->log, LOG_ERR, - "%s attribute flag isn't transitive %d", path_type, flag) ; - - if ((flag & BGP_ATTR_FLAG_OPTIONAL) != (require & BGP_ATTR_FLAG_OPTIONAL)) - zlog (peer->log, LOG_ERR, - "%s attribute flag must %sbe optional %d", path_type, - (flag & BGP_ATTR_FLAG_OPTIONAL) ? "not " : "", flag) ; - - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - + "As-Path attribute flag isn't transitive %d", flag); bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); + return -1; + } - return NULL ; - } ; - - /* Parse the AS_PATH/AS4_PATH body. - * - * For AS_PATH peer with AS4 => 4Byte ASN otherwise 2Byte ASN - * AS4_PATH 4Byte ASN + /* + * peer with AS4 => will get 4Byte ASnums + * otherwise, will get 16 Bit */ - asp = aspath_parse (peer->ibuf, length, - as4_path || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV), as4_path) ; + attr->aspath = aspath_parse (peer->ibuf, length, + CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)); - if (asp != NULL) - { - attr->flag |= ATTR_FLAG_BIT (as4_path ? BGP_ATTR_AS4_PATH - : BGP_ATTR_AS_PATH) ; - } - else + /* In case of IBGP, length will be zero. */ + if (! attr->aspath) { zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length); - - /* TODO: should BGP_NOTIFY_UPDATE_MAL_AS_PATH be sent for AS4_PATH ?? */ bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_AS_PATH); - } ; + return -1; + } + + /* Set aspath attribute flag. */ + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); - return asp ; + return 0; } static int bgp_attr_aspath_check( struct peer *peer, @@ -875,6 +848,21 @@ static int bgp_attr_aspath_check( struct peer *peer, } +/* Parse AS4 path information. This function is another wrapper of + aspath_parse. */ +static int +bgp_attr_as4_path (struct peer *peer, bgp_size_t length, + struct attr *attr, struct aspath **as4_path) +{ + *as4_path = aspath_parse (peer->ibuf, length, 1); + + /* Set aspath attribute flag. */ + if (as4_path) + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH); + + return 0; +} + /* Nexthop attribute. */ static int bgp_attr_nexthop (struct peer *peer, bgp_size_t length, @@ -1613,12 +1601,10 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, ret = bgp_attr_origin (peer, length, attr, flag, startp); break; case BGP_ATTR_AS_PATH: - attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0); - ret = attr->aspath ? 0 : -1 ; + ret = bgp_attr_aspath (peer, length, attr, flag, startp); break; case BGP_ATTR_AS4_PATH: - as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1); - ret = as4_path ? 0 : -1 ; + ret = bgp_attr_as4_path (peer, length, attr, &as4_path ); break; case BGP_ATTR_NEXT_HOP: ret = bgp_attr_nexthop (peer, length, attr, flag, startp); -- cgit v1.2.1 From f6f434b2822c453f898552537180a812538bd19e Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 23 Nov 2010 21:28:03 +0000 Subject: bgpd: Try fix extcommunity resource allocation probs, particularly with 'set extcom..' * Extended communities has some kind of resource allocation problem which causes a double-free if the 'set extcommunity ...' command is used. Try fix by properly interning extcommunities. Also, more generally, make unintern functions take a double pointer so they can NULL out callers references - a usefully defensive programming pattern for functions which make refs invalid. Sadly, this patch doesn't fix the problem entirely - crashes still occur on session clear. * bgp_ecommunity.h: (ecommunity_{free,unintern}) take double pointer args. * bgp_community.h: (community_unintern) ditto * bgp_attr.h: (bgp_attr_intern) ditto * bgp_aspath.h: (bgp_aspath.h) ditto * (general) update all callers of above * bgp_routemap.c: (route_set_ecommunity_{rt,soo}) intern the new extcom added to the attr, and unintern any old one. (route_set_ecommunity_{rt,soo}_compile) intern the extcom to be used for the route-map set. (route_set_ecommunity_*_free) unintern to match, instead of free (route_set_ecommunity_soo) Do as _rt does and don't just leak any pre-existing community, add to it (is additive right though?) --- bgpd/bgp_advertise.c | 10 ++++----- bgpd/bgp_aspath.c | 16 ++++++++------ bgpd/bgp_aspath.h | 2 +- bgpd/bgp_attr.c | 54 ++++++++++++++++++++++++---------------------- bgpd/bgp_attr.h | 2 +- bgpd/bgp_clist.c | 4 ++-- bgpd/bgp_community.c | 13 +++++------ bgpd/bgp_community.h | 2 +- bgpd/bgp_ecommunity.c | 33 ++++++++++++++-------------- bgpd/bgp_ecommunity.h | 4 ++-- bgpd/bgp_packet.c | 8 +++---- bgpd/bgp_route.c | 60 +++++++++++++++++++++++++-------------------------- bgpd/bgp_routemap.c | 27 ++++++++++++++++------- 13 files changed, 126 insertions(+), 109 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c index 87eb7ac7..666218fa 100644 --- a/bgpd/bgp_advertise.c +++ b/bgpd/bgp_advertise.c @@ -140,13 +140,13 @@ bgp_advertise_unintern (struct hash *hash, struct bgp_advertise_attr *baa) baa->refcnt--; if (baa->refcnt && baa->attr) - bgp_attr_unintern (baa->attr); + bgp_attr_unintern (&baa->attr); else { if (baa->attr) { hash_release (hash, baa); - bgp_attr_unintern (baa->attr); + bgp_attr_unintern (&baa->attr); } baa_free (baa); } @@ -319,7 +319,7 @@ bgp_adj_out_remove (struct bgp_node *rn, struct bgp_adj_out *adj, struct peer *peer, afi_t afi, safi_t safi) { if (adj->attr) - bgp_attr_unintern (adj->attr); + bgp_attr_unintern (&adj->attr); if (adj->adv) bgp_advertise_clean (peer, adj, afi, safi); @@ -339,7 +339,7 @@ bgp_adj_in_set (struct bgp_node *rn, struct peer *peer, struct attr *attr) { if (adj->attr != attr) { - bgp_attr_unintern (adj->attr); + bgp_attr_unintern (&adj->attr); adj->attr = bgp_attr_intern (attr); } return; @@ -355,7 +355,7 @@ bgp_adj_in_set (struct bgp_node *rn, struct peer *peer, struct attr *attr) void bgp_adj_in_remove (struct bgp_node *rn, struct bgp_adj_in *bai) { - bgp_attr_unintern (bai->attr); + bgp_attr_unintern (&bai->attr); BGP_ADJ_IN_DEL (rn, bai); peer_unlock (bai->peer); /* adj_in peer reference */ XFREE (MTYPE_BGP_ADJ_IN, bai); diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 89a27531..176a960e 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -340,19 +340,21 @@ aspath_free (struct aspath *aspath) /* Unintern aspath from AS path bucket. */ void -aspath_unintern (struct aspath *aspath) +aspath_unintern (struct aspath **aspath) { struct aspath *ret; + struct aspath *asp = *aspath; + + if (asp->refcnt) + asp->refcnt--; - if (aspath->refcnt) - aspath->refcnt--; - - if (aspath->refcnt == 0) + if (asp->refcnt == 0) { /* This aspath must exist in aspath hash table. */ - ret = hash_release (ashash, aspath); + ret = hash_release (ashash, asp); assert (ret != NULL); - aspath_free (aspath); + aspath_free (asp); + *aspath = NULL; } } diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index b8a5dfab..d55f9ce6 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -80,7 +80,7 @@ extern struct aspath *aspath_empty_get (void); extern struct aspath *aspath_str2aspath (const char *); extern void aspath_free (struct aspath *); extern struct aspath *aspath_intern (struct aspath *); -extern void aspath_unintern (struct aspath *); +extern void aspath_unintern (struct aspath **); extern const char *aspath_print (struct aspath *); extern void aspath_print_vty (struct vty *, const char *, struct aspath *, const char *); extern void aspath_print_all_vty (struct vty *); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 7a0ab560..0c5355b4 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -500,6 +500,7 @@ bgp_attr_intern (struct attr *attr) attre->ecommunity = ecommunity_intern (attre->ecommunity); else attre->ecommunity->refcnt++; + } if (attre->cluster) { @@ -516,10 +517,10 @@ bgp_attr_intern (struct attr *attr) attre->transit->refcnt++; } } - + find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc); find->refcnt++; - + return find; } @@ -561,7 +562,7 @@ bgp_attr_default_intern (u_char origin) new = bgp_attr_intern (&attr); bgp_attr_extra_free (&attr); - aspath_unintern (new->aspath); + aspath_unintern (&new->aspath); return new; } @@ -613,13 +614,13 @@ bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin, new = bgp_attr_intern (&attr); bgp_attr_extra_free (&attr); - aspath_unintern (new->aspath); + aspath_unintern (&new->aspath); return new; } /* Free bgp attribute and aspath. */ void -bgp_attr_unintern (struct attr *attr) +bgp_attr_unintern (struct attr **attr) { struct attr *ret; struct aspath *aspath; @@ -627,34 +628,35 @@ bgp_attr_unintern (struct attr *attr) struct ecommunity *ecommunity = NULL; struct cluster_list *cluster = NULL; struct transit *transit = NULL; - + /* Decrement attribute reference. */ - attr->refcnt--; - aspath = attr->aspath; - community = attr->community; - if (attr->extra) + (*attr)->refcnt--; + aspath = (*attr)->aspath; + community = (*attr)->community; + if ((*attr)->extra) { - ecommunity = attr->extra->ecommunity; - cluster = attr->extra->cluster; - transit = attr->extra->transit; + ecommunity = (*attr)->extra->ecommunity; + cluster = (*attr)->extra->cluster; + transit = (*attr)->extra->transit; } - + /* 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); - bgp_attr_extra_free (attr); - XFREE (MTYPE_ATTR, attr); + bgp_attr_extra_free (*attr); + XFREE (MTYPE_ATTR, *attr); + *attr = NULL; } /* aspath refcount shoud be decrement. */ if (aspath) - aspath_unintern (aspath); + aspath_unintern (&aspath); if (community) - community_unintern (community); + community_unintern (&community); if (ecommunity) - ecommunity_unintern (ecommunity); + ecommunity_unintern (&ecommunity); if (cluster) cluster_unintern (cluster); if (transit) @@ -671,8 +673,9 @@ bgp_attr_flush (struct attr *attr) if (attr->extra) { struct attr_extra *attre = attr->extra; + if (attre->ecommunity && ! attre->ecommunity->refcnt) - ecommunity_free (attre->ecommunity); + ecommunity_free (&attre->ecommunity); if (attre->cluster && ! attre->cluster->refcnt) cluster_free (attre->cluster); if (attre->transit && ! attre->transit->refcnt) @@ -840,7 +843,7 @@ static int bgp_attr_aspath_check( struct peer *peer, { aspath = aspath_dup (attr->aspath); aspath = aspath_add_seq (aspath, peer->change_local_as); - aspath_unintern (attr->aspath); + aspath_unintern (&attr->aspath); attr->aspath = aspath_intern (aspath); } @@ -1146,7 +1149,7 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) ) { newpath = aspath_reconcile_as4 (attr->aspath, as4_path); - aspath_unintern (attr->aspath); + aspath_unintern (&attr->aspath); attr->aspath = aspath_intern (newpath); } return 0; @@ -1707,8 +1710,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, */ if ( as4_path ) { - aspath_unintern( as4_path ); /* unintern - it is in the hash */ - as4_path = NULL; + aspath_unintern (&as4_path); /* unintern - it is in the hash */ /* The flag that we got this is still there, but that does not * do any trouble */ diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index af9dcf5e..3433a1a5 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -142,7 +142,7 @@ extern struct attr_extra *bgp_attr_extra_get (struct attr *); extern void bgp_attr_extra_free (struct attr *); extern void bgp_attr_dup (struct attr *, struct attr *); extern struct attr *bgp_attr_intern (struct attr *attr); -extern void bgp_attr_unintern (struct attr *); +extern void bgp_attr_unintern (struct attr **); extern void bgp_attr_flush (struct attr *); extern struct attr *bgp_attr_default_set (struct attr *attr, u_char); extern struct attr *bgp_attr_default_intern (u_char); diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index d6601674..6c9976e3 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -70,7 +70,7 @@ community_entry_free (struct community_entry *entry) if (entry->config) XFREE (MTYPE_ECOMMUNITY_STR, entry->config); if (entry->u.ecom) - ecommunity_free (entry->u.ecom); + ecommunity_free (&entry->u.ecom); break; case COMMUNITY_LIST_EXPANDED: case EXTCOMMUNITY_LIST_EXPANDED: @@ -806,7 +806,7 @@ extcommunity_list_unset (struct community_list_handler *ch, entry = community_list_entry_lookup (list, str, direct); if (ecom) - ecommunity_free (ecom); + ecommunity_free (&ecom); if (regex) bgp_regex_free (regex); diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index ae1d7a15..2ba45f6e 100644 --- a/bgpd/bgp_community.c +++ b/bgpd/bgp_community.c @@ -321,21 +321,22 @@ community_intern (struct community *com) /* Free community attribute. */ void -community_unintern (struct community *com) +community_unintern (struct community **com) { struct community *ret; - if (com->refcnt) - com->refcnt--; + if ((*com)->refcnt) + (*com)->refcnt--; /* Pull off from hash. */ - if (com->refcnt == 0) + if ((*com)->refcnt == 0) { /* Community value com must exist in hash. */ - ret = (struct community *) hash_release (comhash, com); + ret = (struct community *) hash_release (comhash, *com); assert (ret != NULL); - community_free (com); + community_free (*com); + *com = NULL; } } diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h index bc1e56ef..9e483770 100644 --- a/bgpd/bgp_community.h +++ b/bgpd/bgp_community.h @@ -57,7 +57,7 @@ extern void community_free (struct community *); extern struct community *community_uniq_sort (struct community *); extern struct community *community_parse (u_int32_t *, u_short); extern struct community *community_intern (struct community *); -extern void community_unintern (struct community *); +extern void community_unintern (struct community **); extern char *community_str (struct community *); extern unsigned int community_hash_make (struct community *); extern struct community *community_str2com (const char *); diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 8d5fa741..8d91c746 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -42,13 +42,14 @@ ecommunity_new (void) /* Allocate ecommunities. */ void -ecommunity_free (struct ecommunity *ecom) +ecommunity_free (struct ecommunity **ecom) { - if (ecom->val) - XFREE (MTYPE_ECOMMUNITY_VAL, ecom->val); - if (ecom->str) - XFREE (MTYPE_ECOMMUNITY_STR, ecom->str); - XFREE (MTYPE_ECOMMUNITY, ecom); + if ((*ecom)->val) + XFREE (MTYPE_ECOMMUNITY_VAL, (*ecom)->val); + if ((*ecom)->str) + XFREE (MTYPE_ECOMMUNITY_STR, (*ecom)->str); + XFREE (MTYPE_ECOMMUNITY, *ecom); + ecom = NULL; } /* Add a new Extended Communities value to Extended Communities @@ -197,7 +198,7 @@ ecommunity_intern (struct ecommunity *ecom) find = (struct ecommunity *) hash_get (ecomhash, ecom, hash_alloc_intern); if (find != ecom) - ecommunity_free (ecom); + ecommunity_free (&ecom); find->refcnt++; @@ -209,18 +210,18 @@ ecommunity_intern (struct ecommunity *ecom) /* Unintern Extended Communities Attribute. */ void -ecommunity_unintern (struct ecommunity *ecom) +ecommunity_unintern (struct ecommunity **ecom) { struct ecommunity *ret; - if (ecom->refcnt) - ecom->refcnt--; - + if ((*ecom)->refcnt) + (*ecom)->refcnt--; + /* Pull off from hash. */ - if (ecom->refcnt == 0) + if ((*ecom)->refcnt == 0) { /* Extended community must be in the hash. */ - ret = (struct ecommunity *) hash_release (ecomhash, ecom); + ret = (struct ecommunity *) hash_release (ecomhash, *ecom); assert (ret != NULL); ecommunity_free (ecom); @@ -516,7 +517,7 @@ ecommunity_str2com (const char *str, int type, int keyword_included) if (! keyword_included || keyword) { if (ecom) - ecommunity_free (ecom); + ecommunity_free (&ecom); return NULL; } keyword = 1; @@ -536,7 +537,7 @@ ecommunity_str2com (const char *str, int type, int keyword_included) if (! keyword) { if (ecom) - ecommunity_free (ecom); + ecommunity_free (&ecom); return NULL; } keyword = 0; @@ -549,7 +550,7 @@ ecommunity_str2com (const char *str, int type, int keyword_included) case ecommunity_token_unknown: default: if (ecom) - ecommunity_free (ecom); + ecommunity_free (&ecom); return NULL; } } diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 942fdc73..2f59dc40 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -67,13 +67,13 @@ struct ecommunity_val extern void ecommunity_init (void); extern void ecommunity_finish (void); -extern void ecommunity_free (struct ecommunity *); +extern void ecommunity_free (struct ecommunity **); extern struct ecommunity *ecommunity_parse (u_int8_t *, u_short); extern struct ecommunity *ecommunity_dup (struct ecommunity *); extern struct ecommunity *ecommunity_merge (struct ecommunity *, struct ecommunity *); extern struct ecommunity *ecommunity_intern (struct ecommunity *); extern int ecommunity_cmp (const void *, const void *); -extern void ecommunity_unintern (struct ecommunity *); +extern void ecommunity_unintern (struct ecommunity **); extern unsigned int ecommunity_hash_make (void *); extern struct ecommunity *ecommunity_str2com (const char *, int, int); extern char *ecommunity_ecom2str (struct ecommunity *, int); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 9102add7..dee0b51f 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -206,7 +206,7 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) /* Synchnorize attribute. */ if (adj->attr) - bgp_attr_unintern (adj->attr); + bgp_attr_unintern (&adj->attr); else peer->scount[afi][safi]++; @@ -1785,13 +1785,13 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) /* Everything is done. We unintern temporary structures which interned in bgp_attr_parse(). */ if (attr.aspath) - aspath_unintern (attr.aspath); + aspath_unintern (&attr.aspath); if (attr.community) - community_unintern (attr.community); + community_unintern (&attr.community); if (attr.extra) { if (attr.extra->ecommunity) - ecommunity_unintern (attr.extra->ecommunity); + ecommunity_unintern (&attr.extra->ecommunity); if (attr.extra->cluster) cluster_unintern (attr.extra->cluster); if (attr.extra->transit) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 13ff63ca..87cb677c 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -137,7 +137,7 @@ static void bgp_info_free (struct bgp_info *binfo) { if (binfo->attr) - bgp_attr_unintern (binfo->attr); + bgp_attr_unintern (&binfo->attr); bgp_info_extra_free (&binfo->extra); @@ -1802,14 +1802,14 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, /* Apply import policy. */ if (bgp_import_modifier (rsclient, peer, p, &new_attr, afi, safi) == RMAP_DENY) { - bgp_attr_unintern (attr_new2); + bgp_attr_unintern (&attr_new2); reason = "import-policy;"; goto filtered; } attr_new = bgp_attr_intern (&new_attr); - bgp_attr_unintern (attr_new2); + bgp_attr_unintern (&attr_new2); /* IPv4 unicast next hop check. */ if (afi == AFI_IP && safi == SAFI_UNICAST) @@ -1818,7 +1818,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, if (new_attr.nexthop.s_addr == 0 || ntohl (new_attr.nexthop.s_addr) >= 0xe0000000) { - bgp_attr_unintern (attr_new); + bgp_attr_unintern (&attr_new); reason = "martian next-hop;"; goto filtered; @@ -1848,7 +1848,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, p->prefixlen, rsclient->host); bgp_unlock_node (rn); - bgp_attr_unintern (attr_new); + bgp_attr_unintern (&attr_new); return; } @@ -1868,7 +1868,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); /* Update to new attribute. */ - bgp_attr_unintern (ri->attr); + bgp_attr_unintern (&ri->attr); ri->attr = attr_new; /* Update MPLS tag. */ @@ -2128,7 +2128,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, } bgp_unlock_node (rn); - bgp_attr_unintern (attr_new); + bgp_attr_unintern (&attr_new); bgp_attr_extra_free (&new_attr); return 0; @@ -2175,7 +2175,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, } /* Update to new attribute. */ - bgp_attr_unintern (ri->attr); + bgp_attr_unintern (&ri->attr); ri->attr = attr_new; /* Update MPLS tag. */ @@ -2467,7 +2467,7 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) } bgp_attr_extra_free (&attr); - aspath_unintern (aspath); + aspath_unintern (&aspath); } static void @@ -3215,7 +3215,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, bgp_attr_flush (&attr_tmp); /* Unintern original. */ - aspath_unintern (attr.aspath); + aspath_unintern (&attr.aspath); bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi); bgp_attr_extra_free (&attr); @@ -3242,8 +3242,8 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, bgp->peer_self->rmap_type = 0; - bgp_attr_unintern (attr_new); - aspath_unintern (attr.aspath); + bgp_attr_unintern (&attr_new); + aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi); @@ -3253,7 +3253,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, bgp->peer_self->rmap_type = 0; - bgp_attr_unintern (attr_new); + bgp_attr_unintern (&attr_new); attr_new = bgp_attr_intern (&new_attr); bgp_attr_extra_free (&new_attr); @@ -3268,8 +3268,8 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { bgp_unlock_node (rn); - bgp_attr_unintern (attr_new); - aspath_unintern (attr.aspath); + bgp_attr_unintern (&attr_new); + aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); return; } @@ -3281,14 +3281,14 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, /* Rewrite BGP route information. */ if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) bgp_info_restore(rn, ri); - bgp_attr_unintern (ri->attr); + bgp_attr_unintern (&ri->attr); ri->attr = attr_new; ri->uptime = bgp_clock (); /* Process change. */ bgp_process (bgp, rn, afi, safi); bgp_unlock_node (rn); - aspath_unintern (attr.aspath); + aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); return; } @@ -3313,7 +3313,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, bgp_process (bgp, rn, afi, safi); /* Unintern original. */ - aspath_unintern (attr.aspath); + aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); } @@ -3363,7 +3363,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, bgp_attr_flush (&attr_tmp); /* Unintern original. */ - aspath_unintern (attr.aspath); + aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); bgp_static_withdraw (bgp, p, afi, safi); return; @@ -3384,8 +3384,8 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { bgp_unlock_node (rn); - bgp_attr_unintern (attr_new); - aspath_unintern (attr.aspath); + bgp_attr_unintern (&attr_new); + aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); return; } @@ -3399,7 +3399,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, bgp_info_restore(rn, ri); else bgp_aggregate_decrement (bgp, p, ri, afi, safi); - bgp_attr_unintern (ri->attr); + bgp_attr_unintern (&ri->attr); ri->attr = attr_new; ri->uptime = bgp_clock (); @@ -3407,7 +3407,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, bgp_aggregate_increment (bgp, p, ri, afi, safi); bgp_process (bgp, rn, afi, safi); bgp_unlock_node (rn); - aspath_unintern (attr.aspath); + aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); return; } @@ -3435,7 +3435,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, bgp_process (bgp, rn, afi, safi); /* Unintern original. */ - aspath_unintern (attr.aspath); + aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); } @@ -5297,7 +5297,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop, bgp_attr_extra_free (&attr_new); /* Unintern original. */ - aspath_unintern (attr.aspath); + aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); bgp_redistribute_delete (p, type); return; @@ -5320,8 +5320,8 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop, if (attrhash_cmp (bi->attr, new_attr) && !CHECK_FLAG(bi->flags, BGP_INFO_REMOVED)) { - bgp_attr_unintern (new_attr); - aspath_unintern (attr.aspath); + bgp_attr_unintern (&new_attr); + aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); bgp_unlock_node (bn); return; @@ -5336,7 +5336,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop, bgp_info_restore(bn, bi); else bgp_aggregate_decrement (bgp, p, bi, afi, SAFI_UNICAST); - bgp_attr_unintern (bi->attr); + bgp_attr_unintern (&bi->attr); bi->attr = new_attr; bi->uptime = bgp_clock (); @@ -5344,7 +5344,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop, bgp_aggregate_increment (bgp, p, bi, afi, SAFI_UNICAST); bgp_process (bgp, bn, afi, SAFI_UNICAST); bgp_unlock_node (bn); - aspath_unintern (attr.aspath); + aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); return; } @@ -5366,7 +5366,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop, } /* Unintern original. */ - aspath_unintern (attr.aspath); + aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); } diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 81ff48db..451458b5 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1475,10 +1475,10 @@ route_set_ecommunity_rt (void *rule, struct prefix *prefix, else new_ecom = ecommunity_dup (ecom); - bgp_info->attr->extra->ecommunity = new_ecom; + bgp_info->attr->extra->ecommunity = ecommunity_intern (new_ecom); if (old_ecom) - ecommunity_free (old_ecom); + ecommunity_unintern (&old_ecom); bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); } @@ -1494,7 +1494,7 @@ route_set_ecommunity_rt_compile (const char *arg) ecom = ecommunity_str2com (arg, ECOMMUNITY_ROUTE_TARGET, 0); if (! ecom) return NULL; - return ecom; + return ecommunity_intern (ecom); } /* Free function for set community. */ @@ -1502,7 +1502,7 @@ static void route_set_ecommunity_rt_free (void *rule) { struct ecommunity *ecom = rule; - ecommunity_free (ecom); + ecommunity_unintern (&ecom); } /* Set community rule structure. */ @@ -1521,7 +1521,7 @@ static route_map_result_t route_set_ecommunity_soo (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { - struct ecommunity *ecom; + struct ecommunity *ecom, *old_ecom, *new_ecom; struct bgp_info *bgp_info; if (type == RMAP_BGP) @@ -1532,8 +1532,19 @@ route_set_ecommunity_soo (void *rule, struct prefix *prefix, if (! ecom) return RMAP_OKAY; + old_ecom = (bgp_attr_extra_get (bgp_info->attr))->ecommunity; + + if (old_ecom) + new_ecom = ecommunity_merge (ecommunity_dup (old_ecom), ecom); + else + new_ecom = ecommunity_dup (ecom); + + bgp_info->attr->extra->ecommunity = ecommunity_intern (new_ecom); + + if (old_ecom) + ecommunity_unintern (&old_ecom); + bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); - (bgp_attr_extra_get (bgp_info->attr))->ecommunity = ecommunity_dup (ecom); } return RMAP_OKAY; } @@ -1548,7 +1559,7 @@ route_set_ecommunity_soo_compile (const char *arg) if (! ecom) return NULL; - return ecom; + return ecommunity_intern (ecom); } /* Free function for set community. */ @@ -1556,7 +1567,7 @@ static void route_set_ecommunity_soo_free (void *rule) { struct ecommunity *ecom = rule; - ecommunity_free (ecom); + ecommunity_unintern (&ecom); } /* Set community rule structure. */ -- cgit v1.2.1 From b881c7074bb698aeb1b099175b325734fc6e44d2 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 23 Nov 2010 16:35:42 +0000 Subject: bgpd: Implement revised error handling for partial optional/trans. attributes * BGP error handling generally boils down to "reset session". This was fine when all BGP speakers pretty much understood all BGP messages. However the increasing deployment of new attribute types has shown this approach to cause problems, in particular where a new attribute type is "tunneled" over some speakers which do not understand it, and then arrives at a speaker which does but considers it malformed (e.g. corruption along the way, or because of early implementation bugs/interop issues). To mitigate this drafts before the IDR (likely to be adopted) propose to treat errors in partial (i.e. not understood by neighbour), optional transitive attributes, when received from eBGP peers, as withdrawing only the NLRIs in the affected UPDATE, rather than causing the entire session to be reset. See: http://tools.ietf.org/html/draft-scudder-idr-optional-transitive * bgp_aspath.c: (assegments_parse) Replace the "NULL means valid, 0-length OR an error" return value with an error code - instead taking pointer to result structure as arg. (aspath_parse) adjust to suit previous change, but here NULL really does mean error in the external interface. * bgp_attr.h (bgp_attr_parse) use an explictly typed and enumerated value to indicate return result. (bgp_attr_unintern_sub) cleans up just the members of an attr, but not the attr itself, for benefit of those who use a stack-local attr. * bgp_attr.c: (bgp_attr_unintern_sub) split out from bgp_attr_unintern (bgp_attr_unintern) as previous. (bgp_attr_malformed) helper function to centralise decisions on how to handle errors in attributes. (bgp_attr_{aspathlimit,origin,etc..}) Use bgp_attr_malformed. (bgp_attr_aspathlimit) Subcode for error specifc to this attr should be BGP_NOTIFY_UPDATE_OPT_ATTR_ERR. (bgp_attr_as4_path) be more rigorous about checks, ala bgp_attr_as_path. (bgp_attr_parse) Adjust to deal with the additional error level that bgp_attr_ parsers can raise, and also similarly return appropriate error back up to (bgp_update_receive). Try to avoid leaking as4_path. * bgp_packet.c: (bgp_update_receive) Adjust to deal with BGP_ATTR_PARSE_WITHDRAW error level from bgp_attr_parse, which should lead to a withdraw, by making the attribute parameter in call to (bgp_nlri_parse) conditional on the error, so the update case morphs also into a withdraw. Use bgp_attr_unintern_sub from above, instead of doing this itself. Fix error case returns which were not calling bgp_attr_unintern_sub and probably leaking memory. * tests/aspath_test.c: Fix to work for null return with bad segments --- bgpd/bgp_aspath.c | 26 +-- bgpd/bgp_attr.c | 497 +++++++++++++++++++++++++++++++++--------------------- bgpd/bgp_attr.h | 12 +- bgpd/bgp_packet.c | 76 ++++++--- 4 files changed, 378 insertions(+), 233 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 176a960e..ba4f5b48 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -674,8 +674,9 @@ aspath_hash_alloc (void *arg) } /* parse as-segment byte stream in struct assegment */ -static struct assegment * -assegments_parse (struct stream *s, size_t length, int use32bit) +static int +assegments_parse (struct stream *s, size_t length, + struct assegment **result, int use32bit) { struct assegment_header segh; struct assegment *seg, *prev = NULL, *head = NULL; @@ -683,7 +684,7 @@ assegments_parse (struct stream *s, size_t length, int use32bit) /* empty aspath (ie iBGP or somesuch) */ if (length == 0) - return NULL; + return 0; if (BGP_DEBUG (as4, AS4_SEGMENT)) zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu", @@ -692,7 +693,7 @@ assegments_parse (struct stream *s, size_t length, int use32bit) if ((STREAM_READABLE(s) < length) || (STREAM_READABLE(s) < AS_HEADER_SIZE) || (length % AS16_VALUE_SIZE )) - return NULL; + return -1; while (bytes < length) { @@ -703,7 +704,7 @@ assegments_parse (struct stream *s, size_t length, int use32bit) { if (head) assegment_free_all (head); - return NULL; + return -1; } /* softly softly, get the header first on its own */ @@ -729,7 +730,7 @@ assegments_parse (struct stream *s, size_t length, int use32bit) { if (head) assegment_free_all (head); - return NULL; + return -1; } switch (segh.type) @@ -742,7 +743,7 @@ assegments_parse (struct stream *s, size_t length, int use32bit) default: if (head) assegment_free_all (head); - return NULL; + return -1; } /* now its safe to trust lengths */ @@ -765,12 +766,16 @@ assegments_parse (struct stream *s, size_t length, int use32bit) prev = seg; } - return assegment_normalise (head); + *result = assegment_normalise (head); + return 0; } /* AS path parse function. pnt is a pointer to byte stream and length is length of byte stream. If there is same AS path in the the AS - path hash then return it else make new AS path structure. */ + path hash then return it else make new AS path structure. + + On error NULL is returned. + */ struct aspath * aspath_parse (struct stream *s, size_t length, int use32bit) { @@ -787,7 +792,8 @@ aspath_parse (struct stream *s, size_t length, int use32bit) return NULL; memset (&as, 0, sizeof (struct aspath)); - as.segments = assegments_parse (s, length, use32bit); + if (assegments_parse (s, length, &as.segments, use32bit) < 0) + return NULL; /* If already same aspath exist then return it. */ find = hash_get (ashash, &as, aspath_hash_alloc); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 0c5355b4..6eab5ae8 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -618,26 +618,50 @@ bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin, return new; } +/* Unintern just the sub-components of the attr, but not the attr */ +void +bgp_attr_unintern_sub (struct attr *attr) +{ + /* aspath refcount shoud be decrement. */ + if (attr->aspath) + aspath_unintern (&attr->aspath); + UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH); + + if (attr->community) + community_unintern (&attr->community); + UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES); + + if (attr->extra) + { + if (attr->extra->ecommunity) + ecommunity_unintern (&attr->extra->ecommunity); + UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES); + + if (attr->extra->cluster) + cluster_unintern (attr->extra->cluster); + UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST); + + if (attr->extra->transit) + transit_unintern (attr->extra->transit); + } +} + /* Free bgp attribute and aspath. */ void bgp_attr_unintern (struct attr **attr) { struct attr *ret; - struct aspath *aspath; - struct community *community; - struct ecommunity *ecommunity = NULL; - struct cluster_list *cluster = NULL; - struct transit *transit = NULL; + struct attr tmp; /* Decrement attribute reference. */ (*attr)->refcnt--; - aspath = (*attr)->aspath; - community = (*attr)->community; + + tmp = *(*attr); + if ((*attr)->extra) { - ecommunity = (*attr)->extra->ecommunity; - cluster = (*attr)->extra->cluster; - transit = (*attr)->extra->transit; + tmp.extra = bgp_attr_extra_new (); + memcpy (tmp.extra, (*attr)->extra, sizeof (struct attr_extra)); } /* If reference becomes zero then free attribute object. */ @@ -650,17 +674,7 @@ bgp_attr_unintern (struct attr **attr) *attr = NULL; } - /* aspath refcount shoud be decrement. */ - if (aspath) - aspath_unintern (&aspath); - if (community) - community_unintern (&community); - if (ecommunity) - ecommunity_unintern (&ecommunity); - if (cluster) - cluster_unintern (cluster); - if (transit) - transit_unintern (transit); + bgp_attr_unintern_sub (&tmp); } void @@ -683,8 +697,69 @@ bgp_attr_flush (struct attr *attr) } } +/* Implement draft-scudder-idr-optional-transitive behaviour and + * avoid resetting sessions for malformed attributes which are + * are partial/optional and hence where the error likely was not + * introduced by the sending neighbour. + */ +static bgp_attr_parse_ret_t +bgp_attr_malformed (struct peer *peer, u_char type, u_char flag, + u_char subcode, u_char *startp, bgp_size_t length) +{ + /* Only relax error handling for eBGP peers */ + if (peer_sort (peer) != BGP_PEER_EBGP) + { + bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode, + startp, length); + return BGP_ATTR_PARSE_ERROR; + + } + + switch (type) { + /* where an optional attribute is 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_AGGREGATOR: + case BGP_ATTR_ATOMIC_AGGREGATE: + return BGP_ATTR_PARSE_PROCEED; + + /* Core attributes, particularly ones which may influence route + * selection should always cause session resets + */ + case BGP_ATTR_ORIGIN: + case BGP_ATTR_AS_PATH: + case BGP_ATTR_NEXT_HOP: + case BGP_ATTR_MULTI_EXIT_DISC: + case BGP_ATTR_LOCAL_PREF: + case BGP_ATTR_COMMUNITIES: + case BGP_ATTR_ORIGINATOR_ID: + case BGP_ATTR_CLUSTER_LIST: + case BGP_ATTR_MP_REACH_NLRI: + case BGP_ATTR_MP_UNREACH_NLRI: + case BGP_ATTR_EXT_COMMUNITIES: + bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode, + startp, length); + return BGP_ATTR_PARSE_ERROR; + } + + /* Partial optional attributes that are malformed should not cause + * the whole session to be reset. Instead treat it as a withdrawal + * of the routes, if possible. + */ + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS) + && CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) + && CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) + return BGP_ATTR_PARSE_WITHDRAW; + + /* default to reset */ + return BGP_ATTR_PARSE_ERROR; +} + /* Get origin attribute of the update message. */ -static int +static bgp_attr_parse_ret_t bgp_attr_origin (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag, u_char *startp) { @@ -702,11 +777,9 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, { zlog (peer->log, LOG_ERR, "Origin attribute flag isn't transitive %d", flag); - bgp_notify_send_with_data (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - return -1; + return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); } /* If any recognized attribute has Attribute Length that conflicts @@ -718,10 +791,9 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, { zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d", length); - bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - startp, total); - return -1; + return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + startp, total); } /* Fetch origin attribute. */ @@ -736,12 +808,9 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, { zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d", attr->origin); - - bgp_notify_send_with_data (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_INVAL_ORIGIN, - startp, total); - return -1; + return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, + BGP_NOTIFY_UPDATE_INVAL_ORIGIN, + startp, total); } /* Set oring attribute flag. */ @@ -766,11 +835,9 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length, { zlog (peer->log, LOG_ERR, "As-Path attribute flag isn't transitive %d", flag); - bgp_notify_send_with_data (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - return -1; + return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); } /* @@ -783,21 +850,22 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length, /* In case of IBGP, length will be zero. */ if (! attr->aspath) { - zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length); - bgp_notify_send (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_MAL_AS_PATH); - return -1; + zlog (peer->log, LOG_ERR, + "Malformed AS path from %s, length is %d", + peer->host, length); + return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, + BGP_NOTIFY_UPDATE_MAL_AS_PATH, + NULL, 0); } /* Set aspath attribute flag. */ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); - return 0; + return BGP_ATTR_PARSE_PROCEED; } -static int bgp_attr_aspath_check( struct peer *peer, - struct attr *attr) +static bgp_attr_parse_ret_t +bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag) { /* These checks were part of bgp_attr_aspath, but with * as4 we should to check aspath things when @@ -816,10 +884,9 @@ static int bgp_attr_aspath_check( struct peer *peer, (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath))) { zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host); - bgp_notify_send (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_MAL_AS_PATH); - return -1; + return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, + BGP_NOTIFY_UPDATE_MAL_AS_PATH, + NULL, 0); } /* First AS check for EBGP. */ @@ -830,10 +897,9 @@ static int bgp_attr_aspath_check( struct peer *peer, { zlog (peer->log, LOG_ERR, "%s incorrect first AS (must be %u)", peer->host, peer->as); - bgp_notify_send (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_MAL_AS_PATH); - return -1; + return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, + BGP_NOTIFY_UPDATE_MAL_AS_PATH, + NULL, 0); } } @@ -847,27 +913,53 @@ static int bgp_attr_aspath_check( struct peer *peer, attr->aspath = aspath_intern (aspath); } - return 0; - + return BGP_ATTR_PARSE_PROCEED; } /* Parse AS4 path information. This function is another wrapper of aspath_parse. */ static int -bgp_attr_as4_path (struct peer *peer, bgp_size_t length, - struct attr *attr, struct aspath **as4_path) +bgp_attr_as4_path (struct peer *peer, bgp_size_t length, + struct attr *attr, u_char flag, u_char *startp, + struct aspath **as4_path) { + bgp_size_t total; + + 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, + "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); + /* In case of IBGP, length will be zero. */ + if (!*as4_path) + { + zlog (peer->log, LOG_ERR, + "Malformed AS4 path from %s, length is %d", + peer->host, length); + return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag, + BGP_NOTIFY_UPDATE_MAL_AS_PATH, + NULL, 0); + } + /* Set aspath attribute flag. */ if (as4_path) attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH); - return 0; + return BGP_ATTR_PARSE_PROCEED; } /* Nexthop attribute. */ -static int +static bgp_attr_parse_ret_t bgp_attr_nexthop (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag, u_char *startp) { @@ -881,11 +973,9 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length, { zlog (peer->log, LOG_ERR, "Origin attribute flag isn't transitive %d", flag); - bgp_notify_send_with_data (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - return -1; + return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); } /* Check nexthop attribute length. */ @@ -894,21 +984,19 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length, zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]", length); - bgp_notify_send_with_data (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - startp, total); - return -1; + return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + startp, total); } attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); - return 0; + return BGP_ATTR_PARSE_PROCEED; } /* MED atrribute. */ -static int +static bgp_attr_parse_ret_t bgp_attr_med (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag, u_char *startp) { @@ -921,23 +1009,21 @@ bgp_attr_med (struct peer *peer, bgp_size_t length, { zlog (peer->log, LOG_ERR, "MED attribute length isn't four [%d]", length); - - bgp_notify_send_with_data (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - startp, total); - return -1; + + return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + startp, total); } attr->med = stream_getl (peer->ibuf); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); - return 0; + return BGP_ATTR_PARSE_PROCEED; } /* Local preference attribute. */ -static int +static bgp_attr_parse_ret_t bgp_attr_local_pref (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag) { @@ -947,7 +1033,7 @@ bgp_attr_local_pref (struct peer *peer, bgp_size_t length, if (peer_sort (peer) == BGP_PEER_EBGP) { stream_forward_getp (peer->ibuf, length); - return 0; + return BGP_ATTR_PARSE_PROCEED; } if (length == 4) @@ -958,7 +1044,7 @@ bgp_attr_local_pref (struct peer *peer, bgp_size_t length, /* Set atomic aggregate flag. */ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); - return 0; + return BGP_ATTR_PARSE_PROCEED; } /* Atomic aggregate. */ @@ -970,16 +1056,15 @@ bgp_attr_atomic (struct peer *peer, bgp_size_t length, { zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length); - bgp_notify_send (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); - return -1; + return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + NULL, 0); } /* Set atomic aggregate flag. */ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); - return 0; + return BGP_ATTR_PARSE_PROCEED; } /* Aggregator attribute */ @@ -991,17 +1076,16 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length, struct attr_extra *attre = bgp_attr_extra_get (attr); /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */ - if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) ) + if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) wantedlen = 8; if (length != wantedlen) { zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length); - bgp_notify_send (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); - return -1; + return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + NULL, 0); } if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) ) @@ -1013,36 +1097,35 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length, /* Set atomic aggregate flag. */ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); - return 0; + return BGP_ATTR_PARSE_PROCEED; } /* New Aggregator attribute */ -static int +static bgp_attr_parse_ret_t bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length, - struct attr *attr, as_t *as4_aggregator_as, + struct attr *attr, u_char flag, + as_t *as4_aggregator_as, struct in_addr *as4_aggregator_addr) { if (length != 8) { zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length); - - bgp_notify_send (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); - return -1; + return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + NULL, 0); } *as4_aggregator_as = stream_getl (peer->ibuf); as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR); - return 0; + return BGP_ATTR_PARSE_PROCEED; } /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH. */ -static int -bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, +static bgp_attr_parse_ret_t +bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag, struct aspath *as4_path, as_t as4_aggregator, struct in_addr *as4_aggregator_addr) { @@ -1050,7 +1133,7 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, struct aspath *newpath; struct attr_extra *attre = attr->extra; - 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 * if given. @@ -1068,11 +1151,11 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, peer->host, "AS4 capable peer, yet it sent"); } - return 0; + return BGP_ATTR_PARSE_PROCEED; } - if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH)) - && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))) + 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, @@ -1084,10 +1167,9 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, zlog (peer->log, LOG_ERR, "%s BGP not AS4 capable peer sent AS4_PATH but" " no AS_PATH, cant do anything here", peer->host); - bgp_notify_send (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_MAL_ATTR); - return -1; + 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 @@ -1095,7 +1177,7 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, */ if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) ) { - if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) ) + if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) ) { assert (attre); @@ -1111,7 +1193,7 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, * Aggregating node and the AS_PATH is to be * constructed "as in all other cases" */ - if ( attre->aggregator_as != BGP_AS_TRANS ) + if (attre->aggregator_as != BGP_AS_TRANS) { /* ignore */ if ( BGP_DEBUG(as4, AS4)) @@ -1146,24 +1228,27 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, } /* need to reconcile NEW_AS_PATH and AS_PATH */ - if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) ) + if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH)))) { newpath = aspath_reconcile_as4 (attr->aspath, as4_path); aspath_unintern (&attr->aspath); attr->aspath = aspath_intern (newpath); } - return 0; + return BGP_ATTR_PARSE_PROCEED; } /* Community attribute. */ -static int +static bgp_attr_parse_ret_t bgp_attr_community (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag) + struct attr *attr, u_char flag, u_char *startp) { + bgp_size_t total + = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + if (length == 0) { attr->community = NULL; - return 0; + return BGP_ATTR_PARSE_PROCEED; } attr->community = @@ -1173,15 +1258,17 @@ bgp_attr_community (struct peer *peer, bgp_size_t length, stream_forward_getp (peer->ibuf, length); if (!attr->community) - return -1; + return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + startp, total); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); - return 0; + return BGP_ATTR_PARSE_PROCEED; } /* Originator ID attribute. */ -static int +static bgp_attr_parse_ret_t bgp_attr_originator_id (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag) { @@ -1189,10 +1276,9 @@ bgp_attr_originator_id (struct peer *peer, bgp_size_t length, { zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length); - bgp_notify_send (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); - return -1; + return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + NULL, 0); } (bgp_attr_extra_get (attr))->originator_id.s_addr @@ -1200,11 +1286,11 @@ bgp_attr_originator_id (struct peer *peer, bgp_size_t length, attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID); - return 0; + return BGP_ATTR_PARSE_PROCEED; } /* Cluster list attribute. */ -static int +static bgp_attr_parse_ret_t bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag) { @@ -1213,20 +1299,20 @@ bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, { zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length); - bgp_notify_send (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); - return -1; + return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + NULL, 0); } (bgp_attr_extra_get (attr))->cluster = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length); - - stream_forward_getp (peer->ibuf, length);; + + /* XXX: Fix cluster_parse to use stream API and then remove this */ + stream_forward_getp (peer->ibuf, length); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST); - return 0; + return BGP_ATTR_PARSE_PROCEED; } /* Multiprotocol reachability information parse. */ @@ -1253,7 +1339,7 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, { zlog_info ("%s: %s sent invalid length, %lu", __func__, peer->host, (unsigned long)length); - return -1; + return BGP_ATTR_PARSE_ERROR; } /* Load AFI, SAFI. */ @@ -1267,7 +1353,7 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, { zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute", __func__, peer->host, attre->mp_nexthop_len); - return -1; + return BGP_ATTR_PARSE_ERROR; } /* Nexthop length check. */ @@ -1315,14 +1401,14 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, default: zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d", __func__, peer->host, attre->mp_nexthop_len); - return -1; + return BGP_ATTR_PARSE_ERROR; } if (!LEN_LEFT) { zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)", __func__, peer->host); - return -1; + return BGP_ATTR_PARSE_ERROR; } { @@ -1338,7 +1424,7 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, { zlog_info ("%s: (%s) Failed to read NLRI", __func__, peer->host); - return -1; + return BGP_ATTR_PARSE_ERROR; } if (safi != BGP_SAFI_VPNV4) @@ -1348,7 +1434,7 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, { zlog_info ("%s: (%s) NLRI doesn't pass sanity check", __func__, peer->host); - return -1; + return BGP_ATTR_PARSE_ERROR; } } @@ -1359,7 +1445,7 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, stream_forward_getp (s, nlri_len); - return 0; + return BGP_ATTR_PARSE_PROCEED; #undef LEN_LEFT } @@ -1378,7 +1464,7 @@ bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length, #define BGP_MP_UNREACH_MIN_SIZE 3 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE)) - return -1; + return BGP_ATTR_PARSE_ERROR; afi = stream_getw (s); safi = stream_getc (s); @@ -1389,7 +1475,7 @@ bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length, { ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len); if (ret < 0) - return -1; + return BGP_ATTR_PARSE_ERROR; } mp_withdraw->afi = afi; @@ -1399,20 +1485,23 @@ bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length, stream_forward_getp (s, withdraw_len); - return 0; + return BGP_ATTR_PARSE_PROCEED; } /* Extended Community attribute. */ -static int +static bgp_attr_parse_ret_t bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag) + struct attr *attr, u_char flag, u_char *startp) { + bgp_size_t total + = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + if (length == 0) { if (attr->extra) attr->extra->ecommunity = NULL; /* Empty extcomm doesn't seem to be invalid per se */ - return 0; + return BGP_ATTR_PARSE_PROCEED; } (bgp_attr_extra_get (attr))->ecommunity = @@ -1421,15 +1510,17 @@ bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, stream_forward_getp (peer->ibuf, length); if (!attr->extra->ecommunity) - return -1; + return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES, + flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + startp, total); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); - return 0; + return BGP_ATTR_PARSE_PROCEED; } /* BGP unknown attribute treatment. */ -static int +static bgp_attr_parse_ret_t bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag, u_char type, bgp_size_t length, u_char *startp) { @@ -1455,20 +1546,17 @@ bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag, then the Error Subcode is set to Unrecognized Well-known Attribute. The Data field contains the unrecognized attribute (type, length and value). */ - if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) + if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) { - /* Adjust startp to do not include flag value. */ - bgp_notify_send_with_data (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_UNREC_ATTR, - startp, total); - return -1; + return bgp_attr_malformed (peer, type, flag, + BGP_NOTIFY_UPDATE_UNREC_ATTR, + startp, total); } /* Unrecognized non-transitive optional attributes must be quietly ignored and not passed along to other BGP peers. */ if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) - return 0; + return BGP_ATTR_PARSE_PROCEED; /* If a path with recognized transitive optional attribute is accepted and passed along to other BGP peers and the Partial bit @@ -1491,17 +1579,17 @@ bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag, memcpy (transit->val + transit->length, startp, total); transit->length += total; - return 0; + return BGP_ATTR_PARSE_PROCEED; } /* Read attribute of update packet. This function is called from bgp_update() in bgpd.c. */ -int +bgp_attr_parse_ret_t bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw) { int ret; - u_char flag; + u_char flag = 0; u_char type = 0; bgp_size_t length; u_char *startp, *endp; @@ -1518,7 +1606,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, /* End pointer of BGP attribute. */ endp = BGP_INPUT_PNT (peer) + size; - + /* Get attributes to the end of attribute length. */ while (BGP_INPUT_PNT (peer) < endp) { @@ -1534,7 +1622,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); - return -1; + return BGP_ATTR_PARSE_ERROR; } /* Fetch attribute flag and type. */ @@ -1554,7 +1642,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); - return -1; + return BGP_ATTR_PARSE_ERROR; } /* Check extended attribue length bit. */ @@ -1576,7 +1664,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); - return -1; + return BGP_ATTR_PARSE_ERROR; } /* Set type to bitmap to check duplicate attribute. `type' is @@ -1594,7 +1682,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); - return -1; + return BGP_ATTR_PARSE_ERROR; } /* OK check attribute and store it's value. */ @@ -1607,7 +1695,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, ret = bgp_attr_aspath (peer, length, attr, flag, startp); break; case BGP_ATTR_AS4_PATH: - ret = bgp_attr_as4_path (peer, length, attr, &as4_path ); + ret = bgp_attr_as4_path (peer, length, attr, flag, startp, &as4_path); break; case BGP_ATTR_NEXT_HOP: ret = bgp_attr_nexthop (peer, length, attr, flag, startp); @@ -1625,10 +1713,12 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, ret = bgp_attr_aggregator (peer, length, attr, flag); break; case BGP_ATTR_AS4_AGGREGATOR: - ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr); + ret = bgp_attr_as4_aggregator (peer, length, attr, flag, + &as4_aggregator, + &as4_aggregator_addr); break; case BGP_ATTR_COMMUNITIES: - ret = bgp_attr_community (peer, length, attr, flag); + ret = bgp_attr_community (peer, length, attr, flag, startp); break; case BGP_ATTR_ORIGINATOR_ID: ret = bgp_attr_originator_id (peer, length, attr, flag); @@ -1643,26 +1733,39 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, ret = bgp_mp_unreach_parse (peer, length, mp_withdraw); break; case BGP_ATTR_EXT_COMMUNITIES: - ret = bgp_attr_ext_communities (peer, length, attr, flag); + ret = bgp_attr_ext_communities (peer, length, attr, flag, startp); break; default: ret = bgp_attr_unknown (peer, attr, flag, type, length, startp); break; } - - /* If error occured immediately return to the caller. */ - if (ret < 0) + + /* If hard error occured immediately return to the caller. */ + if (ret == BGP_ATTR_PARSE_ERROR) { zlog (peer->log, LOG_WARNING, "%s: Attribute %s, parse error", peer->host, LOOKUP (attr_str, type)); - bgp_notify_send (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_MAL_ATTR); - return ret; + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_ATTR); + if (as4_path) + aspath_unintern (&as4_path); + return ret; } - + if (ret == BGP_ATTR_PARSE_WITHDRAW) + { + + zlog (peer->log, LOG_WARNING, + "%s: Attribute %s, parse error - treating as withdrawal", + peer->host, + LOOKUP (attr_str, type)); + if (as4_path) + aspath_unintern (&as4_path); + return ret; + } + /* Check the fetched length. */ if (BGP_INPUT_PNT (peer) != attr_endp) { @@ -1672,7 +1775,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); - return -1; + if (as4_path) + aspath_unintern (&as4_path); + return BGP_ATTR_PARSE_ERROR; } } @@ -1685,7 +1790,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); - return -1; + if (as4_path) + aspath_unintern (&as4_path); + return BGP_ATTR_PARSE_ERROR; } /* @@ -1699,16 +1806,20 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, * all attributes first, including these 32bit ones, and now, * afterwards, we look what and if something is to be done for as4. */ - if (bgp_attr_munge_as4_attrs (peer, attr, as4_path, + if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path, as4_aggregator, &as4_aggregator_addr)) - return -1; + { + if (as4_path) + aspath_unintern (&as4_path); + return BGP_ATTR_PARSE_ERROR; + } /* At this stage, we have done all fiddling with as4, and the * resulting info is in attr->aggregator resp. attr->aspath * so we can chuck as4_aggregator and as4_path alltogether in * order to save memory */ - if ( as4_path ) + if (as4_path) { aspath_unintern (&as4_path); /* unintern - it is in the hash */ /* The flag that we got this is still there, but that does not @@ -1725,10 +1836,10 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, * Finally do the checks on the aspath we did not do yet * because we waited for a potentially synthesized aspath. */ - 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 ); - if ( ret < 0 ) + ret = bgp_attr_aspath_check (peer, attr, flag); + if (ret != BGP_ATTR_PARSE_PROCEED) return ret; } @@ -1736,7 +1847,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, if (attr->extra && attr->extra->transit) attr->extra->transit = transit_intern (attr->extra->transit); - return 0; + return BGP_ATTR_PARSE_PROCEED; } /* Well-known attribute check. */ @@ -1767,9 +1878,9 @@ bgp_attr_check (struct peer *peer, struct attr *attr) BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MISS_ATTR, &type, 1); - return -1; + return BGP_ATTR_PARSE_ERROR; } - return 0; + return BGP_ATTR_PARSE_PROCEED; } int stream_put_prefix (struct stream *, struct prefix *); diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 3433a1a5..c0112514 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -132,16 +132,24 @@ struct transit #define ATTR_FLAG_BIT(X) (1 << ((X) - 1)) +typedef enum { + BGP_ATTR_PARSE_PROCEED = 0, + BGP_ATTR_PARSE_ERROR = -1, + BGP_ATTR_PARSE_WITHDRAW = -2, +} bgp_attr_parse_ret_t; + /* Prototypes. */ extern void bgp_attr_init (void); extern void bgp_attr_finish (void); -extern int bgp_attr_parse (struct peer *, struct attr *, bgp_size_t, - struct bgp_nlri *, struct bgp_nlri *); +extern bgp_attr_parse_ret_t bgp_attr_parse (struct peer *, struct attr *, + bgp_size_t, struct bgp_nlri *, + struct bgp_nlri *); extern int bgp_attr_check (struct peer *, struct attr *); extern struct attr_extra *bgp_attr_extra_get (struct attr *); extern void bgp_attr_extra_free (struct attr *); extern void bgp_attr_dup (struct attr *, struct attr *); extern struct attr *bgp_attr_intern (struct attr *attr); +extern void bgp_attr_unintern_sub (struct attr *); extern void bgp_attr_unintern (struct attr **); extern void bgp_attr_flush (struct attr *); extern struct attr *bgp_attr_default_set (struct attr *attr, u_char); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index dee0b51f..8de78c75 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1589,26 +1589,47 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) BGP_NOTIFY_UPDATE_MAL_ATTR); return -1; } + + /* Certain attribute parsing errors should not be considered bad enough + * to reset the session for, most particularly any partial/optional + * attributes that have 'tunneled' over speakers that don't understand + * them. Instead we withdraw only the prefix concerned. + * + * Complicates the flow a little though.. + */ + bgp_attr_parse_ret_t attr_parse_ret = BGP_ATTR_PARSE_PROCEED; + /* This define morphs the update case into a withdraw when lower levels + * have signalled an error condition where this is best. + */ +#define NLRI_ATTR_ARG (attr_parse_ret != BGP_ATTR_PARSE_WITHDRAW ? &attr : NULL) /* Parse attribute when it exists. */ if (attribute_len) { - ret = bgp_attr_parse (peer, &attr, attribute_len, + attr_parse_ret = bgp_attr_parse (peer, &attr, attribute_len, &mp_update, &mp_withdraw); - if (ret < 0) + if (attr_parse_ret == BGP_ATTR_PARSE_ERROR) return -1; } - + /* Logging the attribute. */ - if (BGP_DEBUG (update, UPDATE_IN)) + if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW + || BGP_DEBUG (update, UPDATE_IN)) { ret= bgp_dump_attr (peer, &attr, attrstr, BUFSIZ); + int lvl = (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) + ? LOG_ERR : LOG_DEBUG; + + if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) + zlog (peer->log, LOG_ERR, + "%s rcvd UPDATE with errors in attr(s)!! Withdrawing route.", + peer->host); if (ret) - zlog (peer->log, LOG_DEBUG, "%s rcvd UPDATE w/ attr: %s", + zlog (peer->log, lvl, "%s rcvd UPDATE w/ attr: %s", peer->host, attrstr); } - + /* Network Layer Reachability Information. */ update_len = end - stream_pnt (s); @@ -1617,7 +1638,12 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) /* Check NLRI packet format and prefix length. */ ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), update_len); if (ret < 0) - return -1; + { + bgp_attr_unintern_sub (&attr); + if (attr.extra) + bgp_attr_extra_free (&attr); + return -1; + } /* Set NLRI portion to structure. */ update.afi = AFI_IP; @@ -1640,15 +1666,20 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) update. */ ret = bgp_attr_check (peer, &attr); if (ret < 0) - return -1; + { + bgp_attr_unintern_sub (&attr); + if (attr.extra) + bgp_attr_extra_free (&attr); + return -1; + } - bgp_nlri_parse (peer, &attr, &update); + bgp_nlri_parse (peer, NLRI_ATTR_ARG, &update); } if (mp_update.length && mp_update.afi == AFI_IP && mp_update.safi == SAFI_UNICAST) - bgp_nlri_parse (peer, &attr, &mp_update); + bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP @@ -1675,7 +1706,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (mp_update.length && mp_update.afi == AFI_IP && mp_update.safi == SAFI_MULTICAST) - bgp_nlri_parse (peer, &attr, &mp_update); + bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP @@ -1705,7 +1736,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (mp_update.length && mp_update.afi == AFI_IP6 && mp_update.safi == SAFI_UNICAST) - bgp_nlri_parse (peer, &attr, &mp_update); + bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP6 @@ -1734,7 +1765,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (mp_update.length && mp_update.afi == AFI_IP6 && mp_update.safi == SAFI_MULTICAST) - bgp_nlri_parse (peer, &attr, &mp_update); + bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP6 @@ -1762,7 +1793,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (mp_update.length && mp_update.afi == AFI_IP && mp_update.safi == BGP_SAFI_VPNV4) - bgp_nlri_parse_vpnv4 (peer, &attr, &mp_update); + bgp_nlri_parse_vpnv4 (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP @@ -1784,21 +1815,10 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) /* Everything is done. We unintern temporary structures which interned in bgp_attr_parse(). */ - if (attr.aspath) - aspath_unintern (&attr.aspath); - if (attr.community) - community_unintern (&attr.community); + bgp_attr_unintern_sub (&attr); if (attr.extra) - { - if (attr.extra->ecommunity) - ecommunity_unintern (&attr.extra->ecommunity); - if (attr.extra->cluster) - cluster_unintern (attr.extra->cluster); - if (attr.extra->transit) - transit_unintern (attr.extra->transit); - bgp_attr_extra_free (&attr); - } - + bgp_attr_extra_free (&attr); + /* If peering is stopped due to some reason, do not generate BGP event. */ if (peer->status != Established) -- cgit v1.2.1 From 94431dbc753171b48b5c6806af97fd690813b00a Mon Sep 17 00:00:00 2001 From: CROSS Date: Mon, 26 Sep 2011 13:17:05 +0400 Subject: bgpd: CVE-2011-3327 (ext. comm. buffer overflow) This vulnerability (CERT-FI #513254) was reported by CROSS project. They have also suggested a fix to the problem, which was found acceptable. The problem occurs when bgpd receives an UPDATE message containing 255 unknown AS_PATH attributes in Path Attribute Extended Communities. This causes a buffer overlow in bgpd. * bgp_ecommunity.c * ecommunity_ecom2str(): perform size check earlier --- bgpd/bgp_ecommunity.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 8d91c746..440c15a4 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -620,6 +620,13 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format) for (i = 0; i < ecom->size; i++) { + /* Make it sure size is enough. */ + while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size) + { + str_size *= 2; + str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size); + } + /* Space between each value. */ if (! first) str_buf[str_pnt++] = ' '; @@ -663,13 +670,6 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format) break; } - /* Make it sure size is enough. */ - while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size) - { - str_size *= 2; - str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size); - } - /* Put string into buffer. */ if (encode == ECOMMUNITY_ENCODE_AS4) { -- cgit v1.2.1 From d68ab1009f42c5ed62f7c6b0b5700f5f0469a35b Mon Sep 17 00:00:00 2001 From: heasley Date: Tue, 12 Jul 2011 20:09:18 +0400 Subject: bgpd: consistent log msg format (BZ#565) --- bgpd/bgp_attr.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index d43c104f..0af240e2 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1615,7 +1615,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, { /* XXX warning: long int format, int arg (arg 5) */ zlog (peer->log, LOG_WARNING, - "%s error BGP attribute length %lu is smaller than min len", + "%s: error BGP attribute length %lu is smaller than min len", peer->host, (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer)))); @@ -1635,7 +1635,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1))) { zlog (peer->log, LOG_WARNING, - "%s Extended length set, but just %lu bytes of attr header", + "%s: Extended length set, but just %lu bytes of attr header", peer->host, (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer)))); @@ -1658,7 +1658,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, if (CHECK_BITMAP (seen, type)) { zlog (peer->log, LOG_WARNING, - "%s error BGP attribute type %d appears twice in a message", + "%s: error BGP attribute type %d appears twice in a message", peer->host, type); bgp_notify_send (peer, @@ -1678,7 +1678,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, if (attr_endp > endp) { zlog (peer->log, LOG_WARNING, - "%s BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p", peer->host, type, length, size, attr_endp, endp); + "%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p", peer->host, type, length, size, attr_endp, endp); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); @@ -1785,7 +1785,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, if (BGP_INPUT_PNT (peer) != endp) { zlog (peer->log, LOG_WARNING, - "%s BGP attribute %s, length mismatch", + "%s: BGP attribute %s, length mismatch", peer->host, LOOKUP (attr_str, type)); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, -- cgit v1.2.1 From 1212dc1961e81d5ef6e576b854e979ea29284f51 Mon Sep 17 00:00:00 2001 From: heasley Date: Mon, 12 Sep 2011 13:27:52 +0400 Subject: bgpd: add useful notification logs (BZ#616) * bgp_packet.c * bgp_notify_send_with_data(): add calls to zlog_info() --- bgpd/bgp_packet.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 1d9fcc97..2623cc29 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -895,12 +895,25 @@ bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code, if (sub_code != BGP_NOTIFY_CEASE_CONFIG_CHANGE) { if (sub_code == BGP_NOTIFY_CEASE_ADMIN_RESET) - peer->last_reset = PEER_DOWN_USER_RESET; + { + peer->last_reset = PEER_DOWN_USER_RESET; + zlog_info ("Notification sent to neighbor %s: User reset", peer->host); + } else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN) - peer->last_reset = PEER_DOWN_USER_SHUTDOWN; + { + peer->last_reset = PEER_DOWN_USER_SHUTDOWN; + zlog_info ("Notification sent to neighbor %s: shutdown", peer->host); + } else - peer->last_reset = PEER_DOWN_NOTIFY_SEND; + { + peer->last_reset = PEER_DOWN_NOTIFY_SEND; + zlog_info ("Notification sent to neighbor %s: type %u/%u", + peer->host, code, sub_code); + } } + else + zlog_info ("Notification sent to neighbor %s: configuration change", + peer->host); /* Call imidiately. */ BGP_WRITE_OFF (peer->t_write); -- cgit v1.2.1 From 0ea968d21f194b3960a73aa47a5b06f160632907 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Mon, 19 Sep 2011 16:30:47 +0400 Subject: bgpd: check LOCAL_PREF attribute flags (BZ#674) * bgp_attr.c * bgp_attr_local_pref(): accept extra argument, add checks for "optional" and "transitive" bits, log each error condition independently * bgp_attr_parse(): provide extra argument --- bgpd/bgp_attr.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 0af240e2..337ddb7c 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1025,8 +1025,33 @@ bgp_attr_med (struct peer *peer, bgp_size_t length, /* Local preference attribute. */ static bgp_attr_parse_ret_t bgp_attr_local_pref (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag) + struct attr *attr, u_char flag, u_char *startp) { + bgp_size_t 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 external peer, then this attribute MUST be ignored by the receiving speaker. */ @@ -1704,7 +1729,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, ret = bgp_attr_med (peer, length, attr, flag, startp); break; case BGP_ATTR_LOCAL_PREF: - ret = bgp_attr_local_pref (peer, length, attr, flag); + ret = bgp_attr_local_pref (peer, length, attr, flag, startp); break; case BGP_ATTR_ATOMIC_AGGREGATE: ret = bgp_attr_atomic (peer, length, attr, flag); -- cgit v1.2.1 From 2cfadf09a810e3b660a47a1eb898d0d7c8813c08 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Tue, 20 Sep 2011 10:54:25 +0400 Subject: bgpd: check MULTI_EXIT_DISC attr flags (BZ#677) * bgp_attr.c * bgp_attr_med(): add checks for "optional", "transitive" and "partial" bits, log each error condition independently --- bgpd/bgp_attr.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 337ddb7c..a9866994 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1004,6 +1004,38 @@ bgp_attr_med (struct peer *peer, bgp_size_t length, 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, + "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. */ if (length != 4) { -- cgit v1.2.1 From 9eba2ada189597fcb39c806bbbed414fecf20623 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Tue, 20 Sep 2011 14:43:50 +0400 Subject: bgpd: check ATOMIC_AGGREGATE attr flags (BZ#678) * bgp_attr.c * bgp_attr_atomic(): accept extra argument, add checks for "optional", "transitive" and "partial" bits, log each error condition independently * bgp_attr_parse(): provide extra argument --- bgpd/bgp_attr.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index a9866994..015ae59c 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1107,8 +1107,44 @@ bgp_attr_local_pref (struct peer *peer, bgp_size_t length, /* Atomic aggregate. */ static int bgp_attr_atomic (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag) + struct attr *attr, u_char flag, u_char *startp) { + bgp_size_t 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, + "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. */ if (length != 0) { zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length); @@ -1764,7 +1800,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, ret = bgp_attr_local_pref (peer, length, attr, flag, startp); break; case BGP_ATTR_ATOMIC_AGGREGATE: - ret = bgp_attr_atomic (peer, length, attr, flag); + ret = bgp_attr_atomic (peer, length, attr, flag, startp); break; case BGP_ATTR_AGGREGATOR: ret = bgp_attr_aggregator (peer, length, attr, flag); -- cgit v1.2.1 From 7ccf5e59c13773097dd551b8a7384b99b7f46927 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Sat, 10 Sep 2011 16:53:30 +0400 Subject: bgpd: spelling --- bgpd/bgp_packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bgpd') diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 2623cc29..ab0fa8f5 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -915,7 +915,7 @@ bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code, zlog_info ("Notification sent to neighbor %s: configuration change", peer->host); - /* Call imidiately. */ + /* Call immediately. */ BGP_WRITE_OFF (peer->t_write); bgp_write_notify (peer); -- cgit v1.2.1 From e6ec1c3648cf3304c1a36341487659aadb9dce95 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Sat, 10 Sep 2011 21:50:53 +0400 Subject: bgpd: spelling --- bgpd/bgp_vty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bgpd') diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index e7e7dba1..44c55f2a 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -3707,7 +3707,7 @@ peer_maximum_prefix_set_vty (struct vty *vty, const char *ip_str, afi_t afi, if (! peer) return CMD_WARNING; - VTY_GET_INTEGER ("maxmum number", max, num_str); + VTY_GET_INTEGER ("maximum number", max, num_str); if (threshold_str) threshold = atoi (threshold_str); else -- cgit v1.2.1 From 4b4e07d2d83bdbe46ccf4b4a2fd2aa3842370098 Mon Sep 17 00:00:00 2001 From: Dmitrij Tejblum Date: Wed, 21 Sep 2011 23:13:22 +0400 Subject: bgpd: don't be confused by "unspecific" subcode in the NOTIFY message. * bgp_debug.c (bgp_notify_open_msg, bgp_notify_update_msg, bgp_notify_cease_msg, bgp_notify_capability_msg): add messages for "unspecific" subcode. --- bgpd/bgp_debug.c | 4 ++++ bgpd/bgpd.h | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'bgpd') diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 26b35dfc..8e161864 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -105,6 +105,7 @@ static const int bgp_notify_head_msg_max = BGP_NOTIFY_HEADER_MAX; static const struct message bgp_notify_open_msg[] = { + { BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"}, { BGP_NOTIFY_OPEN_UNSUP_VERSION, "/Unsupported Version Number" }, { BGP_NOTIFY_OPEN_BAD_PEER_AS, "/Bad Peer AS"}, { BGP_NOTIFY_OPEN_BAD_BGP_IDENT, "/Bad BGP Identifier"}, @@ -117,6 +118,7 @@ static const int bgp_notify_open_msg_max = BGP_NOTIFY_OPEN_MAX; static const struct message bgp_notify_update_msg[] = { + { BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"}, { BGP_NOTIFY_UPDATE_MAL_ATTR, "/Malformed Attribute List"}, { BGP_NOTIFY_UPDATE_UNREC_ATTR, "/Unrecognized Well-known Attribute"}, { BGP_NOTIFY_UPDATE_MISS_ATTR, "/Missing Well-known Attribute"}, @@ -133,6 +135,7 @@ static const int bgp_notify_update_msg_max = BGP_NOTIFY_UPDATE_MAX; static const struct message bgp_notify_cease_msg[] = { + { BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"}, { BGP_NOTIFY_CEASE_MAX_PREFIX, "/Maximum Number of Prefixes Reached"}, { BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN, "/Administratively Shutdown"}, { BGP_NOTIFY_CEASE_PEER_UNCONFIG, "/Peer Unconfigured"}, @@ -146,6 +149,7 @@ static const int bgp_notify_cease_msg_max = BGP_NOTIFY_CEASE_MAX; static const struct message bgp_notify_capability_msg[] = { + { BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"}, { BGP_NOTIFY_CAPABILITY_INVALID_ACTION, "/Invalid Action Value" }, { BGP_NOTIFY_CAPABILITY_INVALID_LENGTH, "/Invalid Capability Length"}, { BGP_NOTIFY_CAPABILITY_MALFORMED_CODE, "/Malformed Capability Value"}, diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 4da19e71..d415814c 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -632,6 +632,8 @@ struct bgp_nlri #define BGP_NOTIFY_CAPABILITY_ERR 7 #define BGP_NOTIFY_MAX 8 +#define BGP_NOTIFY_SUBCODE_UNSPECIFIC 0 + /* BGP_NOTIFY_HEADER_ERR sub codes. */ #define BGP_NOTIFY_HEADER_NOT_SYNC 1 #define BGP_NOTIFY_HEADER_BAD_MESLEN 2 @@ -662,7 +664,7 @@ struct bgp_nlri #define BGP_NOTIFY_UPDATE_MAL_AS_PATH 11 #define BGP_NOTIFY_UPDATE_MAX 12 -/* BGP_NOTIFY_CEASE sub codes (draft-ietf-idr-cease-subcode-05). */ +/* BGP_NOTIFY_CEASE sub codes (RFC 4486). */ #define BGP_NOTIFY_CEASE_MAX_PREFIX 1 #define BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN 2 #define BGP_NOTIFY_CEASE_PEER_UNCONFIG 3 -- cgit v1.2.1 From beb1ca03bfe707d6d1fcad21fcbaa63af49c82f8 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Wed, 13 Jul 2011 16:53:13 +0400 Subject: bgpd: fix SAFI for for MPLS labeled VPN-IPv6 * bgpd.h: change value of BGP_SAFI_VPNV6 to 128 (RFC4659, BZ#659) * bgp_route.c: (bgp_table_stats_vty) fix length argument to strncmp() --- bgpd/bgp_route.c | 2 +- bgpd/bgpd.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index aabd264a..eaedbc4c 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -9381,7 +9381,7 @@ bgp_table_stats_vty (struct vty *vty, const char *name, safi = SAFI_UNICAST; else if (strncmp (safi_str, "vpnv4", 5) == 0) safi = BGP_SAFI_VPNV4; - else if (strncmp (safi_str, "vpnv6", 6) == 0) + else if (strncmp (safi_str, "vpnv6", 5) == 0) safi = BGP_SAFI_VPNV6; else { diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index d415814c..f396f726 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -729,7 +729,7 @@ struct bgp_nlri /* SAFI which used in open capability negotiation. */ #define BGP_SAFI_VPNV4 128 -#define BGP_SAFI_VPNV6 129 +#define BGP_SAFI_VPNV6 128 /* Max TTL value. */ #define TTL_MAX 255 -- cgit v1.2.1 From 42e6d745d105018a9469dabad65bd4cf942dcf3c Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Thu, 14 Jul 2011 12:36:19 +0400 Subject: bgpd: more SAFI fixes (with resolved conflict in bgpd/bgp_packet.c) Two macros resolving to the same integer constant broke a case block and a more thorough merge of BGP_SAFI_VPNV4 and BGP_SAFI_VPNV6 was performed. * bgpd.h: MPLS-labeled VPN SAFI is AFI-independent, switch to single * macro * bgp_capability_test.c: update test data * bgp_mp_attr_test.c: idem * bgp_route.c: (bgp_maximum_prefix_overflow, bgp_table_stats_vty) update macro and check conditions (where appropriate) * bgp_packet.c: (bgp_route_refresh_send, bgp_capability_send, bgp_update_receive, bgp_route_refresh_receive): idem * bgp_open.c: (bgp_capability_vty_out, bgp_afi_safi_valid_indices, bgp_open_capability_orf, bgp_open_capability): idem * bgp_attr.c: (bgp_mp_reach_parse, bgp_packet_attribute, bgp_packet_withdraw): idem --- bgpd/bgp_attr.c | 8 ++++---- bgpd/bgp_open.c | 21 ++++++--------------- bgpd/bgp_packet.c | 14 +++++++------- bgpd/bgp_route.c | 15 +++------------ bgpd/bgpd.h | 5 ++--- 5 files changed, 22 insertions(+), 41 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 015ae59c..d1ba0dac 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1520,7 +1520,7 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, 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); if (ret < 0) @@ -1564,7 +1564,7 @@ bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length, 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); if (ret < 0) @@ -2269,7 +2269,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, sizep = stream_get_endp (s); stream_putc (s, 0); /* Length of this attribute. */ stream_putw (s, AFI_IP); /* AFI */ - stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */ + stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */ stream_putc (s, 12); stream_putl (s, 0); @@ -2432,7 +2432,7 @@ bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p, if (safi == SAFI_MPLS_VPN) { /* SAFI */ - stream_putc (s, BGP_SAFI_VPNV4); + stream_putc (s, SAFI_MPLS_LABELED_VPN); /* prefix. */ stream_putc (s, p->prefixlen + 88); diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 37595817..21c7e367 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -96,8 +96,8 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer) case SAFI_UNICAST_MULTICAST: vty_out (vty, "SAFI Unicast Multicast"); break; - case BGP_SAFI_VPNV4: - vty_out (vty, "SAFI MPLS-VPN"); + case SAFI_MPLS_LABELED_VPN: + vty_out (vty, "SAFI MPLS-labeled VPN"); break; default: vty_out (vty, "SAFI Unknown %d ", mpc.safi); @@ -127,14 +127,6 @@ bgp_capability_mp_data (struct stream *s, struct capability_mp_data *mpc) int bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi) { - /* VPNvX are AFI specific */ - if ((afi == AFI_IP6 && *safi == BGP_SAFI_VPNV4) - || (afi == AFI_IP && *safi == BGP_SAFI_VPNV6)) - { - zlog_warn ("Invalid afi/safi combination (%u/%u)", afi, *safi); - return 0; - } - switch (afi) { case AFI_IP: @@ -143,9 +135,8 @@ bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi) #endif switch (*safi) { - /* BGP VPNvX SAFI isn't contigious with others, remap */ - case BGP_SAFI_VPNV4: - case BGP_SAFI_VPNV6: + /* BGP MPLS-labeled VPN SAFI isn't contigious with others, remap */ + case SAFI_MPLS_LABELED_VPN: *safi = SAFI_MPLS_VPN; case SAFI_UNICAST: case SAFI_MULTICAST: @@ -859,7 +850,7 @@ bgp_open_capability_orf (struct stream *s, struct peer *peer, int number_of_orfs = 0; if (safi == SAFI_MPLS_VPN) - safi = BGP_SAFI_VPNV4; + safi = SAFI_MPLS_LABELED_VPN; stream_putc (s, BGP_OPEN_OPT_CAP); capp = stream_get_endp (s); /* Set Capability Len Pointer */ @@ -967,7 +958,7 @@ bgp_open_capability (struct stream *s, struct peer *peer) stream_putc (s, CAPABILITY_CODE_MP_LEN); stream_putw (s, AFI_IP); stream_putc (s, 0); - stream_putc (s, BGP_SAFI_VPNV4); + stream_putc (s, SAFI_MPLS_LABELED_VPN); } #ifdef HAVE_IPV6 /* IPv6 unicast. */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index ab0fa8f5..4854f1dd 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -946,7 +946,7 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi, /* Adjust safi code. */ if (safi == SAFI_MPLS_VPN) - safi = BGP_SAFI_VPNV4; + safi = SAFI_MPLS_LABELED_VPN; s = stream_new (BGP_MAX_PACKET_SIZE); @@ -1036,7 +1036,7 @@ bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi, /* Adjust safi code. */ if (safi == SAFI_MPLS_VPN) - safi = BGP_SAFI_VPNV4; + safi = SAFI_MPLS_LABELED_VPN; s = stream_new (BGP_MAX_PACKET_SIZE); @@ -1799,17 +1799,17 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) { if (mp_update.length && mp_update.afi == AFI_IP - && mp_update.safi == BGP_SAFI_VPNV4) + && mp_update.safi == SAFI_MPLS_LABELED_VPN) bgp_nlri_parse_vpnv4 (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == BGP_SAFI_VPNV4) + && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN) bgp_nlri_parse_vpnv4 (peer, NULL, &mp_withdraw); if (! withdraw_len && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == BGP_SAFI_VPNV4 + && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN && mp_withdraw.length == 0) { /* End-of-RIB received */ @@ -1969,7 +1969,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) /* Check AFI and SAFI. */ if ((afi != AFI_IP && afi != AFI_IP6) || (safi != SAFI_UNICAST && safi != SAFI_MULTICAST - && safi != BGP_SAFI_VPNV4)) + && safi != SAFI_MPLS_LABELED_VPN)) { if (BGP_DEBUG (normal, NORMAL)) { @@ -1980,7 +1980,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) } /* Adjust safi code. */ - if (safi == BGP_SAFI_VPNV4) + if (safi == SAFI_MPLS_LABELED_VPN) safi = SAFI_MPLS_VPN; if (size != BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index eaedbc4c..d2aedb61 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1659,7 +1659,7 @@ bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi, u_int8_t ndata[7]; if (safi == SAFI_MPLS_VPN) - safi = BGP_SAFI_VPNV4; + safi = SAFI_MPLS_LABELED_VPN; ndata[0] = (afi >> 8); ndata[1] = afi; @@ -9379,10 +9379,8 @@ bgp_table_stats_vty (struct vty *vty, const char *name, safi = SAFI_MULTICAST; else if (strncmp (safi_str, "u", 1) == 0) safi = SAFI_UNICAST; - else if (strncmp (safi_str, "vpnv4", 5) == 0) - safi = BGP_SAFI_VPNV4; - else if (strncmp (safi_str, "vpnv6", 5) == 0) - safi = BGP_SAFI_VPNV6; + else if (strncmp (safi_str, "vpnv4", 5) == 0 || strncmp (safi_str, "vpnv6", 5) == 0) + safi = SAFI_MPLS_LABELED_VPN; else { vty_out (vty, "%% Invalid subsequent address family %s%s", @@ -9397,13 +9395,6 @@ bgp_table_stats_vty (struct vty *vty, const char *name, return CMD_WARNING; } - if ((afi == AFI_IP && safi == BGP_SAFI_VPNV6) - || (afi == AFI_IP6 && safi == BGP_SAFI_VPNV4)) - { - vty_out (vty, "%% Invalid subsequent address family %s for %s%s", - afi_str, safi_str, VTY_NEWLINE); - return CMD_WARNING; - } return bgp_table_stats (vty, bgp, afi, safi); } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index f396f726..892e7dec 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -727,9 +727,8 @@ struct bgp_nlri #define BGP_DEFAULT_RESTART_TIME 120 #define BGP_DEFAULT_STALEPATH_TIME 360 -/* SAFI which used in open capability negotiation. */ -#define BGP_SAFI_VPNV4 128 -#define BGP_SAFI_VPNV6 128 +/* RFC4364 */ +#define SAFI_MPLS_LABELED_VPN 128 /* Max TTL value. */ #define TTL_MAX 255 -- cgit v1.2.1 From 0a28130d35bbba47faf47bf9451ba0eb195fcbb7 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Sun, 17 Jul 2011 19:33:21 +0400 Subject: bgpd: rename SAFI 3 according to RFC4760 - SAFI value 3 is reserved. It was assigned by RFC 2858 for a use that was never fully implemented, so it is deprecated by this document. * zebra.h: rename macro * bgp_fsm.c: (bgp_graceful_restart_timer_expire, bgp_graceful_stale_timer_expire, bgp_stop, bgp_establish): update * bgpd.c: (peer_nsf_stop): update * bgp_open.c: (bgp_capability_vty_out): SAFI 3 isn't a recognized case any more --- bgpd/bgp_fsm.c | 8 ++++---- bgpd/bgp_open.c | 3 --- bgpd/bgpd.c | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 487ebddb..813e59ef 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -355,7 +355,7 @@ bgp_graceful_restart_timer_expire (struct thread *thread) /* NSF delete stale route */ for (afi = AFI_IP ; afi < AFI_MAX ; afi++) - for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++) + for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++) if (peer->nsf[afi][safi]) bgp_clear_stale_route (peer, afi, safi); @@ -388,7 +388,7 @@ bgp_graceful_stale_timer_expire (struct thread *thread) /* NSF delete stale route */ for (afi = AFI_IP ; afi < AFI_MAX ; afi++) - for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++) + for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++) if (peer->nsf[afi][safi]) bgp_clear_stale_route (peer, afi, safi); @@ -481,7 +481,7 @@ bgp_stop (struct peer *peer) UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE); for (afi = AFI_IP ; afi < AFI_MAX ; afi++) - for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++) + for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++) peer->nsf[afi][safi] = 0; } @@ -799,7 +799,7 @@ bgp_establish (struct peer *peer) /* graceful restart */ UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT); for (afi = AFI_IP ; afi < AFI_MAX ; afi++) - for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++) + for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++) { if (peer->afc_nego[afi][safi] && CHECK_FLAG (peer->cap, PEER_CAP_RESTART_ADV) diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 21c7e367..31b7369d 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -93,9 +93,6 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer) case SAFI_MULTICAST: vty_out (vty, "SAFI Multicast"); break; - case SAFI_UNICAST_MULTICAST: - vty_out (vty, "SAFI Unicast Multicast"); - break; case SAFI_MPLS_LABELED_VPN: vty_out (vty, "SAFI MPLS-labeled VPN"); break; diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index ee0cc5da..e8038553 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1147,7 +1147,7 @@ peer_nsf_stop (struct peer *peer) UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE); for (afi = AFI_IP ; afi < AFI_MAX ; afi++) - for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++) + for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++) peer->nsf[afi][safi] = 0; if (peer->t_gr_restart) -- cgit v1.2.1 From bc3443ebf032b5fcc9e0ccb94641e4e899cd17d8 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Thu, 22 Sep 2011 12:48:14 +0400 Subject: bgpd: improve NEXT_HOP attribute checks (BZ#680) * lib/prefix.h * IPV4_CLASS_DE(): new helper macro * bgp_attr.c * bgp_attr_nexthop(): add check for "partial" bit, refresh flag error reporting, explain meaning of RFC4271 section 6.3 and implement it Conflicts: bgpd/bgp_attr.c --- bgpd/bgp_attr.c | 45 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index d1ba0dac..6905ab52 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -964,15 +964,31 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag, u_char *startp) { bgp_size_t total; + 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)) + /* Flags check. */ + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) { - zlog (peer->log, LOG_ERR, - "Origin attribute flag isn't transitive %d", flag); + zlog (peer->log, LOG_ERR, + "NEXT_HOP attribute must not be flagged as \"optional\" (%u)", flag); + return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + } + if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) + { + zlog (peer->log, LOG_ERR, + "NEXT_HOP attribute must be flagged as \"transitive\" (%u)", flag); + return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + } + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) + { + zlog (peer->log, LOG_ERR, + "NEXT_HOP attribute must not be flagged as \"partial\" (%u)", flag); return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); @@ -989,7 +1005,24 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length, startp, 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 (peer, BGP_ATTR_NEXT_HOP, flag, + BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, + startp, total); + } + + attr->nexthop.s_addr = nexthop_n; attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); return BGP_ATTR_PARSE_PROCEED; -- cgit v1.2.1 From 214bcaa13e092d9fff8f233e62ba28ca7eefbc43 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Sat, 24 Sep 2011 13:20:43 +0400 Subject: bgpd: add missing "partial" flag checks (BZ#676) ORIGIN handling function used to have "partial" bit check and recent commits added it for NEXT_HOP, MULTI_EXIT_DISC and ATOMIC_AGGREGATE cases. This commit adds "partial" check for AS_PATH and LOCAL_PREF cases, which should leave attributes 1 through 6 inclusive completely covered with attribute flags checks. * bgp_attr.c * bgp_attr_origin(): use bit-by-bit checks for better diagnostics * bgp_attr_aspath(): add flag check * bgp_attr_local_pref(): idem Conflicts: bgpd/bgp_attr.c --- bgpd/bgp_attr.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 6905ab52..aa4ce8f1 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -773,14 +773,30 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, 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 (flag != BGP_ATTR_FLAG_TRANS) + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) { - zlog (peer->log, LOG_ERR, - "Origin attribute flag isn't transitive %d", flag); + zlog (peer->log, LOG_ERR, + "ORIGIN attribute must not be flagged as \"optional\" (%u)", flag); return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); } + if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) + { + zlog (peer->log, LOG_ERR, + "ORIGIN attribute must be flagged as \"transitive\" (%u)", flag); + return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + } + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) + { + zlog (peer->log, LOG_ERR, + "ORIGIN attribute must not be flagged as \"partial\" (%u)", flag); + return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + } /* If any recognized attribute has Attribute Length that conflicts with the expected length (based on the attribute type code), then @@ -830,6 +846,15 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length, total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* Flag check. */ + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) + { + zlog (peer->log, LOG_ERR, + "AS_PATH attribute must not be flagged as \"partial\" (%u)", flag); + return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + } + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) { @@ -1116,6 +1141,16 @@ bgp_attr_local_pref (struct peer *peer, bgp_size_t length, startp, total); return -1; } + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) + { + zlog (peer->log, LOG_ERR, + "LOCAL_PREF 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; + } /* If it is contained in an UPDATE message that is received from an external peer, then this attribute MUST be ignored by the -- cgit v1.2.1 From 2d42e68aa032ed2f11471aee444935918d35c8bb Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Tue, 27 Sep 2011 15:35:39 +0400 Subject: bgpd: ignore 4 bits of attribute flags byte --- bgpd/bgp_attr.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index aa4ce8f1..45a17fac 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1788,7 +1788,10 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, /* Fetch attribute flag and type. */ 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)); /* Check whether Extended-Length applies and is in bounds */ -- cgit v1.2.1 From b84b62dfb6ee9daf46c9e4c2c372b179f33be44c Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Tue, 27 Sep 2011 15:47:25 +0400 Subject: bgpd: improve attr flags checks Do not check each of the Optional/Transitive/Partial attribute flag bits, when their only valid combination is known in advance, but still perform bit-deep error message logging. This change assumes unused (low-order) 4 bits of the flag octet cleared. * bgp_attr.c * bgp_attr_origin(): rewrite check * bgp_attr_nexthop(): idem * bgp_attr_med(): idem * bgp_attr_local_pref(): idem * bgp_attr_atomic(): idem Conflicts: bgpd/bgp_attr.c --- bgpd/bgp_attr.c | 191 ++++++++++++++++---------------------------------------- 1 file changed, 53 insertions(+), 138 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 45a17fac..daf14bd4 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -773,30 +773,16 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, 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 (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) - { - zlog (peer->log, LOG_ERR, - "ORIGIN attribute must not be flagged as \"optional\" (%u)", flag); - return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - } - if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) - { - zlog (peer->log, LOG_ERR, - "ORIGIN attribute must be flagged as \"transitive\" (%u)", flag); - return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - } - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) - { - zlog (peer->log, LOG_ERR, - "ORIGIN attribute must not be flagged as \"partial\" (%u)", flag); - return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - } + if (flag != BGP_ATTR_FLAG_TRANS) + { + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) + zlog (peer->log, LOG_ERR, "ORIGIN attribute must not be flagged as \"optional\" (%u)", flag); + if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) + zlog (peer->log, LOG_ERR, "ORIGIN attribute must be flagged as \"transitive\" (%u)", flag); + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) + zlog (peer->log, LOG_ERR, "ORIGIN attribute must not be flagged as \"partial\" (%u)", flag); + return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); + } /* If any recognized attribute has Attribute Length that conflicts with the expected length (based on the attribute type code), then @@ -994,30 +980,16 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length, total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* Flags check. */ - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) - { - zlog (peer->log, LOG_ERR, - "NEXT_HOP attribute must not be flagged as \"optional\" (%u)", flag); - return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - } - if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) - { - zlog (peer->log, LOG_ERR, - "NEXT_HOP attribute must be flagged as \"transitive\" (%u)", flag); - return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - } - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) - { - zlog (peer->log, LOG_ERR, - "NEXT_HOP attribute must not be flagged as \"partial\" (%u)", flag); - return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - } + if (flag != BGP_ATTR_FLAG_TRANS) + { + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) + zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must not be flagged as \"optional\" (%u)", flag); + if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) + zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must be flagged as \"transitive\" (%u)", flag); + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) + zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must not be flagged as \"partial\" (%u)", flag); + return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); + } /* Check nexthop attribute length. */ if (length != 4) @@ -1063,36 +1035,17 @@ bgp_attr_med (struct peer *peer, bgp_size_t length, 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, - "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; - } + if (flag != BGP_ATTR_FLAG_OPTIONAL) + { + if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) + zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag); + 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); + 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. */ if (length != 4) @@ -1121,36 +1074,17 @@ bgp_attr_local_pref (struct peer *peer, bgp_size_t length, 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 (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) - { - zlog (peer->log, LOG_ERR, - "LOCAL_PREF 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; - } + if (flag != BGP_ATTR_FLAG_TRANS) + { + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) + zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must not be flagged as \"optional\" (%u)", flag); + if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) + zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag); + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) + zlog (peer->log, LOG_ERR, "LOCAL_PREF 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; + } /* If it is contained in an UPDATE message that is received from an external peer, then this attribute MUST be ignored by the @@ -1181,36 +1115,17 @@ bgp_attr_atomic (struct peer *peer, bgp_size_t length, 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, - "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; - } + if (flag != BGP_ATTR_FLAG_TRANS) + { + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) + zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag); + if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) + zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag); + 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. */ if (length != 0) -- cgit v1.2.1 From a624cae2b210a0e81c80c473f86b73e2be169962 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Sat, 8 Oct 2011 13:54:48 +0400 Subject: bgpd: improve attr length error handling (BZ#679) * bgp_attr.c * bgp_attr_parse(): provide extra argument to bgp_attr_aggregator() * bgp_attr_local_pref(): use bgp_notify_send_with_data() * bgp_attr_atomic(): idem * bgp_attr_aggregator(): idem Conflicts: bgpd/bgp_attr.c --- bgpd/bgp_attr.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index daf14bd4..5c3d153a 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1085,6 +1085,16 @@ bgp_attr_local_pref (struct peer *peer, bgp_size_t length, bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); return -1; } + /* Length check. */ + if (length != 4) + { + zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]", length); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + startp, total); + return -1; + } /* If it is contained in an UPDATE message that is received from an external peer, then this attribute MUST be ignored by the @@ -1095,10 +1105,7 @@ bgp_attr_local_pref (struct peer *peer, bgp_size_t length, return BGP_ATTR_PARSE_PROCEED; } - if (length == 4) - attr->local_pref = stream_getl (peer->ibuf); - else - attr->local_pref = 0; + attr->local_pref = stream_getl (peer->ibuf); /* Set atomic aggregate flag. */ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); @@ -1130,11 +1137,10 @@ bgp_attr_atomic (struct peer *peer, bgp_size_t length, /* Length check. */ 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, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - NULL, 0); + startp, total); } /* Set atomic aggregate flag. */ @@ -1146,22 +1152,23 @@ bgp_attr_atomic (struct peer *peer, bgp_size_t length, /* Aggregator attribute */ static int bgp_attr_aggregator (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag) + struct attr *attr, u_char flag, u_char *startp) { int wantedlen = 6; struct attr_extra *attre = bgp_attr_extra_get (attr); + bgp_size_t total; + total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */ if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) wantedlen = 8; 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, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - NULL, 0); + startp, total); } if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) ) @@ -1789,7 +1796,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, ret = bgp_attr_atomic (peer, length, attr, flag, startp); break; case BGP_ATTR_AGGREGATOR: - ret = bgp_attr_aggregator (peer, length, attr, flag); + ret = bgp_attr_aggregator (peer, length, attr, flag, startp); break; case BGP_ATTR_AS4_AGGREGATOR: ret = bgp_attr_as4_aggregator (peer, length, attr, flag, -- cgit v1.2.1 From 21cc76941abc60b5b5ece0a71ace0b69d6f4572c Mon Sep 17 00:00:00 2001 From: Peter Pentchev Date: Mon, 12 Sep 2011 16:30:31 +0400 Subject: bgpd: fix parsing of graceful restart cap. (#663) "While setting up a testbed, I ran across a little problem in the parsing of the "graceful restart" BGP capability that resulted in Quagga not actually activating it for the peer in question - when the peer sent a single AFI/SAFI block." * bgp_open.c * bgp_capability_restart(): actually process the last AFI/SAFI block --- bgpd/bgp_open.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bgpd') diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 31b7369d..82deb3d0 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -380,7 +380,7 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr) peer->v_gr_restart); } - while (stream_get_getp (s) + 4 < end) + while (stream_get_getp (s) + 4 <= end) { afi_t afi = stream_getw (s); safi_t safi = stream_getc (s); -- cgit v1.2.1 From a5b228b3792937c93b589938a2545b9311b7938e Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Wed, 12 Oct 2011 13:54:21 +0400 Subject: bgpd: fix regression in improved attr flag checks Commit 2febf323411c1aed9d7694898f852ce2ef36a7e5 assumed every flag bit except optional/transitive/partial unset, which at times could not be true for "extended length" bit. * bgp_attr.c * bgp_attr_origin(): exclude BGP_ATTR_FLAG_EXTLEN from comparison * bgp_attr_nexthop(): idem * bgp_attr_med(): idem * bgp_attr_local_pref(): idem * bgp_attr_atomic(): idem --- bgpd/bgp_attr.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 5c3d153a..cda522a0 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -773,7 +773,7 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, 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 (flag != BGP_ATTR_FLAG_TRANS) + if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS) { if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) zlog (peer->log, LOG_ERR, "ORIGIN attribute must not be flagged as \"optional\" (%u)", flag); @@ -980,7 +980,7 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length, total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* Flags check. */ - if (flag != BGP_ATTR_FLAG_TRANS) + if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS) { if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must not be flagged as \"optional\" (%u)", flag); @@ -1035,7 +1035,7 @@ bgp_attr_med (struct peer *peer, bgp_size_t length, total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* Flag checks. */ - if (flag != BGP_ATTR_FLAG_OPTIONAL) + if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL) { if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag); @@ -1074,7 +1074,7 @@ bgp_attr_local_pref (struct peer *peer, bgp_size_t length, total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* Flag checks. */ - if (flag != BGP_ATTR_FLAG_TRANS) + if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS) { if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must not be flagged as \"optional\" (%u)", flag); @@ -1122,7 +1122,7 @@ bgp_attr_atomic (struct peer *peer, bgp_size_t length, total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* Flag checks. */ - if (flag != BGP_ATTR_FLAG_TRANS) + if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS) { if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag); -- cgit v1.2.1 From 6d0732c8abad7ace509d033a41814ea03a3a1b16 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 28 Sep 2011 14:23:35 +0400 Subject: IPv6 transport class suppport IPv6 supports the same concept of differentiated service for routing protocols as IPv4, but like too many things, the standards committee decided that having two names for the same thing wasn't good enough and introduced a third more generic term transport class. The socket option to set transport class works the same as IPv4, but the arguments are different. * lib/sockopt.[ch] * setsockopt_ipv6_tclass(): new function * bgpd/bgp_network.c * bgp_connect(): set socket option * bgp_listener(): set socket option * ospf6d/ospf6_network.c * ospf6_set_transport_class(): new function * ospf6_serv_sock(): set socket option * ripngd/ripngd.c * ripng_make_socket(): set socket option --- bgpd/bgp_network.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'bgpd') diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 570cc3b7..c8ff87a6 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -330,6 +330,10 @@ bgp_connect (struct peer *peer) #ifdef IPTOS_PREC_INTERNETCONTROL if (sockunion_family (&peer->su) == AF_INET) setsockopt_ipv4_tos (peer->fd, IPTOS_PREC_INTERNETCONTROL); +# ifdef HAVE_IPV6 + else if (sockunion_family (&peer->su) == AF_INET6) + setsockopt_ipv6_tclass (peer->fd, IPTOS_PREC_INTERNETCONTROL); +# endif #endif if (peer->password) @@ -389,6 +393,10 @@ bgp_listener (int sock, struct sockaddr *sa, socklen_t salen) #ifdef IPTOS_PREC_INTERNETCONTROL if (sa->sa_family == AF_INET) setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL); +# ifdef HAVE_IPV6 + else if (sa->sa_family == AF_INET6) + setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL); +# endif #endif #ifdef IPV6_V6ONLY -- cgit v1.2.1 From d595b566bca1de8b026c469a31ae50f2aee11781 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Fri, 30 Sep 2011 15:08:54 +0400 Subject: bgpd: check ORIGINATOR_ID attribute flags * bgp_attr.c * bgp_attr_originator_id(): accept extra argument, add checks for "optional", "transitive" and "partial" bits, log each error condition independently * bgp_attr_parse(): provide extra arguments --- bgpd/bgp_attr.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index cda522a0..a3db9f15 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1353,8 +1353,24 @@ bgp_attr_community (struct peer *peer, bgp_size_t length, /* Originator ID attribute. */ static bgp_attr_parse_ret_t bgp_attr_originator_id (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag) + struct attr *attr, u_char flag, u_char *startp) { + bgp_size_t total; + + total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + /* Flag checks. */ + if (flag != BGP_ATTR_FLAG_OPTIONAL) + { + if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) + zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must be flagged as \"optional\" (%u)", flag); + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) + zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must not be flagged as \"transitive\" (%u)", flag); + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) + zlog (peer->log, LOG_ERR, "ORIGINATOR_ID 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. */ if (length != 4) { zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length); @@ -1807,7 +1823,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, ret = bgp_attr_community (peer, length, attr, flag, startp); break; case BGP_ATTR_ORIGINATOR_ID: - ret = bgp_attr_originator_id (peer, length, attr, flag); + ret = bgp_attr_originator_id (peer, length, attr, flag, startp); break; case BGP_ATTR_CLUSTER_LIST: ret = bgp_attr_cluster_list (peer, length, attr, flag); -- cgit v1.2.1 From 0b83044b91d7ea50824cfd803d77213b9ff38ed9 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Fri, 30 Sep 2011 15:12:17 +0400 Subject: bgpd: check CLUSTER_LIST attribute flags * bgp_attr.c * bgp_attr_cluster_list(): accept extra argument, add checks for "optional", "transitive" and "partial" bits, log each error condition independently * bgp_attr_parse(): provide extra arguments --- bgpd/bgp_attr.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index a3db9f15..6dd14893 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1391,8 +1391,23 @@ bgp_attr_originator_id (struct peer *peer, bgp_size_t length, /* Cluster list attribute. */ static bgp_attr_parse_ret_t bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag) + struct attr *attr, u_char flag, u_char *startp) { + bgp_size_t total; + + total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + /* Flag checks. */ + if (flag != BGP_ATTR_FLAG_OPTIONAL) + { + if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) + zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must be flagged as \"optional\" (%u)", flag); + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) + zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must not be flagged as \"transitive\" (%u)", flag); + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) + zlog (peer->log, LOG_ERR, "CLUSTER_LIST 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; + } /* Check length. */ if (length % 4) { @@ -1826,7 +1841,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, ret = bgp_attr_originator_id (peer, length, attr, flag, startp); break; case BGP_ATTR_CLUSTER_LIST: - ret = bgp_attr_cluster_list (peer, length, attr, flag); + ret = bgp_attr_cluster_list (peer, length, attr, flag, startp); break; case BGP_ATTR_MP_REACH_NLRI: ret = bgp_mp_reach_parse (peer, length, attr, mp_update); -- cgit v1.2.1 From f8627ff1ef7642c8ee4758b1f046ef0d166dfbec Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Mon, 10 Oct 2011 16:52:20 +0400 Subject: bgpd: fix spelling of CLUSTER_LIST --- bgpd/bgp_attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 6dd14893..8a85fc22 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -51,7 +51,7 @@ static const struct message attr_str [] = { BGP_ATTR_AGGREGATOR, "AGGREGATOR" }, { BGP_ATTR_COMMUNITIES, "COMMUNITY" }, { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" }, - { BGP_ATTR_CLUSTER_LIST, "CLUSTERLIST" }, + { BGP_ATTR_CLUSTER_LIST, "CLUSTER_LIST" }, { BGP_ATTR_DPA, "DPA" }, { BGP_ATTR_ADVERTISER, "ADVERTISER"} , { BGP_ATTR_RCID_PATH, "RCID_PATH" }, -- cgit v1.2.1 From 565b828dc00cafd477dd69ce15f0f551ece67710 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Mon, 10 Oct 2011 21:08:33 +0400 Subject: bgpd: add flag checks for MP_(UN)REACH_NLRI * bgp_attr.[ch] * bgp_mp_reach_parse(): add extra arguments and a uniform flag check block * bgp_mp_unreach_parse(): idem * bgp_attr_parse(): provide extra arguments * bgp_mp_attr_test.c * parse_test(): justify respective calls --- bgpd/bgp_attr.c | 42 ++++++++++++++++++++++++++++++++++++------ bgpd/bgp_attr.h | 7 ++++--- 2 files changed, 40 insertions(+), 9 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 8a85fc22..c2e5fede 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1431,8 +1431,8 @@ bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, /* Multiprotocol reachability information parse. */ int -bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, - struct bgp_nlri *mp_update) +bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length, + struct attr *attr, const u_char flag, u_char *startp, struct bgp_nlri *mp_update) { afi_t afi; safi_t safi; @@ -1441,7 +1441,21 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, int ret; struct stream *s; struct attr_extra *attre = bgp_attr_extra_get(attr); - + bgp_size_t total; + + total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + /* Flag checks. */ + if (flag != BGP_ATTR_FLAG_OPTIONAL) + { + if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) + zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must be flagged as \"optional\" (%u)", flag); + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) + zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must not be flagged as \"transitive\" (%u)", flag); + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) + zlog (peer->log, LOG_ERR, "MP_REACH_NLRI 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; + } /* Set end of packet. */ s = BGP_INPUT(peer); start = stream_get_getp(s); @@ -1565,7 +1579,8 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, /* Multiprotocol unreachable parse */ int -bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length, +bgp_mp_unreach_parse (struct peer *peer, const bgp_size_t length, + const u_char flag, u_char *startp, struct bgp_nlri *mp_withdraw) { struct stream *s; @@ -1573,6 +1588,21 @@ bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length, safi_t safi; u_int16_t withdraw_len; int ret; + bgp_size_t total; + + total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + /* Flag checks. */ + if (flag != BGP_ATTR_FLAG_OPTIONAL) + { + if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) + zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must be flagged as \"optional\" (%u)", flag); + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) + zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must not be flagged as \"transitive\" (%u)", flag); + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) + zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI 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; + } s = peer->ibuf; @@ -1844,10 +1874,10 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, ret = bgp_attr_cluster_list (peer, length, attr, flag, startp); break; case BGP_ATTR_MP_REACH_NLRI: - ret = bgp_mp_reach_parse (peer, length, attr, mp_update); + ret = bgp_mp_reach_parse (peer, length, attr, flag, startp, mp_update); break; case BGP_ATTR_MP_UNREACH_NLRI: - ret = bgp_mp_unreach_parse (peer, length, mp_withdraw); + ret = bgp_mp_unreach_parse (peer, length, flag, startp, mp_withdraw); break; case BGP_ATTR_EXT_COMMUNITIES: ret = bgp_attr_ext_communities (peer, length, attr, flag, startp); diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index c0112514..e6300740 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -180,8 +180,9 @@ extern void cluster_unintern (struct cluster_list *); void transit_unintern (struct transit *); /* Exported for unit-test purposes only */ -extern int bgp_mp_reach_parse (struct peer *, bgp_size_t, struct attr *, - struct bgp_nlri *); -extern int bgp_mp_unreach_parse (struct peer *, bgp_size_t, struct bgp_nlri *); +extern int bgp_mp_reach_parse (struct peer *, const bgp_size_t, struct attr *, + const u_char, u_char *, struct bgp_nlri *); +extern int bgp_mp_unreach_parse (struct peer *, const bgp_size_t, const u_char, + u_char *, struct bgp_nlri *); #endif /* _QUAGGA_BGP_ATTR_H */ -- cgit v1.2.1 From abc384f85b622471ef5ba6c86acc540856da05cf Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Tue, 18 Oct 2011 13:55:07 +0400 Subject: bgpd: use bgp_attr_malformed() Some of the recent attribute flags/length checks copied from QRE use bgp_notify_send_with_data() directly, but master branch assumes using bgp_attr_malformed(). * bgp_attr.c * bgp_attr_med() * bgp_attr_local_pref() * bgp_attr_atomic() * bgp_attr_originator_id() * bgp_attr_cluster_list() * bgp_mp_reach_parse() * bgp_mp_unreach_parse() --- bgpd/bgp_attr.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index c2e5fede..a60bb8e5 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1043,8 +1043,9 @@ bgp_attr_med (struct peer *peer, bgp_size_t length, zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must not be flagged as \"transitive\" (%u)", flag); 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; + return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); } /* Length check. */ @@ -1082,18 +1083,17 @@ bgp_attr_local_pref (struct peer *peer, bgp_size_t length, zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag); if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) zlog (peer->log, LOG_ERR, "LOCAL_PREF 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; + return bgp_attr_malformed (peer, BGP_ATTR_LOCAL_PREF, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); } /* Length check. */ if (length != 4) { zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]", length); - bgp_notify_send_with_data (peer, - BGP_NOTIFY_UPDATE_ERR, + return bgp_attr_malformed (peer, BGP_ATTR_LOCAL_PREF, flag, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, startp, total); - return -1; } /* If it is contained in an UPDATE message that is received from an @@ -1130,8 +1130,9 @@ bgp_attr_atomic (struct peer *peer, bgp_size_t length, zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag); 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; + return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); } /* Length check. */ @@ -1367,8 +1368,9 @@ bgp_attr_originator_id (struct peer *peer, bgp_size_t length, zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must not be flagged as \"transitive\" (%u)", flag); if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) zlog (peer->log, LOG_ERR, "ORIGINATOR_ID 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; + return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); } /* Length check. */ if (length != 4) @@ -1405,8 +1407,9 @@ bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must not be flagged as \"transitive\" (%u)", flag); if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) zlog (peer->log, LOG_ERR, "CLUSTER_LIST 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; + return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); } /* Check length. */ if (length % 4) @@ -1453,8 +1456,9 @@ bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length, zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must not be flagged as \"transitive\" (%u)", flag); if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) zlog (peer->log, LOG_ERR, "MP_REACH_NLRI 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; + return bgp_attr_malformed (peer, BGP_ATTR_MP_REACH_NLRI, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); } /* Set end of packet. */ s = BGP_INPUT(peer); @@ -1600,8 +1604,9 @@ bgp_mp_unreach_parse (struct peer *peer, const bgp_size_t length, zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must not be flagged as \"transitive\" (%u)", flag); if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI 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; + return bgp_attr_malformed (peer, BGP_ATTR_MP_UNREACH_NLRI, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); } s = peer->ibuf; -- cgit v1.2.1 From bbb04bf3bb03be27fbf17b6b3ee903b168201cf0 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Tue, 18 Oct 2011 14:20:04 +0400 Subject: bgpd: fix more regressions in attr flag checks Commit 05a4936b713b9882171d0f7fb20b8439df23939e fixed some of the attributes involved, but not all. This commit should do it. * bgp_attr.c * bgp_attr_originator_id() * bgp_attr_cluster_list() * bgp_mp_reach_parse() * bgp_mp_unreach_parse() --- bgpd/bgp_attr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index a60bb8e5..d7eeec1f 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1360,7 +1360,7 @@ bgp_attr_originator_id (struct peer *peer, bgp_size_t length, total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* Flag checks. */ - if (flag != BGP_ATTR_FLAG_OPTIONAL) + if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL) { if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must be flagged as \"optional\" (%u)", flag); @@ -1399,7 +1399,7 @@ bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* Flag checks. */ - if (flag != BGP_ATTR_FLAG_OPTIONAL) + if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL) { if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must be flagged as \"optional\" (%u)", flag); @@ -1448,7 +1448,7 @@ bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length, total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* Flag checks. */ - if (flag != BGP_ATTR_FLAG_OPTIONAL) + if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL) { if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must be flagged as \"optional\" (%u)", flag); @@ -1596,7 +1596,7 @@ bgp_mp_unreach_parse (struct peer *peer, const bgp_size_t length, total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* Flag checks. */ - if (flag != BGP_ATTR_FLAG_OPTIONAL) + if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL) { if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must be flagged as \"optional\" (%u)", flag); -- cgit v1.2.1 From b4cd2421518be7e18046e974e25b9bf4cf769bd2 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Sat, 22 Oct 2011 22:32:26 +0400 Subject: bgpd: check AGGREGATOR attr flags (BZ#678) * bgp_attr.c * bgp_attr_aggregator(): check Optional/Transitive flag bits --- bgpd/bgp_attr.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index d7eeec1f..75b7c797 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1160,6 +1160,23 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length, bgp_size_t total; total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + /* Flags check. */ + if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) + { + zlog (peer->log, LOG_ERR, + "AGGREGATOR attribute must be flagged as \"optional\" (%u)", flag); + return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + } + if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) + { + zlog (peer->log, LOG_ERR, + "AGGREGATOR attribute must be flagged as \"transitive\" (%u)", flag); + return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + } /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */ if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) wantedlen = 8; -- cgit v1.2.1 From 267551879e57a5c590f9e12b3a7d6985b28b3dac Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Wed, 26 Oct 2011 19:34:30 +0400 Subject: bgpd: fix 2 more cases of length error reporting * bgp_attr.c (bgp_attr_originator_id, bgp_attr_cluster_list): provide required arguments to bgp_attr_malformed() --- bgpd/bgp_attr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 75b7c797..29877eb7 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1396,7 +1396,7 @@ bgp_attr_originator_id (struct peer *peer, bgp_size_t length, return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - NULL, 0); + startp, total); } (bgp_attr_extra_get (attr))->originator_id.s_addr @@ -1435,7 +1435,7 @@ bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - NULL, 0); + startp, total); } (bgp_attr_extra_get (attr))->cluster -- cgit v1.2.1 From 1758dbaa3b69bd6e95fb501c40f044f751557e76 Mon Sep 17 00:00:00 2001 From: "Sergey Y. Afonin" Date: Thu, 27 Oct 2011 17:01:11 +0400 Subject: bgpd: revised fix to --dryrun (BZ#622) --- bgpd/bgpd.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index e8038553..b8215ee6 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2048,6 +2048,10 @@ bgp_get (struct bgp **bgp_val, as_t *as, const char *name) } } + bgp = bgp_create (as, name); + bgp_router_id_set(bgp, &router_id_zebra); + *bgp_val = bgp; + /* Create BGP server socket, if first instance. */ if (list_isempty(bm->bgp)) { @@ -2055,10 +2059,7 @@ bgp_get (struct bgp **bgp_val, as_t *as, const char *name) return BGP_ERR_INVALID_VALUE; } - bgp = bgp_create (as, name); listnode_add (bm->bgp, bgp); - bgp_router_id_set(bgp, &router_id_zebra); - *bgp_val = bgp; return 0; } -- cgit v1.2.1 From 5c88f19d5b166c6afa8a9b8501badb785afa553b Mon Sep 17 00:00:00 2001 From: Chris Luke Date: Tue, 18 Oct 2011 17:26:51 +0400 Subject: bgpd: justify capabilities for TOS setting To set the TOS bits on TCP connections, platforms that restrict capabilities need the priv level to be raised before the sockopt is set, and this requires the ZCAP_NET_ADMIN priv. * bgp_main.c: update _caps_p to include ZCAP_NET_ADMIN * bgp_network.c * bgp_connect(): request ZPRIVS_RAISE/ZPRIVS_LOWER * bgp_listener(): request ZPRIVS_RAISE earlier --- bgpd/bgp_main.c | 1 + bgpd/bgp_network.c | 14 +++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 1a460c6b..0e85d57e 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -119,6 +119,7 @@ static zebra_capabilities_t _caps_p [] = { ZCAP_BIND, ZCAP_NET_RAW, + ZCAP_NET_ADMIN, }; struct zebra_privs_t bgpd_privs = diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index c8ff87a6..52c72b67 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -328,12 +328,16 @@ bgp_connect (struct peer *peer) sockopt_reuseport (peer->fd); #ifdef IPTOS_PREC_INTERNETCONTROL + if (bgpd_privs.change (ZPRIVS_RAISE)) + zlog_err ("%s: could not raise privs", __func__); if (sockunion_family (&peer->su) == AF_INET) setsockopt_ipv4_tos (peer->fd, IPTOS_PREC_INTERNETCONTROL); # ifdef HAVE_IPV6 else if (sockunion_family (&peer->su) == AF_INET6) setsockopt_ipv6_tclass (peer->fd, IPTOS_PREC_INTERNETCONTROL); # endif + if (bgpd_privs.change (ZPRIVS_LOWER)) + zlog_err ("%s: could not lower privs", __func__); #endif if (peer->password) @@ -390,6 +394,9 @@ bgp_listener (int sock, struct sockaddr *sa, socklen_t salen) sockopt_reuseaddr (sock); sockopt_reuseport (sock); + if (bgpd_privs.change (ZPRIVS_RAISE)) + zlog_err ("%s: could not raise privs", __func__); + #ifdef IPTOS_PREC_INTERNETCONTROL if (sa->sa_family == AF_INET) setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL); @@ -408,13 +415,10 @@ bgp_listener (int sock, struct sockaddr *sa, socklen_t salen) } #endif - if (bgpd_privs.change (ZPRIVS_RAISE) ) - zlog_err ("bgp_socket: could not raise privs"); - ret = bind (sock, sa, salen); en = errno; - if (bgpd_privs.change (ZPRIVS_LOWER) ) - zlog_err ("bgp_bind_address: could not lower privs"); + if (bgpd_privs.change (ZPRIVS_LOWER)) + zlog_err ("%s: could not lower privs", __func__); if (ret < 0) { -- cgit v1.2.1 From 3cf1288bfd855e339fe2283c79a3ef3746e61737 Mon Sep 17 00:00:00 2001 From: Dylan Hall Date: Thu, 27 Oct 2011 15:28:17 +0400 Subject: bgpd: fix "nexthop-local unchanged" (BZ#350) --- bgpd/bgpd.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'bgpd') diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index b8215ee6..8bc8d6ed 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -5015,6 +5015,11 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp, && ! peer->af_group[afi][safi]) vty_out (vty, " neighbor %s route-server-client%s", addr, VTY_NEWLINE); + /* Nexthop-local unchanged. */ + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) + && ! peer->af_group[afi][safi]) + vty_out (vty, " neighbor %s nexthop-local unchanged%s", addr, VTY_NEWLINE); + /* Allow AS in. */ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_ALLOWAS_IN)) if (! peer_group_active (peer) -- cgit v1.2.1 From 1727d2e2b939c8670d0f0e0d1a0e5eb0a8be2135 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 2 Feb 2010 20:18:23 +0100 Subject: bgpd: fix update-source for IPv6 (BZ#548) if update-source was given as interface name, bgpd was unconditionally trying to bind to an IPv4 address from that interface. change function to find the best-matching (number of address bits) same-family address on the interface. --- bgpd/bgp_network.c | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 52c72b67..b9cb6223 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -263,21 +263,37 @@ bgp_bind_address (int sock, struct in_addr *addr) return 0; } -static struct in_addr * -bgp_update_address (struct interface *ifp) +static int +bgp_update_address (struct interface *ifp, const union sockunion *dst, + union sockunion *addr) { - struct prefix_ipv4 *p; + struct prefix *p, *sel, *d; struct connected *connected; struct listnode *node; + int common; + + d = sockunion2hostprefix (dst); + sel = NULL; + common = -1; for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected)) { - p = (struct prefix_ipv4 *) connected->address; - - if (p->family == AF_INET) - return &p->prefix; + p = connected->address; + if (p->family != d->family) + continue; + if (prefix_common_bits (p, d) > common) + { + sel = p; + common = prefix_common_bits (sel, d); + } } - return NULL; + + prefix_free (d); + if (!sel) + return 1; + + prefix2sockunion (sel, addr); + return 0; } /* Update source selection. */ @@ -285,7 +301,7 @@ static void bgp_update_source (struct peer *peer) { struct interface *ifp; - struct in_addr *addr; + union sockunion addr; /* Source is specified with interface name. */ if (peer->update_if) @@ -294,11 +310,10 @@ bgp_update_source (struct peer *peer) if (! ifp) return; - addr = bgp_update_address (ifp); - if (! addr) + if (bgp_update_address (ifp, &peer->su, &addr)) return; - bgp_bind_address (peer->fd, addr); + sockunion_bind (peer->fd, &addr, 0, &addr); } /* Source is specified with IP address. */ -- cgit v1.2.1 From 2fbd6f5a62f654c59aec5e1707c859d6ed79c6b0 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 2 Feb 2010 20:20:35 +0100 Subject: bgpd: remove unused function bgp_bind_address bgp_bind_address is replaced with sockunion_bind. --- bgpd/bgp_network.c | 26 -------------------------- 1 file changed, 26 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index b9cb6223..274a989d 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -237,32 +237,6 @@ bgp_bind (struct peer *peer) return 0; } -static int -bgp_bind_address (int sock, struct in_addr *addr) -{ - int ret; - struct sockaddr_in local; - - memset (&local, 0, sizeof (struct sockaddr_in)); - local.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - local.sin_len = sizeof(struct sockaddr_in); -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - memcpy (&local.sin_addr, addr, sizeof (struct in_addr)); - - if ( bgpd_privs.change (ZPRIVS_RAISE) ) - zlog_err ("bgp_bind_address: could not raise privs"); - - ret = bind (sock, (struct sockaddr *)&local, sizeof (struct sockaddr_in)); - if (ret < 0) - ; - - if (bgpd_privs.change (ZPRIVS_LOWER) ) - zlog_err ("bgp_bind_address: could not lower privs"); - - return 0; -} - static int bgp_update_address (struct interface *ifp, const union sockunion *dst, union sockunion *addr) -- cgit v1.2.1 From ce0af6ff5a4f200035ed4134da72a67f49a21dd6 Mon Sep 17 00:00:00 2001 From: "Oleg A. Arkhangelsky" Date: Sat, 3 Dec 2011 15:18:19 +0400 Subject: bgpd: fix memory leak for extra attributes this fixes commit b881c7074bb698aeb1b099175b325734fc6e44d2 --- bgpd/bgp_attr.c | 1 + 1 file changed, 1 insertion(+) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 29877eb7..4e604b18 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -675,6 +675,7 @@ bgp_attr_unintern (struct attr **attr) } bgp_attr_unintern_sub (&tmp); + bgp_attr_extra_free (&tmp); } void -- cgit v1.2.1 From f04a80a5d209dbb54f6fec5d0149b7c0e489d29e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 6 Dec 2011 14:51:10 +0400 Subject: bgpd: store nexthop info for redistributed IPV6 routes BGP was ignoring nexthop info for static and other redistributed routes for IPv6. Build extra attribute info to store the nexthop. See also: https://bugzilla.vyatta.com/show_bug.cgi?id=6073 --- bgpd/bgp_route.c | 12 +++++++++++- bgpd/bgp_route.h | 4 +++- bgpd/bgp_zebra.c | 27 +++++++++++++++++---------- 3 files changed, 31 insertions(+), 12 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index d2aedb61..f0dfcccd 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -5244,7 +5244,8 @@ ALIAS (no_ipv6_aggregate_address_summary_only, /* Redistribute route treatment. */ void -bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop, +bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop, + const struct in6_addr *nexthop6, u_int32_t metric, u_char type) { struct bgp *bgp; @@ -5264,6 +5265,15 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop, if (nexthop) attr.nexthop = *nexthop; +#ifdef HAVE_IPV6 + if (nexthop6) + { + struct attr_extra *extra = bgp_attr_extra_get(&attr); + extra->mp_nexthop_global = *nexthop6; + extra->mp_nexthop_len = 16; + } +#endif + attr.med = metric; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 3e528596..7adc573b 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -192,7 +192,9 @@ extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *); extern int bgp_maximum_prefix_overflow (struct peer *, afi_t, safi_t, int); -extern void bgp_redistribute_add (struct prefix *, struct in_addr *, u_int32_t, u_char); +extern void bgp_redistribute_add (struct prefix *, const struct in_addr *, + const struct in6_addr *, + u_int32_t, u_char); extern void bgp_redistribute_delete (struct prefix *, u_char); extern void bgp_redistribute_withdraw (struct bgp *, afi_t, int); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index f3baeee0..d7af349a 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -281,7 +281,8 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), api.metric); } - bgp_redistribute_add((struct prefix *)&p, &nexthop, api.metric, api.type); + bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL, + api.metric, api.type); } else { @@ -356,23 +357,29 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) { if (BGP_DEBUG(zebra, ZEBRA)) { - char buf[INET6_ADDRSTRLEN]; - zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d metric %u", + char buf[2][INET6_ADDRSTRLEN]; + zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d nexthop %s metric %u", zebra_route_string(api.type), - inet_ntop(AF_INET6, &p.prefix, buf, sizeof(buf)), - p.prefixlen, api.metric); + inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])), + p.prefixlen, + inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), + api.metric); } - bgp_redistribute_add ((struct prefix *)&p, NULL, api.metric, api.type); + bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop, + api.metric, api.type); } else { if (BGP_DEBUG(zebra, ZEBRA)) { - char buf[INET6_ADDRSTRLEN]; - zlog_debug("Zebra rcvd: IPv6 route delete %s %s/%d metric %u", + char buf[2][INET6_ADDRSTRLEN]; + zlog_debug("Zebra rcvd: IPv6 route delete %s %s/%d " + "nexthop %s metric %u", zebra_route_string(api.type), - inet_ntop(AF_INET6, &p.prefix, buf, sizeof(buf)), - p.prefixlen, api.metric); + inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])), + p.prefixlen, + inet_ntop(AF_INET6, &nexthop, buf[1], sizeof(buf[1])), + api.metric); } bgp_redistribute_delete ((struct prefix *) &p, api.type); } -- cgit v1.2.1 From 04d5e24d7425a52f13abcb6d2a30aa6246d837e7 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 7 Dec 2011 00:04:46 +0400 Subject: bgpd: cleanup privs on termination When doing valgrind testing, the privledges from zprivs_init() need to be cleaned up on exit. --- bgpd/bgp_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'bgpd') diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 0e85d57e..822805ce 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -197,6 +197,7 @@ sigint (void) if (! retain_mode) bgp_terminate (); + zprivs_terminate (&bgpd_privs); bgp_exit (0); } -- cgit v1.2.1 From bde12e3fd5e498a266e813a5751c1b2d21e46ca5 Mon Sep 17 00:00:00 2001 From: Ulrich Weber Date: Wed, 16 Nov 2011 19:32:12 +0400 Subject: bgp: use VTY_GET_INTEGER_RANGE() in bgp_clear() Second patch replaces "VTY_GET_LONG ("AS", as_ul, arg);" by "VTY_GET_INTEGER_RANGE ("AS", as, arg, 1, BGP_AS4_MAX);" as done in all other code, which parses AS numbers. --- bgpd/bgp_vty.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 44c55f2a..439aeebe 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -4215,18 +4215,10 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, if (sort == clear_as) { as_t as; - unsigned long as_ul; int find = 0; - VTY_GET_LONG ("AS", as_ul, arg); + VTY_GET_INTEGER_RANGE ("AS", as, arg, 1, BGP_AS4_MAX); - if (!as_ul) - { - vty_out (vty, "Invalid AS number%s", VTY_NEWLINE); - return CMD_WARNING; - } - as = (as_t) as_ul; - for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->as != as) -- cgit v1.2.1 From 1add115a9cfd3a2ee33a61731008b6ece90ec61d Mon Sep 17 00:00:00 2001 From: Vyacheslav Trushkin Date: Tue, 22 Nov 2011 20:15:10 +0400 Subject: bgpd: implement 'match probability' in route-maps New clause 'match probability ' was added in route-maps (bgpd/bgp_routemap.c modified). --- bgpd/bgp_routemap.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) (limited to 'bgpd') diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 178af603..05bc304b 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -790,6 +790,75 @@ struct route_map_rule_cmd route_match_origin_cmd = route_match_origin_compile, route_match_origin_free }; + +/* match probability { */ + +static route_map_result_t +route_match_probability (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + long r; +#if _SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500 + r = random(); +#else + r = (long) rand(); +#endif + + switch (*(unsigned *) rule) + { + case 0: break; + case RAND_MAX: return RMAP_MATCH; + default: + if (r < *(unsigned *) rule) + { + return RMAP_MATCH; + } + } + + return RMAP_NOMATCH; +} + +static void * +route_match_probability_compile (const char *arg) +{ + unsigned *lobule; + unsigned perc; + +#if _SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500 + srandom (time (NULL)); +#else + srand (time (NULL)); +#endif + + perc = atoi (arg); + lobule = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (unsigned)); + + switch (perc) + { + case 0: *lobule = 0; break; + case 100: *lobule = RAND_MAX; break; + default: *lobule = RAND_MAX / 100 * perc; + } + + return lobule; +} + +static void +route_match_probability_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_probability_cmd = +{ + "probability", + route_match_probability, + route_match_probability_compile, + route_match_probability_free +}; + +/* } */ + /* `set ip next-hop IP_ADDRESS' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ @@ -2462,6 +2531,38 @@ ALIAS (no_match_ip_next_hop, "IP access-list number (expanded range)\n" "IP Access-list name\n") +/* match probability { */ + +DEFUN (match_probability, + match_probability_cmd, + "match probability <0-100>", + MATCH_STR + "Match portion of routes defined by percentage value\n" + "Percentage of routes\n") +{ + return bgp_route_match_add (vty, vty->index, "probability", argv[0]); +} + +DEFUN (no_match_probability, + no_match_probability_cmd, + "no match probability", + NO_STR + MATCH_STR + "Match portion of routes defined by percentage value\n") +{ + return bgp_route_match_delete (vty, vty->index, "probability", argc ? argv[0] : NULL); +} + +ALIAS (no_match_probability, + no_match_probability_val_cmd, + "no match probability <1-99>", + NO_STR + MATCH_STR + "Match portion of routes defined by percentage value\n" + "Percentage of routes\n") + +/* } */ + DEFUN (match_ip_route_source, match_ip_route_source_cmd, "match ip route-source (<1-199>|<1300-2699>|WORD)", @@ -3749,6 +3850,7 @@ bgp_route_map_init (void) route_map_install_match (&route_match_ecommunity_cmd); route_map_install_match (&route_match_metric_cmd); route_map_install_match (&route_match_origin_cmd); + route_map_install_match (&route_match_probability_cmd); route_map_install_set (&route_set_ip_nexthop_cmd); route_map_install_set (&route_set_local_pref_cmd); @@ -3780,7 +3882,6 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &match_ip_route_source_cmd); install_element (RMAP_NODE, &no_match_ip_route_source_cmd); install_element (RMAP_NODE, &no_match_ip_route_source_val_cmd); - install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd); @@ -3808,6 +3909,9 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &match_origin_cmd); install_element (RMAP_NODE, &no_match_origin_cmd); install_element (RMAP_NODE, &no_match_origin_val_cmd); + install_element (RMAP_NODE, &match_probability_cmd); + install_element (RMAP_NODE, &no_match_probability_cmd); + install_element (RMAP_NODE, &no_match_probability_val_cmd); install_element (RMAP_NODE, &set_ip_nexthop_cmd); install_element (RMAP_NODE, &set_ip_nexthop_peer_cmd); -- cgit v1.2.1 From b51146856e660bcec723f535c17dc1c38b2f6efc Mon Sep 17 00:00:00 2001 From: Vyacheslav Trushkin Date: Fri, 25 Nov 2011 18:51:48 +0400 Subject: quagga: option "-z" ("--socket ") added All daemons modified to support custom path to zserv socket. lib: generalize a zclient connection zclient_socket_connect added. zclient_socket and zclient_socket_un were hidden under static expression. "zclient_serv_path_set" modified. --- bgpd/bgp_main.c | 7 ++++++- bgpd/bgp_nexthop.c | 7 +------ 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 822805ce..8dede587 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -54,6 +54,7 @@ static const struct option longopts[] = { "daemon", no_argument, NULL, 'd'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, + { "socket", required_argument, NULL, 'z'}, { "bgp_port", required_argument, NULL, 'p'}, { "listenon", required_argument, NULL, 'l'}, { "vty_addr", required_argument, NULL, 'A'}, @@ -150,6 +151,7 @@ redistribution between different routing protocols.\n\n\ -d, --daemon Runs in daemon mode\n\ -f, --config_file Set configuration file name\n\ -i, --pid_file Set process identifier file name\n\ +-z, --socket Set path of zebra socket\n\ -p, --bgp_port Set bgp protocol's port number\n\ -l, --listenon Listen on specified address (implies -n)\n\ -A, --vty_addr Set vty's bind address\n\ @@ -337,7 +339,7 @@ main (int argc, char **argv) /* Command line argument treatment. */ while (1) { - opt = getopt_long (argc, argv, "df:i:hp:l:A:P:rnu:g:vC", longopts, 0); + opt = getopt_long (argc, argv, "df:i:z:hp:l:A:P:rnu:g:vC", longopts, 0); if (opt == EOF) break; @@ -355,6 +357,9 @@ main (int argc, char **argv) case 'i': pid_file = optarg; break; + case 'z': + zclient_serv_path_set (optarg); + break; case 'p': tmp_port = atoi (optarg); if (tmp_port <= 0 || tmp_port > 0xffff) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 719cb966..60efa195 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -1098,12 +1098,7 @@ zlookup_connect (struct thread *t) if (zlookup->sock != -1) return 0; -#ifdef HAVE_TCP_ZEBRA - zlookup->sock = zclient_socket (); -#else - zlookup->sock = zclient_socket_un (ZEBRA_SERV_PATH); -#endif /* HAVE_TCP_ZEBRA */ - if (zlookup->sock < 0) + if (zclient_socket_connect (zlookup) < 0) return -1; return 0; -- cgit v1.2.1 From 05e54ee3df973194f2a00e3ea0b1da7bebc71fd6 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Sat, 3 Dec 2011 17:45:17 +0400 Subject: build: delete .cvsignore files --- bgpd/.cvsignore | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 bgpd/.cvsignore (limited to 'bgpd') diff --git a/bgpd/.cvsignore b/bgpd/.cvsignore deleted file mode 100644 index f4504f62..00000000 --- a/bgpd/.cvsignore +++ /dev/null @@ -1,15 +0,0 @@ -Makefile -Makefile.in -*.o -bgpd -bgp_btoa -bgpd.conf -tags -TAGS -.deps -.nfs* -*.lo -*.la -*.libs -.arch-inventory -.arch-ids -- cgit v1.2.1 From e0ca5fde7be5b5ce90dae78c2477e8245aecb8e9 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 16 Sep 2009 01:52:42 +0200 Subject: lib: put route_types.txt to real use this replaces most occurences of routing protocol lists by preprocessor defines from route_types.h. the latter is autogenerated from route_types.txt by a perl script (previously awk). adding a routing protocol now is mostly a matter of changing route_types.txt and log.c. Conflicts: lib/route_types.awk --- bgpd/bgp_vty.c | 269 ++++++++++++++++----------------------------------------- 1 file changed, 76 insertions(+), 193 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 439aeebe..f65bb157 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -8373,57 +8373,16 @@ ALIAS (show_bgp_instance_ipv6_safi_rsclient_summary, /* Redistribute VTY commands. */ -/* Utility function to convert user input route type string to route - type. */ -static int -bgp_str2route_type (int afi, const char *str) -{ - if (! str) - return 0; - - if (afi == AFI_IP) - { - if (strncmp (str, "k", 1) == 0) - return ZEBRA_ROUTE_KERNEL; - else if (strncmp (str, "c", 1) == 0) - return ZEBRA_ROUTE_CONNECT; - else if (strncmp (str, "s", 1) == 0) - return ZEBRA_ROUTE_STATIC; - else if (strncmp (str, "r", 1) == 0) - return ZEBRA_ROUTE_RIP; - else if (strncmp (str, "o", 1) == 0) - return ZEBRA_ROUTE_OSPF; - } - if (afi == AFI_IP6) - { - if (strncmp (str, "k", 1) == 0) - return ZEBRA_ROUTE_KERNEL; - else if (strncmp (str, "c", 1) == 0) - return ZEBRA_ROUTE_CONNECT; - else if (strncmp (str, "s", 1) == 0) - return ZEBRA_ROUTE_STATIC; - else if (strncmp (str, "r", 1) == 0) - return ZEBRA_ROUTE_RIPNG; - else if (strncmp (str, "o", 1) == 0) - return ZEBRA_ROUTE_OSPF6; - } - return 0; -} - DEFUN (bgp_redistribute_ipv4, bgp_redistribute_ipv4_cmd, - "redistribute (connected|kernel|ospf|rip|static)", + "redistribute " QUAGGA_IP_REDIST_STR_BGPD, "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n") + QUAGGA_IP_REDIST_HELP_STR_BGPD) { int type; - type = bgp_str2route_type (AFI_IP, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8433,20 +8392,16 @@ DEFUN (bgp_redistribute_ipv4, DEFUN (bgp_redistribute_ipv4_rmap, bgp_redistribute_ipv4_rmap_cmd, - "redistribute (connected|kernel|ospf|rip|static) route-map WORD", + "redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD", "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n" + QUAGGA_IP_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") { int type; - type = bgp_str2route_type (AFI_IP, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8458,21 +8413,17 @@ DEFUN (bgp_redistribute_ipv4_rmap, DEFUN (bgp_redistribute_ipv4_metric, bgp_redistribute_ipv4_metric_cmd, - "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>", + "redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295>", "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n" + QUAGGA_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") { int type; u_int32_t metric; - type = bgp_str2route_type (AFI_IP, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8485,13 +8436,9 @@ DEFUN (bgp_redistribute_ipv4_metric, DEFUN (bgp_redistribute_ipv4_rmap_metric, bgp_redistribute_ipv4_rmap_metric_cmd, - "redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>", + "redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n" + QUAGGA_IP_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" @@ -8500,8 +8447,8 @@ DEFUN (bgp_redistribute_ipv4_rmap_metric, int type; u_int32_t metric; - type = bgp_str2route_type (AFI_IP, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8515,13 +8462,9 @@ DEFUN (bgp_redistribute_ipv4_rmap_metric, DEFUN (bgp_redistribute_ipv4_metric_rmap, bgp_redistribute_ipv4_metric_rmap_cmd, - "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD", + "redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n" + QUAGGA_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" @@ -8530,8 +8473,8 @@ DEFUN (bgp_redistribute_ipv4_metric_rmap, int type; u_int32_t metric; - type = bgp_str2route_type (AFI_IP, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8545,19 +8488,15 @@ DEFUN (bgp_redistribute_ipv4_metric_rmap, DEFUN (no_bgp_redistribute_ipv4, no_bgp_redistribute_ipv4_cmd, - "no redistribute (connected|kernel|ospf|rip|static)", + "no redistribute " QUAGGA_IP_REDIST_STR_BGPD, NO_STR "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n") + QUAGGA_IP_REDIST_HELP_STR_BGPD) { int type; - type = bgp_str2route_type (AFI_IP, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8568,21 +8507,17 @@ DEFUN (no_bgp_redistribute_ipv4, DEFUN (no_bgp_redistribute_ipv4_rmap, no_bgp_redistribute_ipv4_rmap_cmd, - "no redistribute (connected|kernel|ospf|rip|static) route-map WORD", + "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD", NO_STR "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n" + QUAGGA_IP_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") { int type; - type = bgp_str2route_type (AFI_IP, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8594,21 +8529,17 @@ DEFUN (no_bgp_redistribute_ipv4_rmap, DEFUN (no_bgp_redistribute_ipv4_metric, no_bgp_redistribute_ipv4_metric_cmd, - "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>", + "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n" + QUAGGA_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") { int type; - type = bgp_str2route_type (AFI_IP, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8620,14 +8551,10 @@ DEFUN (no_bgp_redistribute_ipv4_metric, DEFUN (no_bgp_redistribute_ipv4_rmap_metric, no_bgp_redistribute_ipv4_rmap_metric_cmd, - "no redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>", + "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n" + QUAGGA_IP_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" @@ -8635,8 +8562,8 @@ DEFUN (no_bgp_redistribute_ipv4_rmap_metric, { int type; - type = bgp_str2route_type (AFI_IP, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8649,14 +8576,10 @@ DEFUN (no_bgp_redistribute_ipv4_rmap_metric, ALIAS (no_bgp_redistribute_ipv4_rmap_metric, no_bgp_redistribute_ipv4_metric_rmap_cmd, - "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD", + "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", NO_STR "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n" + QUAGGA_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" @@ -8665,18 +8588,14 @@ ALIAS (no_bgp_redistribute_ipv4_rmap_metric, #ifdef HAVE_IPV6 DEFUN (bgp_redistribute_ipv6, bgp_redistribute_ipv6_cmd, - "redistribute (connected|kernel|ospf6|ripng|static)", + "redistribute " QUAGGA_IP6_REDIST_STR_BGPD, "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n") + QUAGGA_IP6_REDIST_HELP_STR_BGPD) { int type; - type = bgp_str2route_type (AFI_IP6, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8687,20 +8606,16 @@ DEFUN (bgp_redistribute_ipv6, DEFUN (bgp_redistribute_ipv6_rmap, bgp_redistribute_ipv6_rmap_cmd, - "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD", + "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD", "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n" + QUAGGA_IP6_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") { int type; - type = bgp_str2route_type (AFI_IP6, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8712,21 +8627,17 @@ DEFUN (bgp_redistribute_ipv6_rmap, DEFUN (bgp_redistribute_ipv6_metric, bgp_redistribute_ipv6_metric_cmd, - "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>", + "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295>", "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n" + QUAGGA_IP6_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") { int type; u_int32_t metric; - type = bgp_str2route_type (AFI_IP6, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8739,13 +8650,9 @@ DEFUN (bgp_redistribute_ipv6_metric, DEFUN (bgp_redistribute_ipv6_rmap_metric, bgp_redistribute_ipv6_rmap_metric_cmd, - "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>", + "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n" + QUAGGA_IP6_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" @@ -8754,8 +8661,8 @@ DEFUN (bgp_redistribute_ipv6_rmap_metric, int type; u_int32_t metric; - type = bgp_str2route_type (AFI_IP6, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8769,13 +8676,9 @@ DEFUN (bgp_redistribute_ipv6_rmap_metric, DEFUN (bgp_redistribute_ipv6_metric_rmap, bgp_redistribute_ipv6_metric_rmap_cmd, - "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD", + "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n" + QUAGGA_IP6_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" @@ -8784,8 +8687,8 @@ DEFUN (bgp_redistribute_ipv6_metric_rmap, int type; u_int32_t metric; - type = bgp_str2route_type (AFI_IP6, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8799,19 +8702,15 @@ DEFUN (bgp_redistribute_ipv6_metric_rmap, DEFUN (no_bgp_redistribute_ipv6, no_bgp_redistribute_ipv6_cmd, - "no redistribute (connected|kernel|ospf6|ripng|static)", + "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD, NO_STR "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n") + QUAGGA_IP6_REDIST_HELP_STR_BGPD) { int type; - type = bgp_str2route_type (AFI_IP6, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8822,21 +8721,17 @@ DEFUN (no_bgp_redistribute_ipv6, DEFUN (no_bgp_redistribute_ipv6_rmap, no_bgp_redistribute_ipv6_rmap_cmd, - "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD", + "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD", NO_STR "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n" + QUAGGA_IP6_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") { int type; - type = bgp_str2route_type (AFI_IP6, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8848,21 +8743,17 @@ DEFUN (no_bgp_redistribute_ipv6_rmap, DEFUN (no_bgp_redistribute_ipv6_metric, no_bgp_redistribute_ipv6_metric_cmd, - "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>", + "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n" + QUAGGA_IP6_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") { int type; - type = bgp_str2route_type (AFI_IP6, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8874,14 +8765,10 @@ DEFUN (no_bgp_redistribute_ipv6_metric, DEFUN (no_bgp_redistribute_ipv6_rmap_metric, no_bgp_redistribute_ipv6_rmap_metric_cmd, - "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>", + "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n" + QUAGGA_IP6_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" @@ -8889,8 +8776,8 @@ DEFUN (no_bgp_redistribute_ipv6_rmap_metric, { int type; - type = bgp_str2route_type (AFI_IP6, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8903,14 +8790,10 @@ DEFUN (no_bgp_redistribute_ipv6_rmap_metric, ALIAS (no_bgp_redistribute_ipv6_rmap_metric, no_bgp_redistribute_ipv6_metric_rmap_cmd, - "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD", + "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", NO_STR "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n" + QUAGGA_IP6_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" -- cgit v1.2.1 From ca0512692156d5bbb902523d2f123fc89dbec1ab Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sun, 4 Oct 2009 16:21:49 +0200 Subject: lib: add sockopt helper for setting IPV6_V6ONLY and use it getaddrinfo returns a list of socket parameters for listening. it will contain both IPv4 and IPv6 listening sockets. unless we use IPV6_V6ONLY on the IPv6 ones, only the socket listed first will work. if the IPv4 one came first, the IPv6 one would get an "Address in use" error. this functionality was already present for bgpd and its listening sockets. as it is needed for vtys as well, make it a common helper. Conflicts: lib/sockunion.c --- bgpd/bgp_network.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 274a989d..a7dca531 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -395,14 +395,7 @@ bgp_listener (int sock, struct sockaddr *sa, socklen_t salen) # endif #endif -#ifdef IPV6_V6ONLY - /* Want only IPV6 on ipv6 socket (not mapped addresses) */ - if (sa->sa_family == AF_INET6) { - int on = 1; - setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, - (void *) &on, sizeof (on)); - } -#endif + sockopt_v6only (sa->sa_family, sock); ret = bind (sock, sa, salen); en = errno; -- cgit v1.2.1 From bb915f5fa60de1a5b7e6089fcfc680281a590463 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Tue, 13 Dec 2011 21:11:39 +0400 Subject: bgpd: fix regression in ORF procesing (BZ#688) This issue has been pointed out by Lou Berger and Tim Browski. * bgp_packet.c * bgp_route_refresh_receive(): restore if() condition, which was broken by commit fdbc8e77c88f751924299d0bc752371d5cc31116 --- bgpd/bgp_packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bgpd') diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 4854f1dd..2c0113da 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -2054,7 +2054,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) break; } ok = ((p_end - p_pnt) >= sizeof(u_int32_t)) ; - if (!ok) + if (ok) { memcpy (&seq, p_pnt, sizeof (u_int32_t)); p_pnt += sizeof (u_int32_t); -- cgit v1.2.1 From 9206f9ecd5526778bf449bbb12f056d681d3b040 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 18 Dec 2011 19:43:40 +0400 Subject: fix set never used warnings (This patch was modified to leave calls to stream_getl() in place, they are necessary for the stream's internal pointer to advance to the correct position. -- Denis) Signed-off-by: Denis Ovsienko Fix gcc warnings about varables that are set but never used. * bgpd/bgp_attr.c * cluster_unintern(): ret * transit_unintern(): ret * bgp_attr_default_intern(): attre * bgp_mp_reach_parse(): rd_high, rd_low * bgpd/bgp_route.c * bgp_announce_check_rsclient(): bgp * bgpd/bgp_zebra.c * zebra_read_ipv4(): ifindex * zebra_read_ipv6(): ifindex * bgpd/bgpd.c * bgp_config_write_peer(): filter * lib/distribute.c * distribute_list_all(): dist * distribute_list(): dist * distribute_list_prefix_all(): dist * distribute_list_prefix(): dist * lib/if_rmap.c * if_rmap(): if_rmap * lib/vty.c * vty_accept(): vty * lib/zclient.c * zclient_read(): ret * zebra/irdp_interface.c * if_group(): zi * zebra/rt_netlink.c * kernel_read(): ret, sock --- bgpd/bgp_attr.c | 22 ++++++---------------- bgpd/bgp_route.c | 2 -- bgpd/bgp_zebra.c | 8 ++------ bgpd/bgpd.c | 2 -- 4 files changed, 8 insertions(+), 26 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 4e604b18..a2d4f4ba 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -175,14 +175,12 @@ cluster_intern (struct cluster_list *cluster) void cluster_unintern (struct cluster_list *cluster) { - struct cluster_list *ret; - if (cluster->refcnt) cluster->refcnt--; if (cluster->refcnt == 0) { - ret = hash_release (cluster_hash, cluster); + hash_release (cluster_hash, cluster); cluster_free (cluster); } } @@ -235,14 +233,12 @@ transit_intern (struct transit *transit) void transit_unintern (struct transit *transit) { - struct transit *ret; - if (transit->refcnt) transit->refcnt--; if (transit->refcnt == 0) { - ret = hash_release (transit_hash, transit); + hash_release (transit_hash, transit); transit_free (transit); } } @@ -552,10 +548,9 @@ bgp_attr_default_intern (u_char origin) { struct attr attr; struct attr *new; - struct attr_extra *attre; memset (&attr, 0, sizeof (struct attr)); - attre = bgp_attr_extra_get (&attr); + bgp_attr_extra_get (&attr); bgp_attr_default_set(&attr, origin); @@ -1516,14 +1511,9 @@ bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length, memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4); break; case 12: - { - u_int32_t rd_high; - u_int32_t rd_low; - - rd_high = stream_getl (s); - rd_low = stream_getl (s); - stream_get (&attre->mp_nexthop_global_in, s, 4); - } + stream_getl (s); /* RD high */ + stream_getl (s); /* RD low */ + stream_get (&attre->mp_nexthop_global_in, s, 4); break; #ifdef HAVE_IPV6 case 16: diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index f0dfcccd..e325f66f 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1069,11 +1069,9 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, struct bgp_filter *filter; struct bgp_info info; struct peer *from; - struct bgp *bgp; from = ri->peer; filter = &rsclient->filter[afi][safi]; - bgp = rsclient->bgp; if (DISABLE_BGP_ANNOUNCE) return 0; diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index d7af349a..76c519cb 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -232,12 +232,10 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv4 api; - unsigned long ifindex; struct in_addr nexthop; struct prefix_ipv4 p; s = zclient->ibuf; - ifindex = 0; nexthop.s_addr = 0; /* Type, flags, message. */ @@ -260,7 +258,7 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); - ifindex = stream_getl (s); + stream_getl (s); /* ifindex, unused */ } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); @@ -310,12 +308,10 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv6 api; - unsigned long ifindex; struct in6_addr nexthop; struct prefix_ipv6 p; s = zclient->ibuf; - ifindex = 0; memset (&nexthop, 0, sizeof (struct in6_addr)); /* Type, flags, message. */ @@ -338,7 +334,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); - ifindex = stream_getl (s); + stream_getl (s); /* ifindex, unused */ } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 8bc8d6ed..a75fb939 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -4721,12 +4721,10 @@ static void bgp_config_write_peer (struct vty *vty, struct bgp *bgp, struct peer *peer, afi_t afi, safi_t safi) { - struct bgp_filter *filter; struct peer *g_peer = NULL; char buf[SU_ADDRSTRLEN]; char *addr; - filter = &peer->filter[afi][safi]; addr = peer->host; if (peer_group_active (peer)) g_peer = peer->group->conf; -- cgit v1.2.1 From 733cd9e5792648de50da3c00805aacb51cb27048 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Sat, 17 Dec 2011 19:39:30 +0400 Subject: bgpd: justify checks for IPv4 class D/E * lib/prefix.h * IPV4_CLASS_DE(): make consistent with counterpart macros * bgp_packet.c * bgp_open_receive(): test using macro instead of ">=" * bgp_route.c * bgp_update_rsclient(): idem * bgp_update_main(): idem --- bgpd/bgp_packet.c | 2 +- bgpd/bgp_route.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 2c0113da..f5a74d1b 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1381,7 +1381,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) /* remote router-id check. */ if (remote_id.s_addr == 0 - || ntohl (remote_id.s_addr) >= 0xe0000000 + || IPV4_CLASS_DE (ntohl (remote_id.s_addr)) || ntohl (peer->local_id.s_addr) == ntohl (remote_id.s_addr)) { if (BGP_DEBUG (normal, NORMAL)) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index e325f66f..6477a7cc 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1812,9 +1812,9 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, /* IPv4 unicast next hop check. */ if (afi == AFI_IP && safi == SAFI_UNICAST) { - /* Next hop must not be 0.0.0.0 nor Class E address. */ + /* Next hop must not be 0.0.0.0 nor Class D/E address. */ if (new_attr.nexthop.s_addr == 0 - || ntohl (new_attr.nexthop.s_addr) >= 0xe0000000) + || IPV4_CLASS_DE (ntohl (new_attr.nexthop.s_addr))) { bgp_attr_unintern (&attr_new); @@ -2068,11 +2068,11 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, goto filtered; } - /* Next hop must not be 0.0.0.0 nor Class E address. Next hop + /* Next hop must not be 0.0.0.0 nor Class D/E address. Next hop must not be my own address. */ if (bgp_nexthop_self (afi, &new_attr) || new_attr.nexthop.s_addr == 0 - || ntohl (new_attr.nexthop.s_addr) >= 0xe0000000) + || IPV4_CLASS_DE (ntohl (new_attr.nexthop.s_addr))) { reason = "martian next-hop;"; goto filtered; -- cgit v1.2.1 From 664711c1f4cc218073783ff6ce362093debd7b53 Mon Sep 17 00:00:00 2001 From: Ulrich Weber Date: Wed, 21 Dec 2011 02:24:11 +0400 Subject: lib: fix some strtoul() use cases ...otherwise 4294967295 is not a valid value on 32bit systems --- bgpd/bgp_mplsvpn.c | 8 ++++++-- bgpd/bgp_routemap.c | 20 ++++++++++++++------ 2 files changed, 20 insertions(+), 8 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 72ad089e..c1f1fbb3 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -233,9 +233,13 @@ str2tag (const char *str, u_char *tag) char *endptr; u_int32_t t; - l = strtoul (str, &endptr, 10); + if (*str == '-') + return 0; - if (*endptr == '\0' || l == ULONG_MAX || l > UINT32_MAX) + errno = 0; + l = strtoul (str, &endptr, 10); + + if (*endptr != '\0' || errno || l > UINT32_MAX) return 0; t = (u_int32_t) l; diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 05bc304b..abb85fd2 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -525,8 +525,13 @@ route_match_metric_compile (const char *arg) char *endptr = NULL; unsigned long tmpval; + /* Metric value shoud be integer. */ + if (! all_digit (arg)) + return NULL; + + errno = 0; tmpval = strtoul (arg, &endptr, 10); - if (*endptr != '\0' || tmpval == ULONG_MAX || tmpval > UINT32_MAX) + if (*endptr != '\0' || errno || tmpval > UINT32_MAX) return NULL; med = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); @@ -1002,8 +1007,9 @@ route_set_local_pref_compile (const char *arg) if (! all_digit (arg)) return NULL; + errno = 0; tmp = strtoul (arg, &endptr, 10); - if (*endptr != '\0' || tmp == ULONG_MAX || tmp > UINT32_MAX) + if (*endptr != '\0' || errno || tmp > UINT32_MAX) return NULL; local_pref = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); @@ -1070,9 +1076,9 @@ route_set_weight_compile (const char *arg) if (! all_digit (arg)) return NULL; - + errno = 0; tmp = strtoul (arg, &endptr, 10); - if (*endptr != '\0' || tmp == ULONG_MAX || tmp > UINT32_MAX) + if (*endptr != '\0' || errno || tmp > UINT32_MAX) return NULL; weight = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); @@ -1161,8 +1167,9 @@ route_set_metric_compile (const char *arg) if (all_digit (arg)) { /* set metric value check*/ + errno = 0; larg = strtoul (arg, &endptr, 10); - if (*endptr != '\0' || larg == ULONG_MAX || larg > UINT32_MAX) + if (*endptr != '\0' || errno || larg > UINT32_MAX) return NULL; metric = larg; } @@ -1174,8 +1181,9 @@ route_set_metric_compile (const char *arg) || (! all_digit (arg+1))) return NULL; + errno = 0; larg = strtoul (arg+1, &endptr, 10); - if (*endptr != '\0' || larg == ULONG_MAX || larg > UINT32_MAX) + if (*endptr != '\0' || errno || larg > UINT32_MAX) return NULL; metric = larg; } -- cgit v1.2.1 From f63f06da2e7be6b17c72dd6110aae179f42f3700 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 8 Apr 2011 12:44:43 +0100 Subject: general: remove inline qualifiers and move in-header functions to objects * (general) Move functions in headers into files, to be compiled into shared object files. Remove inline qualifier from functions. Let the compiler do the work. --- bgpd/bgp_aspath.c | 8 ++++---- bgpd/bgpd.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index ba4f5b48..776c7127 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -91,13 +91,13 @@ static struct hash *ashash; /* Stream for SNMP. See aspath_snmp_pathseg */ static struct stream *snmp_stream; -static inline as_t * +static as_t * assegment_data_new (int num) { return (XCALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1))); } -static inline void +static void assegment_data_free (as_t *asdata) { XFREE (MTYPE_AS_SEG_DATA,asdata); @@ -812,7 +812,7 @@ aspath_parse (struct stream *s, size_t length, int use32bit) return find; } -static inline void +static void assegment_data_put (struct stream *s, as_t *as, int num, int use32bit) { int i; @@ -830,7 +830,7 @@ assegment_data_put (struct stream *s, as_t *as, int num, int use32bit) } } -static inline size_t +static size_t assegment_header_put (struct stream *s, u_char type, int length) { size_t lenp; diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index a75fb939..5dc014be 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -695,7 +695,7 @@ peer_sort (struct peer *peer) } } -static inline void +static void peer_free (struct peer *peer) { assert (peer->status == Deleted); -- cgit v1.2.1 From 8e80bdf20f493a71bcf74262ed3aa3a2437f4df6 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Fri, 5 Aug 2011 18:52:52 +0400 Subject: bgpd: touch nexthop handling code bgp_nexthop_lookup_ipv6(): declare variables where they are actually used, drop no-op initialization (the field is already 0) bgp_nexthop_lookup(): ditto bgp_nexthop_check_ebgp(): rename to bgp_nexthop_onlink() bgp_nexthop_cache_changed(): rename to bgp_nexthop_cache_different() --- bgpd/bgp_nexthop.c | 30 +++++++++++++----------------- bgpd/bgp_nexthop.h | 2 +- bgpd/bgp_route.c | 2 +- 3 files changed, 15 insertions(+), 19 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 60efa195..d888c8f2 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -146,7 +146,7 @@ bgp_nexthop_same (struct nexthop *next1, struct nexthop *next2) } static int -bgp_nexthop_cache_changed (struct bgp_nexthop_cache *bnc1, +bgp_nexthop_cache_different (struct bgp_nexthop_cache *bnc1, struct bgp_nexthop_cache *bnc2) { int i; @@ -171,7 +171,7 @@ bgp_nexthop_cache_changed (struct bgp_nexthop_cache *bnc1, /* If nexthop exists on connected network return 1. */ int -bgp_nexthop_check_ebgp (afi_t afi, struct attr *attr) +bgp_nexthop_onlink (afi_t afi, struct attr *attr) { struct bgp_node *rn; @@ -256,12 +256,11 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, bnc = zlookup_query_ipv6 (&attr->extra->mp_nexthop_global); if (bnc) { - struct bgp_table *old; - struct bgp_node *oldrn; - struct bgp_nexthop_cache *oldbnc; - if (changed) { + struct bgp_table *old; + struct bgp_node *oldrn; + if (bgp_nexthop_cache_table[AFI_IP6] == cache1_table[AFI_IP6]) old = cache2_table[AFI_IP6]; else @@ -270,9 +269,9 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, oldrn = bgp_node_lookup (old, &p); if (oldrn) { - oldbnc = oldrn->info; + struct bgp_nexthop_cache *oldbnc = oldrn->info; - bnc->changed = bgp_nexthop_cache_changed (bnc, oldbnc); + bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc); if (bnc->metric != oldbnc->metric) bnc->metricchanged = 1; @@ -284,7 +283,6 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, else { bnc = bnc_new (); - bnc->valid = 0; } rn->info = bnc; } @@ -347,12 +345,11 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, bnc = zlookup_query (addr); if (bnc) { - struct bgp_table *old; - struct bgp_node *oldrn; - struct bgp_nexthop_cache *oldbnc; - if (changed) { + struct bgp_table *old; + struct bgp_node *oldrn; + if (bgp_nexthop_cache_table[AFI_IP] == cache1_table[AFI_IP]) old = cache2_table[AFI_IP]; else @@ -361,9 +358,9 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, oldrn = bgp_node_lookup (old, &p); if (oldrn) { - oldbnc = oldrn->info; + struct bgp_nexthop_cache *oldbnc = oldrn->info; - bnc->changed = bgp_nexthop_cache_changed (bnc, oldbnc); + bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc); if (bnc->metric != oldbnc->metric) bnc->metricchanged = 1; @@ -375,7 +372,6 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, else { bnc = bnc_new (); - bnc->valid = 0; } rn->info = bnc; } @@ -462,7 +458,7 @@ bgp_scan (afi_t afi, safi_t safi) metricchanged = 0; if (peer_sort (bi->peer) == BGP_PEER_EBGP && bi->peer->ttl == 1) - valid = bgp_nexthop_check_ebgp (afi, bi->attr); + valid = bgp_nexthop_onlink (afi, bi->attr); else valid = bgp_nexthop_lookup (afi, bi->peer, bi, &changed, &metricchanged); diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index 2dad742f..874f3bba 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -54,7 +54,7 @@ extern void bgp_connected_add (struct connected *c); extern void bgp_connected_delete (struct connected *c); extern int bgp_multiaccess_check_v4 (struct in_addr, char *); extern int bgp_config_write_scan_time (struct vty *); -extern int bgp_nexthop_check_ebgp (afi_t, struct attr *); +extern int bgp_nexthop_onlink (afi_t, struct attr *); extern int bgp_nexthop_self (afi_t, struct attr *); #endif /* _QUAGGA_BGP_NEXTHOP_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 6477a7cc..68d05484 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2061,7 +2061,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* If the peer is EBGP and nexthop is not on connected route, discard it. */ if (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl == 1 - && ! bgp_nexthop_check_ebgp (afi, &new_attr) + && ! bgp_nexthop_onlink (afi, &new_attr) && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) { reason = "non-connected next-hop;"; -- cgit v1.2.1 From 318f0d8a7f5e8e87086bbf2a9e7c4b35638951ac Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Fri, 5 Aug 2011 21:47:08 +0400 Subject: bgpd: add "show ip bgp scan detail" command * bgp_nexthop.c: (show_ip_bgp_scan) transform into show_ip_bgp_scan_tables(), which uses inet_ntop() and can dump nexthops on request; (show_ip_bgp_scan_detail_cmd) new function --- bgpd/bgp_nexthop.c | 59 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 15 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index d888c8f2..db121d2c 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -1192,16 +1192,13 @@ ALIAS (no_bgp_scan_time, "Configure background scanner interval\n" "Scanner interval (seconds)\n") -DEFUN (show_ip_bgp_scan, - show_ip_bgp_scan_cmd, - "show ip bgp scan", - SHOW_STR - IP_STR - BGP_STR - "BGP scan status\n") +static int +show_ip_bgp_scan_tables (struct vty *vty, const char detail) { struct bgp_node *rn; struct bgp_nexthop_cache *bnc; + char buf[INET6_ADDRSTRLEN]; + u_char i; if (bgp_scan_thread) vty_out (vty, "BGP scan is running%s", VTY_NEWLINE); @@ -1214,28 +1211,37 @@ DEFUN (show_ip_bgp_scan, if ((bnc = rn->info) != NULL) { if (bnc->valid) + { vty_out (vty, " %s valid [IGP metric %d]%s", - inet_ntoa (rn->p.u.prefix4), bnc->metric, VTY_NEWLINE); + inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), bnc->metric, VTY_NEWLINE); + if (detail) + for (i = 0; i < bnc->nexthop_num; i++) + vty_out (vty, " %s%s", inet_ntop (AF_INET, &bnc->nexthop[i].gate.ipv4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); + } else vty_out (vty, " %s invalid%s", - inet_ntoa (rn->p.u.prefix4), VTY_NEWLINE); + inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); } #ifdef HAVE_IPV6 { - char buf[BUFSIZ]; for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP6]); rn; rn = bgp_route_next (rn)) if ((bnc = rn->info) != NULL) { if (bnc->valid) + { vty_out (vty, " %s valid [IGP metric %d]%s", - inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), + inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN), bnc->metric, VTY_NEWLINE); + if (detail) + for (i = 0; i < bnc->nexthop_num; i++) + vty_out (vty, " %s%s", inet_ntop (AF_INET6, &bnc->nexthop[i].gate.ipv4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); + } else vty_out (vty, " %s invalid%s", - inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), + inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); } } @@ -1251,14 +1257,12 @@ DEFUN (show_ip_bgp_scan, #ifdef HAVE_IPV6 { - char buf[BUFSIZ]; - for (rn = bgp_table_top (bgp_connected_table[AFI_IP6]); rn; rn = bgp_route_next (rn)) if (rn->info != NULL) vty_out (vty, " %s/%d%s", - inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), + inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN), rn->p.prefixlen, VTY_NEWLINE); } @@ -1267,6 +1271,29 @@ DEFUN (show_ip_bgp_scan, return CMD_SUCCESS; } +DEFUN (show_ip_bgp_scan, + show_ip_bgp_scan_cmd, + "show ip bgp scan", + SHOW_STR + IP_STR + BGP_STR + "BGP scan status\n") +{ + return show_ip_bgp_scan_tables (vty, 0); +} + +DEFUN (show_ip_bgp_scan_detail, + show_ip_bgp_scan_detail_cmd, + "show ip bgp scan detail", + SHOW_STR + IP_STR + BGP_STR + "BGP scan status\n" + "More detailed output\n") +{ + return show_ip_bgp_scan_tables (vty, 1); +} + int bgp_config_write_scan_time (struct vty *vty) { @@ -1308,8 +1335,10 @@ bgp_scan_init (void) install_element (BGP_NODE, &no_bgp_scan_time_cmd); install_element (BGP_NODE, &no_bgp_scan_time_val_cmd); install_element (VIEW_NODE, &show_ip_bgp_scan_cmd); + install_element (VIEW_NODE, &show_ip_bgp_scan_detail_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_scan_cmd); install_element (ENABLE_NODE, &show_ip_bgp_scan_cmd); + install_element (ENABLE_NODE, &show_ip_bgp_scan_detail_cmd); } void -- cgit v1.2.1 From b64bfc1c4a552fc0b4dd024d5f77171ec848a5df Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Mon, 8 Aug 2011 19:36:44 +0400 Subject: bgpd: dismiss some zlookup checks bgp_nexthop_onlink(): zlookup is not used here at all bgp_nexthop_lookup_ipv6(): rely on the detection performed by "query" function (this also changes the fallback value to 0), reorder if-block bgp_nexthop_lookup(): idem --- bgpd/bgp_nexthop.c | 38 ++++++-------------------------------- 1 file changed, 6 insertions(+), 32 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index db121d2c..dc448f9f 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -175,10 +175,6 @@ bgp_nexthop_onlink (afi_t afi, struct attr *attr) { struct bgp_node *rn; - /* If zebra is not enabled return */ - if (zlookup->sock < 0) - return 1; - /* Lookup the address is onlink or not. */ if (afi == AFI_IP) { @@ -223,14 +219,6 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, struct bgp_nexthop_cache *bnc; struct attr *attr; - /* If lookup is not enabled, return valid. */ - if (zlookup->sock < 0) - { - if (ri->extra) - ri->extra->igpmetric = 0; - return 1; - } - /* Only check IPv6 global address only nexthop. */ attr = ri->attr; @@ -253,8 +241,9 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, } else { - bnc = zlookup_query_ipv6 (&attr->extra->mp_nexthop_global); - if (bnc) + if (NULL == (bnc = zlookup_query_ipv6 (&attr->extra->mp_nexthop_global))) + bnc = bnc_new (); + else { if (changed) { @@ -280,10 +269,6 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, } } } - else - { - bnc = bnc_new (); - } rn->info = bnc; } @@ -312,14 +297,6 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, struct bgp_nexthop_cache *bnc; struct in_addr addr; - /* If lookup is not enabled, return valid. */ - if (zlookup->sock < 0) - { - if (ri->extra) - ri->extra->igpmetric = 0; - return 1; - } - #ifdef HAVE_IPV6 if (afi == AFI_IP6) return bgp_nexthop_lookup_ipv6 (peer, ri, changed, metricchanged); @@ -342,8 +319,9 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, } else { - bnc = zlookup_query (addr); - if (bnc) + if (NULL == (bnc = zlookup_query (addr))) + bnc = bnc_new (); + else { if (changed) { @@ -369,10 +347,6 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, } } } - else - { - bnc = bnc_new (); - } rn->info = bnc; } -- cgit v1.2.1 From 0e8032d69961ae196c11ba6ead856084c7acf7c2 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Tue, 9 Aug 2011 14:42:58 +0400 Subject: bgpd: improve "show ip bgp scan detail" * bgp_nexthop.c (show_ip_bgp_scan_tables): access proper structure field in AF_INET6 case, handle ifindex NH type properly --- bgpd/bgp_nexthop.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index dc448f9f..e9c78b3f 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -1190,7 +1190,17 @@ show_ip_bgp_scan_tables (struct vty *vty, const char detail) inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), bnc->metric, VTY_NEWLINE); if (detail) for (i = 0; i < bnc->nexthop_num; i++) - vty_out (vty, " %s%s", inet_ntop (AF_INET, &bnc->nexthop[i].gate.ipv4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); + switch (bnc->nexthop[i].type) + { + case NEXTHOP_TYPE_IPV4: + vty_out (vty, " gate %s%s", inet_ntop (AF_INET, &bnc->nexthop[i].gate.ipv4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); + break; + case NEXTHOP_TYPE_IFINDEX: + vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE); + break; + default: + vty_out (vty, " invalid nexthop type %u%s", bnc->nexthop[i].type, VTY_NEWLINE); + } } else vty_out (vty, " %s invalid%s", @@ -1211,7 +1221,17 @@ show_ip_bgp_scan_tables (struct vty *vty, const char detail) bnc->metric, VTY_NEWLINE); if (detail) for (i = 0; i < bnc->nexthop_num; i++) - vty_out (vty, " %s%s", inet_ntop (AF_INET6, &bnc->nexthop[i].gate.ipv4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); + switch (bnc->nexthop[i].type) + { + case NEXTHOP_TYPE_IPV6: + vty_out (vty, " gate %s%s", inet_ntop (AF_INET6, &bnc->nexthop[i].gate.ipv6, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); + break; + case NEXTHOP_TYPE_IFINDEX: + vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE); + break; + default: + vty_out (vty, " invalid nexthop type %u%s", bnc->nexthop[i].type, VTY_NEWLINE); + } } else vty_out (vty, " %s invalid%s", -- cgit v1.2.1 From afcb767922509c4d998f1c567e350b9809c148ab Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Sun, 23 Oct 2011 22:32:44 +0400 Subject: bgpd: rewrite attr flag error logging * bgp_attr.c * attr_flag_str: new message list * bgp_attr_flags_diagnose(): new function, implements previously added error logging in a generic way * bgp_attr_origin(): use bgp_attr_flags_diagnose() * bgp_attr_nexthop(): ditto * bgp_attr_med(): ditto * bgp_attr_local_pref(): ditto * bgp_attr_atomic(): ditto * bgp_attr_originator_id(): ditto * bgp_attr_cluster_list(): ditto * bgp_mp_reach_parse(): ditto * bgp_mp_unreach_parse(): ditto --- bgpd/bgp_attr.c | 108 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 54 insertions(+), 54 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index a2d4f4ba..b013c23f 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -63,6 +63,17 @@ static const struct message attr_str [] = { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" }, }; static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]); + +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 = + sizeof (attr_flag_str) / sizeof (attr_flag_str[0]); static struct hash *cluster_hash; @@ -754,6 +765,40 @@ bgp_attr_malformed (struct peer *peer, u_char type, u_char flag, return BGP_ATTR_PARSE_ERROR; } +/* Find out what is wrong with the path attribute flag bits and log the error. + "Flag bits" here stand for Optional, Transitive and Partial, but not for + Extended Length. Checking O/T/P bits at once implies, that the attribute + being diagnosed is defined by RFC as either a "well-known" or an "optional, + non-transitive" attribute. */ +static void +bgp_attr_flags_diagnose +( + struct peer * peer, + const u_int8_t attr_code, + u_int8_t desired_flags, /* how RFC says it must be */ + u_int8_t real_flags /* on wire */ +) +{ + u_char seen = 0, i; + + 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 (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; + } + assert (seen); +} + /* Get origin attribute of the update message. */ static bgp_attr_parse_ret_t bgp_attr_origin (struct peer *peer, bgp_size_t length, @@ -771,12 +816,7 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, attribute (type, length and value). */ if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS) { - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) - zlog (peer->log, LOG_ERR, "ORIGIN attribute must not be flagged as \"optional\" (%u)", flag); - if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) - zlog (peer->log, LOG_ERR, "ORIGIN attribute must be flagged as \"transitive\" (%u)", flag); - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) - zlog (peer->log, LOG_ERR, "ORIGIN attribute must not be flagged as \"partial\" (%u)", flag); + bgp_attr_flags_diagnose (peer, BGP_ATTR_ORIGIN, BGP_ATTR_FLAG_TRANS, flag); return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); } @@ -978,12 +1018,7 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length, /* Flags check. */ if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS) { - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) - zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must not be flagged as \"optional\" (%u)", flag); - if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) - zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must be flagged as \"transitive\" (%u)", flag); - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) - zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must not be flagged as \"partial\" (%u)", flag); + bgp_attr_flags_diagnose (peer, BGP_ATTR_NEXT_HOP, BGP_ATTR_FLAG_TRANS, flag); return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); } @@ -1033,12 +1068,7 @@ bgp_attr_med (struct peer *peer, bgp_size_t length, /* Flag checks. */ if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL) { - if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) - zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag); - 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); - 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_attr_flags_diagnose (peer, BGP_ATTR_MULTI_EXIT_DISC, BGP_ATTR_FLAG_OPTIONAL, flag); return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); @@ -1073,12 +1103,7 @@ bgp_attr_local_pref (struct peer *peer, bgp_size_t length, /* Flag checks. */ if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS) { - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) - zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must not be flagged as \"optional\" (%u)", flag); - if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) - zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag); - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) - zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must not be flagged as \"partial\" (%u)", flag); + bgp_attr_flags_diagnose (peer, BGP_ATTR_LOCAL_PREF, BGP_ATTR_FLAG_TRANS, flag); return bgp_attr_malformed (peer, BGP_ATTR_LOCAL_PREF, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); @@ -1120,12 +1145,7 @@ bgp_attr_atomic (struct peer *peer, bgp_size_t length, /* Flag checks. */ if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS) { - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) - zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag); - if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) - zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag); - 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_attr_flags_diagnose (peer, BGP_ATTR_ATOMIC_AGGREGATE, BGP_ATTR_FLAG_TRANS, flag); return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); @@ -1375,12 +1395,7 @@ bgp_attr_originator_id (struct peer *peer, bgp_size_t length, /* Flag checks. */ if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL) { - if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) - zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must be flagged as \"optional\" (%u)", flag); - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) - zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must not be flagged as \"transitive\" (%u)", flag); - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) - zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must not be flagged as \"partial\" (%u)", flag); + bgp_attr_flags_diagnose (peer, BGP_ATTR_ORIGINATOR_ID, BGP_ATTR_FLAG_OPTIONAL, flag); return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); @@ -1414,12 +1429,7 @@ bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, /* Flag checks. */ if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL) { - if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) - zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must be flagged as \"optional\" (%u)", flag); - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) - zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must not be flagged as \"transitive\" (%u)", flag); - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) - zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must not be flagged as \"partial\" (%u)", flag); + bgp_attr_flags_diagnose (peer, BGP_ATTR_CLUSTER_LIST, BGP_ATTR_FLAG_OPTIONAL, flag); return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); @@ -1463,12 +1473,7 @@ bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length, /* Flag checks. */ if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL) { - if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) - zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must be flagged as \"optional\" (%u)", flag); - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) - zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must not be flagged as \"transitive\" (%u)", flag); - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) - zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must not be flagged as \"partial\" (%u)", flag); + bgp_attr_flags_diagnose (peer, BGP_ATTR_MP_REACH_NLRI, BGP_ATTR_FLAG_OPTIONAL, flag); return bgp_attr_malformed (peer, BGP_ATTR_MP_REACH_NLRI, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); @@ -1606,12 +1611,7 @@ bgp_mp_unreach_parse (struct peer *peer, const bgp_size_t length, /* Flag checks. */ if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL) { - if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) - zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must be flagged as \"optional\" (%u)", flag); - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) - zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must not be flagged as \"transitive\" (%u)", flag); - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) - zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must not be flagged as \"partial\" (%u)", flag); + bgp_attr_flags_diagnose (peer, BGP_ATTR_MP_UNREACH_NLRI, BGP_ATTR_FLAG_OPTIONAL, flag); return bgp_attr_malformed (peer, BGP_ATTR_MP_UNREACH_NLRI, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); -- cgit v1.2.1 From 83a9a2213a73aeb9796b69327c87e89e2d3327ed Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sun, 8 Jan 2012 14:15:03 +0000 Subject: bgpd: Improve flag error messages in bgp_attr_aspath * bgpd/bgp_attr.c: (bgp_attr_aspath) error message could be misleading, clearly log what flag was incorrect. (Problem noted in "bgpd: fix error message in bgp_attr_aspath()" in Quagga-RE) --- bgpd/bgp_attr.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index b013c23f..1c13d11c 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -867,7 +867,7 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length, total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - /* Flag check. */ + /* Flags check. */ if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) { zlog (peer->log, LOG_ERR, @@ -877,11 +877,20 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length, startp, total); } - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) - || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) + if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) + { + zlog (peer->log, LOG_ERR, + "AS_PATH attribute must be flagged as \"transitive\" (%u)", flag); + return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + } + + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) { zlog (peer->log, LOG_ERR, - "As-Path attribute flag isn't transitive %d", flag); + "AS_PATH attribute must not be flagged as \"optional\" (%u)", flag); + return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); -- cgit v1.2.1 From f31d6927b2df4340bf9ff1cc9f20d52e168a3766 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sun, 8 Jan 2012 14:17:42 +0000 Subject: bgpd: Fix incorrect attribute type code in call to bgp_attr_malformed --- bgpd/bgp_attr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 1c13d11c..92c1a09f 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -872,7 +872,7 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length, { zlog (peer->log, LOG_ERR, "AS_PATH attribute must not be flagged as \"partial\" (%u)", flag); - return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, + return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); } @@ -989,7 +989,7 @@ bgp_attr_as4_path (struct peer *peer, bgp_size_t length, { 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, + return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); } -- cgit v1.2.1 From fc98d16ea77372f4ab4231e8904f8467e8d1ef71 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 9 Jan 2012 11:36:23 +0000 Subject: bgpd: reinstate zlookup checks, required for BGP without zebra * bgp_nexthop.c: The nexthop lookup cache has to return success for queried nexthops if bgpd isn't connected to zebra, or else BGP without zebra doesn't work. --- bgpd/bgp_nexthop.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index e9c78b3f..fdf251b2 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -174,7 +174,11 @@ int bgp_nexthop_onlink (afi_t afi, struct attr *attr) { struct bgp_node *rn; - + + /* If zebra is not enabled return */ + if (zlookup->sock < 0) + return 1; + /* Lookup the address is onlink or not. */ if (afi == AFI_IP) { @@ -218,7 +222,15 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, struct prefix p; struct bgp_nexthop_cache *bnc; struct attr *attr; - + + /* If lookup is not enabled, return valid. */ + if (zlookup->sock < 0) + { + if (ri->extra) + ri->extra->igpmetric = 0; + return 1; + } + /* Only check IPv6 global address only nexthop. */ attr = ri->attr; @@ -296,7 +308,15 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, struct prefix p; struct bgp_nexthop_cache *bnc; struct in_addr addr; - + + /* If lookup is not enabled, return valid. */ + if (zlookup->sock < 0) + { + if (ri->extra) + ri->extra->igpmetric = 0; + return 1; + } + #ifdef HAVE_IPV6 if (afi == AFI_IP6) return bgp_nexthop_lookup_ipv6 (peer, ri, changed, metricchanged); -- cgit v1.2.1 From 5a616c08ce089e25dc0e8da920727af4d11279bf Mon Sep 17 00:00:00 2001 From: "G.Balaji" Date: Sat, 26 Nov 2011 21:58:42 +0400 Subject: bgpd: IPv4 MP-BGP Routes addition and deletion This patch contains the following: 1. Addition of IPv4 SAFI_MULTICAST BGP routes into the BGP Multicast RIB. 2. Deletion of IPv4 SAFI_MULTICAST BGP routes from the BGP Multicast RIB. --- bgpd/bgp_route.c | 16 ++++++++-------- bgpd/bgp_zebra.c | 6 ++++-- bgpd/bgp_zebra.h | 4 ++-- 3 files changed, 14 insertions(+), 12 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 68d05484..3e5e9c2f 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1491,7 +1491,7 @@ bgp_process_main (struct work_queue *wq, void *data) if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED)) { if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED)) - bgp_zebra_announce (p, old_select, bgp); + bgp_zebra_announce (p, old_select, bgp, safi); UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED); return WQ_SUCCESS; @@ -1514,20 +1514,20 @@ bgp_process_main (struct work_queue *wq, void *data) } /* FIB update. */ - if (safi == SAFI_UNICAST && ! bgp->name && - ! bgp_option_check (BGP_OPT_NO_FIB)) + if ((safi == SAFI_UNICAST || safi == SAFI_MULTICAST) && (! bgp->name && + ! bgp_option_check (BGP_OPT_NO_FIB))) { if (new_select && new_select->type == ZEBRA_ROUTE_BGP && new_select->sub_type == BGP_ROUTE_NORMAL) - bgp_zebra_announce (p, new_select, bgp); + bgp_zebra_announce (p, new_select, bgp, safi); else { /* Withdraw the route from the kernel. */ if (old_select && old_select->type == ZEBRA_ROUTE_BGP && old_select->sub_type == BGP_ROUTE_NORMAL) - bgp_zebra_withdraw (p, old_select); + bgp_zebra_withdraw (p, old_select, safi); } } @@ -1810,7 +1810,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, bgp_attr_unintern (&attr_new2); /* IPv4 unicast next hop check. */ - if (afi == AFI_IP && safi == SAFI_UNICAST) + if ((afi == AFI_IP) && ((safi == SAFI_UNICAST) || safi == SAFI_MULTICAST)) { /* Next hop must not be 0.0.0.0 nor Class D/E address. */ if (new_attr.nexthop.s_addr == 0 @@ -2934,7 +2934,7 @@ bgp_cleanup_routes (void) if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->type == ZEBRA_ROUTE_BGP && ri->sub_type == BGP_ROUTE_NORMAL) - bgp_zebra_withdraw (&rn->p, ri); + bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST); table = bgp->rib[AFI_IP6][SAFI_UNICAST]; @@ -2943,7 +2943,7 @@ bgp_cleanup_routes (void) if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->type == ZEBRA_ROUTE_BGP && ri->sub_type == BGP_ROUTE_NORMAL) - bgp_zebra_withdraw (&rn->p, ri); + bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST); } } diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 76c519cb..baf76fb0 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -643,7 +643,7 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote, } void -bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp) +bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, safi_t safi) { int flags; u_char distance; @@ -678,6 +678,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp) api.type = ZEBRA_ROUTE_BGP; api.message = 0; + api.safi = safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; @@ -778,7 +779,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp) } void -bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info) +bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) { int flags; struct peer *peer; @@ -812,6 +813,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info) api.type = ZEBRA_ROUTE_BGP; api.message = 0; + api.safi = safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index bd953864..1351333f 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -25,8 +25,8 @@ extern void bgp_zebra_init (void); extern int bgp_if_update_all (void); extern int bgp_config_write_redistribute (struct vty *, struct bgp *, afi_t, safi_t, int *); -extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *); -extern void bgp_zebra_withdraw (struct prefix *, struct bgp_info *); +extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *, safi_t); +extern void bgp_zebra_withdraw (struct prefix *, struct bgp_info *, safi_t); extern int bgp_redistribute_set (struct bgp *, afi_t, int); extern int bgp_redistribute_rmap_set (struct bgp *, afi_t, int, const char *); -- cgit v1.2.1 From c7ec179a95c1ed4fcd3d3be3f981c8c20dce534a Mon Sep 17 00:00:00 2001 From: "G.Balaji" Date: Sat, 26 Nov 2011 22:04:05 +0400 Subject: bgpd: IPv6 MP-BGP Routes addition and deletion This patch contains the following: 1. Addition of IPv6 SAFI_MULTICAST BGP routes into the BGP Multicast RIB. 2. Deletion of IPv6 SAFI_MULTICAST BGP routes from the BGP Multicast RIB. --- bgpd/bgp_zebra.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'bgpd') diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index baf76fb0..20feba0f 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -753,6 +753,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, sa api.flags = flags; api.type = ZEBRA_ROUTE_BGP; api.message = 0; + api.safi = safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; @@ -869,6 +870,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) api.flags = flags; api.type = ZEBRA_ROUTE_BGP; api.message = 0; + api.safi = safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; -- cgit v1.2.1 From 73bfe0bd9adb8e4dfcee7239e56a425c6d58f4e9 Mon Sep 17 00:00:00 2001 From: "G.Balaji" Date: Fri, 23 Sep 2011 22:36:20 +0530 Subject: bgpd: Addition of ipv6 network command in Multicast address family mode. The patch adds the ipv6 network command in the BGP multicast address family mode. --- bgpd/bgp_route.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 3e5e9c2f..ba530321 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4167,7 +4167,7 @@ DEFUN (ipv6_bgp_network, "Specify a network to announce via BGP\n" "IPv6 prefix /\n") { - return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST, + return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, bgp_node_safi(vty), NULL, 0); } @@ -4190,7 +4190,7 @@ DEFUN (no_ipv6_bgp_network, "Specify a network to announce via BGP\n" "IPv6 prefix /\n") { - return bgp_static_unset (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST); + return bgp_static_unset (vty, vty->index, argv[0], AFI_IP6, bgp_node_safi(vty)); } ALIAS (no_ipv6_bgp_network, @@ -12580,6 +12580,9 @@ bgp_route_init (void) install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd); install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_summary_only_cmd); + install_element (BGP_IPV6M_NODE, &ipv6_bgp_network_cmd); + install_element (BGP_IPV6M_NODE, &no_ipv6_bgp_network_cmd); + /* Old config IPv6 BGP commands. */ install_element (BGP_NODE, &old_ipv6_bgp_network_cmd); install_element (BGP_NODE, &old_no_ipv6_bgp_network_cmd); -- cgit v1.2.1 From 3ecab4c8549574d09f8d8366098939a8ad3da6c4 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 17 Jan 2012 13:31:33 +0000 Subject: bgpd: consolidate attribute flag checks * bgpd/bgp_attr.c: (attr_flags_values []) array of required flags for attributes, EXTLEN & PARTIAL masked off as "dont care" as appropriate. (bgp_attr_flag_invalid) check if flags may be invalid, according to the above table & RFC rules. (bgp_attr_*) Use bgp_attr_flag_invalid. (bgp_attr_as4_aggregator) ditto, also take startp argument for the NOTIFY data. (bgp_attr_parse) pass startp to bgp_attr_as4_aggregator --- bgpd/bgp_attr.c | 221 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 133 insertions(+), 88 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 92c1a09f..d8ca831a 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -799,6 +799,92 @@ bgp_attr_flags_diagnose assert (seen); } +/* Required flags for attributes. EXTLEN will be masked off when testing, + * as will PARTIAL for optional+transitive attributes. + */ +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]); + +static int +bgp_attr_flag_invalid (struct peer *peer, u_int8_t attr_code, u_int8_t flags) +{ + u_int8_t mask = BGP_ATTR_FLAG_EXTLEN; + + /* 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, + "%s well-known attributes must have transitive flag set (%x)", + LOOKUP (attr_str, attr_code), flags); + return 1; + } + + /* "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 & ~attr_flags_values[attr_code]) + == attr_flags_values[attr_code]) + return 0; + + bgp_attr_flags_diagnose (peer, attr_code, attr_flags_values[attr_code], + flags); + return 1; +} + /* Get origin attribute of the update message. */ static bgp_attr_parse_ret_t bgp_attr_origin (struct peer *peer, bgp_size_t length, @@ -814,11 +900,10 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, 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 ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS) - { - bgp_attr_flags_diagnose (peer, BGP_ATTR_ORIGIN, BGP_ATTR_FLAG_TRANS, flag); - return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); - } + if (bgp_attr_flag_invalid (peer, BGP_ATTR_ORIGIN, flag)) + return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); /* If any recognized attribute has Attribute Length that conflicts with the expected length (based on the attribute type code), then @@ -866,36 +951,11 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length, bgp_size_t total; total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - - /* Flags check. */ - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) - { - zlog (peer->log, LOG_ERR, - "AS_PATH attribute must not be flagged as \"partial\" (%u)", flag); - return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - } - - if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) - { - zlog (peer->log, LOG_ERR, - "AS_PATH attribute must be flagged as \"transitive\" (%u)", flag); + + if (bgp_attr_flag_invalid (peer, BGP_ATTR_AS_PATH, flag)) return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); - } - - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) - { - zlog (peer->log, LOG_ERR, - "AS_PATH attribute must not be flagged as \"optional\" (%u)", 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 * otherwise, will get 16 Bit @@ -984,16 +1044,11 @@ bgp_attr_as4_path (struct peer *peer, bgp_size_t length, 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, - "As4-Path attribute flag isn't optional/transitive %d", flag); + if (bgp_attr_flag_invalid (peer, BGP_ATTR_AS4_PATH, flag)) return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); - } - + *as4_path = aspath_parse (peer->ibuf, length, 1); /* In case of IBGP, length will be zero. */ @@ -1025,11 +1080,10 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length, total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* Flags check. */ - if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS) - { - bgp_attr_flags_diagnose (peer, BGP_ATTR_NEXT_HOP, BGP_ATTR_FLAG_TRANS, flag); - return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); - } + if (bgp_attr_flag_invalid (peer, BGP_ATTR_NEXT_HOP, flag)) + return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); /* Check nexthop attribute length. */ if (length != 4) @@ -1075,13 +1129,10 @@ bgp_attr_med (struct peer *peer, bgp_size_t length, total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* Flag checks. */ - if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL) - { - bgp_attr_flags_diagnose (peer, BGP_ATTR_MULTI_EXIT_DISC, BGP_ATTR_FLAG_OPTIONAL, flag); + if (bgp_attr_flag_invalid (peer, BGP_ATTR_MULTI_EXIT_DISC, flag)) return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); - } /* Length check. */ if (length != 4) @@ -1110,13 +1161,11 @@ bgp_attr_local_pref (struct peer *peer, bgp_size_t length, total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* Flag checks. */ - if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS) - { - bgp_attr_flags_diagnose (peer, BGP_ATTR_LOCAL_PREF, BGP_ATTR_FLAG_TRANS, flag); + if (bgp_attr_flag_invalid (peer, BGP_ATTR_LOCAL_PREF, flag)) return bgp_attr_malformed (peer, BGP_ATTR_LOCAL_PREF, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); - } + /* Length check. */ if (length != 4) { @@ -1152,14 +1201,11 @@ bgp_attr_atomic (struct peer *peer, bgp_size_t length, total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* Flag checks. */ - if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS) - { - bgp_attr_flags_diagnose (peer, BGP_ATTR_ATOMIC_AGGREGATE, BGP_ATTR_FLAG_TRANS, flag); + if (bgp_attr_flag_invalid (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag)) return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); - } - + /* Length check. */ if (length != 0) { @@ -1186,22 +1232,11 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length, total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* Flags check. */ - if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) - { - zlog (peer->log, LOG_ERR, - "AGGREGATOR attribute must be flagged as \"optional\" (%u)", flag); - return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - } - if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) - { - zlog (peer->log, LOG_ERR, - "AGGREGATOR attribute must be flagged as \"transitive\" (%u)", flag); + if (bgp_attr_flag_invalid (peer, BGP_ATTR_AGGREGATOR, flag)) return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); - } + /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */ if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) wantedlen = 8; @@ -1231,8 +1266,11 @@ static bgp_attr_parse_ret_t bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length, struct attr *attr, u_char flag, as_t *as4_aggregator_as, - struct in_addr *as4_aggregator_addr) + struct in_addr *as4_aggregator_addr, + u_char *startp) { + bgp_size_t total; + if (length != 8) { zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length); @@ -1240,6 +1278,13 @@ bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, NULL, 0); } + total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + /* Flags check. */ + if (bgp_attr_flag_invalid (peer, BGP_ATTR_AS4_AGGREGATOR, flag)) + return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + *as4_aggregator_as = stream_getl (peer->ibuf); as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf); @@ -1377,6 +1422,12 @@ bgp_attr_community (struct peer *peer, bgp_size_t length, return BGP_ATTR_PARSE_PROCEED; } + /* Flags check. */ + if (bgp_attr_flag_invalid (peer, BGP_ATTR_COMMUNITIES, flag)) + return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + attr->community = community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length); @@ -1402,13 +1453,10 @@ bgp_attr_originator_id (struct peer *peer, bgp_size_t length, total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* Flag checks. */ - if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL) - { - bgp_attr_flags_diagnose (peer, BGP_ATTR_ORIGINATOR_ID, BGP_ATTR_FLAG_OPTIONAL, flag); + if (bgp_attr_flag_invalid (peer, BGP_ATTR_ORIGINATOR_ID, flag)) return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); - } /* Length check. */ if (length != 4) { @@ -1436,13 +1484,10 @@ bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* Flag checks. */ - if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL) - { - bgp_attr_flags_diagnose (peer, BGP_ATTR_CLUSTER_LIST, BGP_ATTR_FLAG_OPTIONAL, flag); + if (bgp_attr_flag_invalid (peer, BGP_ATTR_CLUSTER_LIST, flag)) return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); - } /* Check length. */ if (length % 4) { @@ -1480,13 +1525,10 @@ bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length, total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* Flag checks. */ - if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL) - { - bgp_attr_flags_diagnose (peer, BGP_ATTR_MP_REACH_NLRI, BGP_ATTR_FLAG_OPTIONAL, flag); + if (bgp_attr_flag_invalid (peer, BGP_ATTR_MP_REACH_NLRI, flag)) return bgp_attr_malformed (peer, BGP_ATTR_MP_REACH_NLRI, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); - } /* Set end of packet. */ s = BGP_INPUT(peer); start = stream_get_getp(s); @@ -1618,13 +1660,10 @@ bgp_mp_unreach_parse (struct peer *peer, const bgp_size_t length, total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); /* Flag checks. */ - if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL) - { - bgp_attr_flags_diagnose (peer, BGP_ATTR_MP_UNREACH_NLRI, BGP_ATTR_FLAG_OPTIONAL, flag); + if (bgp_attr_flag_invalid (peer, BGP_ATTR_MP_UNREACH_NLRI, flag)) return bgp_attr_malformed (peer, BGP_ATTR_MP_UNREACH_NLRI, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); - } s = peer->ibuf; @@ -1670,6 +1709,12 @@ bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, return BGP_ATTR_PARSE_PROCEED; } + /* Flags check. */ + if (bgp_attr_flag_invalid (peer, BGP_ATTR_EXT_COMMUNITIES, flag)) + return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + (bgp_attr_extra_get (attr))->ecommunity = ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length); /* XXX: fix ecommunity_parse to use stream API */ @@ -1884,7 +1929,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, case BGP_ATTR_AS4_AGGREGATOR: ret = bgp_attr_as4_aggregator (peer, length, attr, flag, &as4_aggregator, - &as4_aggregator_addr); + &as4_aggregator_addr, startp); break; case BGP_ATTR_COMMUNITIES: ret = bgp_attr_community (peer, length, attr, flag, startp); -- cgit v1.2.1 From 835315bfb49bff2b2fb354f2075c6d6693c2a151 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 18 Jan 2012 12:28:30 +0000 Subject: bgpd: Move up flag-check calls, parcel up attr-parser args, and other cleanups * bgp_attr.h: (struct bgp_attr_parser_args) Attribute parsing context, containing common arguments. * bgp_attr.c: (general) Move the bgp_attr_flag_invalid flag-check calls up, out of each individual attr parser function, to be done once in attr_parse. Similarly move the calculation of the 'total' attribute length field up to attr_parse. Bundle together common arguments to attr-parsing functions and helpers into (struct bgp_attr_parser_args), so it can be passed by reference down the stack & also de-clutter the argument lists & make it easier to add/modify the context for attr-parsing - add local const aliases to avoid modifying body of code too much. This also should help avoid cut & paste errors, where calls to helpers with hard-coded attribute types are pasted to other functions but the code isn't changed. (bgp_attr_flags_diagnose) as above. (bgp_attr_flag_invalid) as above. (bgp_attr_{origin,aspath,as4_path,nexthop,med,local_pref,atomic}) as above. (bgp_attr_{aggregator,as4_aggregator,community,originator_id}) as above (bgp_attr_{cluster_list,ext_communities},bgp_mp_{un,}reach_parse) as above (bgp_attr_unknown) as above. (bgp_attr_malformed) as above. Also, startp and length have to be special-cased, because whether or not to send attribute data depends on the particular error - a separate length argument, distinct from args->length, indicates whether or not the attribute data should be sent in the NOTIFY. (bgp_attr_aspath_check) Call to bgp_attr_malformed is wrong here, there is no attribute parsing context - e.g. the 'flag' argument is unlikely to be right, remove it. Explicitly handle the error instead. (bgp_attr_munge_as4_attrs) Flag argument is pointless. As the comment notes, the check here is pointless as AS_PATH presence already checked elsewhere. (bgp_attr_parse) Do bgp_attr_flag_invalid call here. Use (struct bgp_attr_parser_args) for args to attr parser functions. Remove out-of-context 'flag' argument to as4 checking functions. --- bgpd/bgp_attr.c | 467 +++++++++++++++++++++++--------------------------------- bgpd/bgp_attr.h | 19 ++- 2 files changed, 208 insertions(+), 278 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index d8ca831a..b02cfee3 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -710,9 +710,17 @@ bgp_attr_flush (struct attr *attr) * introduced by the sending neighbour. */ static bgp_attr_parse_ret_t -bgp_attr_malformed (struct peer *peer, u_char type, u_char flag, - u_char subcode, u_char *startp, bgp_size_t length) -{ +bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode, + 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 *startp = (length > 0 ? args->startp : NULL); + /* Only relax error handling for eBGP peers */ if (peer_sort (peer) != BGP_PEER_EBGP) { @@ -722,7 +730,7 @@ bgp_attr_malformed (struct peer *peer, u_char type, u_char flag, } - switch (type) { + switch (args->type) { /* where an optional attribute is 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 @@ -756,9 +764,9 @@ bgp_attr_malformed (struct peer *peer, u_char type, u_char flag, * the whole session to be reset. Instead treat it as a withdrawal * of the routes, if possible. */ - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS) - && CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) - && CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) + if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS) + && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL) + && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL)) return BGP_ATTR_PARSE_WITHDRAW; /* default to reset */ @@ -771,16 +779,14 @@ bgp_attr_malformed (struct peer *peer, u_char type, u_char flag, being diagnosed is defined by RFC as either a "well-known" or an "optional, non-transitive" attribute. */ static void -bgp_attr_flags_diagnose -( - struct peer * peer, - const u_int8_t attr_code, - u_int8_t desired_flags, /* how RFC says it must be */ - u_int8_t real_flags /* on wire */ +bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args, + u_int8_t desired_flags /* how RFC says it must be */ ) { 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 */ @@ -790,7 +796,7 @@ bgp_attr_flags_diagnose CHECK_FLAG (real_flags, attr_flag_str[i].key) ) { - zlog (peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"", + 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); @@ -823,9 +829,12 @@ static const size_t attr_flags_values_max = sizeof (attr_flags_values) / sizeof (attr_flags_values[0]); static int -bgp_attr_flag_invalid (struct peer *peer, u_int8_t attr_code, u_int8_t flags) +bgp_attr_flag_invalid (struct bgp_attr_parser_args *args) { u_int8_t mask = BGP_ATTR_FLAG_EXTLEN; + 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) @@ -880,31 +889,18 @@ bgp_attr_flag_invalid (struct peer *peer, u_int8_t attr_code, u_int8_t flags) == attr_flags_values[attr_code]) return 0; - bgp_attr_flags_diagnose (peer, attr_code, attr_flags_values[attr_code], - flags); + 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 peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp) +bgp_attr_origin (struct bgp_attr_parser_args *args) { - bgp_size_t total; - - /* total is entire attribute length include Attribute Flags (1), - Attribute Type code (1) and Attribute length (1 or 2). */ - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - - /* 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 (peer, BGP_ATTR_ORIGIN, flag)) - return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - + 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 with the expected length (based on the attribute type code), then the Error Subcode is set to Attribute Length Error. The Data @@ -914,9 +910,9 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, { zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d", length); - return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, + return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - startp, total); + args->total); } /* Fetch origin attribute. */ @@ -931,9 +927,9 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, { zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d", attr->origin); - return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, + return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_INVAL_ORIGIN, - startp, total); + args->total); } /* Set oring attribute flag. */ @@ -945,17 +941,12 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, /* Parse AS path information. This function is wrapper of aspath_parse. */ static int -bgp_attr_aspath (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp) +bgp_attr_aspath (struct bgp_attr_parser_args *args) { - bgp_size_t total; - - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + struct attr *const attr = args->attr; + struct peer *const peer = args->peer; + const bgp_size_t length = args->length; - if (bgp_attr_flag_invalid (peer, BGP_ATTR_AS_PATH, 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 * otherwise, will get 16 Bit @@ -969,9 +960,7 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length, zlog (peer->log, LOG_ERR, "Malformed AS path from %s, length is %d", peer->host, length); - return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, - BGP_NOTIFY_UPDATE_MAL_AS_PATH, - NULL, 0); + return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0); } /* Set aspath attribute flag. */ @@ -981,7 +970,7 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length, } 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 * as4 we should to check aspath things when @@ -1000,9 +989,9 @@ bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag) (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath))) { zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host); - return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, - BGP_NOTIFY_UPDATE_MAL_AS_PATH, - NULL, 0); + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_AS_PATH); + return BGP_ATTR_PARSE_ERROR; } /* First AS check for EBGP. */ @@ -1013,9 +1002,9 @@ bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag) { zlog (peer->log, LOG_ERR, "%s incorrect first AS (must be %u)", peer->host, peer->as); - return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, - BGP_NOTIFY_UPDATE_MAL_AS_PATH, - NULL, 0); + bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_AS_PATH); + return BGP_ATTR_PARSE_ERROR; } } @@ -1035,19 +1024,11 @@ bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag) /* Parse AS4 path information. This function is another wrapper of aspath_parse. */ static int -bgp_attr_as4_path (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp, - struct aspath **as4_path) +bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path) { - bgp_size_t total; - - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - - /* Flag check. */ - if (bgp_attr_flag_invalid (peer, BGP_ATTR_AS4_PATH, flag)) - return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); + struct peer *const peer = args->peer; + struct attr *const attr = args->attr; + const bgp_size_t length = args->length; *as4_path = aspath_parse (peer->ibuf, length, 1); @@ -1057,9 +1038,9 @@ bgp_attr_as4_path (struct peer *peer, bgp_size_t length, zlog (peer->log, LOG_ERR, "Malformed AS4 path from %s, length is %d", peer->host, length); - return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag, + return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, - NULL, 0); + 0); } /* Set aspath attribute flag. */ @@ -1071,29 +1052,23 @@ bgp_attr_as4_path (struct peer *peer, bgp_size_t length, /* Nexthop attribute. */ static bgp_attr_parse_ret_t -bgp_attr_nexthop (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp) +bgp_attr_nexthop (struct bgp_attr_parser_args *args) { - 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); - - /* Flags check. */ - if (bgp_attr_flag_invalid (peer, BGP_ATTR_NEXT_HOP, flag)) - return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - /* Check nexthop attribute length. */ if (length != 4) { zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]", length); - return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, + return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - startp, total); + args->total); } /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP @@ -1108,9 +1083,9 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length, 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 (peer, BGP_ATTR_NEXT_HOP, flag, + return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, - startp, total); + args->total); } attr->nexthop.s_addr = nexthop_n; @@ -1121,28 +1096,21 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length, /* MED atrribute. */ static bgp_attr_parse_ret_t -bgp_attr_med (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp) +bgp_attr_med (struct bgp_attr_parser_args *args) { - bgp_size_t total; - - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - - /* Flag checks. */ - if (bgp_attr_flag_invalid (peer, BGP_ATTR_MULTI_EXIT_DISC, flag)) - return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, 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, "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, - startp, total); + args->total); } attr->med = stream_getl (peer->ibuf); @@ -1154,25 +1122,20 @@ bgp_attr_med (struct peer *peer, bgp_size_t length, /* Local preference attribute. */ static bgp_attr_parse_ret_t -bgp_attr_local_pref (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp) +bgp_attr_local_pref (struct bgp_attr_parser_args *args) { - bgp_size_t total; - - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - /* Flag checks. */ - if (bgp_attr_flag_invalid (peer, BGP_ATTR_LOCAL_PREF, flag)) - return bgp_attr_malformed (peer, BGP_ATTR_LOCAL_PREF, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, 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 (peer, BGP_ATTR_LOCAL_PREF, flag, + 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, - startp, total); + args->total); } /* If it is contained in an UPDATE message that is received from an @@ -1194,25 +1157,20 @@ bgp_attr_local_pref (struct peer *peer, bgp_size_t length, /* Atomic aggregate. */ static int -bgp_attr_atomic (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp) +bgp_attr_atomic (struct bgp_attr_parser_args *args) { - bgp_size_t total; - - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - /* Flag checks. */ - if (bgp_attr_flag_invalid (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag)) - return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); + struct peer *const peer = args->peer; + struct attr *const attr = args->attr; + const bgp_size_t length = args->length; /* Length check. */ if (length != 0) { - zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]", length); - return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag, + zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]", + length); + return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - startp, total); + args->total); } /* Set atomic aggregate flag. */ @@ -1223,19 +1181,14 @@ bgp_attr_atomic (struct peer *peer, bgp_size_t length, /* Aggregator attribute */ static int -bgp_attr_aggregator (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp) +bgp_attr_aggregator (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; + int wantedlen = 6; struct attr_extra *attre = bgp_attr_extra_get (attr); - bgp_size_t total; - - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - /* Flags check. */ - if (bgp_attr_flag_invalid (peer, BGP_ATTR_AGGREGATOR, flag)) - return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */ if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) @@ -1243,10 +1196,11 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length, if (length != wantedlen) { - zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]", wantedlen, length); - return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag, + zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]", + wantedlen, length); + return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - startp, total); + args->total); } if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) ) @@ -1263,27 +1217,22 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length, /* New Aggregator attribute */ static bgp_attr_parse_ret_t -bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, - as_t *as4_aggregator_as, - struct in_addr *as4_aggregator_addr, - u_char *startp) +bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args, + as_t *as4_aggregator_as, + struct in_addr *as4_aggregator_addr) { - bgp_size_t total; - + struct peer *const peer = args->peer; + struct attr *const attr = args->attr; + const bgp_size_t length = args->length; + if (length != 8) { - zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length); - return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag, + zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", + length); + return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - NULL, 0); + 0); } - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - /* Flags check. */ - if (bgp_attr_flag_invalid (peer, BGP_ATTR_AS4_AGGREGATOR, flag)) - return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); *as4_aggregator_as = stream_getl (peer->ibuf); as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf); @@ -1296,7 +1245,8 @@ bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length, /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH. */ 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 in_addr *as4_aggregator_addr) { @@ -1325,24 +1275,6 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag, 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 * because that may override AS4_PATH */ @@ -1410,11 +1342,11 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag, /* Community attribute. */ static bgp_attr_parse_ret_t -bgp_attr_community (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp) +bgp_attr_community (struct bgp_attr_parser_args *args) { - bgp_size_t total - = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + struct peer *const peer = args->peer; + struct attr *const attr = args->attr; + const bgp_size_t length = args->length; if (length == 0) { @@ -1422,12 +1354,6 @@ bgp_attr_community (struct peer *peer, bgp_size_t length, return BGP_ATTR_PARSE_PROCEED; } - /* Flags check. */ - if (bgp_attr_flag_invalid (peer, BGP_ATTR_COMMUNITIES, flag)) - return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - attr->community = community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length); @@ -1435,9 +1361,9 @@ bgp_attr_community (struct peer *peer, bgp_size_t length, stream_forward_getp (peer->ibuf, length); if (!attr->community) - return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag, + return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, - startp, total); + args->total); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); @@ -1446,25 +1372,20 @@ bgp_attr_community (struct peer *peer, bgp_size_t length, /* Originator ID attribute. */ static bgp_attr_parse_ret_t -bgp_attr_originator_id (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp) +bgp_attr_originator_id (struct bgp_attr_parser_args *args) { - bgp_size_t total; - - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - /* Flag checks. */ - if (bgp_attr_flag_invalid (peer, BGP_ATTR_ORIGINATOR_ID, flag)) - return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, 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, "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, - startp, total); + args->total); } (bgp_attr_extra_get (attr))->originator_id.s_addr @@ -1477,25 +1398,19 @@ bgp_attr_originator_id (struct peer *peer, bgp_size_t length, /* Cluster list attribute. */ static bgp_attr_parse_ret_t -bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp) +bgp_attr_cluster_list (struct bgp_attr_parser_args *args) { - bgp_size_t total; - - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - /* Flag checks. */ - if (bgp_attr_flag_invalid (peer, BGP_ATTR_CLUSTER_LIST, flag)) - return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); + struct peer *const peer = args->peer; + struct attr *const attr = args->attr; + const bgp_size_t length = args->length; + /* Check length. */ if (length % 4) { zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length); - return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - startp, total); + return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + args->total); } (bgp_attr_extra_get (attr))->cluster @@ -1511,8 +1426,8 @@ bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, /* Multiprotocol reachability information parse. */ int -bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length, - struct attr *attr, const u_char flag, u_char *startp, struct bgp_nlri *mp_update) +bgp_mp_reach_parse (struct bgp_attr_parser_args *args, + struct bgp_nlri *mp_update) { afi_t afi; safi_t safi; @@ -1520,15 +1435,11 @@ bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length, size_t start; int ret; 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); - bgp_size_t total; - - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - /* Flag checks. */ - if (bgp_attr_flag_invalid (peer, BGP_ATTR_MP_REACH_NLRI, flag)) - return bgp_attr_malformed (peer, BGP_ATTR_MP_REACH_NLRI, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); + /* Set end of packet. */ s = BGP_INPUT(peer); start = stream_get_getp(s); @@ -1647,8 +1558,7 @@ bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length, /* Multiprotocol unreachable parse */ int -bgp_mp_unreach_parse (struct peer *peer, const bgp_size_t length, - const u_char flag, u_char *startp, +bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, struct bgp_nlri *mp_withdraw) { struct stream *s; @@ -1656,14 +1566,8 @@ bgp_mp_unreach_parse (struct peer *peer, const bgp_size_t length, safi_t safi; u_int16_t withdraw_len; int ret; - bgp_size_t total; - - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - /* Flag checks. */ - if (bgp_attr_flag_invalid (peer, BGP_ATTR_MP_UNREACH_NLRI, flag)) - return bgp_attr_malformed (peer, BGP_ATTR_MP_UNREACH_NLRI, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); + struct peer *const peer = args->peer; + const bgp_size_t length = args->length; s = peer->ibuf; @@ -1695,11 +1599,11 @@ bgp_mp_unreach_parse (struct peer *peer, const bgp_size_t length, /* Extended Community attribute. */ static bgp_attr_parse_ret_t -bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp) +bgp_attr_ext_communities (struct bgp_attr_parser_args *args) { - bgp_size_t total - = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + struct peer *const peer = args->peer; + struct attr *const attr = args->attr; + const bgp_size_t length = args->length; if (length == 0) { @@ -1709,21 +1613,15 @@ bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, return BGP_ATTR_PARSE_PROCEED; } - /* Flags check. */ - if (bgp_attr_flag_invalid (peer, BGP_ATTR_EXT_COMMUNITIES, flag)) - return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - (bgp_attr_extra_get (attr))->ecommunity = ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length); /* XXX: fix ecommunity_parse to use stream API */ stream_forward_getp (peer->ibuf, length); if (!attr->extra->ecommunity) - return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES, - flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, - startp, total); + return bgp_attr_malformed (args, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + args->total); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); @@ -1732,12 +1630,18 @@ bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, /* BGP unknown attribute treatment. */ static bgp_attr_parse_ret_t -bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag, - u_char type, bgp_size_t length, u_char *startp) +bgp_attr_unknown (struct bgp_attr_parser_args *args) { bgp_size_t total; struct transit *transit; 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)) zlog_debug ("%s Unknown attribute is received (type %d, length %d)", @@ -1750,18 +1654,15 @@ bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag, /* Forward read pointer of input stream. */ 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, then the Error Subcode is set to Unrecognized Well-known Attribute. The Data field contains the unrecognized attribute (type, length and value). */ 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, - startp, total); + args->total); } /* Unrecognized non-transitive optional attributes must be quietly @@ -1858,7 +1759,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); return BGP_ATTR_PARSE_ERROR; } - + /* Check extended attribue length bit. */ if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)) length = stream_getw (BGP_INPUT (peer)); @@ -1898,59 +1799,79 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); 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)) + return bgp_attr_malformed (&attr_args, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + attr_args.total); /* OK check attribute and store it's value. */ switch (type) { case BGP_ATTR_ORIGIN: - ret = bgp_attr_origin (peer, length, attr, flag, startp); + ret = bgp_attr_origin (&attr_args); break; case BGP_ATTR_AS_PATH: - ret = bgp_attr_aspath (peer, length, attr, flag, startp); + ret = bgp_attr_aspath (&attr_args); break; 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; case BGP_ATTR_NEXT_HOP: - ret = bgp_attr_nexthop (peer, length, attr, flag, startp); + ret = bgp_attr_nexthop (&attr_args); break; case BGP_ATTR_MULTI_EXIT_DISC: - ret = bgp_attr_med (peer, length, attr, flag, startp); + ret = bgp_attr_med (&attr_args); break; case BGP_ATTR_LOCAL_PREF: - ret = bgp_attr_local_pref (peer, length, attr, flag, startp); + ret = bgp_attr_local_pref (&attr_args); break; case BGP_ATTR_ATOMIC_AGGREGATE: - ret = bgp_attr_atomic (peer, length, attr, flag, startp); + ret = bgp_attr_atomic (&attr_args); break; case BGP_ATTR_AGGREGATOR: - ret = bgp_attr_aggregator (peer, length, attr, flag, startp); + ret = bgp_attr_aggregator (&attr_args); break; case BGP_ATTR_AS4_AGGREGATOR: - ret = bgp_attr_as4_aggregator (peer, length, attr, flag, - &as4_aggregator, - &as4_aggregator_addr, startp); + ret = bgp_attr_as4_aggregator (&attr_args, + &as4_aggregator, + &as4_aggregator_addr); break; case BGP_ATTR_COMMUNITIES: - ret = bgp_attr_community (peer, length, attr, flag, startp); + ret = bgp_attr_community (&attr_args); break; case BGP_ATTR_ORIGINATOR_ID: - ret = bgp_attr_originator_id (peer, length, attr, flag, startp); + ret = bgp_attr_originator_id (&attr_args); break; case BGP_ATTR_CLUSTER_LIST: - ret = bgp_attr_cluster_list (peer, length, attr, flag, startp); + ret = bgp_attr_cluster_list (&attr_args); break; case BGP_ATTR_MP_REACH_NLRI: - ret = bgp_mp_reach_parse (peer, length, attr, flag, startp, mp_update); + ret = bgp_mp_reach_parse (&attr_args, mp_update); break; case BGP_ATTR_MP_UNREACH_NLRI: - ret = bgp_mp_unreach_parse (peer, length, flag, startp, mp_withdraw); + ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw); break; case BGP_ATTR_EXT_COMMUNITIES: - ret = bgp_attr_ext_communities (peer, length, attr, flag, startp); + ret = bgp_attr_ext_communities (&attr_args); break; default: - ret = bgp_attr_unknown (peer, attr, flag, type, length, startp); + ret = bgp_attr_unknown (&attr_args); break; } @@ -2020,7 +1941,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, * all attributes first, including these 32bit ones, and now, * 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)) { if (as4_path) @@ -2052,7 +1973,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, */ 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) return ret; } diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index e6300740..df87c863 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -179,10 +179,19 @@ extern void cluster_unintern (struct cluster_list *); /* Transit attribute prototypes. */ void transit_unintern (struct transit *); -/* Exported for unit-test purposes only */ -extern int bgp_mp_reach_parse (struct peer *, const bgp_size_t, struct attr *, - const u_char, u_char *, struct bgp_nlri *); -extern int bgp_mp_unreach_parse (struct peer *, const bgp_size_t, const u_char, - u_char *, struct bgp_nlri *); +/* Below exported for unit-test purposes only */ +struct bgp_attr_parser_args { + struct peer *peer; + bgp_size_t length; /* attribute data length; */ + bgp_size_t total; /* total length, inc header */ + struct attr *attr; + u_int8_t type; + u_int8_t flags; + u_char *startp; +}; +extern int bgp_mp_reach_parse (struct bgp_attr_parser_args *args, + struct bgp_nlri *); +extern int bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, + struct bgp_nlri *); #endif /* _QUAGGA_BGP_ATTR_H */ -- cgit v1.2.1 From 5861739f8c38bc36ea9955e5cb2be2bf2f482d70 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 9 Jan 2012 20:59:26 +0000 Subject: bgpd: Open option parse errors don't NOTIFY, resulting in abort & DoS * bgp_packet.c: (bgp_open_receive) Errors from bgp_open_option_parse are detected, and the code will stop processing the OPEN and return. However it does so without calling bgp_notify_send to send a NOTIFY - which means the peer FSM doesn't get stopped, and bgp_read will be called again later. Because it returns, it doesn't go through the code near the end of the function that removes the current message from the peer input streaam. Thus the next call to bgp_read will try to parse a half-parsed stream as if it were a new BGP message, leading to an assert later in the code when it tries to read stuff that isn't there. Add the required call to bgp_notify_send before returning. * bgp_open.c: (bgp_capability_as4) Be a bit stricter, check the length field corresponds to the only value it can be, which is the amount we're going to read off the stream. And make sure the capability flag gets set, so callers can know this capability was read, regardless. (peek_for_as4_capability) Let bgp_capability_as4 do the length check. --- bgpd/bgp_open.c | 14 +++++++++----- bgpd/bgp_packet.c | 10 +++++++--- 2 files changed, 16 insertions(+), 8 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 82deb3d0..b5b50bb5 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -421,13 +421,20 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr) static as_t bgp_capability_as4 (struct peer *peer, struct capability_header *hdr) { + SET_FLAG (peer->cap, PEER_CAP_AS4_RCV); + + if (hdr->length != CAPABILITY_CODE_AS4_LEN) + { + zlog_err ("%s AS4 capability has incorrect data length %d", + peer->host, hdr->length); + return 0; + } + as_t as4 = stream_getl (BGP_INPUT(peer)); if (BGP_DEBUG (as4, AS4)) zlog_debug ("%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u", peer->host, as4); - SET_FLAG (peer->cap, PEER_CAP_AS4_RCV); - return as4; } @@ -689,9 +696,6 @@ peek_for_as4_capability (struct peer *peer, u_char length) if (hdr.code == CAPABILITY_CODE_AS4) { - if (hdr.length != CAPABILITY_CODE_AS4_LEN) - goto end; - if (BGP_DEBUG (as4, AS4)) zlog_info ("[AS4] found AS4 capability, about to parse"); as4 = bgp_capability_as4 (peer, &hdr); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index f5a74d1b..5d8087a8 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1459,9 +1459,13 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) /* Open option part parse. */ if (optlen != 0) { - ret = bgp_open_option_parse (peer, optlen, &capability); - if (ret < 0) - return ret; + if ((ret = bgp_open_option_parse (peer, optlen, &capability)) < 0) + { + bgp_notify_send (peer, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_UNACEP_HOLDTIME); + return ret; + } } else { -- cgit v1.2.1 From bd471fea4ec965c71d6c2201745995092fbc36f6 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 15 Mar 2012 11:30:00 +0000 Subject: bgpd: malformed attribute error that can still proceed should fixup getp * bgp_attr.c: (bgp_attr_malformed) When a malformed attribute error can be ignored, and BGP message processing may still proceed, the stream getp should be adjusted to the end of the attribute - the caller may not have consumed all the attribute. Problem noted by Martin Winter in bug 678. Also, rename the 'startp' local to 'notify_datap', for clarity. --- bgpd/bgp_attr.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index b02cfee3..d204cec1 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -719,17 +719,24 @@ bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode, * send the attribute data with the NOTIFY depends on the error, * the caller therefore signals this with the seperate length argument */ - u_char *startp = (length > 0 ? args->startp : NULL); + u_char *notify_datap = (length > 0 ? args->startp : NULL); /* Only relax error handling for eBGP peers */ if (peer_sort (peer) != BGP_PEER_EBGP) { bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode, - startp, length); + notify_datap, length); return BGP_ATTR_PARSE_ERROR; } + /* Adjust the stream getp to the end of the attribute, in case we can + * still proceed but the caller hasn't read all the attribute. + */ + stream_set_getp (BGP_INPUT (peer), + (args->startp - STREAM_DATA (BGP_INPUT (peer))) + + args->total); + switch (args->type) { /* where an optional attribute is inconsequential, e.g. it does not affect * route selection, and can be safely ignored then any such attributes @@ -756,7 +763,7 @@ bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode, case BGP_ATTR_MP_UNREACH_NLRI: case BGP_ATTR_EXT_COMMUNITIES: bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode, - startp, length); + notify_datap, length); return BGP_ATTR_PARSE_ERROR; } -- cgit v1.2.1 From 683f2b86d89fa356d3d1f7a54b0c269baa38b836 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 23 Mar 2012 14:58:45 +0000 Subject: bgpd: Fix silly mistake in bgp_attr_flag_invalid * bgp_attr.c: (bgp_attr_flag_invalid) flags is meant to be masked off with the mask variable... --- bgpd/bgp_attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index d204cec1..66704169 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -892,7 +892,7 @@ bgp_attr_flag_invalid (struct bgp_attr_parser_args *args) && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)) SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL); - if ((flags & ~attr_flags_values[attr_code]) + if ((flags & ~mask) == attr_flags_values[attr_code]) return 0; -- cgit v1.2.1 From fa61e16ddebe10a71d98bcd2eba0f630071ea4a7 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sun, 25 Mar 2012 21:31:47 +0100 Subject: bgpd: attr_parse call to attr_malformed should deal with PROCEED error case * bgpd/bgp_attr.c: (bgp_attr_parse) the invalid flag check call to bgp_attr_malformed is pretty useless if it doesn't actually allow for the PROCEED non-error case. --- bgpd/bgp_attr.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 66704169..c21655c0 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -738,10 +738,10 @@ bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode, + args->total); switch (args->type) { - /* where an optional attribute is 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. + /* 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_AGGREGATOR: @@ -749,7 +749,7 @@ bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode, return BGP_ATTR_PARSE_PROCEED; /* 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_AS_PATH: @@ -1823,9 +1823,15 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, Attribute Flags Error. The Data field contains the erroneous attribute (type, length and value). */ if (bgp_attr_flag_invalid (&attr_args)) - return bgp_attr_malformed (&attr_args, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - attr_args.total); + { + 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. */ switch (type) -- cgit v1.2.1 From fa5831e85ae9ba7008fb4b4e2d4c7561ae5cb697 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Tue, 27 Mar 2012 11:54:04 +0100 Subject: bgpd: bgp_attr_flags_diagnose shouldn't assert * bgpd/bgp_attr.c: (bgp_attr_flags_diagnose) debug code for error-handling paths probably shouldn't assert, instead it should just log that there was no problem. --- bgpd/bgp_attr.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'bgpd') diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index c21655c0..0d82aba0 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -809,7 +809,14 @@ bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args, attr_flag_str[i].str); seen = 1; } - assert (seen); + 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); + } } /* Required flags for attributes. EXTLEN will be masked off when testing, -- cgit v1.2.1