diff options
Diffstat (limited to 'bgpd')
-rw-r--r-- | bgpd/bgp_advertise.c | 10 | ||||
-rw-r--r-- | bgpd/bgp_aspath.c | 167 | ||||
-rw-r--r-- | bgpd/bgp_aspath.h | 4 | ||||
-rw-r--r-- | bgpd/bgp_attr.c | 763 | ||||
-rw-r--r-- | bgpd/bgp_attr.h | 14 | ||||
-rw-r--r-- | bgpd/bgp_clist.c | 4 | ||||
-rw-r--r-- | bgpd/bgp_community.c | 13 | ||||
-rw-r--r-- | bgpd/bgp_community.h | 2 | ||||
-rw-r--r-- | bgpd/bgp_ecommunity.c | 33 | ||||
-rw-r--r-- | bgpd/bgp_ecommunity.h | 4 | ||||
-rw-r--r-- | bgpd/bgp_main.c | 10 | ||||
-rw-r--r-- | bgpd/bgp_network.c | 20 | ||||
-rw-r--r-- | bgpd/bgp_nexthop.c | 22 | ||||
-rw-r--r-- | bgpd/bgp_packet.c | 158 | ||||
-rw-r--r-- | bgpd/bgp_route.c | 1088 | ||||
-rw-r--r-- | bgpd/bgp_routemap.c | 34 | ||||
-rw-r--r-- | bgpd/bgp_table.c | 1 | ||||
-rw-r--r-- | bgpd/bgp_vty.c | 219 | ||||
-rw-r--r-- | bgpd/bgp_zebra.c | 8 | ||||
-rw-r--r-- | bgpd/bgpd.c | 177 | ||||
-rw-r--r-- | bgpd/bgpd.h | 8 |
21 files changed, 2064 insertions, 695 deletions
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 5a73eeff..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); @@ -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; } } @@ -671,78 +673,78 @@ 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. - */ -static struct assegment * -assegments_parse (struct stream *s, size_t length, int use32bit, int as4_path) +/* parse as-segment byte stream in struct assegment */ +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; + 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 0; 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) - return NULL; + /* basic checks */ + if ((STREAM_READABLE(s) < length) + || (STREAM_READABLE(s) < AS_HEADER_SIZE) + || (length % AS16_VALUE_SIZE )) + return -1; - /* 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 -1; + } + + /* 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; + return -1; } - 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 -1; + } /* now its safe to trust lengths */ seg = assegment_new (segh.type, segh.length); @@ -755,52 +757,47 @@ 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; } - return assegment_normalise (head); + *result = assegment_normalise (head); + return 0; } -/* 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. + + On error NULL is returned. */ 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)); + 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); - assert(find) ; /* valid aspath, so must find or create */ - /* aspath_hash_alloc dupes segments too. that probably could be * optimised out. */ @@ -808,12 +805,14 @@ 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; } -static inline void +static void assegment_data_put (struct stream *s, as_t *as, int num, int use32bit) { int i; @@ -831,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; @@ -1631,7 +1630,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..d55f9ce6 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 *); @@ -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 2205e267..92c1a09f 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -28,6 +28,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "stream.h" #include "log.h" #include "hash.h" +#include "jhash.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" @@ -127,18 +128,9 @@ cluster_loop_check (struct cluster_list *cluster, struct in_addr originator) static unsigned int cluster_hash_key_make (void *p) { - struct cluster_list * cluster = (struct cluster_list *) p; - unsigned int key = 0; - int length; - caddr_t pnt; + const struct cluster_list *cluster = p; - length = cluster->length; - pnt = (caddr_t) cluster->list; - - while (length) - key += pnt[--length]; - - return key; + return jhash(cluster->list, cluster->length, 0); } static int @@ -194,14 +186,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); } } @@ -254,14 +244,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); } } @@ -269,18 +257,9 @@ transit_unintern (struct transit *transit) static unsigned int transit_hash_key_make (void *p) { - struct transit * transit = (struct transit *) p; - unsigned int key = 0; - int length; - caddr_t pnt; - - length = transit->length; - pnt = (caddr_t) transit->val; - - while (length) - key += pnt[--length]; + const struct transit * transit = p; - return key; + return jhash(transit->val, transit->length, 0); } static int @@ -363,8 +342,14 @@ attr_unknown_count (void) unsigned int attrhash_key_make (void *p) { - struct attr * attr = (struct attr *) p; - unsigned int key = 0; + const struct attr * attr = (struct attr *) p; + uint32_t key = 0; +#define MIX(val) key = jhash_1word(val, key) + + MIX(attr->origin); + MIX(attr->nexthop.s_addr); + MIX(attr->med); + MIX(attr->local_pref); key += attr->origin; key += attr->nexthop.s_addr; @@ -373,36 +358,30 @@ attrhash_key_make (void *p) if (attr->extra) { - key += attr->extra->aggregator_as; - key += attr->extra->aggregator_addr.s_addr; - key += attr->extra->weight; - key += attr->extra->mp_nexthop_global_in.s_addr; + MIX(attr->extra->aggregator_as); + MIX(attr->extra->aggregator_addr.s_addr); + MIX(attr->extra->weight); + MIX(attr->extra->mp_nexthop_global_in.s_addr); } if (attr->aspath) - key += aspath_key_make (attr->aspath); + MIX(aspath_key_make (attr->aspath)); if (attr->community) - key += community_hash_make (attr->community); + MIX(community_hash_make (attr->community)); if (attr->extra) { if (attr->extra->ecommunity) - key += ecommunity_hash_make (attr->extra->ecommunity); + MIX(ecommunity_hash_make (attr->extra->ecommunity)); if (attr->extra->cluster) - key += cluster_hash_key_make (attr->extra->cluster); + MIX(cluster_hash_key_make (attr->extra->cluster)); if (attr->extra->transit) - key += transit_hash_key_make (attr->extra->transit); + MIX(transit_hash_key_make (attr->extra->transit)); #ifdef HAVE_IPV6 - { - int i; - - key += attr->extra->mp_nexthop_len; - for (i = 0; i < 16; i++) - key += attr->extra->mp_nexthop_global.s6_addr[i]; - for (i = 0; i < 16; i++) - key += attr->extra->mp_nexthop_local.s6_addr[i]; - } + MIX(attr->extra->mp_nexthop_len); + key = jhash(attr->extra->mp_nexthop_global.s6_addr, 16, key); + key = jhash(attr->extra->mp_nexthop_local.s6_addr, 16, key); #endif /* HAVE_IPV6 */ } @@ -528,6 +507,7 @@ bgp_attr_intern (struct attr *attr) attre->ecommunity = ecommunity_intern (attre->ecommunity); else attre->ecommunity->refcnt++; + } if (attre->cluster) { @@ -544,10 +524,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; } @@ -579,17 +559,16 @@ 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); new = bgp_attr_intern (&attr); bgp_attr_extra_free (&attr); - aspath_unintern (new->aspath); + aspath_unintern (&new->aspath); return new; } @@ -641,52 +620,68 @@ 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; } +/* 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) +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; - if (attr->extra) + (*attr)->refcnt--; + + 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. */ - 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); - 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); + bgp_attr_extra_free (&tmp); } void @@ -699,8 +694,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) @@ -708,6 +704,67 @@ 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; +} + /* 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 @@ -743,7 +800,7 @@ bgp_attr_flags_diagnose } /* 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) { @@ -760,8 +817,7 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS) { bgp_attr_flags_diagnose (peer, BGP_ATTR_ORIGIN, BGP_ATTR_FLAG_TRANS, 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 @@ -773,10 +829,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. */ @@ -791,12 +846,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. */ @@ -804,93 +856,72 @@ 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; total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - /* Check the attribute flags */ - if (!as4_path && CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) + /* 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); - bgp_notify_send_with_data (peer, - BGP_NOTIFY_UPDATE_ERR, + return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); - return NULL; } - require = as4_path ? BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS - : BGP_ATTR_FLAG_TRANS ; - - if ((flag & (BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS)) != require) + if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) { - const char* path_type ; - - 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, - CHECK_FLAG (require, BGP_ATTR_FLAG_OPTIONAL) ? "" : "not ", flag); - - bgp_notify_send_with_data (peer, - BGP_NOTIFY_UPDATE_ERR, + 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 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); + } - 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) + /* In case of IBGP, length will be zero. */ + if (! attr->aspath) { - attr->flag |= ATTR_FLAG_BIT (as4_path ? BGP_ATTR_AS4_PATH - : BGP_ATTR_AS_PATH) ; + 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); } - else - { - 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); - } ; + /* Set aspath attribute flag. */ + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); - return asp ; + 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 @@ -909,10 +940,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. */ @@ -923,10 +953,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); } } @@ -936,16 +965,57 @@ 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); } - 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, 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_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. */ + 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 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) { @@ -958,8 +1028,7 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length, if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS) { bgp_attr_flags_diagnose (peer, BGP_ATTR_NEXT_HOP, BGP_ATTR_FLAG_TRANS, 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. */ @@ -968,11 +1037,9 @@ 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); } /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP @@ -987,21 +1054,19 @@ 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); - bgp_notify_send_with_data (peer, - BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, - startp, total); - return -1; + 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 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) { @@ -1013,8 +1078,9 @@ bgp_attr_med (struct peer *peer, bgp_size_t length, 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); - 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. */ @@ -1022,23 +1088,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, u_char *startp) { @@ -1049,18 +1113,17 @@ bgp_attr_local_pref (struct peer *peer, bgp_size_t length, if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS) { bgp_attr_flags_diagnose (peer, BGP_ATTR_LOCAL_PREF, BGP_ATTR_FLAG_TRANS, 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 @@ -1069,7 +1132,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; } attr->local_pref = stream_getl (peer->ibuf); @@ -1077,7 +1140,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. */ @@ -1092,25 +1155,24 @@ bgp_attr_atomic (struct peer *peer, bgp_size_t length, if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS) { bgp_attr_flags_diagnose (peer, BGP_ATTR_ATOMIC_AGGREGATE, BGP_ATTR_FLAG_TRANS, 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. */ if (length != 0) { zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]", 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_ATOMIC_AGGREGATE, flag, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + startp, total); } /* Set atomic aggregate flag. */ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); - return 0; + return BGP_ATTR_PARSE_PROCEED; } /* Aggregator attribute */ @@ -1128,34 +1190,28 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length, { zlog (peer->log, LOG_ERR, "AGGREGATOR attribute must be flagged as \"optional\" (%u)", flag); - bgp_notify_send_with_data (peer, - BGP_NOTIFY_UPDATE_ERR, + return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); - return -1; } if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) { zlog (peer->log, LOG_ERR, "AGGREGATOR attribute must be flagged as \"transitive\" (%u)", flag); - bgp_notify_send_with_data (peer, - BGP_NOTIFY_UPDATE_ERR, + return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total); - return -1; } /* 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 attribute length isn't %u [%u]", wantedlen, 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_AGGREGATOR, flag, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + startp, total); } if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) ) @@ -1167,36 +1223,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) { @@ -1204,7 +1259,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. @@ -1222,11 +1277,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, @@ -1238,10 +1293,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 @@ -1249,7 +1303,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); @@ -1265,7 +1319,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)) @@ -1300,24 +1354,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); + 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 = @@ -1327,15 +1384,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, u_char *startp) { @@ -1346,19 +1405,18 @@ bgp_attr_originator_id (struct peer *peer, bgp_size_t length, if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL) { bgp_attr_flags_diagnose (peer, BGP_ATTR_ORIGINATOR_ID, BGP_ATTR_FLAG_OPTIONAL, 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) { zlog (peer->log, LOG_ERR, "Bad originator ID length %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_ORIGINATOR_ID, flag, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + startp, total); } (bgp_attr_extra_get (attr))->originator_id.s_addr @@ -1366,11 +1424,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, u_char *startp) { @@ -1381,29 +1439,29 @@ bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL) { bgp_attr_flags_diagnose (peer, BGP_ATTR_CLUSTER_LIST, BGP_ATTR_FLAG_OPTIONAL, 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) { zlog (peer->log, LOG_ERR, "Bad cluster list length %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_CLUSTER_LIST, flag, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + startp, total); } (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. */ @@ -1425,8 +1483,9 @@ bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length, 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); - 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); @@ -1439,7 +1498,7 @@ bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length, { zlog_info ("%s: %s sent invalid length, %lu", __func__, peer->host, (unsigned long)length); - return -1; + return BGP_ATTR_PARSE_ERROR; } /* Load AFI, SAFI. */ @@ -1453,7 +1512,7 @@ bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length, { 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. */ @@ -1466,14 +1525,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: @@ -1501,14 +1555,14 @@ bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length, 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; } { @@ -1524,7 +1578,7 @@ bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length, { zlog_info ("%s: (%s) Failed to read NLRI", __func__, peer->host); - return -1; + return BGP_ATTR_PARSE_ERROR; } if (safi != SAFI_MPLS_LABELED_VPN) @@ -1534,7 +1588,7 @@ bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length, { zlog_info ("%s: (%s) NLRI doesn't pass sanity check", __func__, peer->host); - return -1; + return BGP_ATTR_PARSE_ERROR; } } @@ -1545,7 +1599,7 @@ bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length, stream_forward_getp (s, nlri_len); - return 0; + return BGP_ATTR_PARSE_PROCEED; #undef LEN_LEFT } @@ -1567,15 +1621,16 @@ bgp_mp_unreach_parse (struct peer *peer, const bgp_size_t length, 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); - 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; #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); @@ -1586,7 +1641,7 @@ bgp_mp_unreach_parse (struct peer *peer, const 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; @@ -1596,20 +1651,23 @@ bgp_mp_unreach_parse (struct peer *peer, const 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 = @@ -1618,15 +1676,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) { @@ -1652,20 +1712,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 @@ -1688,17 +1745,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; @@ -1715,7 +1772,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) { @@ -1731,7 +1788,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. */ @@ -1754,7 +1811,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. */ @@ -1776,7 +1833,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 @@ -1794,7 +1851,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. */ @@ -1804,12 +1861,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, flag, startp, &as4_path); break; case BGP_ATTR_NEXT_HOP: ret = bgp_attr_nexthop (peer, length, attr, flag, startp); @@ -1827,10 +1882,12 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, ret = bgp_attr_aggregator (peer, length, attr, flag, startp); 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, startp); @@ -1845,26 +1902,39 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, 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); + 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) { @@ -1874,7 +1944,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; } } @@ -1887,7 +1959,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; } /* @@ -1901,19 +1975,22 @@ 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 */ - 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 */ @@ -1928,10 +2005,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; } @@ -1939,7 +2016,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. */ @@ -1970,9 +2047,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 4cb70678..e6300740 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -132,17 +132,25 @@ 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 (struct 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); 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 e7eb0a07..440c15a4 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_main.c b/bgpd/bgp_main.c index f835fe77..8dede587 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -247,7 +247,15 @@ bgp_exit (int status) if (retain_mode) if_add_hook (IF_DELETE_HOOK, NULL); for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) - if_delete (ifp); + { + struct listnode *c_node, *c_nnode; + struct connected *c; + + for (ALL_LIST_ELEMENTS (ifp->connected, c_node, c_nnode, c)) + bgp_connected_delete (c); + + if_delete (ifp); + } list_free (iflist); /* reverse bgp_attr_init */ diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index b5c4c602..a7dca531 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -30,6 +30,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "command.h" #include "privs.h" #include "linklist.h" +#include "network.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_fsm.h" @@ -150,6 +151,7 @@ bgp_accept (struct thread *thread) zlog_err ("[Error] BGP socket accept failed (%s)", safe_strerror (errno)); return -1; } + set_nonblocking (bgp_sock); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("[Event] BGP connection from host %s", inet_sutop (&su, buf)); @@ -172,8 +174,11 @@ bgp_accept (struct thread *thread) } /* In case of peer is EBGP, we should set TTL for this connection. */ - if (peer_sort (peer1) == BGP_PEER_EBGP) + if (peer_sort (peer1) == BGP_PEER_EBGP) { sockopt_ttl (peer1->su.sa.sa_family, bgp_sock, peer1->ttl); + if (peer1->gtsm_hops) + sockopt_minttl (peer1->su.sa.sa_family, bgp_sock, MAXTTL + 1 - peer1->gtsm_hops); + } /* Make dummy peer until read Open packet. */ if (BGP_DEBUG (events, EVENTS)) @@ -302,8 +307,11 @@ bgp_connect (struct peer *peer) return -1; /* If we can get socket for the peer, adjest TTL and make connection. */ - if (peer_sort (peer) == BGP_PEER_EBGP) + if (peer_sort (peer) == BGP_PEER_EBGP) { sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); + if (peer->gtsm_hops) + sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - peer->gtsm_hops); + } sockopt_reuseaddr (peer->fd); sockopt_reuseport (peer->fd); @@ -455,7 +463,10 @@ bgp_socket (unsigned short port, const char *address) zlog_err ("socket: %s", safe_strerror (errno)); continue; } - + + /* if we intend to implement ttl-security, this socket needs ttl=255 */ + sockopt_ttl (ainfo->ai_family, sock, MAXTTL); + ret = bgp_listener (sock, ainfo->ai_addr, ainfo->ai_addrlen); if (ret == 0) ++count; @@ -488,6 +499,9 @@ bgp_socket (unsigned short port, const char *address) return sock; } + /* if we intend to implement ttl-security, this socket needs ttl=255 */ + sockopt_ttl (AF_INET, sock, MAXTTL); + memset (&sin, 0, sizeof (struct sockaddr_in)); sin.sin_family = AF_INET; sin.sin_port = htons (port); diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index f8d1adec..e9c78b3f 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -264,6 +264,8 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, if (bnc->metric != oldbnc->metric) bnc->metricchanged = 1; + + bgp_unlock_node (oldrn); } } } @@ -340,6 +342,8 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, if (bnc->metric != oldbnc->metric) bnc->metricchanged = 1; + + bgp_unlock_node (oldrn); } } } @@ -541,7 +545,7 @@ bgp_connected_add (struct connected *ifc) } else { - bc = XCALLOC (0, sizeof (struct bgp_connected_ref)); + bc = XCALLOC (MTYPE_BGP_CONN, sizeof (struct bgp_connected_ref)); bc->refcnt = 1; rn->info = bc; } @@ -566,7 +570,7 @@ bgp_connected_add (struct connected *ifc) } else { - bc = XCALLOC (0, sizeof (struct bgp_connected_ref)); + bc = XCALLOC (MTYPE_BGP_CONN, sizeof (struct bgp_connected_ref)); bc->refcnt = 1; rn->info = bc; } @@ -606,7 +610,7 @@ bgp_connected_delete (struct connected *ifc) bc->refcnt--; if (bc->refcnt == 0) { - XFREE (0, bc); + XFREE (MTYPE_BGP_CONN, bc); rn->info = NULL; } bgp_unlock_node (rn); @@ -632,7 +636,7 @@ bgp_connected_delete (struct connected *ifc) bc->refcnt--; if (bc->refcnt == 0) { - XFREE (0, bc); + XFREE (MTYPE_BGP_CONN, bc); rn->info = NULL; } bgp_unlock_node (rn); @@ -1101,11 +1105,15 @@ bgp_multiaccess_check_v4 (struct in_addr nexthop, char *peer) rn1 = bgp_node_match (bgp_connected_table[AFI_IP], &p1); if (! rn1) return 0; + bgp_unlock_node (rn1); rn2 = bgp_node_match (bgp_connected_table[AFI_IP], &p2); if (! rn2) return 0; + bgp_unlock_node (rn2); + /* This is safe, even with above unlocks, since we are just + comparing pointers to the objects, not the objects themselves. */ if (rn1 == rn2) return 1; @@ -1330,6 +1338,9 @@ bgp_scan_init (void) void bgp_scan_finish (void) { + /* Only the current one needs to be reset. */ + bgp_nexthop_cache_reset (bgp_nexthop_cache_table[AFI_IP]); + bgp_table_unlock (cache1_table[AFI_IP]); cache1_table[AFI_IP] = NULL; @@ -1340,6 +1351,9 @@ bgp_scan_finish (void) bgp_connected_table[AFI_IP] = NULL; #ifdef HAVE_IPV6 + /* Only the current one needs to be reset. */ + bgp_nexthop_cache_reset (bgp_nexthop_cache_table[AFI_IP6]); + bgp_table_unlock (cache1_table[AFI_IP6]); cache1_table[AFI_IP6] = NULL; diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index fc653e21..f5a74d1b 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]++; @@ -598,7 +598,6 @@ bgp_write (struct thread *thread) struct stream *s; int num; unsigned int count = 0; - int write_errno; /* Yes first of all get peer pointer. */ peer = THREAD_ARG (thread); @@ -611,46 +610,37 @@ bgp_write (struct thread *thread) return 0; } - /* Nonblocking write until TCP output buffer is full. */ - while (1) + s = bgp_write_packet (peer); + if (!s) + return 0; /* nothing to send */ + + sockopt_cork (peer->fd, 1); + + /* Nonblocking write until TCP output buffer is full. */ + do { int writenum; - int val; - - s = bgp_write_packet (peer); - if (! s) - return 0; - - /* XXX: FIXME, the socket should be NONBLOCK from the start - * status shouldnt need to be toggled on each write - */ - val = fcntl (peer->fd, F_GETFL, 0); - fcntl (peer->fd, F_SETFL, val|O_NONBLOCK); /* Number of bytes to be sent. */ writenum = stream_get_endp (s) - stream_get_getp (s); /* Call write() system call. */ num = write (peer->fd, STREAM_PNT (s), writenum); - write_errno = errno; - fcntl (peer->fd, F_SETFL, val); - if (num <= 0) + if (num < 0) { - /* Partial write. */ - if (write_errno == EWOULDBLOCK || write_errno == EAGAIN) - break; + /* write failed either retry needed or error */ + if (ERRNO_IO_RETRY(errno)) + break; - BGP_EVENT_ADD (peer, TCP_fatal_error); + BGP_EVENT_ADD (peer, TCP_fatal_error); return 0; } + if (num != writenum) { + /* Partial write */ stream_forward_getp (s, num); - - if (write_errno == EAGAIN) - break; - - continue; + break; } /* Retrieve BGP packet type. */ @@ -691,13 +681,14 @@ bgp_write (struct thread *thread) /* OK we send packet so delete it. */ bgp_packet_delete (peer); - - if (++count >= BGP_WRITE_PACKET_MAX) - break; } + while (++count < BGP_WRITE_PACKET_MAX && + (s = bgp_write_packet (peer)) != NULL); if (bgp_write_proceed (peer)) BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); + else + sockopt_cork (peer->fd, 0); return 0; } @@ -706,7 +697,7 @@ bgp_write (struct thread *thread) static int bgp_write_notify (struct peer *peer) { - int ret; + int ret, val; u_char type; struct stream *s; @@ -716,7 +707,10 @@ bgp_write_notify (struct peer *peer) return 0; assert (stream_get_endp (s) >= BGP_HEADER_SIZE); - /* I'm not sure fd is writable. */ + /* Put socket in blocking mode. */ + val = fcntl (peer->fd, F_GETFL, 0); + fcntl (peer->fd, F_SETFL, val & ~O_NONBLOCK); + ret = writen (peer->fd, STREAM_DATA (s), stream_get_endp (s)); if (ret <= 0) { @@ -1602,26 +1596,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); @@ -1630,7 +1645,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; @@ -1653,15 +1673,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 @@ -1688,7 +1713,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 @@ -1718,7 +1743,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 @@ -1747,7 +1772,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 @@ -1775,7 +1800,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (mp_update.length && mp_update.afi == AFI_IP && mp_update.safi == SAFI_MPLS_LABELED_VPN) - 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 @@ -1797,21 +1822,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) @@ -2028,7 +2042,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) * as possible without going beyond the bounds of the entry, * to maximise debug information. */ - int ok ; + int ok; memset (&orfp, 0, sizeof (struct orf_prefix)); common = *p_pnt++; /* after ++: p_pnt <= p_end */ @@ -2042,9 +2056,9 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) ok = ((p_end - p_pnt) >= sizeof(u_int32_t)) ; if (ok) { - memcpy (&seq, p_pnt, sizeof (u_int32_t)); - p_pnt += sizeof (u_int32_t); - orfp.seq = ntohl (seq); + memcpy (&seq, p_pnt, sizeof (u_int32_t)); + p_pnt += sizeof (u_int32_t); + orfp.seq = ntohl (seq); } else p_pnt = p_end ; @@ -2082,16 +2096,17 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) inet_ntop (orfp.p.family, &orfp.p.u.prefix, buf, BUFSIZ), orfp.p.prefixlen, orfp.ge, orfp.le, ok ? "" : " MALFORMED"); - + if (ok) - ret = prefix_bgp_orf_set (name, afi, &orfp, - (common & ORF_COMMON_PART_DENY ? 0 : 1 ), - (common & ORF_COMMON_PART_REMOVE ? 0 : 1)); + ret = prefix_bgp_orf_set (name, afi, &orfp, + (common & ORF_COMMON_PART_DENY ? 0 : 1 ), + (common & ORF_COMMON_PART_REMOVE ? 0 : 1)); if (!ok || (ret != CMD_SUCCESS)) { if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s Received misformatted prefixlist ORF. Remove All pfxlist", peer->host); + zlog_debug ("%s Received misformatted prefixlist ORF." + " Remove All pfxlist", peer->host); prefix_bgp_orf_remove_all (name); break; } @@ -2276,12 +2291,13 @@ bgp_read_packet (struct peer *peer) return 0; /* Read packet from fd. */ - nbytes = stream_read_unblock (peer->ibuf, peer->fd, readsize); + nbytes = stream_read_try (peer->ibuf, peer->fd, readsize); /* If read byte is smaller than zero then error occured. */ if (nbytes < 0) { - if (errno == EAGAIN) + /* Transient error should retry */ + if (nbytes == -2) return -1; plog_err (peer->log, "%s [Error] bgp_read_packet error: %s", diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 189929a0..68d05484 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); @@ -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; @@ -1568,14 +1566,13 @@ bgp_process_queue_init (void) } bm->process_main_queue->spec.workfunc = &bgp_process_main; - bm->process_rsclient_queue->spec.workfunc = &bgp_process_rsclient; bm->process_main_queue->spec.del_item_data = &bgp_processq_del; - bm->process_rsclient_queue->spec.del_item_data - = bm->process_main_queue->spec.del_item_data; - bm->process_main_queue->spec.max_retries - = bm->process_main_queue->spec.max_retries = 0; - bm->process_rsclient_queue->spec.hold - = bm->process_main_queue->spec.hold = 50; + bm->process_main_queue->spec.max_retries = 0; + bm->process_main_queue->spec.hold = 50; + + memcpy (bm->process_rsclient_queue, bm->process_main_queue, + sizeof (struct work_queue *)); + bm->process_rsclient_queue->spec.workfunc = &bgp_process_rsclient; } void @@ -1803,14 +1800,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) @@ -1819,7 +1816,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, if (new_attr.nexthop.s_addr == 0 || IPV4_CLASS_DE (ntohl (new_attr.nexthop.s_addr))) { - bgp_attr_unintern (attr_new); + bgp_attr_unintern (&attr_new); reason = "martian next-hop;"; goto filtered; @@ -1849,7 +1846,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; } @@ -1869,7 +1866,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. */ @@ -2129,7 +2126,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; @@ -2176,7 +2173,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. */ @@ -2468,7 +2465,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 @@ -3216,7 +3213,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); @@ -3227,7 +3224,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, else attr_new = bgp_attr_intern (&attr); - new_attr = *attr_new; + bgp_attr_dup(&new_attr, attr_new); SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_NETWORK); @@ -3243,8 +3240,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); @@ -3254,8 +3251,9 @@ 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); for (ri = rn->info; ri; ri = ri->next) if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP @@ -3268,8 +3266,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 +3279,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 +3311,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 +3361,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 +3382,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 +3397,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 +3405,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 +3433,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); } @@ -4806,9 +4804,8 @@ bgp_aggregate_delete (struct bgp *bgp, struct prefix *p, afi_t afi, #define AGGREGATE_AS_SET 1 static int -bgp_aggregate_set (struct vty *vty, const char *prefix_str, - afi_t afi, safi_t safi, - u_char summary_only, u_char as_set) +bgp_aggregate_unset (struct vty *vty, const char *prefix_str, + afi_t afi, safi_t safi) { int ret; struct prefix p; @@ -4829,34 +4826,33 @@ bgp_aggregate_set (struct vty *vty, const char *prefix_str, bgp = vty->index; /* Old configuration check. */ - rn = bgp_node_get (bgp->aggregate[afi][safi], &p); - - if (rn->info) + rn = bgp_node_lookup (bgp->aggregate[afi][safi], &p); + if (! rn) { - vty_out (vty, "There is already same aggregate network.%s", VTY_NEWLINE); - bgp_unlock_node (rn); + vty_out (vty, "%% There is no aggregate-address configuration.%s", + VTY_NEWLINE); return CMD_WARNING; } - /* Make aggregate address structure. */ - aggregate = bgp_aggregate_new (); - aggregate->summary_only = summary_only; - aggregate->as_set = as_set; - aggregate->safi = safi; - rn->info = aggregate; + aggregate = rn->info; + if (aggregate->safi & SAFI_UNICAST) + bgp_aggregate_delete (bgp, &p, afi, SAFI_UNICAST, aggregate); + if (aggregate->safi & SAFI_MULTICAST) + bgp_aggregate_delete (bgp, &p, afi, SAFI_MULTICAST, aggregate); - /* Aggregate address insert into BGP routing table. */ - if (safi & SAFI_UNICAST) - bgp_aggregate_add (bgp, &p, afi, SAFI_UNICAST, aggregate); - if (safi & SAFI_MULTICAST) - bgp_aggregate_add (bgp, &p, afi, SAFI_MULTICAST, aggregate); + /* Unlock aggregate address configuration. */ + rn->info = NULL; + bgp_aggregate_free (aggregate); + bgp_unlock_node (rn); + bgp_unlock_node (rn); return CMD_SUCCESS; } static int -bgp_aggregate_unset (struct vty *vty, const char *prefix_str, - afi_t afi, safi_t safi) +bgp_aggregate_set (struct vty *vty, const char *prefix_str, + afi_t afi, safi_t safi, + u_char summary_only, u_char as_set) { int ret; struct prefix p; @@ -4877,25 +4873,33 @@ bgp_aggregate_unset (struct vty *vty, const char *prefix_str, bgp = vty->index; /* Old configuration check. */ - rn = bgp_node_lookup (bgp->aggregate[afi][safi], &p); - if (! rn) + rn = bgp_node_get (bgp->aggregate[afi][safi], &p); + + if (rn->info) { - vty_out (vty, "%% There is no aggregate-address configuration.%s", - VTY_NEWLINE); - return CMD_WARNING; + vty_out (vty, "There is already same aggregate network.%s", VTY_NEWLINE); + /* try to remove the old entry */ + ret = bgp_aggregate_unset (vty, prefix_str, afi, safi); + if (ret) + { + vty_out (vty, "Error deleting aggregate.%s", VTY_NEWLINE); + bgp_unlock_node (rn); + return CMD_WARNING; + } } - aggregate = rn->info; - if (aggregate->safi & SAFI_UNICAST) - bgp_aggregate_delete (bgp, &p, afi, SAFI_UNICAST, aggregate); - if (aggregate->safi & SAFI_MULTICAST) - bgp_aggregate_delete (bgp, &p, afi, SAFI_MULTICAST, aggregate); + /* Make aggregate address structure. */ + aggregate = bgp_aggregate_new (); + aggregate->summary_only = summary_only; + aggregate->as_set = as_set; + aggregate->safi = safi; + rn->info = aggregate; - /* Unlock aggregate address configuration. */ - rn->info = NULL; - bgp_aggregate_free (aggregate); - bgp_unlock_node (rn); - bgp_unlock_node (rn); + /* Aggregate address insert into BGP routing table. */ + if (safi & SAFI_UNICAST) + bgp_aggregate_add (bgp, &p, afi, SAFI_UNICAST, aggregate); + if (safi & SAFI_MULTICAST) + bgp_aggregate_add (bgp, &p, afi, SAFI_MULTICAST, aggregate); return CMD_SUCCESS; } @@ -5303,7 +5307,7 @@ bgp_redistribute_add (struct prefix *p, const 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; @@ -5326,8 +5330,8 @@ bgp_redistribute_add (struct prefix *p, const 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; @@ -5342,7 +5346,7 @@ bgp_redistribute_add (struct prefix *p, const 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 (); @@ -5350,7 +5354,7 @@ bgp_redistribute_add (struct prefix *p, const 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; } @@ -5372,7 +5376,7 @@ bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop, } /* Unintern original. */ - aspath_unintern (attr.aspath); + aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); } @@ -6381,7 +6385,10 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp, if ((rm = bgp_node_match (table, &match)) != NULL) { if (prefix_check && rm->p.prefixlen != match.prefixlen) - continue; + { + bgp_unlock_node (rm); + continue; + } for (ri = rm->info; ri; ri = ri->next) { @@ -6395,6 +6402,8 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp, display++; route_vty_out_detail (vty, bgp, &rm->p, ri, AFI_IP, SAFI_MPLS_VPN); } + + bgp_unlock_node (rm); } } } @@ -6418,6 +6427,8 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp, route_vty_out_detail (vty, bgp, &rn->p, ri, afi, safi); } } + + bgp_unlock_node (rn); } } @@ -6490,6 +6501,15 @@ DEFUN (show_ip_bgp_ipv4, return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL); } +ALIAS (show_ip_bgp_ipv4, + show_bgp_ipv4_safi_cmd, + "show bgp ipv4 (unicast|multicast)", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n") + DEFUN (show_ip_bgp_route, show_ip_bgp_route_cmd, "show ip bgp A.B.C.D", @@ -6518,6 +6538,16 @@ DEFUN (show_ip_bgp_ipv4_route, return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0); } +ALIAS (show_ip_bgp_ipv4_route, + show_bgp_ipv4_safi_route_cmd, + "show bgp ipv4 (unicast|multicast) A.B.C.D", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Network in the BGP routing table to display\n") + DEFUN (show_ip_bgp_vpnv4_all_route, show_ip_bgp_vpnv4_all_route_cmd, "show ip bgp vpnv4 all A.B.C.D", @@ -6582,6 +6612,16 @@ DEFUN (show_ip_bgp_ipv4_prefix, return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); } +ALIAS (show_ip_bgp_ipv4_prefix, + show_bgp_ipv4_safi_prefix_cmd, + "show bgp ipv4 (unicast|multicast) A.B.C.D/M", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n") + DEFUN (show_ip_bgp_vpnv4_all_prefix, show_ip_bgp_vpnv4_all_prefix_cmd, "show ip bgp vpnv4 all A.B.C.D/M", @@ -6684,6 +6724,22 @@ ALIAS (show_bgp, BGP_STR "Address family\n") +DEFUN (show_bgp_ipv6_safi, + show_bgp_ipv6_safi_cmd, + "show bgp ipv6 (unicast|multicast)", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, bgp_show_type_normal, + NULL); + + return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal, NULL); +} + /* old command */ DEFUN (show_ipv6_bgp, show_ipv6_bgp_cmd, @@ -6714,6 +6770,22 @@ ALIAS (show_bgp_route, "Address family\n" "Network in the BGP routing table to display\n") +DEFUN (show_bgp_ipv6_safi_route, + show_bgp_ipv6_safi_route_cmd, + "show bgp ipv6 (unicast|multicast) X:X::X:X", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Network in the BGP routing table to display\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 0); + + return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0); +} + /* old command */ DEFUN (show_ipv6_bgp_route, show_ipv6_bgp_route_cmd, @@ -6744,6 +6816,22 @@ ALIAS (show_bgp_prefix, "Address family\n" "IPv6 prefix <network>/<length>\n") +DEFUN (show_bgp_ipv6_safi_prefix, + show_bgp_ipv6_safi_prefix_cmd, + "show bgp ipv6 (unicast|multicast) X:X::X:X/M", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 1); + + return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1); +} + /* old command */ DEFUN (show_ipv6_bgp_prefix, show_ipv6_bgp_prefix_cmd, @@ -7448,15 +7536,36 @@ DEFUN (show_ipv6_mbgp_community_all, #endif /* HAVE_IPV6 */ static int -bgp_show_community (struct vty *vty, int argc, const char **argv, int exact, - afi_t afi, safi_t safi) +bgp_show_community (struct vty *vty, const char *view_name, int argc, + const char **argv, int exact, afi_t afi, safi_t safi) { struct community *com; struct buffer *b; + struct bgp *bgp; int i; char *str; int first = 0; + /* BGP structure lookup */ + if (view_name) + { + bgp = bgp_lookup_by_name (view_name); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + b = buffer_new (1024); for (i = 0; i < argc; i++) { @@ -7484,7 +7593,7 @@ bgp_show_community (struct vty *vty, int argc, const char **argv, int exact, return CMD_WARNING; } - return bgp_show (vty, NULL, afi, safi, + return bgp_show (vty, bgp, afi, safi, (exact ? bgp_show_type_community_exact : bgp_show_type_community), com); } @@ -7501,7 +7610,7 @@ DEFUN (show_ip_bgp_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") { - return bgp_show_community (vty, argc, argv, 0, AFI_IP, SAFI_UNICAST); + return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP, SAFI_UNICAST); } ALIAS (show_ip_bgp_community, @@ -7580,9 +7689,9 @@ DEFUN (show_ip_bgp_ipv4_community, "Do not export to next AS (well-known community)\n") { if (strncmp (argv[0], "m", 1) == 0) - return bgp_show_community (vty, argc, argv, 0, AFI_IP, SAFI_MULTICAST); + return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP, SAFI_MULTICAST); - return bgp_show_community (vty, argc, argv, 0, AFI_IP, SAFI_UNICAST); + return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP, SAFI_UNICAST); } ALIAS (show_ip_bgp_ipv4_community, @@ -7654,6 +7763,177 @@ ALIAS (show_ip_bgp_ipv4_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") +DEFUN (show_bgp_view_afi_safi_community_all, + show_bgp_view_afi_safi_community_all_cmd, +#ifdef HAVE_IPV6 + "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community", +#else + "show bgp view WORD ipv4 (unicast|multicast) community", +#endif + SHOW_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Address family\n" +#ifdef HAVE_IPV6 + "Address family\n" +#endif + "Address Family modifier\n" + "Address Family modifier\n" + "Display routes containing communities\n") +{ + int afi; + int safi; + struct bgp *bgp; + + /* BGP structure lookup. */ + bgp = bgp_lookup_by_name (argv[0]); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + +#ifdef HAVE_IPV6 + afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; + safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; +#else + afi = AFI_IP; + safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; +#endif + return bgp_show (vty, bgp, afi, safi, bgp_show_type_community_all, NULL); +} + +DEFUN (show_bgp_view_afi_safi_community, + show_bgp_view_afi_safi_community_cmd, +#ifdef HAVE_IPV6 + "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", +#else + "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", +#endif + SHOW_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Address family\n" +#ifdef HAVE_IPV6 + "Address family\n" +#endif + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") +{ + int afi; + int safi; + +#ifdef HAVE_IPV6 + afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; + safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + return bgp_show_community (vty, argv[0], argc-3, &argv[3], 0, afi, safi); +#else + afi = AFI_IP; + safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + return bgp_show_community (vty, argv[0], argc-2, &argv[2], 0, afi, safi); +#endif +} + +ALIAS (show_bgp_view_afi_safi_community, + show_bgp_view_afi_safi_community2_cmd, +#ifdef HAVE_IPV6 + "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +#else + "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +#endif + SHOW_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Address family\n" +#ifdef HAVE_IPV6 + "Address family\n" +#endif + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_view_afi_safi_community, + show_bgp_view_afi_safi_community3_cmd, +#ifdef HAVE_IPV6 + "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +#else + "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +#endif + SHOW_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Address family\n" +#ifdef HAVE_IPV6 + "Address family\n" +#endif + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + +ALIAS (show_bgp_view_afi_safi_community, + show_bgp_view_afi_safi_community4_cmd, +#ifdef HAVE_IPV6 + "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +#else + "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", +#endif + SHOW_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Address family\n" +#ifdef HAVE_IPV6 + "Address family\n" +#endif + "Address family modifier\n" + "Address family modifier\n" + "Display routes matching the communities\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "community number\n" + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n") + DEFUN (show_ip_bgp_community_exact, show_ip_bgp_community_exact_cmd, "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", @@ -7667,7 +7947,7 @@ DEFUN (show_ip_bgp_community_exact, "Do not export to next AS (well-known community)\n" "Exact match of the communities") { - return bgp_show_community (vty, argc, argv, 1, AFI_IP, SAFI_UNICAST); + return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP, SAFI_UNICAST); } ALIAS (show_ip_bgp_community_exact, @@ -7750,9 +8030,9 @@ DEFUN (show_ip_bgp_ipv4_community_exact, "Exact match of the communities") { if (strncmp (argv[0], "m", 1) == 0) - return bgp_show_community (vty, argc, argv, 1, AFI_IP, SAFI_MULTICAST); + return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP, SAFI_MULTICAST); - return bgp_show_community (vty, argc, argv, 1, AFI_IP, SAFI_UNICAST); + return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP, SAFI_UNICAST); } ALIAS (show_ip_bgp_ipv4_community_exact, @@ -7839,7 +8119,7 @@ DEFUN (show_bgp_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") { - return bgp_show_community (vty, argc, argv, 0, AFI_IP6, SAFI_UNICAST); + return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP6, SAFI_UNICAST); } ALIAS (show_bgp_community, @@ -7984,7 +8264,7 @@ DEFUN (show_ipv6_bgp_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") { - return bgp_show_community (vty, argc, argv, 0, AFI_IP6, SAFI_UNICAST); + return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP6, SAFI_UNICAST); } /* old command */ @@ -8062,7 +8342,7 @@ DEFUN (show_bgp_community_exact, "Do not export to next AS (well-known community)\n" "Exact match of the communities") { - return bgp_show_community (vty, argc, argv, 1, AFI_IP6, SAFI_UNICAST); + return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP6, SAFI_UNICAST); } ALIAS (show_bgp_community_exact, @@ -8215,7 +8495,7 @@ DEFUN (show_ipv6_bgp_community_exact, "Do not export to next AS (well-known community)\n" "Exact match of the communities") { - return bgp_show_community (vty, argc, argv, 1, AFI_IP6, SAFI_UNICAST); + return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP6, SAFI_UNICAST); } /* old command */ @@ -8297,7 +8577,7 @@ DEFUN (show_ipv6_mbgp_community, "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") { - return bgp_show_community (vty, argc, argv, 0, AFI_IP6, SAFI_MULTICAST); + return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP6, SAFI_MULTICAST); } /* old command */ @@ -8377,7 +8657,7 @@ DEFUN (show_ipv6_mbgp_community_exact, "Do not export to next AS (well-known community)\n" "Exact match of the communities") { - return bgp_show_community (vty, argc, argv, 1, AFI_IP6, SAFI_MULTICAST); + return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP6, SAFI_MULTICAST); } /* old command */ @@ -9777,6 +10057,56 @@ DEFUN (show_ip_bgp_ipv4_neighbor_received_routes, return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 1); } +DEFUN (show_bgp_view_afi_safi_neighbor_adv_recd_routes, + show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd, +#ifdef HAVE_IPV6 + "show bgp view WORD (ipv4|ipv6) (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) (advertised-routes|received-routes)", +#else + "show bgp view WORD ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) (advertised-routes|received-routes)", +#endif + SHOW_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Address family\n" +#ifdef HAVE_IPV6 + "Address family\n" +#endif + "Address family modifier\n" + "Address family modifier\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Neighbor to display information about\n" + "Display the advertised routes to neighbor\n" + "Display the received routes from neighbor\n") +{ + int afi; + int safi; + int in; + struct peer *peer; + +#ifdef HAVE_IPV6 + peer = peer_lookup_in_view (vty, argv[0], argv[3]); +#else + peer = peer_lookup_in_view (vty, argv[0], argv[2]); +#endif + + if (! peer) + return CMD_WARNING; + +#ifdef HAVE_IPV6 + afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; + safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + in = (strncmp (argv[4], "r", 1) == 0) ? 1 : 0; +#else + afi = AFI_IP; + safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + in = (strncmp (argv[3], "r", 1) == 0) ? 1 : 0; +#endif + + return peer_adj_routes (vty, peer, afi, safi, in); +} + DEFUN (show_ip_bgp_neighbor_received_prefix_filter, show_ip_bgp_neighbor_received_prefix_filter_cmd, "show ip bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter", @@ -10184,6 +10514,65 @@ ALIAS (show_ip_bgp_view_rsclient, "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) +DEFUN (show_bgp_view_ipv4_safi_rsclient, + show_bgp_view_ipv4_safi_rsclient_cmd, + "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", + SHOW_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR) +{ + struct bgp_table *table; + struct peer *peer; + safi_t safi; + + if (argc == 3) { + peer = peer_lookup_in_view (vty, argv[0], argv[2]); + safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + } else { + peer = peer_lookup_in_view (vty, NULL, argv[1]); + safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + } + + if (! peer) + return CMD_WARNING; + + if (! peer->afc[AFI_IP][safi]) + { + vty_out (vty, "%% Activate the neighbor for the address family first%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][safi], + PEER_FLAG_RSERVER_CLIENT)) + { + vty_out (vty, "%% Neighbor is not a Route-Server client%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + table = peer->rib[AFI_IP][safi]; + + return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL); +} + +ALIAS (show_bgp_view_ipv4_safi_rsclient, + show_bgp_ipv4_safi_rsclient_cmd, + "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR) + DEFUN (show_ip_bgp_view_rsclient_route, show_ip_bgp_view_rsclient_route_cmd, "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D", @@ -10257,6 +10646,87 @@ ALIAS (show_ip_bgp_view_rsclient_route, NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") +DEFUN (show_bgp_view_ipv4_safi_rsclient_route, + show_bgp_view_ipv4_safi_rsclient_route_cmd, + "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D", + SHOW_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "Network in the BGP routing table to display\n") +{ + struct bgp *bgp; + struct peer *peer; + safi_t safi; + + /* BGP structure lookup. */ + if (argc == 4) + { + bgp = bgp_lookup_by_name (argv[0]); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (argc == 4) { + peer = peer_lookup_in_view (vty, argv[0], argv[2]); + safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + } else { + peer = peer_lookup_in_view (vty, NULL, argv[1]); + safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + } + + if (! peer) + return CMD_WARNING; + + if (! peer->afc[AFI_IP][safi]) + { + vty_out (vty, "%% Activate the neighbor for the address family first%s", + VTY_NEWLINE); + return CMD_WARNING; +} + + if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][safi], + PEER_FLAG_RSERVER_CLIENT)) + { + vty_out (vty, "%% Neighbor is not a Route-Server client%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][safi], + (argc == 4) ? argv[3] : argv[2], + AFI_IP, safi, NULL, 0); +} + +ALIAS (show_bgp_view_ipv4_safi_rsclient_route, + show_bgp_ipv4_safi_rsclient_route_cmd, + "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "Network in the BGP routing table to display\n") + DEFUN (show_ip_bgp_view_rsclient_prefix, show_ip_bgp_view_rsclient_prefix_cmd, "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", @@ -10330,6 +10800,86 @@ ALIAS (show_ip_bgp_view_rsclient_prefix, NEIGHBOR_ADDR_STR "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n") +DEFUN (show_bgp_view_ipv4_safi_rsclient_prefix, + show_bgp_view_ipv4_safi_rsclient_prefix_cmd, + "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", + SHOW_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n") +{ + struct bgp *bgp; + struct peer *peer; + safi_t safi; + + /* BGP structure lookup. */ + if (argc == 4) + { + bgp = bgp_lookup_by_name (argv[0]); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (argc == 4) { + peer = peer_lookup_in_view (vty, argv[0], argv[2]); + safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + } else { + peer = peer_lookup_in_view (vty, NULL, argv[1]); + safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + } + + if (! peer) + return CMD_WARNING; + + if (! peer->afc[AFI_IP][safi]) + { + vty_out (vty, "%% Activate the neighbor for the address family first%s", + VTY_NEWLINE); + return CMD_WARNING; +} + + if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][safi], + PEER_FLAG_RSERVER_CLIENT)) +{ + vty_out (vty, "%% Neighbor is not a Route-Server client%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][safi], + (argc == 4) ? argv[3] : argv[2], + AFI_IP, safi, NULL, 1); +} + +ALIAS (show_bgp_view_ipv4_safi_rsclient_prefix, + show_bgp_ipv4_safi_rsclient_prefix_cmd, + "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n") #ifdef HAVE_IPV6 DEFUN (show_bgp_view_neighbor_routes, @@ -10596,6 +11146,65 @@ ALIAS (show_bgp_view_rsclient, "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) +DEFUN (show_bgp_view_ipv6_safi_rsclient, + show_bgp_view_ipv6_safi_rsclient_cmd, + "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", + SHOW_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR) +{ + struct bgp_table *table; + struct peer *peer; + safi_t safi; + + if (argc == 3) { + peer = peer_lookup_in_view (vty, argv[0], argv[2]); + safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + } else { + peer = peer_lookup_in_view (vty, NULL, argv[1]); + safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + } + + if (! peer) + return CMD_WARNING; + + if (! peer->afc[AFI_IP6][safi]) + { + vty_out (vty, "%% Activate the neighbor for the address family first%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][safi], + PEER_FLAG_RSERVER_CLIENT)) + { + vty_out (vty, "%% Neighbor is not a Route-Server client%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + table = peer->rib[AFI_IP6][safi]; + + return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL); +} + +ALIAS (show_bgp_view_ipv6_safi_rsclient, + show_bgp_ipv6_safi_rsclient_cmd, + "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR) + DEFUN (show_bgp_view_rsclient_route, show_bgp_view_rsclient_route_cmd, "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X", @@ -10667,6 +11276,87 @@ ALIAS (show_bgp_view_rsclient_route, NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") +DEFUN (show_bgp_view_ipv6_safi_rsclient_route, + show_bgp_view_ipv6_safi_rsclient_route_cmd, + "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X", + SHOW_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "Network in the BGP routing table to display\n") +{ + struct bgp *bgp; + struct peer *peer; + safi_t safi; + + /* BGP structure lookup. */ + if (argc == 4) + { + bgp = bgp_lookup_by_name (argv[0]); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (argc == 4) { + peer = peer_lookup_in_view (vty, argv[0], argv[2]); + safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + } else { + peer = peer_lookup_in_view (vty, NULL, argv[1]); + safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + } + + if (! peer) + return CMD_WARNING; + + if (! peer->afc[AFI_IP6][safi]) + { + vty_out (vty, "%% Activate the neighbor for the address family first%s", + VTY_NEWLINE); + return CMD_WARNING; +} + + if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][safi], + PEER_FLAG_RSERVER_CLIENT)) + { + vty_out (vty, "%% Neighbor is not a Route-Server client%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][safi], + (argc == 4) ? argv[3] : argv[2], + AFI_IP6, safi, NULL, 0); +} + +ALIAS (show_bgp_view_ipv6_safi_rsclient_route, + show_bgp_ipv6_safi_rsclient_route_cmd, + "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "Network in the BGP routing table to display\n") + DEFUN (show_bgp_view_rsclient_prefix, show_bgp_view_rsclient_prefix_cmd, "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", @@ -10738,6 +11428,87 @@ ALIAS (show_bgp_view_rsclient_prefix, NEIGHBOR_ADDR_STR "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n") +DEFUN (show_bgp_view_ipv6_safi_rsclient_prefix, + show_bgp_view_ipv6_safi_rsclient_prefix_cmd, + "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", + SHOW_STR + BGP_STR + "BGP view\n" + "BGP view name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "IP prefix <network>/<length>, e.g., 3ffe::/16\n") +{ + struct bgp *bgp; + struct peer *peer; + safi_t safi; + + /* BGP structure lookup. */ + if (argc == 4) + { + bgp = bgp_lookup_by_name (argv[0]); + if (bgp == NULL) + { + vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + } + else + { + bgp = bgp_get_default (); + if (bgp == NULL) + { + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (argc == 4) { + peer = peer_lookup_in_view (vty, argv[0], argv[2]); + safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + } else { + peer = peer_lookup_in_view (vty, NULL, argv[1]); + safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + } + + if (! peer) + return CMD_WARNING; + + if (! peer->afc[AFI_IP6][safi]) + { + vty_out (vty, "%% Activate the neighbor for the address family first%s", + VTY_NEWLINE); + return CMD_WARNING; +} + + if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][safi], + PEER_FLAG_RSERVER_CLIENT)) +{ + vty_out (vty, "%% Neighbor is not a Route-Server client%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][safi], + (argc == 4) ? argv[3] : argv[2], + AFI_IP6, safi, NULL, 1); +} + +ALIAS (show_bgp_view_ipv6_safi_rsclient_prefix, + show_bgp_ipv6_safi_rsclient_prefix_cmd, + "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Client\n" + NEIGHBOR_ADDR_STR + "IP prefix <network>/<length>, e.g., 3ffe::/16\n") + #endif /* HAVE_IPV6 */ struct bgp_table *bgp_distance_table; @@ -11166,41 +11937,49 @@ bgp_clear_damp_route (struct vty *vty, const char *view_name, if ((table = rn->info) != NULL) if ((rm = bgp_node_match (table, &match)) != NULL) - if (! prefix_check || rm->p.prefixlen == match.prefixlen) - { - ri = rm->info; - while (ri) - { - if (ri->extra && ri->extra->damp_info) - { - ri_temp = ri->next; - bgp_damp_info_free (ri->extra->damp_info, 1); - ri = ri_temp; - } - else - ri = ri->next; - } - } + { + if (! prefix_check || rm->p.prefixlen == match.prefixlen) + { + ri = rm->info; + while (ri) + { + if (ri->extra && ri->extra->damp_info) + { + ri_temp = ri->next; + bgp_damp_info_free (ri->extra->damp_info, 1); + ri = ri_temp; + } + else + ri = ri->next; + } + } + + bgp_unlock_node (rm); + } } } else { if ((rn = bgp_node_match (bgp->rib[afi][safi], &match)) != NULL) - if (! prefix_check || rn->p.prefixlen == match.prefixlen) - { - ri = rn->info; - while (ri) - { - if (ri->extra && ri->extra->damp_info) - { - ri_temp = ri->next; - bgp_damp_info_free (ri->extra->damp_info, 1); - ri = ri_temp; - } - else - ri = ri->next; - } - } + { + if (! prefix_check || rn->p.prefixlen == match.prefixlen) + { + ri = rn->info; + while (ri) + { + if (ri->extra && ri->extra->damp_info) + { + ri_temp = ri->next; + bgp_damp_info_free (ri->extra->damp_info, 1); + ri = ri_temp; + } + else + ri = ri->next; + } + } + + bgp_unlock_node (rn); + } } return CMD_SUCCESS; @@ -11555,12 +12334,15 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_ip_bgp_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_cmd); install_element (VIEW_NODE, &show_ip_bgp_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_cmd); @@ -11586,6 +12368,11 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_cmd); + install_element (VIEW_NODE, &show_bgp_view_afi_safi_community_all_cmd); + install_element (VIEW_NODE, &show_bgp_view_afi_safi_community_cmd); + install_element (VIEW_NODE, &show_bgp_view_afi_safi_community2_cmd); + install_element (VIEW_NODE, &show_bgp_view_afi_safi_community3_cmd); + install_element (VIEW_NODE, &show_bgp_view_afi_safi_community4_cmd); install_element (VIEW_NODE, &show_ip_bgp_community_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_community2_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_community3_exact_cmd); @@ -11604,6 +12391,7 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd); + install_element (VIEW_NODE, &show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); @@ -11621,20 +12409,28 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_ip_bgp_neighbor_flap_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_damp_cmd); install_element (VIEW_NODE, &show_ip_bgp_rsclient_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_cmd); install_element (VIEW_NODE, &show_ip_bgp_rsclient_route_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_rsclient_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_cmd); + install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_route_cmd); + install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd); /* Restricted node: VIEW_NODE - (set of dangerous commands) */ install_element (RESTRICTED_NODE, &show_ip_bgp_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_route_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_view_route_cmd); @@ -11647,6 +12443,11 @@ bgp_route_init (void) install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community2_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community3_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community4_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community_all_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community2_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community3_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community4_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_community_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_community3_exact_cmd); @@ -11656,18 +12457,25 @@ bgp_route_init (void) install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_route_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_route_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_cmd); install_element (ENABLE_NODE, &show_ip_bgp_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_cmd); @@ -11693,6 +12501,11 @@ bgp_route_init (void) install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_cmd); + install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community_all_cmd); + install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community_cmd); + install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community2_cmd); + install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community3_cmd); + install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community4_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community2_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community3_exact_cmd); @@ -11711,6 +12524,7 @@ bgp_route_init (void) install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd); + install_element (ENABLE_NODE, &show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); @@ -11728,13 +12542,19 @@ bgp_route_init (void) install_element (ENABLE_NODE, &show_ip_bgp_neighbor_flap_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_ip_bgp_rsclient_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_cmd); install_element (ENABLE_NODE, &show_ip_bgp_rsclient_route_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_rsclient_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_cmd); + install_element (ENABLE_NODE, &show_bgp_view_ipv4_safi_rsclient_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_route_cmd); + install_element (ENABLE_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd); /* BGP dampening clear commands */ install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd); @@ -11771,10 +12591,13 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_bgp_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_cmd); install_element (VIEW_NODE, &show_bgp_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_route_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_route_cmd); install_element (VIEW_NODE, &show_bgp_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_cmd); install_element (VIEW_NODE, &show_bgp_regexp_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_regexp_cmd); install_element (VIEW_NODE, &show_bgp_prefix_list_cmd); @@ -11820,8 +12643,11 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_bgp_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_rsclient_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_rsclient_route_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_rsclient_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_cmd); install_element (VIEW_NODE, &show_bgp_view_route_cmd); @@ -11841,16 +12667,21 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_bgp_view_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_view_rsclient_cmd); + install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_view_rsclient_route_cmd); + install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_view_rsclient_prefix_cmd); + install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd); /* Restricted: * VIEW_NODE - (set of dangerous commands) - (commands dependent on prev) */ install_element (RESTRICTED_NODE, &show_bgp_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_route_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_community_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community_cmd); install_element (RESTRICTED_NODE, &show_bgp_community2_cmd); @@ -11868,7 +12699,9 @@ bgp_route_init (void) install_element (RESTRICTED_NODE, &show_bgp_community4_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community4_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_rsclient_route_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_rsclient_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_prefix_cmd); @@ -11876,14 +12709,19 @@ bgp_route_init (void) install_element (RESTRICTED_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_route_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_prefix_cmd); + install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_cmd); install_element (ENABLE_NODE, &show_bgp_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_route_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_route_cmd); install_element (ENABLE_NODE, &show_bgp_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_regexp_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_regexp_cmd); install_element (ENABLE_NODE, &show_bgp_prefix_list_cmd); @@ -11929,8 +12767,11 @@ bgp_route_init (void) install_element (ENABLE_NODE, &show_bgp_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_bgp_rsclient_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_rsclient_route_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_rsclient_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_view_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_cmd); install_element (ENABLE_NODE, &show_bgp_view_route_cmd); @@ -11950,8 +12791,11 @@ bgp_route_init (void) install_element (ENABLE_NODE, &show_bgp_view_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_bgp_view_rsclient_cmd); + install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_view_rsclient_route_cmd); + install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_rsclient_prefix_cmd); + install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd); /* Statistics */ install_element (ENABLE_NODE, &show_bgp_statistics_cmd); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 42c3e053..abb85fd2 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1470,6 +1470,13 @@ route_set_community_delete (void *rule, struct prefix *prefix, new = community_uniq_sort (merge); community_free (merge); + /* HACK: if the old community is not intern'd, + * we should free it here, or all reference to it may be lost. + * Really need to cleanup attribute caching sometime. + */ + if (old->refcnt == 0) + community_free (old); + if (new->size == 0) { binfo->attr->community = NULL; @@ -1552,10 +1559,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); } @@ -1571,7 +1578,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. */ @@ -1579,7 +1586,7 @@ static void route_set_ecommunity_rt_free (void *rule) { struct ecommunity *ecom = rule; - ecommunity_free (ecom); + ecommunity_unintern (&ecom); } /* Set community rule structure. */ @@ -1598,7 +1605,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) @@ -1609,8 +1616,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; } @@ -1625,7 +1643,7 @@ route_set_ecommunity_soo_compile (const char *arg) if (! ecom) return NULL; - return ecom; + return ecommunity_intern (ecom); } /* Free function for set community. */ @@ -1633,7 +1651,7 @@ static void route_set_ecommunity_soo_free (void *rule) { struct ecommunity *ecom = rule; - ecommunity_free (ecom); + ecommunity_unintern (&ecom); } /* Set community rule structure. */ diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index 91cab606..a249c23d 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -350,7 +350,6 @@ bgp_node_get (struct bgp_table *const table, struct prefix *p) if (new->p.prefixlen != p->prefixlen) { match = new; - bgp_lock_node (match); new = bgp_node_set (table, p); set_link (match, new); table->count++; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 9cb30182..f65bb157 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -213,6 +213,12 @@ bgp_vty_return (struct vty *vty, int ret) case BGP_ERR_TCPSIG_FAILED: str = "Error while applying TCP-Sig to session(s)"; break; + case BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK: + str = "ebgp-multihop and ttl-security cannot be configured together"; + break; + case BGP_ERR_NO_IBGP_WITH_TTLHACK: + str = "ttl-security only allowed for EBGP peers"; + break; } if (str) { @@ -2636,9 +2642,7 @@ peer_ebgp_multihop_set_vty (struct vty *vty, const char *ip_str, else VTY_GET_INTEGER_RANGE ("TTL", ttl, ttl_str, 1, 255); - peer_ebgp_multihop_set (peer, ttl); - - return CMD_SUCCESS; + return bgp_vty_return (vty, peer_ebgp_multihop_set (peer, ttl)); } static int @@ -2650,9 +2654,7 @@ peer_ebgp_multihop_unset_vty (struct vty *vty, const char *ip_str) if (! peer) return CMD_WARNING; - peer_ebgp_multihop_unset (peer); - - return CMD_SUCCESS; + return bgp_vty_return (vty, peer_ebgp_multihop_unset (peer)); } /* neighbor ebgp-multihop. */ @@ -3954,6 +3956,42 @@ DEFUN (no_neighbor_allowas_in, return bgp_vty_return (vty, ret); } +DEFUN (neighbor_ttl_security, + neighbor_ttl_security_cmd, + NEIGHBOR_CMD2 "ttl-security hops <1-254>", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Specify the maximum number of hops to the BGP peer\n") +{ + struct peer *peer; + int gtsm_hops; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + VTY_GET_INTEGER_RANGE ("", gtsm_hops, argv[1], 1, 254); + + return bgp_vty_return (vty, peer_ttl_security_hops_set (peer, gtsm_hops)); +} + +DEFUN (no_neighbor_ttl_security, + no_neighbor_ttl_security_cmd, + NO_NEIGHBOR_CMD2 "ttl-security hops <1-254>", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Specify the maximum number of hops to the BGP peer\n") +{ + struct peer *peer; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + return bgp_vty_return (vty, peer_ttl_security_hops_unset (peer)); +} + /* Address family configuration. */ DEFUN (address_family_ipv4, address_family_ipv4_cmd, @@ -6856,6 +6894,16 @@ DEFUN (show_ip_bgp_ipv4_summary, return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); } +ALIAS (show_ip_bgp_ipv4_summary, + show_bgp_ipv4_safi_summary_cmd, + "show bgp ipv4 (unicast|multicast) summary", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Summary of BGP neighbor status\n") + DEFUN (show_ip_bgp_instance_ipv4_summary, show_ip_bgp_instance_ipv4_summary_cmd, "show ip bgp view WORD ipv4 (unicast|multicast) summary", @@ -6875,6 +6923,18 @@ DEFUN (show_ip_bgp_instance_ipv4_summary, return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); } +ALIAS (show_ip_bgp_instance_ipv4_summary, + show_bgp_instance_ipv4_safi_summary_cmd, + "show bgp view WORD ipv4 (unicast|multicast) summary", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Summary of BGP neighbor status\n") + DEFUN (show_ip_bgp_vpnv4_all_summary, show_ip_bgp_vpnv4_all_summary_cmd, "show ip bgp vpnv4 all summary", @@ -6953,6 +7013,40 @@ ALIAS (show_bgp_instance_summary, "Address family\n" "Summary of BGP neighbor status\n") +DEFUN (show_bgp_ipv6_safi_summary, + show_bgp_ipv6_safi_summary_cmd, + "show bgp ipv6 (unicast|multicast) summary", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Summary of BGP neighbor status\n") +{ + if (strncmp (argv[0], "m", 1) == 0) + return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST); + + return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); +} + +DEFUN (show_bgp_instance_ipv6_safi_summary, + show_bgp_instance_ipv6_safi_summary_cmd, + "show bgp view WORD ipv6 (unicast|multicast) summary", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Summary of BGP neighbor status\n") +{ + if (strncmp (argv[1], "m", 1) == 0) + return bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_MULTICAST); + + return bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); +} + /* old command */ DEFUN (show_ipv6_bgp_summary, show_ipv6_bgp_summary_cmd, @@ -7544,10 +7638,16 @@ bgp_show_peer (struct vty *vty, struct peer *p) p->host, VTY_NEWLINE); } - /* EBGP Multihop */ - if (peer_sort (p) != BGP_PEER_IBGP && p->ttl > 1) - vty_out (vty, " External BGP neighbor may be up to %d hops away.%s", - p->ttl, VTY_NEWLINE); + /* EBGP Multihop and GTSM */ + if (peer_sort (p) != BGP_PEER_IBGP) + { + if (p->gtsm_hops > 0) + vty_out (vty, " External BGP neighbor may be up to %d hops away.%s", + p->gtsm_hops, VTY_NEWLINE); + else if (p->ttl > 1) + vty_out (vty, " External BGP neighbor may be up to %d hops away.%s", + p->ttl, VTY_NEWLINE); + } /* Local address. */ if (p->su_local) @@ -8154,6 +8254,41 @@ DEFUN (show_ip_bgp_instance_ipv4_rsclient_summary, return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); } +DEFUN (show_bgp_instance_ipv4_safi_rsclient_summary, + show_bgp_instance_ipv4_safi_rsclient_summary_cmd, + "show bgp view WORD ipv4 (unicast|multicast) rsclient summary", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Clients\n" + "Summary of all Route Server Clients\n") +{ + safi_t safi; + + if (argc == 2) { + safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, safi); + } else { + safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, safi); + } +} + +ALIAS (show_bgp_instance_ipv4_safi_rsclient_summary, + show_bgp_ipv4_safi_rsclient_summary_cmd, + "show bgp ipv4 (unicast|multicast) rsclient summary", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Clients\n" + "Summary of all Route Server Clients\n") + #ifdef HAVE_IPV6 DEFUN (show_bgp_rsclient_summary, show_bgp_rsclient_summary_cmd, @@ -8198,6 +8333,42 @@ ALIAS (show_bgp_instance_rsclient_summary, "Address family\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") + +DEFUN (show_bgp_instance_ipv6_safi_rsclient_summary, + show_bgp_instance_ipv6_safi_rsclient_summary_cmd, + "show bgp view WORD ipv6 (unicast|multicast) rsclient summary", + SHOW_STR + BGP_STR + "BGP view\n" + "View name\n" + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Clients\n" + "Summary of all Route Server Clients\n") +{ + safi_t safi; + + if (argc == 2) { + safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, safi); + } else { + safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; + return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, safi); + } +} + +ALIAS (show_bgp_instance_ipv6_safi_rsclient_summary, + show_bgp_ipv6_safi_rsclient_summary_cmd, + "show bgp ipv6 (unicast|multicast) rsclient summary", + SHOW_STR + BGP_STR + "Address family\n" + "Address Family modifier\n" + "Address Family modifier\n" + "Information about Route Server Clients\n" + "Summary of all Route Server Clients\n") + #endif /* HAVE IPV6 */ /* Redistribute VTY commands. */ @@ -9627,38 +9798,50 @@ bgp_vty_init (void) install_element (VIEW_NODE, &show_ip_bgp_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_instance_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_summary_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); + install_element (VIEW_NODE, &show_bgp_instance_ipv4_safi_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); #ifdef HAVE_IPV6 install_element (VIEW_NODE, &show_bgp_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_summary_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_summary_cmd); + install_element (VIEW_NODE, &show_bgp_instance_ipv6_safi_summary_cmd); #endif /* HAVE_IPV6 */ install_element (RESTRICTED_NODE, &show_ip_bgp_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_summary_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); + install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_safi_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); #ifdef HAVE_IPV6 install_element (RESTRICTED_NODE, &show_bgp_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_summary_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_summary_cmd); + install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_safi_summary_cmd); #endif /* HAVE_IPV6 */ install_element (ENABLE_NODE, &show_ip_bgp_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_instance_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_instance_ipv4_safi_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); #ifdef HAVE_IPV6 install_element (ENABLE_NODE, &show_bgp_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_instance_ipv6_safi_summary_cmd); #endif /* HAVE_IPV6 */ /* "show ip bgp neighbors" commands. */ @@ -9722,28 +9905,40 @@ bgp_vty_init (void) install_element (VIEW_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); + install_element (VIEW_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd); + install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); + install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd); #ifdef HAVE_IPV6 install_element (VIEW_NODE, &show_bgp_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); + install_element (VIEW_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); + install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); + install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); + install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); + install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd); #endif /* HAVE_IPV6 */ /* "show ip bgp paths" commands. */ @@ -9784,6 +9979,10 @@ bgp_vty_init (void) install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_rmap_cmd); #endif /* HAVE_IPV6 */ + /* ttl_security commands */ + install_element (BGP_NODE, &neighbor_ttl_security_cmd); + install_element (BGP_NODE, &no_neighbor_ttl_security_cmd); + /* "show bgp memory" commands. */ install_element (VIEW_NODE, &show_bgp_memory_cmd); install_element (RESTRICTED_NODE, &show_bgp_memory_cmd); 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 0d462db9..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); @@ -1379,6 +1379,7 @@ peer_group_get (struct bgp *bgp, const char *name) group->conf->group = group; group->conf->as = 0; group->conf->ttl = 1; + group->conf->gtsm_hops = 0; group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; UNSET_FLAG (group->conf->config, PEER_CONFIG_TIMER); UNSET_FLAG (group->conf->config, PEER_CONFIG_CONNECT); @@ -1416,6 +1417,9 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer, /* TTL */ peer->ttl = conf->ttl; + /* GTSM hops */ + peer->gtsm_hops = conf->gtsm_hops; + /* Weight */ peer->weight = conf->weight; @@ -2664,10 +2668,36 @@ peer_ebgp_multihop_set (struct peer *peer, int ttl) { struct peer_group *group; struct listnode *node, *nnode; + struct peer *peer1; if (peer_sort (peer) == BGP_PEER_IBGP) return 0; + /* see comment in peer_ttl_security_hops_set() */ + if (ttl != MAXTTL) + { + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + if (group->conf->gtsm_hops != 0) + return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; + + for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) + { + if (peer_sort (peer1) == BGP_PEER_IBGP) + continue; + + if (peer1->gtsm_hops != 0) + return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; + } + } + else + { + if (peer->gtsm_hops != 0) + return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; + } + } + peer->ttl = ttl; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) @@ -2701,6 +2731,9 @@ peer_ebgp_multihop_unset (struct peer *peer) if (peer_sort (peer) == BGP_PEER_IBGP) return 0; + if (peer->gtsm_hops != 0 && peer->ttl != MAXTTL) + return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; + if (peer_group_active (peer)) peer->ttl = peer->group->conf->ttl; else @@ -4332,6 +4365,137 @@ peer_maximum_prefix_unset (struct peer *peer, afi_t afi, safi_t safi) return 0; } +/* Set # of hops between us and BGP peer. */ +int +peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops) +{ + struct peer_group *group; + struct listnode *node, *nnode; + struct peer *peer1; + int ret; + + zlog_debug ("peer_ttl_security_hops_set: set gtsm_hops to %d for %s", gtsm_hops, peer->host); + + if (peer_sort (peer) == BGP_PEER_IBGP) + return BGP_ERR_NO_IBGP_WITH_TTLHACK; + + /* We cannot configure ttl-security hops when ebgp-multihop is already + set. For non peer-groups, the check is simple. For peer-groups, it's + slightly messy, because we need to check both the peer-group structure + and all peer-group members for any trace of ebgp-multihop configuration + before actually applying the ttl-security rules. Cisco really made a + mess of this configuration parameter, and OpenBGPD got it right. + */ + + if (peer->gtsm_hops == 0) { + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + if (group->conf->ttl != 1) + return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; + + for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) + { + if (peer_sort (peer1) == BGP_PEER_IBGP) + continue; + + if (peer1->ttl != 1) + return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; + } + } + else + { + if (peer->ttl != 1) + return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; + } + /* specify MAXTTL on outgoing packets */ + ret = peer_ebgp_multihop_set (peer, MAXTTL); + if (ret != 0) + return ret; + } + + peer->gtsm_hops = gtsm_hops; + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP) + sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - gtsm_hops); + } + else + { + group = peer->group; + for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) + { + if (peer_sort (peer) == BGP_PEER_IBGP) + continue; + + peer->gtsm_hops = group->conf->gtsm_hops; + + /* Change setting of existing peer + * established then change value (may break connectivity) + * not established yet (teardown session and restart) + * no session then do nothing (will get handled by next connection) + */ + if (peer->status == Established) + { + if (peer->fd >= 0 && peer->gtsm_hops != 0) + sockopt_minttl (peer->su.sa.sa_family, peer->fd, + MAXTTL + 1 - peer->gtsm_hops); + } + else if (peer->status < Established) + { + if (BGP_DEBUG (events, EVENTS)) + zlog_debug ("%s Min-ttl changed", peer->host); + BGP_EVENT_ADD (peer, BGP_Stop); + } + } + } + + return 0; +} + +int +peer_ttl_security_hops_unset (struct peer *peer) +{ + struct peer_group *group; + struct listnode *node, *nnode; + struct peer *opeer; + + zlog_debug ("peer_ttl_security_hops_unset: set gtsm_hops to zero for %s", peer->host); + + if (peer_sort (peer) == BGP_PEER_IBGP) + return 0; + + /* if a peer-group member, then reset to peer-group default rather than 0 */ + if (peer_group_active (peer)) + peer->gtsm_hops = peer->group->conf->gtsm_hops; + else + peer->gtsm_hops = 0; + + opeer = peer; + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP) + sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0); + } + else + { + group = peer->group; + for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) + { + if (peer_sort (peer) == BGP_PEER_IBGP) + continue; + + peer->gtsm_hops = 0; + + if (peer->fd >= 0) + sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0); + } + } + + return peer_ebgp_multihop_unset (opeer); +} + int peer_clear (struct peer *peer) { @@ -4557,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; @@ -4636,12 +4798,19 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp, vty_out (vty, " neighbor %s passive%s", addr, VTY_NEWLINE); /* EBGP multihop. */ - if (peer_sort (peer) != BGP_PEER_IBGP && peer->ttl != 1) + if (peer_sort (peer) != BGP_PEER_IBGP && peer->ttl != 1 && + !(peer->gtsm_hops != 0 && peer->ttl == MAXTTL)) if (! peer_group_active (peer) || g_peer->ttl != peer->ttl) vty_out (vty, " neighbor %s ebgp-multihop %d%s", addr, peer->ttl, VTY_NEWLINE); + /* ttl-security hops */ + if (peer_sort (peer) != BGP_PEER_IBGP && peer->gtsm_hops != 0) + if (! peer_group_active (peer) || g_peer->gtsm_hops != peer->gtsm_hops) + vty_out (vty, " neighbor %s ttl-security hops %d%s", addr, + peer->gtsm_hops, VTY_NEWLINE); + /* disable-connected-check. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) if (! peer_group_active (peer) || diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 91773e3c..892e7dec 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -303,6 +303,7 @@ struct peer /* Peer information */ int fd; /* File descriptor */ int ttl; /* TTL of TCP connection to the peer. */ + int gtsm_hops; /* minimum hopcount to peer */ char *desc; /* Description of the peer. */ unsigned short port; /* Destination port for peer */ char *host; /* Printable address of the peer. */ @@ -801,7 +802,9 @@ enum bgp_clear_type #define BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP -27 #define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS -28 #define BGP_ERR_TCPSIG_FAILED -29 -#define BGP_ERR_MAX -30 +#define BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK -30 +#define BGP_ERR_NO_IBGP_WITH_TTLHACK -31 +#define BGP_ERR_MAX -32 extern struct bgp_master *bm; @@ -954,4 +957,7 @@ extern int peer_maximum_prefix_unset (struct peer *, afi_t, safi_t); extern int peer_clear (struct peer *); extern int peer_clear_soft (struct peer *, afi_t, safi_t, enum bgp_clear_type); +extern int peer_ttl_security_hops_set (struct peer *, int); +extern int peer_ttl_security_hops_unset (struct peer *); + #endif /* _QUAGGA_BGPD_H */ |