summaryrefslogtreecommitdiff
path: root/bgpd
diff options
context:
space:
mode:
authorAvneesh Sachdev <avneesh@opensourcerouting.org>2012-04-09 00:25:15 -0700
committerAvneesh Sachdev <avneesh@opensourcerouting.org>2012-04-09 00:25:15 -0700
commit3cf6c2b4e43f44a977d218c96c26250654ae333e (patch)
treee017cde2015fbf3ef6c250327428d7c6152aa8f7 /bgpd
parent01d7ff0a2166a422c56bd26f04fc22832a9e690b (diff)
parente96b312150d8e376c1ef463793d1929eca3618d5 (diff)
Merge branch 'quagga' into google-bgp-multipath
Conflicts: bgpd/bgp_route.c
Diffstat (limited to 'bgpd')
-rw-r--r--bgpd/.cvsignore15
-rw-r--r--bgpd/bgp_advertise.c10
-rw-r--r--bgpd/bgp_aspath.c160
-rw-r--r--bgpd/bgp_aspath.h4
-rw-r--r--bgpd/bgp_attr.c1010
-rw-r--r--bgpd/bgp_attr.h30
-rw-r--r--bgpd/bgp_clist.c4
-rw-r--r--bgpd/bgp_community.c13
-rw-r--r--bgpd/bgp_community.h2
-rw-r--r--bgpd/bgp_debug.c4
-rw-r--r--bgpd/bgp_ecommunity.c47
-rw-r--r--bgpd/bgp_ecommunity.h4
-rw-r--r--bgpd/bgp_fsm.c8
-rw-r--r--bgpd/bgp_main.c9
-rw-r--r--bgpd/bgp_mplsvpn.c8
-rw-r--r--bgpd/bgp_network.c94
-rw-r--r--bgpd/bgp_nexthop.c146
-rw-r--r--bgpd/bgp_nexthop.h2
-rw-r--r--bgpd/bgp_open.c40
-rw-r--r--bgpd/bgp_packet.c127
-rw-r--r--bgpd/bgp_route.c122
-rw-r--r--bgpd/bgp_route.h4
-rw-r--r--bgpd/bgp_routemap.c153
-rw-r--r--bgpd/bgp_vty.c281
-rw-r--r--bgpd/bgp_zebra.c43
-rw-r--r--bgpd/bgp_zebra.h4
-rw-r--r--bgpd/bgpd.c18
-rw-r--r--bgpd/bgpd.h9
28 files changed, 1357 insertions, 1014 deletions
diff --git a/bgpd/.cvsignore b/bgpd/.cvsignore
deleted file mode 100644
index f4504f62..00000000
--- a/bgpd/.cvsignore
+++ /dev/null
@@ -1,15 +0,0 @@
-Makefile
-Makefile.in
-*.o
-bgpd
-bgp_btoa
-bgpd.conf
-tags
-TAGS
-.deps
-.nfs*
-*.lo
-*.la
-*.libs
-.arch-inventory
-.arch-ids
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 de0d6876..64b36775 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,80 +673,79 @@ 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)
{
- assegment_free_all (head);
- return NULL;
+ 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);
+ /* 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).
+ */
+ || ((sizeof segh.length > 1)
+ && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX)))
+ {
+ if (head)
+ assegment_free_all (head);
+ return -1;
+ }
+
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 ;
- }
-
- /* 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"
- */
- if ((seg_size == 0) || (seg_size > length) || (segh.length == 0))
- {
- assegment_free_all (head);
- return NULL;
+ break;
+ default:
+ if (head)
+ assegment_free_all (head);
+ return -1;
}
- length -= seg_size ;
-
/* now its safe to trust lengths */
seg = assegment_new (segh.type, segh.length);
@@ -756,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.
*/
@@ -809,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;
@@ -832,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;
@@ -1632,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 b881b654..fc4dd6b7 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 *);
@@ -81,7 +81,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 01598c87..0d82aba0 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -51,7 +51,7 @@ static const struct message attr_str [] =
{ BGP_ATTR_AGGREGATOR, "AGGREGATOR" },
{ BGP_ATTR_COMMUNITIES, "COMMUNITY" },
{ BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" },
- { BGP_ATTR_CLUSTER_LIST, "CLUSTERLIST" },
+ { BGP_ATTR_CLUSTER_LIST, "CLUSTER_LIST" },
{ BGP_ATTR_DPA, "DPA" },
{ BGP_ATTR_ADVERTISER, "ADVERTISER"} ,
{ BGP_ATTR_RCID_PATH, "RCID_PATH" },
@@ -63,6 +63,17 @@ static const struct message attr_str [] =
{ BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" },
};
static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
+
+static const struct message attr_flag_str[] =
+{
+ { BGP_ATTR_FLAG_OPTIONAL, "Optional" },
+ { BGP_ATTR_FLAG_TRANS, "Transitive" },
+ { BGP_ATTR_FLAG_PARTIAL, "Partial" },
+ /* bgp_attr_flags_diagnose() relies on this bit being last in this list */
+ { BGP_ATTR_FLAG_EXTLEN, "Extended Length" },
+};
+static const size_t attr_flag_str_max =
+ sizeof (attr_flag_str) / sizeof (attr_flag_str[0]);
static struct hash *cluster_hash;
@@ -175,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);
}
}
@@ -235,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);
}
}
@@ -500,6 +507,7 @@ bgp_attr_intern (struct attr *attr)
attre->ecommunity = ecommunity_intern (attre->ecommunity);
else
attre->ecommunity->refcnt++;
+
}
if (attre->cluster)
{
@@ -516,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;
}
@@ -551,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;
}
@@ -613,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
@@ -671,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)
@@ -680,32 +704,217 @@ bgp_attr_flush (struct attr *attr)
}
}
-/* Get origin attribute of the update message. */
-static int
-bgp_attr_origin (struct peer *peer, bgp_size_t length,
- struct attr *attr, u_char flag, u_char *startp)
+/* 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 bgp_attr_parser_args *args, u_char subcode,
+ bgp_size_t length)
{
- bgp_size_t total;
+ struct peer *const peer = args->peer;
+ const u_int8_t flags = args->flags;
+ /* startp and length must be special-cased, as whether or not to
+ * send the attribute data with the NOTIFY depends on the error,
+ * the caller therefore signals this with the seperate length argument
+ */
+ u_char *notify_datap = (length > 0 ? args->startp : NULL);
+
+ /* Only relax error handling for eBGP peers */
+ if (peer_sort (peer) != BGP_PEER_EBGP)
+ {
+ bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
+ notify_datap, length);
+ return BGP_ATTR_PARSE_ERROR;
+
+ }
+
+ /* Adjust the stream getp to the end of the attribute, in case we can
+ * still proceed but the caller hasn't read all the attribute.
+ */
+ stream_set_getp (BGP_INPUT (peer),
+ (args->startp - STREAM_DATA (BGP_INPUT (peer)))
+ + args->total);
+
+ switch (args->type) {
+ /* where an attribute is relatively inconsequential, e.g. it does not
+ * affect route selection, and can be safely ignored, then any such
+ * attributes which are malformed should just be ignored and the route
+ * processed as normal.
+ */
+ case BGP_ATTR_AS4_AGGREGATOR:
+ case BGP_ATTR_AGGREGATOR:
+ 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,
+ notify_datap, 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 (flags, BGP_ATTR_FLAG_TRANS)
+ && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
+ && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
+ return BGP_ATTR_PARSE_WITHDRAW;
+
+ /* default to reset */
+ return BGP_ATTR_PARSE_ERROR;
+}
+
+/* Find out what is wrong with the path attribute flag bits and log the error.
+ "Flag bits" here stand for Optional, Transitive and Partial, but not for
+ Extended Length. Checking O/T/P bits at once implies, that the attribute
+ being diagnosed is defined by RFC as either a "well-known" or an "optional,
+ non-transitive" attribute. */
+static void
+bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args,
+ u_int8_t desired_flags /* how RFC says it must be */
+)
+{
+ u_char seen = 0, i;
+ u_char real_flags = args->flags;
+ const u_int8_t attr_code = args->type;
+
+ desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
+ real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
+ for (i = 0; i <= 2; i++) /* O,T,P, but not E */
+ if
+ (
+ CHECK_FLAG (desired_flags, attr_flag_str[i].key) !=
+ CHECK_FLAG (real_flags, attr_flag_str[i].key)
+ )
+ {
+ zlog (args->peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"",
+ LOOKUP (attr_str, attr_code),
+ CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
+ attr_flag_str[i].str);
+ seen = 1;
+ }
+ if (!seen)
+ {
+ zlog (args->peer->log, LOG_DEBUG,
+ "Strange, %s called for attr %s, but no problem found with flags"
+ " (real flags 0x%x, desired 0x%x)",
+ __func__, LOOKUP (attr_str, attr_code),
+ real_flags, desired_flags);
+ }
+}
- /* total is entire attribute length include Attribute Flags (1),
- Attribute Type code (1) and Attribute length (1 or 2). */
- total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
+/* Required flags for attributes. EXTLEN will be masked off when testing,
+ * as will PARTIAL for optional+transitive attributes.
+ */
+const u_int8_t attr_flags_values [] = {
+ [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL,
+ [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
+ [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
+ [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL,
+ [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL,
+ [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
+ [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
+ [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
+};
+static const size_t attr_flags_values_max =
+ sizeof (attr_flags_values) / sizeof (attr_flags_values[0]);
- /* If any recognized attribute has Attribute Flags that conflict
- with the Attribute Type Code, then the Error Subcode is set to
- Attribute Flags Error. The Data field contains the erroneous
- attribute (type, length and value). */
- if (flag != BGP_ATTR_FLAG_TRANS)
+static int
+bgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
+{
+ u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
+ const u_int8_t flags = args->flags;
+ const u_int8_t attr_code = args->type;
+ struct peer *const peer = args->peer;
+
+ /* there may be attributes we don't know about */
+ if (attr_code > attr_flags_values_max)
+ return 0;
+ if (attr_flags_values[attr_code] == 0)
+ return 0;
+
+ /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
+ * 1."
+ */
+ if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags)
+ && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags))
{
- zlog (peer->log, LOG_ERR,
- "Origin attribute flag isn't transitive %d", flag);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
- startp, total);
- return -1;
+ zlog (peer->log, LOG_ERR,
+ "%s well-known attributes must have transitive flag set (%x)",
+ LOOKUP (attr_str, attr_code), flags);
+ return 1;
}
+
+ /* "For well-known attributes and for optional non-transitive attributes,
+ * the Partial bit MUST be set to 0."
+ */
+ if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
+ {
+ if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL))
+ {
+ zlog (peer->log, LOG_ERR,
+ "%s well-known attribute "
+ "must NOT have the partial flag set (%x)",
+ LOOKUP (attr_str, attr_code), flags);
+ return 1;
+ }
+ if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
+ && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
+ {
+ zlog (peer->log, LOG_ERR,
+ "%s optional + transitive attribute "
+ "must NOT have the partial flag set (%x)",
+ LOOKUP (attr_str, attr_code), flags);
+ return 1;
+ }
+ }
+
+ /* Optional transitive attributes may go through speakers that don't
+ * reocgnise them and set the Partial bit.
+ */
+ if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
+ && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
+ SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL);
+
+ if ((flags & ~mask)
+ == attr_flags_values[attr_code])
+ return 0;
+
+ bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]);
+ return 1;
+}
+/* Get origin attribute of the update message. */
+static bgp_attr_parse_ret_t
+bgp_attr_origin (struct bgp_attr_parser_args *args)
+{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
/* If any recognized attribute has Attribute Length that conflicts
with the expected length (based on the attribute type code), then
the Error Subcode is set to Attribute Length Error. The Data
@@ -715,10 +924,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 (args,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
}
/* Fetch origin attribute. */
@@ -733,12 +941,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 (args,
+ BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
+ args->total);
}
/* Set oring attribute flag. */
@@ -746,82 +951,40 @@ 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 *
-bgp_attr_aspath (struct peer *peer, bgp_size_t length,
- struct attr *attr, u_char flag, u_char *startp, int as4_path)
-{
- u_char require ;
- struct aspath *asp ;
-
- /* Check the attribute flags */
- 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)
- {
- const char* path_type ;
- bgp_size_t total;
-
- path_type = as4_path ? "AS4_PATH" : "AS_PATH" ;
-
- if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS))
- zlog (peer->log, LOG_ERR,
- "%s attribute flag isn't transitive %d", path_type, flag) ;
- if ((flag & BGP_ATTR_FLAG_OPTIONAL) != (require & BGP_ATTR_FLAG_OPTIONAL))
- zlog (peer->log, LOG_ERR,
- "%s attribute flag must %sbe optional %d", path_type,
- (flag & BGP_ATTR_FLAG_OPTIONAL) ? "not " : "", flag) ;
-
- total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
-
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- 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
+/* Parse AS path information. This function is wrapper of
+ aspath_parse. */
+static int
+bgp_attr_aspath (struct bgp_attr_parser_args *args)
+{
+ struct attr *const attr = args->attr;
+ struct peer *const peer = args->peer;
+ const bgp_size_t length = args->length;
+
+ /*
+ * 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 (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 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 *const peer, struct attr *const attr)
{
/* These checks were part of bgp_attr_aspath, but with
* as4 we should to check aspath things when
@@ -840,10 +1003,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;
+ bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_AS_PATH);
+ return BGP_ATTR_PARSE_ERROR;
}
/* First AS check for EBGP. */
@@ -854,10 +1016,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;
+ bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_AS_PATH);
+ return BGP_ATTR_PARSE_ERROR;
}
}
@@ -867,150 +1028,193 @@ 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;
}
-/* Nexthop attribute. */
+/* Parse AS4 path information. This function is another wrapper of
+ aspath_parse. */
static int
-bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
- struct attr *attr, u_char flag, u_char *startp)
+bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path)
{
- bgp_size_t total;
-
- total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
+ *as4_path = aspath_parse (peer->ibuf, length, 1);
- /* Flag check. */
- if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
- || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
+ /* In case of IBGP, length will be zero. */
+ if (!*as4_path)
{
- zlog (peer->log, LOG_ERR,
- "Origin attribute flag isn't transitive %d", flag);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
- startp, total);
- return -1;
+ zlog (peer->log, LOG_ERR,
+ "Malformed AS4 path from %s, length is %d",
+ peer->host, length);
+ return bgp_attr_malformed (args,
+ BGP_NOTIFY_UPDATE_MAL_AS_PATH,
+ 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 bgp_attr_parse_ret_t
+bgp_attr_nexthop (struct bgp_attr_parser_args *args)
+{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
+ in_addr_t nexthop_h, nexthop_n;
+
/* Check nexthop attribute length. */
if (length != 4)
{
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 (args,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
}
- attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
+ /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
+ attribute must result in a NOTIFICATION message (this is implemented below).
+ At the same time, semantically incorrect NEXT_HOP is more likely to be just
+ logged locally (this is implemented somewhere else). The UPDATE message
+ gets ignored in any of these cases. */
+ nexthop_n = stream_get_ipv4 (peer->ibuf);
+ nexthop_h = ntohl (nexthop_n);
+ if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
+ {
+ char buf[INET_ADDRSTRLEN];
+ inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
+ zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
+ return bgp_attr_malformed (args,
+ BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
+ args->total);
+ }
+
+ attr->nexthop.s_addr = nexthop_n;
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* MED atrribute. */
-static int
-bgp_attr_med (struct peer *peer, bgp_size_t length,
- struct attr *attr, u_char flag, u_char *startp)
+static bgp_attr_parse_ret_t
+bgp_attr_med (struct bgp_attr_parser_args *args)
{
- bgp_size_t total;
-
- total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
-
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
/* Length check. */
if (length != 4)
{
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 (args,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->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
-bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
- struct attr *attr, u_char flag)
+static bgp_attr_parse_ret_t
+bgp_attr_local_pref (struct bgp_attr_parser_args *args)
{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
+ /* Length check. */
+ if (length != 4)
+ {
+ zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]",
+ length);
+ return bgp_attr_malformed (args,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
/* If it is contained in an UPDATE message that is received from an
external peer, then this attribute MUST be ignored by the
receiving speaker. */
if (peer_sort (peer) == BGP_PEER_EBGP)
{
stream_forward_getp (peer->ibuf, length);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
- if (length == 4)
- attr->local_pref = stream_getl (peer->ibuf);
- else
- attr->local_pref = 0;
+ attr->local_pref = stream_getl (peer->ibuf);
/* Set atomic aggregate flag. */
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Atomic aggregate. */
static int
-bgp_attr_atomic (struct peer *peer, bgp_size_t length,
- struct attr *attr, u_char flag)
+bgp_attr_atomic (struct bgp_attr_parser_args *args)
{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
+ /* Length check. */
if (length != 0)
{
- zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
-
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
- return -1;
+ zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
+ length);
+ return bgp_attr_malformed (args,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
}
/* Set atomic aggregate flag. */
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Aggregator attribute */
static int
-bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
- struct attr *attr, u_char flag)
+bgp_attr_aggregator (struct bgp_attr_parser_args *args)
{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
int wantedlen = 6;
struct attr_extra *attre = bgp_attr_extra_get (attr);
/* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
- if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
+ if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
wantedlen = 8;
if (length != wantedlen)
{
- zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
-
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
- return -1;
+ zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]",
+ wantedlen, length);
+ return bgp_attr_malformed (args,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
}
if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
@@ -1022,36 +1226,41 @@ 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
-bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
- struct attr *attr, as_t *as4_aggregator_as,
- struct in_addr *as4_aggregator_addr)
+static bgp_attr_parse_ret_t
+bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args,
+ as_t *as4_aggregator_as,
+ struct in_addr *as4_aggregator_addr)
{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
if (length != 8)
{
- 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;
+ zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]",
+ length);
+ return bgp_attr_malformed (args,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ 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 *const peer,
+ struct attr *const attr,
struct aspath *as4_path, as_t as4_aggregator,
struct in_addr *as4_aggregator_addr)
{
@@ -1059,7 +1268,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.
@@ -1077,34 +1286,15 @@ 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))))
- {
- /* Hu? This is not supposed to happen at all!
- * got as4_path and no aspath,
- * This should already
- * have been handled by 'well known attributes missing'
- * But... yeah, paranoia
- * Take this as a "malformed attribute"
- */
- zlog (peer->log, LOG_ERR,
- "%s BGP not AS4 capable peer sent AS4_PATH but"
- " no AS_PATH, cant do anything here", peer->host);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
- return -1;
- }
-
/* We have a asn16 peer. First, look for AS4_AGGREGATOR
* because that may override AS4_PATH
*/
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);
@@ -1120,7 +1310,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))
@@ -1155,24 +1345,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
-bgp_attr_community (struct peer *peer, bgp_size_t length,
- struct attr *attr, u_char flag)
+static bgp_attr_parse_ret_t
+bgp_attr_community (struct bgp_attr_parser_args *args)
{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
if (length == 0)
{
attr->community = NULL;
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
attr->community =
@@ -1182,26 +1375,31 @@ 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 (args,
+ BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ args->total);
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Originator ID attribute. */
-static int
-bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
- struct attr *attr, u_char flag)
+static bgp_attr_parse_ret_t
+bgp_attr_originator_id (struct bgp_attr_parser_args *args)
{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
+ /* Length check. */
if (length != 4)
{
zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
- return -1;
+ return bgp_attr_malformed (args,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
}
(bgp_attr_extra_get (attr))->originator_id.s_addr
@@ -1209,39 +1407,41 @@ 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
-bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
- struct attr *attr, u_char flag)
+static bgp_attr_parse_ret_t
+bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
/* Check length. */
if (length % 4)
{
zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
- return -1;
+ return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->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. */
int
-bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
- struct bgp_nlri *mp_update)
+bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
+ struct bgp_nlri *mp_update)
{
afi_t afi;
safi_t safi;
@@ -1249,6 +1449,9 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
size_t start;
int ret;
struct stream *s;
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
struct attr_extra *attre = bgp_attr_extra_get(attr);
/* Set end of packet. */
@@ -1262,7 +1465,7 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
{
zlog_info ("%s: %s sent invalid length, %lu",
__func__, peer->host, (unsigned long)length);
- return -1;
+ return BGP_ATTR_PARSE_ERROR;
}
/* Load AFI, SAFI. */
@@ -1276,7 +1479,7 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
{
zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
__func__, peer->host, attre->mp_nexthop_len);
- return -1;
+ return BGP_ATTR_PARSE_ERROR;
}
/* Nexthop length check. */
@@ -1289,14 +1492,9 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
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:
@@ -1324,14 +1522,14 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
default:
zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
__func__, peer->host, attre->mp_nexthop_len);
- return -1;
+ return BGP_ATTR_PARSE_ERROR;
}
if (!LEN_LEFT)
{
zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
__func__, peer->host);
- return -1;
+ return BGP_ATTR_PARSE_ERROR;
}
{
@@ -1347,17 +1545,17 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
{
zlog_info ("%s: (%s) Failed to read NLRI",
__func__, peer->host);
- return -1;
+ return BGP_ATTR_PARSE_ERROR;
}
- if (safi != BGP_SAFI_VPNV4)
+ if (safi != SAFI_MPLS_LABELED_VPN)
{
ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
if (ret < 0)
{
zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
__func__, peer->host);
- return -1;
+ return BGP_ATTR_PARSE_ERROR;
}
}
@@ -1368,13 +1566,13 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
stream_forward_getp (s, nlri_len);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
#undef LEN_LEFT
}
/* Multiprotocol unreachable parse */
int
-bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
+bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
struct bgp_nlri *mp_withdraw)
{
struct stream *s;
@@ -1382,23 +1580,25 @@ bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
safi_t safi;
u_int16_t withdraw_len;
int ret;
+ struct peer *const peer = args->peer;
+ const bgp_size_t length = args->length;
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);
withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
- if (safi != BGP_SAFI_VPNV4)
+ if (safi != SAFI_MPLS_LABELED_VPN)
{
ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
if (ret < 0)
- return -1;
+ return BGP_ATTR_PARSE_ERROR;
}
mp_withdraw->afi = afi;
@@ -1408,20 +1608,23 @@ bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
stream_forward_getp (s, withdraw_len);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Extended Community attribute. */
-static int
-bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
- struct attr *attr, u_char flag)
+static bgp_attr_parse_ret_t
+bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
if (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 =
@@ -1430,21 +1633,29 @@ 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 (args,
+ BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ args->total);
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* BGP unknown attribute treatment. */
-static int
-bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
- u_char type, bgp_size_t length, u_char *startp)
+static bgp_attr_parse_ret_t
+bgp_attr_unknown (struct bgp_attr_parser_args *args)
{
bgp_size_t total;
struct transit *transit;
struct attr_extra *attre;
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ u_char *const startp = args->startp;
+ const u_char type = args->type;
+ const u_char flag = args->flags;
+ const bgp_size_t length = args->length;
+
if (BGP_DEBUG (normal, NORMAL))
zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
@@ -1457,27 +1668,21 @@ bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
/* Forward read pointer of input stream. */
stream_forward_getp (peer->ibuf, length);
- /* Adjest total length to include type and length. */
- total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
-
/* If any of the mandatory well-known attributes are not recognized,
then the Error Subcode is set to Unrecognized Well-known
Attribute. The Data field contains the unrecognized attribute
(type, length and value). */
- if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
+ 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 (args,
+ BGP_NOTIFY_UPDATE_UNREC_ATTR,
+ args->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
@@ -1500,17 +1705,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;
@@ -1527,7 +1732,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)
{
@@ -1536,19 +1741,22 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
{
/* XXX warning: long int format, int arg (arg 5) */
zlog (peer->log, LOG_WARNING,
- "%s error BGP attribute length %lu is smaller than min len",
+ "%s: error BGP attribute length %lu is smaller than min len",
peer->host,
(unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
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. */
startp = BGP_INPUT_PNT (peer);
- flag = stream_getc (BGP_INPUT (peer));
+ /* "The lower-order four bits of the Attribute Flags octet are
+ unused. They MUST be zero when sent and MUST be ignored when
+ received." */
+ flag = 0xF0 & stream_getc (BGP_INPUT (peer));
type = stream_getc (BGP_INPUT (peer));
/* Check whether Extended-Length applies and is in bounds */
@@ -1556,16 +1764,16 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
&& ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
{
zlog (peer->log, LOG_WARNING,
- "%s Extended length set, but just %lu bytes of attr header",
+ "%s: Extended length set, but just %lu bytes of attr header",
peer->host,
(unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
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. */
if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
length = stream_getw (BGP_INPUT (peer));
@@ -1579,13 +1787,13 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
if (CHECK_BITMAP (seen, type))
{
zlog (peer->log, LOG_WARNING,
- "%s error BGP attribute type %d appears twice in a message",
+ "%s: error BGP attribute type %d appears twice in a message",
peer->host, type);
bgp_notify_send (peer,
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
@@ -1599,81 +1807,120 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
if (attr_endp > endp)
{
zlog (peer->log, LOG_WARNING,
- "%s BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p", peer->host, type, length, size, attr_endp, endp);
+ "%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p", peer->host, type, length, size, attr_endp, endp);
bgp_notify_send (peer,
BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
- return -1;
+ return BGP_ATTR_PARSE_ERROR;
}
+
+ struct bgp_attr_parser_args attr_args = {
+ .peer = peer,
+ .length = length,
+ .attr = attr,
+ .type = type,
+ .flags = flag,
+ .startp = startp,
+ .total = attr_endp - startp,
+ };
+
+
+ /* If any recognized attribute has Attribute Flags that conflict
+ with the Attribute Type Code, then the Error Subcode is set to
+ Attribute Flags Error. The Data field contains the erroneous
+ attribute (type, length and value). */
+ if (bgp_attr_flag_invalid (&attr_args))
+ {
+ bgp_attr_parse_ret_t ret;
+ ret = bgp_attr_malformed (&attr_args,
+ BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+ attr_args.total);
+ if (ret == BGP_ATTR_PARSE_PROCEED)
+ continue;
+ return ret;
+ }
/* OK check attribute and store it's value. */
switch (type)
{
case BGP_ATTR_ORIGIN:
- ret = bgp_attr_origin (peer, length, attr, flag, startp);
+ ret = bgp_attr_origin (&attr_args);
break;
case BGP_ATTR_AS_PATH:
- attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0);
- ret = attr->aspath ? 0 : -1 ;
+ ret = bgp_attr_aspath (&attr_args);
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 (&attr_args, &as4_path);
break;
case BGP_ATTR_NEXT_HOP:
- ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
+ ret = bgp_attr_nexthop (&attr_args);
break;
case BGP_ATTR_MULTI_EXIT_DISC:
- ret = bgp_attr_med (peer, length, attr, flag, startp);
+ ret = bgp_attr_med (&attr_args);
break;
case BGP_ATTR_LOCAL_PREF:
- ret = bgp_attr_local_pref (peer, length, attr, flag);
+ ret = bgp_attr_local_pref (&attr_args);
break;
case BGP_ATTR_ATOMIC_AGGREGATE:
- ret = bgp_attr_atomic (peer, length, attr, flag);
+ ret = bgp_attr_atomic (&attr_args);
break;
case BGP_ATTR_AGGREGATOR:
- ret = bgp_attr_aggregator (peer, length, attr, flag);
+ ret = bgp_attr_aggregator (&attr_args);
break;
case BGP_ATTR_AS4_AGGREGATOR:
- ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
+ ret = bgp_attr_as4_aggregator (&attr_args,
+ &as4_aggregator,
+ &as4_aggregator_addr);
break;
case BGP_ATTR_COMMUNITIES:
- ret = bgp_attr_community (peer, length, attr, flag);
+ ret = bgp_attr_community (&attr_args);
break;
case BGP_ATTR_ORIGINATOR_ID:
- ret = bgp_attr_originator_id (peer, length, attr, flag);
+ ret = bgp_attr_originator_id (&attr_args);
break;
case BGP_ATTR_CLUSTER_LIST:
- ret = bgp_attr_cluster_list (peer, length, attr, flag);
+ ret = bgp_attr_cluster_list (&attr_args);
break;
case BGP_ATTR_MP_REACH_NLRI:
- ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
+ ret = bgp_mp_reach_parse (&attr_args, mp_update);
break;
case BGP_ATTR_MP_UNREACH_NLRI:
- ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
+ ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw);
break;
case BGP_ATTR_EXT_COMMUNITIES:
- ret = bgp_attr_ext_communities (peer, length, attr, flag);
+ ret = bgp_attr_ext_communities (&attr_args);
break;
default:
- ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
+ ret = bgp_attr_unknown (&attr_args);
break;
}
-
- /* 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)
{
@@ -1683,7 +1930,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;
}
}
@@ -1691,12 +1940,14 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
if (BGP_INPUT_PNT (peer) != endp)
{
zlog (peer->log, LOG_WARNING,
- "%s BGP attribute %s, length mismatch",
+ "%s: BGP attribute %s, length mismatch",
peer->host, LOOKUP (attr_str, type));
bgp_notify_send (peer,
BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
- return -1;
+ if (as4_path)
+ aspath_unintern (&as4_path);
+ return BGP_ATTR_PARSE_ERROR;
}
/*
@@ -1712,17 +1963,20 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
*/
if (bgp_attr_munge_as4_attrs (peer, attr, 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
*/
@@ -1737,10 +1991,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);
+ if (ret != BGP_ATTR_PARSE_PROCEED)
return ret;
}
@@ -1748,7 +2002,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. */
@@ -1779,9 +2033,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 *);
@@ -2077,7 +2331,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
sizep = stream_get_endp (s);
stream_putc (s, 0); /* Length of this attribute. */
stream_putw (s, AFI_IP); /* AFI */
- stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
+ stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
stream_putc (s, 12);
stream_putl (s, 0);
@@ -2240,7 +2494,7 @@ bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
if (safi == SAFI_MPLS_VPN)
{
/* SAFI */
- stream_putc (s, BGP_SAFI_VPNV4);
+ stream_putc (s, SAFI_MPLS_LABELED_VPN);
/* prefix. */
stream_putc (s, p->prefixlen + 88);
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index af9dcf5e..df87c863 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);
@@ -171,9 +179,19 @@ extern void cluster_unintern (struct cluster_list *);
/* Transit attribute prototypes. */
void transit_unintern (struct transit *);
-/* Exported for unit-test purposes only */
-extern int bgp_mp_reach_parse (struct peer *, bgp_size_t, struct attr *,
+/* Below exported for unit-test purposes only */
+struct bgp_attr_parser_args {
+ struct peer *peer;
+ bgp_size_t length; /* attribute data length; */
+ bgp_size_t total; /* total length, inc header */
+ struct attr *attr;
+ u_int8_t type;
+ u_int8_t flags;
+ u_char *startp;
+};
+extern int bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
struct bgp_nlri *);
-extern int bgp_mp_unreach_parse (struct peer *, bgp_size_t, struct bgp_nlri *);
+extern int bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
+ struct bgp_nlri *);
#endif /* _QUAGGA_BGP_ATTR_H */
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_debug.c b/bgpd/bgp_debug.c
index 26b35dfc..8e161864 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -105,6 +105,7 @@ static const int bgp_notify_head_msg_max = BGP_NOTIFY_HEADER_MAX;
static const struct message bgp_notify_open_msg[] =
{
+ { BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"},
{ BGP_NOTIFY_OPEN_UNSUP_VERSION, "/Unsupported Version Number" },
{ BGP_NOTIFY_OPEN_BAD_PEER_AS, "/Bad Peer AS"},
{ BGP_NOTIFY_OPEN_BAD_BGP_IDENT, "/Bad BGP Identifier"},
@@ -117,6 +118,7 @@ static const int bgp_notify_open_msg_max = BGP_NOTIFY_OPEN_MAX;
static const struct message bgp_notify_update_msg[] =
{
+ { BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"},
{ BGP_NOTIFY_UPDATE_MAL_ATTR, "/Malformed Attribute List"},
{ BGP_NOTIFY_UPDATE_UNREC_ATTR, "/Unrecognized Well-known Attribute"},
{ BGP_NOTIFY_UPDATE_MISS_ATTR, "/Missing Well-known Attribute"},
@@ -133,6 +135,7 @@ static const int bgp_notify_update_msg_max = BGP_NOTIFY_UPDATE_MAX;
static const struct message bgp_notify_cease_msg[] =
{
+ { BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"},
{ BGP_NOTIFY_CEASE_MAX_PREFIX, "/Maximum Number of Prefixes Reached"},
{ BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN, "/Administratively Shutdown"},
{ BGP_NOTIFY_CEASE_PEER_UNCONFIG, "/Peer Unconfigured"},
@@ -146,6 +149,7 @@ static const int bgp_notify_cease_msg_max = BGP_NOTIFY_CEASE_MAX;
static const struct message bgp_notify_capability_msg[] =
{
+ { BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"},
{ BGP_NOTIFY_CAPABILITY_INVALID_ACTION, "/Invalid Action Value" },
{ BGP_NOTIFY_CAPABILITY_INVALID_LENGTH, "/Invalid Capability Length"},
{ BGP_NOTIFY_CAPABILITY_MALFORMED_CODE, "/Malformed Capability Value"},
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 244ffd16..9f4aaa4b 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;
}
}
@@ -619,6 +620,13 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
for (i = 0; i < ecom->size; i++)
{
+ /* Make it sure size is enough. */
+ while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size)
+ {
+ str_size *= 2;
+ str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size);
+ }
+
/* Space between each value. */
if (! first)
str_buf[str_pnt++] = ' ';
@@ -662,13 +670,6 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
break;
}
- /* Make it sure size is enough. */
- while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size)
- {
- str_size *= 2;
- str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size);
- }
-
/* Put string into buffer. */
if (encode == ECOMMUNITY_ENCODE_AS4)
{
diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h
index 1a225270..92affccc 100644
--- a/bgpd/bgp_ecommunity.h
+++ b/bgpd/bgp_ecommunity.h
@@ -67,14 +67,14 @@ 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_uniq_sort (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_fsm.c b/bgpd/bgp_fsm.c
index 487ebddb..813e59ef 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -355,7 +355,7 @@ bgp_graceful_restart_timer_expire (struct thread *thread)
/* NSF delete stale route */
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
- for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
+ for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++)
if (peer->nsf[afi][safi])
bgp_clear_stale_route (peer, afi, safi);
@@ -388,7 +388,7 @@ bgp_graceful_stale_timer_expire (struct thread *thread)
/* NSF delete stale route */
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
- for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
+ for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++)
if (peer->nsf[afi][safi])
bgp_clear_stale_route (peer, afi, safi);
@@ -481,7 +481,7 @@ bgp_stop (struct peer *peer)
UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
- for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
+ for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++)
peer->nsf[afi][safi] = 0;
}
@@ -799,7 +799,7 @@ bgp_establish (struct peer *peer)
/* graceful restart */
UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
- for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
+ for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++)
{
if (peer->afc_nego[afi][safi]
&& CHECK_FLAG (peer->cap, PEER_CAP_RESTART_ADV)
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index e5fa79d6..0f1d4829 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -56,6 +56,7 @@ static const struct option longopts[] =
{ "daemon", no_argument, NULL, 'd'},
{ "config_file", required_argument, NULL, 'f'},
{ "pid_file", required_argument, NULL, 'i'},
+ { "socket", required_argument, NULL, 'z'},
{ "bgp_port", required_argument, NULL, 'p'},
{ "listenon", required_argument, NULL, 'l'},
{ "vty_addr", required_argument, NULL, 'A'},
@@ -121,6 +122,7 @@ static zebra_capabilities_t _caps_p [] =
{
ZCAP_BIND,
ZCAP_NET_RAW,
+ ZCAP_NET_ADMIN,
};
struct zebra_privs_t bgpd_privs =
@@ -151,6 +153,7 @@ redistribution between different routing protocols.\n\n\
-d, --daemon Runs in daemon mode\n\
-f, --config_file Set configuration file name\n\
-i, --pid_file Set process identifier file name\n\
+-z, --socket Set path of zebra socket\n\
-p, --bgp_port Set bgp protocol's port number\n\
-l, --listenon Listen on specified address (implies -n)\n\
-A, --vty_addr Set vty's bind address\n\
@@ -198,6 +201,7 @@ sigint (void)
if (! retain_mode)
bgp_terminate ();
+ zprivs_terminate (&bgpd_privs);
bgp_exit (0);
}
@@ -339,7 +343,7 @@ main (int argc, char **argv)
/* Command line argument treatment. */
while (1)
{
- opt = getopt_long (argc, argv, "df:i:hp:l:A:P:rnu:g:vC", longopts, 0);
+ opt = getopt_long (argc, argv, "df:i:z:hp:l:A:P:rnu:g:vC", longopts, 0);
if (opt == EOF)
break;
@@ -357,6 +361,9 @@ main (int argc, char **argv)
case 'i':
pid_file = optarg;
break;
+ case 'z':
+ zclient_serv_path_set (optarg);
+ break;
case 'p':
tmp_port = atoi (optarg);
if (tmp_port <= 0 || tmp_port > 0xffff)
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 72ad089e..c1f1fbb3 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -233,9 +233,13 @@ str2tag (const char *str, u_char *tag)
char *endptr;
u_int32_t t;
- l = strtoul (str, &endptr, 10);
+ if (*str == '-')
+ return 0;
- if (*endptr == '\0' || l == ULONG_MAX || l > UINT32_MAX)
+ errno = 0;
+ l = strtoul (str, &endptr, 10);
+
+ if (*endptr != '\0' || errno || l > UINT32_MAX)
return 0;
t = (u_int32_t) l;
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 570cc3b7..a7dca531 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -238,46 +238,36 @@ bgp_bind (struct peer *peer)
}
static int
-bgp_bind_address (int sock, struct in_addr *addr)
+bgp_update_address (struct interface *ifp, const union sockunion *dst,
+ union sockunion *addr)
{
- int ret;
- struct sockaddr_in local;
-
- memset (&local, 0, sizeof (struct sockaddr_in));
- local.sin_family = AF_INET;
-#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
- local.sin_len = sizeof(struct sockaddr_in);
-#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
- memcpy (&local.sin_addr, addr, sizeof (struct in_addr));
-
- if ( bgpd_privs.change (ZPRIVS_RAISE) )
- zlog_err ("bgp_bind_address: could not raise privs");
-
- ret = bind (sock, (struct sockaddr *)&local, sizeof (struct sockaddr_in));
- if (ret < 0)
- ;
-
- if (bgpd_privs.change (ZPRIVS_LOWER) )
- zlog_err ("bgp_bind_address: could not lower privs");
-
- return 0;
-}
-
-static struct in_addr *
-bgp_update_address (struct interface *ifp)
-{
- struct prefix_ipv4 *p;
+ struct prefix *p, *sel, *d;
struct connected *connected;
struct listnode *node;
+ int common;
+
+ d = sockunion2hostprefix (dst);
+ sel = NULL;
+ common = -1;
for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
{
- p = (struct prefix_ipv4 *) connected->address;
-
- if (p->family == AF_INET)
- return &p->prefix;
+ p = connected->address;
+ if (p->family != d->family)
+ continue;
+ if (prefix_common_bits (p, d) > common)
+ {
+ sel = p;
+ common = prefix_common_bits (sel, d);
+ }
}
- return NULL;
+
+ prefix_free (d);
+ if (!sel)
+ return 1;
+
+ prefix2sockunion (sel, addr);
+ return 0;
}
/* Update source selection. */
@@ -285,7 +275,7 @@ static void
bgp_update_source (struct peer *peer)
{
struct interface *ifp;
- struct in_addr *addr;
+ union sockunion addr;
/* Source is specified with interface name. */
if (peer->update_if)
@@ -294,11 +284,10 @@ bgp_update_source (struct peer *peer)
if (! ifp)
return;
- addr = bgp_update_address (ifp);
- if (! addr)
+ if (bgp_update_address (ifp, &peer->su, &addr))
return;
- bgp_bind_address (peer->fd, addr);
+ sockunion_bind (peer->fd, &addr, 0, &addr);
}
/* Source is specified with IP address. */
@@ -328,8 +317,16 @@ bgp_connect (struct peer *peer)
sockopt_reuseport (peer->fd);
#ifdef IPTOS_PREC_INTERNETCONTROL
+ if (bgpd_privs.change (ZPRIVS_RAISE))
+ zlog_err ("%s: could not raise privs", __func__);
if (sockunion_family (&peer->su) == AF_INET)
setsockopt_ipv4_tos (peer->fd, IPTOS_PREC_INTERNETCONTROL);
+# ifdef HAVE_IPV6
+ else if (sockunion_family (&peer->su) == AF_INET6)
+ setsockopt_ipv6_tclass (peer->fd, IPTOS_PREC_INTERNETCONTROL);
+# endif
+ if (bgpd_privs.change (ZPRIVS_LOWER))
+ zlog_err ("%s: could not lower privs", __func__);
#endif
if (peer->password)
@@ -386,27 +383,24 @@ bgp_listener (int sock, struct sockaddr *sa, socklen_t salen)
sockopt_reuseaddr (sock);
sockopt_reuseport (sock);
+ if (bgpd_privs.change (ZPRIVS_RAISE))
+ zlog_err ("%s: could not raise privs", __func__);
+
#ifdef IPTOS_PREC_INTERNETCONTROL
if (sa->sa_family == AF_INET)
setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL);
+# ifdef HAVE_IPV6
+ else if (sa->sa_family == AF_INET6)
+ setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL);
+# endif
#endif
-#ifdef IPV6_V6ONLY
- /* Want only IPV6 on ipv6 socket (not mapped addresses) */
- if (sa->sa_family == AF_INET6) {
- int on = 1;
- setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY,
- (void *) &on, sizeof (on));
- }
-#endif
-
- if (bgpd_privs.change (ZPRIVS_RAISE) )
- zlog_err ("bgp_socket: could not raise privs");
+ sockopt_v6only (sa->sa_family, sock);
ret = bind (sock, sa, salen);
en = errno;
- if (bgpd_privs.change (ZPRIVS_LOWER) )
- zlog_err ("bgp_bind_address: could not lower privs");
+ if (bgpd_privs.change (ZPRIVS_LOWER))
+ zlog_err ("%s: could not lower privs", __func__);
if (ret < 0)
{
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index 719cb966..fdf251b2 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -146,7 +146,7 @@ bgp_nexthop_same (struct nexthop *next1, struct nexthop *next2)
}
static int
-bgp_nexthop_cache_changed (struct bgp_nexthop_cache *bnc1,
+bgp_nexthop_cache_different (struct bgp_nexthop_cache *bnc1,
struct bgp_nexthop_cache *bnc2)
{
int i;
@@ -171,14 +171,14 @@ bgp_nexthop_cache_changed (struct bgp_nexthop_cache *bnc1,
/* If nexthop exists on connected network return 1. */
int
-bgp_nexthop_check_ebgp (afi_t afi, struct attr *attr)
+bgp_nexthop_onlink (afi_t afi, struct attr *attr)
{
struct bgp_node *rn;
-
+
/* If zebra is not enabled return */
if (zlookup->sock < 0)
return 1;
-
+
/* Lookup the address is onlink or not. */
if (afi == AFI_IP)
{
@@ -222,7 +222,7 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed,
struct prefix p;
struct bgp_nexthop_cache *bnc;
struct attr *attr;
-
+
/* If lookup is not enabled, return valid. */
if (zlookup->sock < 0)
{
@@ -230,7 +230,7 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed,
ri->extra->igpmetric = 0;
return 1;
}
-
+
/* Only check IPv6 global address only nexthop. */
attr = ri->attr;
@@ -253,15 +253,15 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed,
}
else
{
- bnc = zlookup_query_ipv6 (&attr->extra->mp_nexthop_global);
- if (bnc)
+ if (NULL == (bnc = zlookup_query_ipv6 (&attr->extra->mp_nexthop_global)))
+ bnc = bnc_new ();
+ else
{
- struct bgp_table *old;
- struct bgp_node *oldrn;
- struct bgp_nexthop_cache *oldbnc;
-
if (changed)
{
+ struct bgp_table *old;
+ struct bgp_node *oldrn;
+
if (bgp_nexthop_cache_table[AFI_IP6] == cache1_table[AFI_IP6])
old = cache2_table[AFI_IP6];
else
@@ -270,9 +270,9 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed,
oldrn = bgp_node_lookup (old, &p);
if (oldrn)
{
- oldbnc = oldrn->info;
+ struct bgp_nexthop_cache *oldbnc = oldrn->info;
- bnc->changed = bgp_nexthop_cache_changed (bnc, oldbnc);
+ bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc);
if (bnc->metric != oldbnc->metric)
bnc->metricchanged = 1;
@@ -281,11 +281,6 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed,
}
}
}
- else
- {
- bnc = bnc_new ();
- bnc->valid = 0;
- }
rn->info = bnc;
}
@@ -313,7 +308,7 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri,
struct prefix p;
struct bgp_nexthop_cache *bnc;
struct in_addr addr;
-
+
/* If lookup is not enabled, return valid. */
if (zlookup->sock < 0)
{
@@ -321,7 +316,7 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri,
ri->extra->igpmetric = 0;
return 1;
}
-
+
#ifdef HAVE_IPV6
if (afi == AFI_IP6)
return bgp_nexthop_lookup_ipv6 (peer, ri, changed, metricchanged);
@@ -344,15 +339,15 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri,
}
else
{
- bnc = zlookup_query (addr);
- if (bnc)
+ if (NULL == (bnc = zlookup_query (addr)))
+ bnc = bnc_new ();
+ else
{
- struct bgp_table *old;
- struct bgp_node *oldrn;
- struct bgp_nexthop_cache *oldbnc;
-
if (changed)
{
+ struct bgp_table *old;
+ struct bgp_node *oldrn;
+
if (bgp_nexthop_cache_table[AFI_IP] == cache1_table[AFI_IP])
old = cache2_table[AFI_IP];
else
@@ -361,9 +356,9 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri,
oldrn = bgp_node_lookup (old, &p);
if (oldrn)
{
- oldbnc = oldrn->info;
+ struct bgp_nexthop_cache *oldbnc = oldrn->info;
- bnc->changed = bgp_nexthop_cache_changed (bnc, oldbnc);
+ bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc);
if (bnc->metric != oldbnc->metric)
bnc->metricchanged = 1;
@@ -372,11 +367,6 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri,
}
}
}
- else
- {
- bnc = bnc_new ();
- bnc->valid = 0;
- }
rn->info = bnc;
}
@@ -462,7 +452,7 @@ bgp_scan (afi_t afi, safi_t safi)
metricchanged = 0;
if (peer_sort (bi->peer) == BGP_PEER_EBGP && bi->peer->ttl == 1)
- valid = bgp_nexthop_check_ebgp (afi, bi->attr);
+ valid = bgp_nexthop_onlink (afi, bi->attr);
else
valid = bgp_nexthop_lookup (afi, bi->peer, bi,
&changed, &metricchanged);
@@ -1098,12 +1088,7 @@ zlookup_connect (struct thread *t)
if (zlookup->sock != -1)
return 0;
-#ifdef HAVE_TCP_ZEBRA
- zlookup->sock = zclient_socket ();
-#else
- zlookup->sock = zclient_socket_un (ZEBRA_SERV_PATH);
-#endif /* HAVE_TCP_ZEBRA */
- if (zlookup->sock < 0)
+ if (zclient_socket_connect (zlookup) < 0)
return -1;
return 0;
@@ -1201,16 +1186,13 @@ ALIAS (no_bgp_scan_time,
"Configure background scanner interval\n"
"Scanner interval (seconds)\n")
-DEFUN (show_ip_bgp_scan,
- show_ip_bgp_scan_cmd,
- "show ip bgp scan",
- SHOW_STR
- IP_STR
- BGP_STR
- "BGP scan status\n")
+static int
+show_ip_bgp_scan_tables (struct vty *vty, const char detail)
{
struct bgp_node *rn;
struct bgp_nexthop_cache *bnc;
+ char buf[INET6_ADDRSTRLEN];
+ u_char i;
if (bgp_scan_thread)
vty_out (vty, "BGP scan is running%s", VTY_NEWLINE);
@@ -1223,28 +1205,57 @@ DEFUN (show_ip_bgp_scan,
if ((bnc = rn->info) != NULL)
{
if (bnc->valid)
+ {
vty_out (vty, " %s valid [IGP metric %d]%s",
- inet_ntoa (rn->p.u.prefix4), bnc->metric, VTY_NEWLINE);
+ inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), bnc->metric, VTY_NEWLINE);
+ if (detail)
+ for (i = 0; i < bnc->nexthop_num; i++)
+ switch (bnc->nexthop[i].type)
+ {
+ case NEXTHOP_TYPE_IPV4:
+ vty_out (vty, " gate %s%s", inet_ntop (AF_INET, &bnc->nexthop[i].gate.ipv4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE);
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE);
+ break;
+ default:
+ vty_out (vty, " invalid nexthop type %u%s", bnc->nexthop[i].type, VTY_NEWLINE);
+ }
+ }
else
vty_out (vty, " %s invalid%s",
- inet_ntoa (rn->p.u.prefix4), VTY_NEWLINE);
+ inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE);
}
#ifdef HAVE_IPV6
{
- char buf[BUFSIZ];
for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP6]);
rn;
rn = bgp_route_next (rn))
if ((bnc = rn->info) != NULL)
{
if (bnc->valid)
+ {
vty_out (vty, " %s valid [IGP metric %d]%s",
- inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ),
+ inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN),
bnc->metric, VTY_NEWLINE);
+ if (detail)
+ for (i = 0; i < bnc->nexthop_num; i++)
+ switch (bnc->nexthop[i].type)
+ {
+ case NEXTHOP_TYPE_IPV6:
+ vty_out (vty, " gate %s%s", inet_ntop (AF_INET6, &bnc->nexthop[i].gate.ipv6, buf, INET6_ADDRSTRLEN), VTY_NEWLINE);
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE);
+ break;
+ default:
+ vty_out (vty, " invalid nexthop type %u%s", bnc->nexthop[i].type, VTY_NEWLINE);
+ }
+ }
else
vty_out (vty, " %s invalid%s",
- inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ),
+ inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN),
VTY_NEWLINE);
}
}
@@ -1260,14 +1271,12 @@ DEFUN (show_ip_bgp_scan,
#ifdef HAVE_IPV6
{
- char buf[BUFSIZ];
-
for (rn = bgp_table_top (bgp_connected_table[AFI_IP6]);
rn;
rn = bgp_route_next (rn))
if (rn->info != NULL)
vty_out (vty, " %s/%d%s",
- inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ),
+ inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN),
rn->p.prefixlen,
VTY_NEWLINE);
}
@@ -1276,6 +1285,29 @@ DEFUN (show_ip_bgp_scan,
return CMD_SUCCESS;
}
+DEFUN (show_ip_bgp_scan,
+ show_ip_bgp_scan_cmd,
+ "show ip bgp scan",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "BGP scan status\n")
+{
+ return show_ip_bgp_scan_tables (vty, 0);
+}
+
+DEFUN (show_ip_bgp_scan_detail,
+ show_ip_bgp_scan_detail_cmd,
+ "show ip bgp scan detail",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "BGP scan status\n"
+ "More detailed output\n")
+{
+ return show_ip_bgp_scan_tables (vty, 1);
+}
+
int
bgp_config_write_scan_time (struct vty *vty)
{
@@ -1317,8 +1349,10 @@ bgp_scan_init (void)
install_element (BGP_NODE, &no_bgp_scan_time_cmd);
install_element (BGP_NODE, &no_bgp_scan_time_val_cmd);
install_element (VIEW_NODE, &show_ip_bgp_scan_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_scan_detail_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_scan_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_scan_cmd);
+ install_element (ENABLE_NODE, &show_ip_bgp_scan_detail_cmd);
}
void
diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h
index 2dad742f..874f3bba 100644
--- a/bgpd/bgp_nexthop.h
+++ b/bgpd/bgp_nexthop.h
@@ -54,7 +54,7 @@ extern void bgp_connected_add (struct connected *c);
extern void bgp_connected_delete (struct connected *c);
extern int bgp_multiaccess_check_v4 (struct in_addr, char *);
extern int bgp_config_write_scan_time (struct vty *);
-extern int bgp_nexthop_check_ebgp (afi_t, struct attr *);
+extern int bgp_nexthop_onlink (afi_t, struct attr *);
extern int bgp_nexthop_self (afi_t, struct attr *);
#endif /* _QUAGGA_BGP_NEXTHOP_H */
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 37595817..b5b50bb5 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -93,11 +93,8 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer)
case SAFI_MULTICAST:
vty_out (vty, "SAFI Multicast");
break;
- case SAFI_UNICAST_MULTICAST:
- vty_out (vty, "SAFI Unicast Multicast");
- break;
- case BGP_SAFI_VPNV4:
- vty_out (vty, "SAFI MPLS-VPN");
+ case SAFI_MPLS_LABELED_VPN:
+ vty_out (vty, "SAFI MPLS-labeled VPN");
break;
default:
vty_out (vty, "SAFI Unknown %d ", mpc.safi);
@@ -127,14 +124,6 @@ bgp_capability_mp_data (struct stream *s, struct capability_mp_data *mpc)
int
bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi)
{
- /* VPNvX are AFI specific */
- if ((afi == AFI_IP6 && *safi == BGP_SAFI_VPNV4)
- || (afi == AFI_IP && *safi == BGP_SAFI_VPNV6))
- {
- zlog_warn ("Invalid afi/safi combination (%u/%u)", afi, *safi);
- return 0;
- }
-
switch (afi)
{
case AFI_IP:
@@ -143,9 +132,8 @@ bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi)
#endif
switch (*safi)
{
- /* BGP VPNvX SAFI isn't contigious with others, remap */
- case BGP_SAFI_VPNV4:
- case BGP_SAFI_VPNV6:
+ /* BGP MPLS-labeled VPN SAFI isn't contigious with others, remap */
+ case SAFI_MPLS_LABELED_VPN:
*safi = SAFI_MPLS_VPN;
case SAFI_UNICAST:
case SAFI_MULTICAST:
@@ -392,7 +380,7 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)
peer->v_gr_restart);
}
- while (stream_get_getp (s) + 4 < end)
+ while (stream_get_getp (s) + 4 <= end)
{
afi_t afi = stream_getw (s);
safi_t safi = stream_getc (s);
@@ -433,13 +421,20 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)
static as_t
bgp_capability_as4 (struct peer *peer, struct capability_header *hdr)
{
+ SET_FLAG (peer->cap, PEER_CAP_AS4_RCV);
+
+ if (hdr->length != CAPABILITY_CODE_AS4_LEN)
+ {
+ zlog_err ("%s AS4 capability has incorrect data length %d",
+ peer->host, hdr->length);
+ return 0;
+ }
+
as_t as4 = stream_getl (BGP_INPUT(peer));
if (BGP_DEBUG (as4, AS4))
zlog_debug ("%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u",
peer->host, as4);
- SET_FLAG (peer->cap, PEER_CAP_AS4_RCV);
-
return as4;
}
@@ -701,9 +696,6 @@ peek_for_as4_capability (struct peer *peer, u_char length)
if (hdr.code == CAPABILITY_CODE_AS4)
{
- if (hdr.length != CAPABILITY_CODE_AS4_LEN)
- goto end;
-
if (BGP_DEBUG (as4, AS4))
zlog_info ("[AS4] found AS4 capability, about to parse");
as4 = bgp_capability_as4 (peer, &hdr);
@@ -859,7 +851,7 @@ bgp_open_capability_orf (struct stream *s, struct peer *peer,
int number_of_orfs = 0;
if (safi == SAFI_MPLS_VPN)
- safi = BGP_SAFI_VPNV4;
+ safi = SAFI_MPLS_LABELED_VPN;
stream_putc (s, BGP_OPEN_OPT_CAP);
capp = stream_get_endp (s); /* Set Capability Len Pointer */
@@ -967,7 +959,7 @@ bgp_open_capability (struct stream *s, struct peer *peer)
stream_putc (s, CAPABILITY_CODE_MP_LEN);
stream_putw (s, AFI_IP);
stream_putc (s, 0);
- stream_putc (s, BGP_SAFI_VPNV4);
+ stream_putc (s, SAFI_MPLS_LABELED_VPN);
}
#ifdef HAVE_IPV6
/* IPv6 unicast. */
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index ed2cb73e..5d8087a8 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]++;
@@ -895,14 +895,27 @@ bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code,
if (sub_code != BGP_NOTIFY_CEASE_CONFIG_CHANGE)
{
if (sub_code == BGP_NOTIFY_CEASE_ADMIN_RESET)
- peer->last_reset = PEER_DOWN_USER_RESET;
+ {
+ peer->last_reset = PEER_DOWN_USER_RESET;
+ zlog_info ("Notification sent to neighbor %s: User reset", peer->host);
+ }
else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN)
- peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
+ {
+ peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
+ zlog_info ("Notification sent to neighbor %s: shutdown", peer->host);
+ }
else
- peer->last_reset = PEER_DOWN_NOTIFY_SEND;
+ {
+ peer->last_reset = PEER_DOWN_NOTIFY_SEND;
+ zlog_info ("Notification sent to neighbor %s: type %u/%u",
+ peer->host, code, sub_code);
+ }
}
+ else
+ zlog_info ("Notification sent to neighbor %s: configuration change",
+ peer->host);
- /* Call imidiately. */
+ /* Call immediately. */
BGP_WRITE_OFF (peer->t_write);
bgp_write_notify (peer);
@@ -933,7 +946,7 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi,
/* Adjust safi code. */
if (safi == SAFI_MPLS_VPN)
- safi = BGP_SAFI_VPNV4;
+ safi = SAFI_MPLS_LABELED_VPN;
s = stream_new (BGP_MAX_PACKET_SIZE);
@@ -1023,7 +1036,7 @@ bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi,
/* Adjust safi code. */
if (safi == SAFI_MPLS_VPN)
- safi = BGP_SAFI_VPNV4;
+ safi = SAFI_MPLS_LABELED_VPN;
s = stream_new (BGP_MAX_PACKET_SIZE);
@@ -1368,7 +1381,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
/* remote router-id check. */
if (remote_id.s_addr == 0
- || ntohl (remote_id.s_addr) >= 0xe0000000
+ || IPV4_CLASS_DE (ntohl (remote_id.s_addr))
|| ntohl (peer->local_id.s_addr) == ntohl (remote_id.s_addr))
{
if (BGP_DEBUG (normal, NORMAL))
@@ -1446,9 +1459,13 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
/* Open option part parse. */
if (optlen != 0)
{
- ret = bgp_open_option_parse (peer, optlen, &capability);
- if (ret < 0)
- return ret;
+ if ((ret = bgp_open_option_parse (peer, optlen, &capability)) < 0)
+ {
+ bgp_notify_send (peer,
+ BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_UNACEP_HOLDTIME);
+ return ret;
+ }
}
else
{
@@ -1583,26 +1600,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);
@@ -1611,7 +1649,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;
@@ -1634,15 +1677,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
@@ -1669,7 +1717,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
@@ -1699,7 +1747,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
@@ -1728,7 +1776,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
@@ -1755,17 +1803,17 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
{
if (mp_update.length
&& mp_update.afi == AFI_IP
- && mp_update.safi == BGP_SAFI_VPNV4)
- bgp_nlri_parse_vpnv4 (peer, &attr, &mp_update);
+ && mp_update.safi == SAFI_MPLS_LABELED_VPN)
+ bgp_nlri_parse_vpnv4 (peer, NLRI_ATTR_ARG, &mp_update);
if (mp_withdraw.length
&& mp_withdraw.afi == AFI_IP
- && mp_withdraw.safi == BGP_SAFI_VPNV4)
+ && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN)
bgp_nlri_parse_vpnv4 (peer, NULL, &mp_withdraw);
if (! withdraw_len
&& mp_withdraw.afi == AFI_IP
- && mp_withdraw.safi == BGP_SAFI_VPNV4
+ && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN
&& mp_withdraw.length == 0)
{
/* End-of-RIB received */
@@ -1778,21 +1826,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)
@@ -1936,7 +1973,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
/* Check AFI and SAFI. */
if ((afi != AFI_IP && afi != AFI_IP6)
|| (safi != SAFI_UNICAST && safi != SAFI_MULTICAST
- && safi != BGP_SAFI_VPNV4))
+ && safi != SAFI_MPLS_LABELED_VPN))
{
if (BGP_DEBUG (normal, NORMAL))
{
@@ -1947,7 +1984,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
}
/* Adjust safi code. */
- if (safi == BGP_SAFI_VPNV4)
+ if (safi == SAFI_MPLS_LABELED_VPN)
safi = SAFI_MPLS_VPN;
if (size != BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE)
@@ -2021,7 +2058,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
break;
}
ok = ((p_end - p_pnt) >= sizeof(u_int32_t)) ;
- if (!ok)
+ if (ok)
{
memcpy (&seq, p_pnt, sizeof (u_int32_t));
p_pnt += sizeof (u_int32_t);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index a4923f57..087f8396 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -138,7 +138,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);
bgp_info_mpath_free (&binfo->mpath);
@@ -1092,12 +1092,10 @@ 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;
struct attr *riattr;
from = ri->peer;
filter = &rsclient->filter[afi][safi];
- bgp = rsclient->bgp;
riattr = bgp_info_mpath_count (ri) ? bgp_info_mpath_attr (ri) : ri->attr;
if (DISABLE_BGP_ANNOUNCE)
@@ -1568,7 +1566,7 @@ bgp_process_main (struct work_queue *wq, void *data)
{
if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED) ||
CHECK_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG))
- bgp_zebra_announce (p, old_select, bgp);
+ bgp_zebra_announce (p, old_select, bgp, safi);
UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG);
UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
@@ -1593,20 +1591,20 @@ bgp_process_main (struct work_queue *wq, void *data)
}
/* FIB update. */
- if (safi == SAFI_UNICAST && ! bgp->name &&
- ! bgp_option_check (BGP_OPT_NO_FIB))
+ if ((safi == SAFI_UNICAST || safi == SAFI_MULTICAST) && (! bgp->name &&
+ ! bgp_option_check (BGP_OPT_NO_FIB)))
{
if (new_select
&& new_select->type == ZEBRA_ROUTE_BGP
&& new_select->sub_type == BGP_ROUTE_NORMAL)
- bgp_zebra_announce (p, new_select, bgp);
+ bgp_zebra_announce (p, new_select, bgp, safi);
else
{
/* Withdraw the route from the kernel. */
if (old_select
&& old_select->type == ZEBRA_ROUTE_BGP
&& old_select->sub_type == BGP_ROUTE_NORMAL)
- bgp_zebra_withdraw (p, old_select);
+ bgp_zebra_withdraw (p, old_select, safi);
}
}
@@ -1736,7 +1734,7 @@ bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
u_int8_t ndata[7];
if (safi == SAFI_MPLS_VPN)
- safi = BGP_SAFI_VPNV4;
+ safi = SAFI_MPLS_LABELED_VPN;
ndata[0] = (afi >> 8);
ndata[1] = afi;
@@ -1879,23 +1877,23 @@ 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)
+ if ((afi == AFI_IP) && ((safi == SAFI_UNICAST) || safi == SAFI_MULTICAST))
{
- /* Next hop must not be 0.0.0.0 nor Class E address. */
+ /* Next hop must not be 0.0.0.0 nor Class D/E address. */
if (new_attr.nexthop.s_addr == 0
- || ntohl (new_attr.nexthop.s_addr) >= 0xe0000000)
+ || IPV4_CLASS_DE (ntohl (new_attr.nexthop.s_addr)))
{
- bgp_attr_unintern (attr_new);
+ bgp_attr_unintern (&attr_new);
reason = "martian next-hop;";
goto filtered;
@@ -1925,7 +1923,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;
}
@@ -1945,7 +1943,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. */
@@ -2140,18 +2138,18 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
/* If the peer is EBGP and nexthop is not on connected route,
discard it. */
if (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl == 1
- && ! bgp_nexthop_check_ebgp (afi, &new_attr)
+ && ! bgp_nexthop_onlink (afi, &new_attr)
&& ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
{
reason = "non-connected next-hop;";
goto filtered;
}
- /* Next hop must not be 0.0.0.0 nor Class E address. Next hop
+ /* Next hop must not be 0.0.0.0 nor Class D/E address. Next hop
must not be my own address. */
if (bgp_nexthop_self (afi, &new_attr)
|| new_attr.nexthop.s_addr == 0
- || ntohl (new_attr.nexthop.s_addr) >= 0xe0000000)
+ || IPV4_CLASS_DE (ntohl (new_attr.nexthop.s_addr)))
{
reason = "martian next-hop;";
goto filtered;
@@ -2205,7 +2203,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;
@@ -2252,7 +2250,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. */
@@ -2544,7 +2542,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
@@ -3013,7 +3011,7 @@ bgp_cleanup_routes (void)
if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)
&& ri->type == ZEBRA_ROUTE_BGP
&& ri->sub_type == BGP_ROUTE_NORMAL)
- bgp_zebra_withdraw (&rn->p, ri);
+ bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST);
table = bgp->rib[AFI_IP6][SAFI_UNICAST];
@@ -3022,7 +3020,7 @@ bgp_cleanup_routes (void)
if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)
&& ri->type == ZEBRA_ROUTE_BGP
&& ri->sub_type == BGP_ROUTE_NORMAL)
- bgp_zebra_withdraw (&rn->p, ri);
+ bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST);
}
}
@@ -3292,7 +3290,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);
@@ -3319,8 +3317,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);
@@ -3330,7 +3328,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
bgp->peer_self->rmap_type = 0;
- bgp_attr_unintern (attr_new);
+ bgp_attr_unintern (&attr_new);
attr_new = bgp_attr_intern (&new_attr);
bgp_attr_extra_free (&new_attr);
@@ -3345,8 +3343,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;
}
@@ -3358,14 +3356,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;
}
@@ -3390,7 +3388,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);
}
@@ -3440,7 +3438,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;
@@ -3461,8 +3459,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;
}
@@ -3476,7 +3474,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 ();
@@ -3484,7 +3482,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;
}
@@ -3512,7 +3510,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);
}
@@ -4246,7 +4244,7 @@ DEFUN (ipv6_bgp_network,
"Specify a network to announce via BGP\n"
"IPv6 prefix <network>/<length>\n")
{
- return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST,
+ return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, bgp_node_safi(vty),
NULL, 0);
}
@@ -4269,7 +4267,7 @@ DEFUN (no_ipv6_bgp_network,
"Specify a network to announce via BGP\n"
"IPv6 prefix <network>/<length>\n")
{
- return bgp_static_unset (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST);
+ return bgp_static_unset (vty, vty->index, argv[0], AFI_IP6, bgp_node_safi(vty));
}
ALIAS (no_ipv6_bgp_network,
@@ -5321,7 +5319,8 @@ ALIAS (no_ipv6_aggregate_address_summary_only,
/* Redistribute route treatment. */
void
-bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
+bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop,
+ const struct in6_addr *nexthop6,
u_int32_t metric, u_char type)
{
struct bgp *bgp;
@@ -5341,6 +5340,15 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
if (nexthop)
attr.nexthop = *nexthop;
+#ifdef HAVE_IPV6
+ if (nexthop6)
+ {
+ struct attr_extra *extra = bgp_attr_extra_get(&attr);
+ extra->mp_nexthop_global = *nexthop6;
+ extra->mp_nexthop_len = 16;
+ }
+#endif
+
attr.med = metric;
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
@@ -5376,7 +5384,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
bgp_attr_extra_free (&attr_new);
/* Unintern original. */
- aspath_unintern (attr.aspath);
+ aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
bgp_redistribute_delete (p, type);
return;
@@ -5399,8 +5407,8 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
if (attrhash_cmp (bi->attr, new_attr) &&
!CHECK_FLAG(bi->flags, BGP_INFO_REMOVED))
{
- bgp_attr_unintern (new_attr);
- aspath_unintern (attr.aspath);
+ bgp_attr_unintern (&new_attr);
+ aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
bgp_unlock_node (bn);
return;
@@ -5415,7 +5423,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
bgp_info_restore(bn, bi);
else
bgp_aggregate_decrement (bgp, p, bi, afi, SAFI_UNICAST);
- bgp_attr_unintern (bi->attr);
+ bgp_attr_unintern (&bi->attr);
bi->attr = new_attr;
bi->uptime = bgp_clock ();
@@ -5423,7 +5431,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
bgp_aggregate_increment (bgp, p, bi, afi, SAFI_UNICAST);
bgp_process (bgp, bn, afi, SAFI_UNICAST);
bgp_unlock_node (bn);
- aspath_unintern (attr.aspath);
+ aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
return;
}
@@ -5445,7 +5453,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
}
/* Unintern original. */
- aspath_unintern (attr.aspath);
+ aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
}
@@ -9461,10 +9469,8 @@ bgp_table_stats_vty (struct vty *vty, const char *name,
safi = SAFI_MULTICAST;
else if (strncmp (safi_str, "u", 1) == 0)
safi = SAFI_UNICAST;
- else if (strncmp (safi_str, "vpnv4", 5) == 0)
- safi = BGP_SAFI_VPNV4;
- else if (strncmp (safi_str, "vpnv6", 6) == 0)
- safi = BGP_SAFI_VPNV6;
+ else if (strncmp (safi_str, "vpnv4", 5) == 0 || strncmp (safi_str, "vpnv6", 5) == 0)
+ safi = SAFI_MPLS_LABELED_VPN;
else
{
vty_out (vty, "%% Invalid subsequent address family %s%s",
@@ -9479,13 +9485,6 @@ bgp_table_stats_vty (struct vty *vty, const char *name,
return CMD_WARNING;
}
- if ((afi == AFI_IP && safi == BGP_SAFI_VPNV6)
- || (afi == AFI_IP6 && safi == BGP_SAFI_VPNV4))
- {
- vty_out (vty, "%% Invalid subsequent address family %s for %s%s",
- afi_str, safi_str, VTY_NEWLINE);
- return CMD_WARNING;
- }
return bgp_table_stats (vty, bgp, afi, safi);
}
@@ -12663,6 +12662,9 @@ bgp_route_init (void)
install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd);
install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_summary_only_cmd);
+ install_element (BGP_IPV6M_NODE, &ipv6_bgp_network_cmd);
+ install_element (BGP_IPV6M_NODE, &no_ipv6_bgp_network_cmd);
+
/* Old config IPv6 BGP commands. */
install_element (BGP_NODE, &old_ipv6_bgp_network_cmd);
install_element (BGP_NODE, &old_no_ipv6_bgp_network_cmd);
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 45e8d2e8..3d2eea51 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -198,7 +198,9 @@ extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *);
extern int bgp_maximum_prefix_overflow (struct peer *, afi_t, safi_t, int);
-extern void bgp_redistribute_add (struct prefix *, struct in_addr *, u_int32_t, u_char);
+extern void bgp_redistribute_add (struct prefix *, const struct in_addr *,
+ const struct in6_addr *,
+ u_int32_t, u_char);
extern void bgp_redistribute_delete (struct prefix *, u_char);
extern void bgp_redistribute_withdraw (struct bgp *, afi_t, int);
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 255b25ae..abb85fd2 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -525,8 +525,13 @@ route_match_metric_compile (const char *arg)
char *endptr = NULL;
unsigned long tmpval;
+ /* Metric value shoud be integer. */
+ if (! all_digit (arg))
+ return NULL;
+
+ errno = 0;
tmpval = strtoul (arg, &endptr, 10);
- if (*endptr != '\0' || tmpval == ULONG_MAX || tmpval > UINT32_MAX)
+ if (*endptr != '\0' || errno || tmpval > UINT32_MAX)
return NULL;
med = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
@@ -790,6 +795,75 @@ struct route_map_rule_cmd route_match_origin_cmd =
route_match_origin_compile,
route_match_origin_free
};
+
+/* match probability { */
+
+static route_map_result_t
+route_match_probability (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ long r;
+#if _SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500
+ r = random();
+#else
+ r = (long) rand();
+#endif
+
+ switch (*(unsigned *) rule)
+ {
+ case 0: break;
+ case RAND_MAX: return RMAP_MATCH;
+ default:
+ if (r < *(unsigned *) rule)
+ {
+ return RMAP_MATCH;
+ }
+ }
+
+ return RMAP_NOMATCH;
+}
+
+static void *
+route_match_probability_compile (const char *arg)
+{
+ unsigned *lobule;
+ unsigned perc;
+
+#if _SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500
+ srandom (time (NULL));
+#else
+ srand (time (NULL));
+#endif
+
+ perc = atoi (arg);
+ lobule = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (unsigned));
+
+ switch (perc)
+ {
+ case 0: *lobule = 0; break;
+ case 100: *lobule = RAND_MAX; break;
+ default: *lobule = RAND_MAX / 100 * perc;
+ }
+
+ return lobule;
+}
+
+static void
+route_match_probability_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_probability_cmd =
+{
+ "probability",
+ route_match_probability,
+ route_match_probability_compile,
+ route_match_probability_free
+};
+
+/* } */
+
/* `set ip next-hop IP_ADDRESS' */
/* Set nexthop to object. ojbect must be pointer to struct attr. */
@@ -933,8 +1007,9 @@ route_set_local_pref_compile (const char *arg)
if (! all_digit (arg))
return NULL;
+ errno = 0;
tmp = strtoul (arg, &endptr, 10);
- if (*endptr != '\0' || tmp == ULONG_MAX || tmp > UINT32_MAX)
+ if (*endptr != '\0' || errno || tmp > UINT32_MAX)
return NULL;
local_pref = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
@@ -1001,9 +1076,9 @@ route_set_weight_compile (const char *arg)
if (! all_digit (arg))
return NULL;
-
+ errno = 0;
tmp = strtoul (arg, &endptr, 10);
- if (*endptr != '\0' || tmp == ULONG_MAX || tmp > UINT32_MAX)
+ if (*endptr != '\0' || errno || tmp > UINT32_MAX)
return NULL;
weight = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
@@ -1092,8 +1167,9 @@ route_set_metric_compile (const char *arg)
if (all_digit (arg))
{
/* set metric value check*/
+ errno = 0;
larg = strtoul (arg, &endptr, 10);
- if (*endptr != '\0' || larg == ULONG_MAX || larg > UINT32_MAX)
+ if (*endptr != '\0' || errno || larg > UINT32_MAX)
return NULL;
metric = larg;
}
@@ -1105,8 +1181,9 @@ route_set_metric_compile (const char *arg)
|| (! all_digit (arg+1)))
return NULL;
+ errno = 0;
larg = strtoul (arg+1, &endptr, 10);
- if (*endptr != '\0' || larg == ULONG_MAX || larg > UINT32_MAX)
+ if (*endptr != '\0' || errno || larg > UINT32_MAX)
return NULL;
metric = larg;
}
@@ -1482,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);
}
@@ -1501,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. */
@@ -1509,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. */
@@ -1528,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)
@@ -1539,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;
}
@@ -1555,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. */
@@ -1563,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. */
@@ -2451,6 +2539,38 @@ ALIAS (no_match_ip_next_hop,
"IP access-list number (expanded range)\n"
"IP Access-list name\n")
+/* match probability { */
+
+DEFUN (match_probability,
+ match_probability_cmd,
+ "match probability <0-100>",
+ MATCH_STR
+ "Match portion of routes defined by percentage value\n"
+ "Percentage of routes\n")
+{
+ return bgp_route_match_add (vty, vty->index, "probability", argv[0]);
+}
+
+DEFUN (no_match_probability,
+ no_match_probability_cmd,
+ "no match probability",
+ NO_STR
+ MATCH_STR
+ "Match portion of routes defined by percentage value\n")
+{
+ return bgp_route_match_delete (vty, vty->index, "probability", argc ? argv[0] : NULL);
+}
+
+ALIAS (no_match_probability,
+ no_match_probability_val_cmd,
+ "no match probability <1-99>",
+ NO_STR
+ MATCH_STR
+ "Match portion of routes defined by percentage value\n"
+ "Percentage of routes\n")
+
+/* } */
+
DEFUN (match_ip_route_source,
match_ip_route_source_cmd,
"match ip route-source (<1-199>|<1300-2699>|WORD)",
@@ -3738,6 +3858,7 @@ bgp_route_map_init (void)
route_map_install_match (&route_match_ecommunity_cmd);
route_map_install_match (&route_match_metric_cmd);
route_map_install_match (&route_match_origin_cmd);
+ route_map_install_match (&route_match_probability_cmd);
route_map_install_set (&route_set_ip_nexthop_cmd);
route_map_install_set (&route_set_local_pref_cmd);
@@ -3769,7 +3890,6 @@ bgp_route_map_init (void)
install_element (RMAP_NODE, &match_ip_route_source_cmd);
install_element (RMAP_NODE, &no_match_ip_route_source_cmd);
install_element (RMAP_NODE, &no_match_ip_route_source_val_cmd);
-
install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd);
install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd);
@@ -3797,6 +3917,9 @@ bgp_route_map_init (void)
install_element (RMAP_NODE, &match_origin_cmd);
install_element (RMAP_NODE, &no_match_origin_cmd);
install_element (RMAP_NODE, &no_match_origin_val_cmd);
+ install_element (RMAP_NODE, &match_probability_cmd);
+ install_element (RMAP_NODE, &no_match_probability_cmd);
+ install_element (RMAP_NODE, &no_match_probability_val_cmd);
install_element (RMAP_NODE, &set_ip_nexthop_cmd);
install_element (RMAP_NODE, &set_ip_nexthop_peer_cmd);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 2c44efc2..cbe0b443 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -3851,7 +3851,7 @@ peer_maximum_prefix_set_vty (struct vty *vty, const char *ip_str, afi_t afi,
if (! peer)
return CMD_WARNING;
- VTY_GET_INTEGER ("maxmum number", max, num_str);
+ VTY_GET_INTEGER ("maximum number", max, num_str);
if (threshold_str)
threshold = atoi (threshold_str);
else
@@ -4359,18 +4359,10 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
if (sort == clear_as)
{
as_t as;
- unsigned long as_ul;
int find = 0;
- VTY_GET_LONG ("AS", as_ul, arg);
+ VTY_GET_INTEGER_RANGE ("AS", as, arg, 1, BGP_AS4_MAX);
- if (!as_ul)
- {
- vty_out (vty, "Invalid AS number%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- as = (as_t) as_ul;
-
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
if (peer->as != as)
@@ -8525,57 +8517,16 @@ ALIAS (show_bgp_instance_ipv6_safi_rsclient_summary,
/* Redistribute VTY commands. */
-/* Utility function to convert user input route type string to route
- type. */
-static int
-bgp_str2route_type (int afi, const char *str)
-{
- if (! str)
- return 0;
-
- if (afi == AFI_IP)
- {
- if (strncmp (str, "k", 1) == 0)
- return ZEBRA_ROUTE_KERNEL;
- else if (strncmp (str, "c", 1) == 0)
- return ZEBRA_ROUTE_CONNECT;
- else if (strncmp (str, "s", 1) == 0)
- return ZEBRA_ROUTE_STATIC;
- else if (strncmp (str, "r", 1) == 0)
- return ZEBRA_ROUTE_RIP;
- else if (strncmp (str, "o", 1) == 0)
- return ZEBRA_ROUTE_OSPF;
- }
- if (afi == AFI_IP6)
- {
- if (strncmp (str, "k", 1) == 0)
- return ZEBRA_ROUTE_KERNEL;
- else if (strncmp (str, "c", 1) == 0)
- return ZEBRA_ROUTE_CONNECT;
- else if (strncmp (str, "s", 1) == 0)
- return ZEBRA_ROUTE_STATIC;
- else if (strncmp (str, "r", 1) == 0)
- return ZEBRA_ROUTE_RIPNG;
- else if (strncmp (str, "o", 1) == 0)
- return ZEBRA_ROUTE_OSPF6;
- }
- return 0;
-}
-
DEFUN (bgp_redistribute_ipv4,
bgp_redistribute_ipv4_cmd,
- "redistribute (connected|kernel|ospf|rip|static)",
+ "redistribute " QUAGGA_IP_REDIST_STR_BGPD,
"Redistribute information from another routing protocol\n"
- "Connected\n"
- "Kernel routes\n"
- "Open Shurtest Path First (OSPF)\n"
- "Routing Information Protocol (RIP)\n"
- "Static routes\n")
+ QUAGGA_IP_REDIST_HELP_STR_BGPD)
{
int type;
- type = bgp_str2route_type (AFI_IP, argv[0]);
- if (! type)
+ type = proto_redistnum (AFI_IP, argv[0]);
+ if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -8585,20 +8536,16 @@ DEFUN (bgp_redistribute_ipv4,
DEFUN (bgp_redistribute_ipv4_rmap,
bgp_redistribute_ipv4_rmap_cmd,
- "redistribute (connected|kernel|ospf|rip|static) route-map WORD",
+ "redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD",
"Redistribute information from another routing protocol\n"
- "Connected\n"
- "Kernel routes\n"
- "Open Shurtest Path First (OSPF)\n"
- "Routing Information Protocol (RIP)\n"
- "Static routes\n"
+ QUAGGA_IP_REDIST_HELP_STR_BGPD
"Route map reference\n"
"Pointer to route-map entries\n")
{
int type;
- type = bgp_str2route_type (AFI_IP, argv[0]);
- if (! type)
+ type = proto_redistnum (AFI_IP, argv[0]);
+ if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -8610,21 +8557,17 @@ DEFUN (bgp_redistribute_ipv4_rmap,
DEFUN (bgp_redistribute_ipv4_metric,
bgp_redistribute_ipv4_metric_cmd,
- "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>",
+ "redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295>",
"Redistribute information from another routing protocol\n"
- "Connected\n"
- "Kernel routes\n"
- "Open Shurtest Path First (OSPF)\n"
- "Routing Information Protocol (RIP)\n"
- "Static routes\n"
+ QUAGGA_IP_REDIST_HELP_STR_BGPD
"Metric for redistributed routes\n"
"Default metric\n")
{
int type;
u_int32_t metric;
- type = bgp_str2route_type (AFI_IP, argv[0]);
- if (! type)
+ type = proto_redistnum (AFI_IP, argv[0]);
+ if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -8637,13 +8580,9 @@ DEFUN (bgp_redistribute_ipv4_metric,
DEFUN (bgp_redistribute_ipv4_rmap_metric,
bgp_redistribute_ipv4_rmap_metric_cmd,
- "redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>",
+ "redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>",
"Redistribute information from another routing protocol\n"
- "Connected\n"
- "Kernel routes\n"
- "Open Shurtest Path First (OSPF)\n"
- "Routing Information Protocol (RIP)\n"
- "Static routes\n"
+ QUAGGA_IP_REDIST_HELP_STR_BGPD
"Route map reference\n"
"Pointer to route-map entries\n"
"Metric for redistributed routes\n"
@@ -8652,8 +8591,8 @@ DEFUN (bgp_redistribute_ipv4_rmap_metric,
int type;
u_int32_t metric;
- type = bgp_str2route_type (AFI_IP, argv[0]);
- if (! type)
+ type = proto_redistnum (AFI_IP, argv[0]);
+ if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -8667,13 +8606,9 @@ DEFUN (bgp_redistribute_ipv4_rmap_metric,
DEFUN (bgp_redistribute_ipv4_metric_rmap,
bgp_redistribute_ipv4_metric_rmap_cmd,
- "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD",
+ "redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD",
"Redistribute information from another routing protocol\n"
- "Connected\n"
- "Kernel routes\n"
- "Open Shurtest Path First (OSPF)\n"
- "Routing Information Protocol (RIP)\n"
- "Static routes\n"
+ QUAGGA_IP_REDIST_HELP_STR_BGPD
"Metric for redistributed routes\n"
"Default metric\n"
"Route map reference\n"
@@ -8682,8 +8617,8 @@ DEFUN (bgp_redistribute_ipv4_metric_rmap,
int type;
u_int32_t metric;
- type = bgp_str2route_type (AFI_IP, argv[0]);
- if (! type)
+ type = proto_redistnum (AFI_IP, argv[0]);
+ if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -8697,19 +8632,15 @@ DEFUN (bgp_redistribute_ipv4_metric_rmap,
DEFUN (no_bgp_redistribute_ipv4,
no_bgp_redistribute_ipv4_cmd,
- "no redistribute (connected|kernel|ospf|rip|static)",
+ "no redistribute " QUAGGA_IP_REDIST_STR_BGPD,
NO_STR
"Redistribute information from another routing protocol\n"
- "Connected\n"
- "Kernel routes\n"
- "Open Shurtest Path First (OSPF)\n"
- "Routing Information Protocol (RIP)\n"
- "Static routes\n")
+ QUAGGA_IP_REDIST_HELP_STR_BGPD)
{
int type;
- type = bgp_str2route_type (AFI_IP, argv[0]);
- if (! type)
+ type = proto_redistnum (AFI_IP, argv[0]);
+ if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -8720,21 +8651,17 @@ DEFUN (no_bgp_redistribute_ipv4,
DEFUN (no_bgp_redistribute_ipv4_rmap,
no_bgp_redistribute_ipv4_rmap_cmd,
- "no redistribute (connected|kernel|ospf|rip|static) route-map WORD",
+ "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD",
NO_STR
"Redistribute information from another routing protocol\n"
- "Connected\n"
- "Kernel routes\n"
- "Open Shurtest Path First (OSPF)\n"
- "Routing Information Protocol (RIP)\n"
- "Static routes\n"
+ QUAGGA_IP_REDIST_HELP_STR_BGPD
"Route map reference\n"
"Pointer to route-map entries\n")
{
int type;
- type = bgp_str2route_type (AFI_IP, argv[0]);
- if (! type)
+ type = proto_redistnum (AFI_IP, argv[0]);
+ if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -8746,21 +8673,17 @@ DEFUN (no_bgp_redistribute_ipv4_rmap,
DEFUN (no_bgp_redistribute_ipv4_metric,
no_bgp_redistribute_ipv4_metric_cmd,
- "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>",
+ "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295>",
NO_STR
"Redistribute information from another routing protocol\n"
- "Connected\n"
- "Kernel routes\n"
- "Open Shurtest Path First (OSPF)\n"
- "Routing Information Protocol (RIP)\n"
- "Static routes\n"
+ QUAGGA_IP_REDIST_HELP_STR_BGPD
"Metric for redistributed routes\n"
"Default metric\n")
{
int type;
- type = bgp_str2route_type (AFI_IP, argv[0]);
- if (! type)
+ type = proto_redistnum (AFI_IP, argv[0]);
+ if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -8772,14 +8695,10 @@ DEFUN (no_bgp_redistribute_ipv4_metric,
DEFUN (no_bgp_redistribute_ipv4_rmap_metric,
no_bgp_redistribute_ipv4_rmap_metric_cmd,
- "no redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>",
+ "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>",
NO_STR
"Redistribute information from another routing protocol\n"
- "Connected\n"
- "Kernel routes\n"
- "Open Shurtest Path First (OSPF)\n"
- "Routing Information Protocol (RIP)\n"
- "Static routes\n"
+ QUAGGA_IP_REDIST_HELP_STR_BGPD
"Route map reference\n"
"Pointer to route-map entries\n"
"Metric for redistributed routes\n"
@@ -8787,8 +8706,8 @@ DEFUN (no_bgp_redistribute_ipv4_rmap_metric,
{
int type;
- type = bgp_str2route_type (AFI_IP, argv[0]);
- if (! type)
+ type = proto_redistnum (AFI_IP, argv[0]);
+ if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -8801,14 +8720,10 @@ DEFUN (no_bgp_redistribute_ipv4_rmap_metric,
ALIAS (no_bgp_redistribute_ipv4_rmap_metric,
no_bgp_redistribute_ipv4_metric_rmap_cmd,
- "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD",
+ "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD",
NO_STR
"Redistribute information from another routing protocol\n"
- "Connected\n"
- "Kernel routes\n"
- "Open Shurtest Path First (OSPF)\n"
- "Routing Information Protocol (RIP)\n"
- "Static routes\n"
+ QUAGGA_IP_REDIST_HELP_STR_BGPD
"Metric for redistributed routes\n"
"Default metric\n"
"Route map reference\n"
@@ -8817,18 +8732,14 @@ ALIAS (no_bgp_redistribute_ipv4_rmap_metric,
#ifdef HAVE_IPV6
DEFUN (bgp_redistribute_ipv6,
bgp_redistribute_ipv6_cmd,
- "redistribute (connected|kernel|ospf6|ripng|static)",
+ "redistribute " QUAGGA_IP6_REDIST_STR_BGPD,
"Redistribute information from another routing protocol\n"
- "Connected\n"
- "Kernel routes\n"
- "Open Shurtest Path First (OSPFv3)\n"
- "Routing Information Protocol (RIPng)\n"
- "Static routes\n")
+ QUAGGA_IP6_REDIST_HELP_STR_BGPD)
{
int type;
- type = bgp_str2route_type (AFI_IP6, argv[0]);
- if (! type)
+ type = proto_redistnum (AFI_IP6, argv[0]);
+ if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -8839,20 +8750,16 @@ DEFUN (bgp_redistribute_ipv6,
DEFUN (bgp_redistribute_ipv6_rmap,
bgp_redistribute_ipv6_rmap_cmd,
- "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD",
+ "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD",
"Redistribute information from another routing protocol\n"
- "Connected\n"
- "Kernel routes\n"
- "Open Shurtest Path First (OSPFv3)\n"
- "Routing Information Protocol (RIPng)\n"
- "Static routes\n"
+ QUAGGA_IP6_REDIST_HELP_STR_BGPD
"Route map reference\n"
"Pointer to route-map entries\n")
{
int type;
- type = bgp_str2route_type (AFI_IP6, argv[0]);
- if (! type)
+ type = proto_redistnum (AFI_IP6, argv[0]);
+ if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -8864,21 +8771,17 @@ DEFUN (bgp_redistribute_ipv6_rmap,
DEFUN (bgp_redistribute_ipv6_metric,
bgp_redistribute_ipv6_metric_cmd,
- "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>",
+ "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295>",
"Redistribute information from another routing protocol\n"
- "Connected\n"
- "Kernel routes\n"
- "Open Shurtest Path First (OSPFv3)\n"
- "Routing Information Protocol (RIPng)\n"
- "Static routes\n"
+ QUAGGA_IP6_REDIST_HELP_STR_BGPD
"Metric for redistributed routes\n"
"Default metric\n")
{
int type;
u_int32_t metric;
- type = bgp_str2route_type (AFI_IP6, argv[0]);
- if (! type)
+ type = proto_redistnum (AFI_IP6, argv[0]);
+ if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -8891,13 +8794,9 @@ DEFUN (bgp_redistribute_ipv6_metric,
DEFUN (bgp_redistribute_ipv6_rmap_metric,
bgp_redistribute_ipv6_rmap_metric_cmd,
- "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>",
+ "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>",
"Redistribute information from another routing protocol\n"
- "Connected\n"
- "Kernel routes\n"
- "Open Shurtest Path First (OSPFv3)\n"
- "Routing Information Protocol (RIPng)\n"
- "Static routes\n"
+ QUAGGA_IP6_REDIST_HELP_STR_BGPD
"Route map reference\n"
"Pointer to route-map entries\n"
"Metric for redistributed routes\n"
@@ -8906,8 +8805,8 @@ DEFUN (bgp_redistribute_ipv6_rmap_metric,
int type;
u_int32_t metric;
- type = bgp_str2route_type (AFI_IP6, argv[0]);
- if (! type)
+ type = proto_redistnum (AFI_IP6, argv[0]);
+ if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -8921,13 +8820,9 @@ DEFUN (bgp_redistribute_ipv6_rmap_metric,
DEFUN (bgp_redistribute_ipv6_metric_rmap,
bgp_redistribute_ipv6_metric_rmap_cmd,
- "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD",
+ "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD",
"Redistribute information from another routing protocol\n"
- "Connected\n"
- "Kernel routes\n"
- "Open Shurtest Path First (OSPFv3)\n"
- "Routing Information Protocol (RIPng)\n"
- "Static routes\n"
+ QUAGGA_IP6_REDIST_HELP_STR_BGPD
"Metric for redistributed routes\n"
"Default metric\n"
"Route map reference\n"
@@ -8936,8 +8831,8 @@ DEFUN (bgp_redistribute_ipv6_metric_rmap,
int type;
u_int32_t metric;
- type = bgp_str2route_type (AFI_IP6, argv[0]);
- if (! type)
+ type = proto_redistnum (AFI_IP6, argv[0]);
+ if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -8951,19 +8846,15 @@ DEFUN (bgp_redistribute_ipv6_metric_rmap,
DEFUN (no_bgp_redistribute_ipv6,
no_bgp_redistribute_ipv6_cmd,
- "no redistribute (connected|kernel|ospf6|ripng|static)",
+ "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD,
NO_STR
"Redistribute information from another routing protocol\n"
- "Connected\n"
- "Kernel routes\n"
- "Open Shurtest Path First (OSPFv3)\n"
- "Routing Information Protocol (RIPng)\n"
- "Static routes\n")
+ QUAGGA_IP6_REDIST_HELP_STR_BGPD)
{
int type;
- type = bgp_str2route_type (AFI_IP6, argv[0]);
- if (! type)
+ type = proto_redistnum (AFI_IP6, argv[0]);
+ if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -8974,21 +8865,17 @@ DEFUN (no_bgp_redistribute_ipv6,
DEFUN (no_bgp_redistribute_ipv6_rmap,
no_bgp_redistribute_ipv6_rmap_cmd,
- "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD",
+ "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD",
NO_STR
"Redistribute information from another routing protocol\n"
- "Connected\n"
- "Kernel routes\n"
- "Open Shurtest Path First (OSPFv3)\n"
- "Routing Information Protocol (RIPng)\n"
- "Static routes\n"
+ QUAGGA_IP6_REDIST_HELP_STR_BGPD
"Route map reference\n"
"Pointer to route-map entries\n")
{
int type;
- type = bgp_str2route_type (AFI_IP6, argv[0]);
- if (! type)
+ type = proto_redistnum (AFI_IP6, argv[0]);
+ if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -9000,21 +8887,17 @@ DEFUN (no_bgp_redistribute_ipv6_rmap,
DEFUN (no_bgp_redistribute_ipv6_metric,
no_bgp_redistribute_ipv6_metric_cmd,
- "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>",
+ "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295>",
NO_STR
"Redistribute information from another routing protocol\n"
- "Connected\n"
- "Kernel routes\n"
- "Open Shurtest Path First (OSPFv3)\n"
- "Routing Information Protocol (RIPng)\n"
- "Static routes\n"
+ QUAGGA_IP6_REDIST_HELP_STR_BGPD
"Metric for redistributed routes\n"
"Default metric\n")
{
int type;
- type = bgp_str2route_type (AFI_IP6, argv[0]);
- if (! type)
+ type = proto_redistnum (AFI_IP6, argv[0]);
+ if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -9026,14 +8909,10 @@ DEFUN (no_bgp_redistribute_ipv6_metric,
DEFUN (no_bgp_redistribute_ipv6_rmap_metric,
no_bgp_redistribute_ipv6_rmap_metric_cmd,
- "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>",
+ "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>",
NO_STR
"Redistribute information from another routing protocol\n"
- "Connected\n"
- "Kernel routes\n"
- "Open Shurtest Path First (OSPFv3)\n"
- "Routing Information Protocol (RIPng)\n"
- "Static routes\n"
+ QUAGGA_IP6_REDIST_HELP_STR_BGPD
"Route map reference\n"
"Pointer to route-map entries\n"
"Metric for redistributed routes\n"
@@ -9041,8 +8920,8 @@ DEFUN (no_bgp_redistribute_ipv6_rmap_metric,
{
int type;
- type = bgp_str2route_type (AFI_IP6, argv[0]);
- if (! type)
+ type = proto_redistnum (AFI_IP6, argv[0]);
+ if (type < 0 || type == ZEBRA_ROUTE_BGP)
{
vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -9055,14 +8934,10 @@ DEFUN (no_bgp_redistribute_ipv6_rmap_metric,
ALIAS (no_bgp_redistribute_ipv6_rmap_metric,
no_bgp_redistribute_ipv6_metric_rmap_cmd,
- "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD",
+ "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD",
NO_STR
"Redistribute information from another routing protocol\n"
- "Connected\n"
- "Kernel routes\n"
- "Open Shurtest Path First (OSPFv3)\n"
- "Routing Information Protocol (RIPng)\n"
- "Static routes\n"
+ QUAGGA_IP6_REDIST_HELP_STR_BGPD
"Metric for redistributed routes\n"
"Default metric\n"
"Route map reference\n"
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 6c21230a..5c0dbb88 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -236,12 +236,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. */
@@ -264,7 +262,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);
@@ -285,7 +283,8 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)
inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
api.metric);
}
- bgp_redistribute_add((struct prefix *)&p, &nexthop, api.metric, api.type);
+ bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL,
+ api.metric, api.type);
}
else
{
@@ -313,12 +312,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. */
@@ -341,7 +338,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);
@@ -360,23 +357,29 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length)
{
if (BGP_DEBUG(zebra, ZEBRA))
{
- char buf[INET6_ADDRSTRLEN];
- zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d metric %u",
+ char buf[2][INET6_ADDRSTRLEN];
+ zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d nexthop %s metric %u",
zebra_route_string(api.type),
- inet_ntop(AF_INET6, &p.prefix, buf, sizeof(buf)),
- p.prefixlen, api.metric);
+ inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])),
+ p.prefixlen,
+ inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
+ api.metric);
}
- bgp_redistribute_add ((struct prefix *)&p, NULL, api.metric, api.type);
+ bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop,
+ api.metric, api.type);
}
else
{
if (BGP_DEBUG(zebra, ZEBRA))
{
- char buf[INET6_ADDRSTRLEN];
- zlog_debug("Zebra rcvd: IPv6 route delete %s %s/%d metric %u",
+ char buf[2][INET6_ADDRSTRLEN];
+ zlog_debug("Zebra rcvd: IPv6 route delete %s %s/%d "
+ "nexthop %s metric %u",
zebra_route_string(api.type),
- inet_ntop(AF_INET6, &p.prefix, buf, sizeof(buf)),
- p.prefixlen, api.metric);
+ inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])),
+ p.prefixlen,
+ inet_ntop(AF_INET6, &nexthop, buf[1], sizeof(buf[1])),
+ api.metric);
}
bgp_redistribute_delete ((struct prefix *) &p, api.type);
}
@@ -644,7 +647,7 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote,
}
void
-bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp)
+bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, safi_t safi)
{
int flags;
u_char distance;
@@ -703,6 +706,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp)
api.type = ZEBRA_ROUTE_BGP;
api.message = 0;
+ api.safi = safi;
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = 1 + bgp_info_mpath_count (info);
api.nexthop = (struct in_addr **)STREAM_DATA (bgp_nexthop_buf);
@@ -783,6 +787,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp)
api.flags = flags;
api.type = ZEBRA_ROUTE_BGP;
api.message = 0;
+ api.safi = safi;
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = 1;
api.nexthop = &nexthop;
@@ -809,7 +814,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp)
}
void
-bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info)
+bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
{
int flags;
struct peer *peer;
@@ -843,6 +848,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info)
api.type = ZEBRA_ROUTE_BGP;
api.message = 0;
+ api.safi = safi;
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = 1;
api.nexthop = &nexthop;
@@ -898,6 +904,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info)
api.flags = flags;
api.type = ZEBRA_ROUTE_BGP;
api.message = 0;
+ api.safi = safi;
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = 1;
api.nexthop = &nexthop;
diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h
index 461255e3..80991930 100644
--- a/bgpd/bgp_zebra.h
+++ b/bgpd/bgp_zebra.h
@@ -31,8 +31,8 @@ extern int bgp_config_write_maxpaths (struct vty *, struct bgp *, afi_t,
safi_t, int *);
extern int bgp_config_write_redistribute (struct vty *, struct bgp *, afi_t, safi_t,
int *);
-extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *);
-extern void bgp_zebra_withdraw (struct prefix *, struct bgp_info *);
+extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *, safi_t);
+extern void bgp_zebra_withdraw (struct prefix *, struct bgp_info *, safi_t);
extern int bgp_redistribute_set (struct bgp *, afi_t, int);
extern int bgp_redistribute_rmap_set (struct bgp *, afi_t, int, const char *);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index e86fca34..9c8eda88 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -696,7 +696,7 @@ peer_sort (struct peer *peer)
}
}
-static inline void
+static void
peer_free (struct peer *peer)
{
assert (peer->status == Deleted);
@@ -1148,7 +1148,7 @@ peer_nsf_stop (struct peer *peer)
UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
- for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++)
+ for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++)
peer->nsf[afi][safi] = 0;
if (peer->t_gr_restart)
@@ -2051,6 +2051,10 @@ bgp_get (struct bgp **bgp_val, as_t *as, const char *name)
}
}
+ bgp = bgp_create (as, name);
+ bgp_router_id_set(bgp, &router_id_zebra);
+ *bgp_val = bgp;
+
/* Create BGP server socket, if first instance. */
if (list_isempty(bm->bgp))
{
@@ -2058,10 +2062,7 @@ bgp_get (struct bgp **bgp_val, as_t *as, const char *name)
return BGP_ERR_INVALID_VALUE;
}
- bgp = bgp_create (as, name);
listnode_add (bm->bgp, bgp);
- bgp_router_id_set(bgp, &router_id_zebra);
- *bgp_val = bgp;
return 0;
}
@@ -4723,12 +4724,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;
@@ -5017,6 +5016,11 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
&& ! peer->af_group[afi][safi])
vty_out (vty, " neighbor %s route-server-client%s", addr, VTY_NEWLINE);
+ /* Nexthop-local unchanged. */
+ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED)
+ && ! peer->af_group[afi][safi])
+ vty_out (vty, " neighbor %s nexthop-local unchanged%s", addr, VTY_NEWLINE);
+
/* Allow AS in. */
if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_ALLOWAS_IN))
if (! peer_group_active (peer)
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index bd03f653..09a3435c 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -638,6 +638,8 @@ struct bgp_nlri
#define BGP_NOTIFY_CAPABILITY_ERR 7
#define BGP_NOTIFY_MAX 8
+#define BGP_NOTIFY_SUBCODE_UNSPECIFIC 0
+
/* BGP_NOTIFY_HEADER_ERR sub codes. */
#define BGP_NOTIFY_HEADER_NOT_SYNC 1
#define BGP_NOTIFY_HEADER_BAD_MESLEN 2
@@ -668,7 +670,7 @@ struct bgp_nlri
#define BGP_NOTIFY_UPDATE_MAL_AS_PATH 11
#define BGP_NOTIFY_UPDATE_MAX 12
-/* BGP_NOTIFY_CEASE sub codes (draft-ietf-idr-cease-subcode-05). */
+/* BGP_NOTIFY_CEASE sub codes (RFC 4486). */
#define BGP_NOTIFY_CEASE_MAX_PREFIX 1
#define BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN 2
#define BGP_NOTIFY_CEASE_PEER_UNCONFIG 3
@@ -731,9 +733,8 @@ struct bgp_nlri
#define BGP_DEFAULT_RESTART_TIME 120
#define BGP_DEFAULT_STALEPATH_TIME 360
-/* SAFI which used in open capability negotiation. */
-#define BGP_SAFI_VPNV4 128
-#define BGP_SAFI_VPNV6 129
+/* RFC4364 */
+#define SAFI_MPLS_LABELED_VPN 128
/* Max TTL value. */
#define TTL_MAX 255