summaryrefslogtreecommitdiffstats
path: root/bgpd
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd')
-rw-r--r--bgpd/bgp_advertise.c10
-rw-r--r--bgpd/bgp_aspath.c18
-rw-r--r--bgpd/bgp_aspath.h4
-rw-r--r--bgpd/bgp_attr.c671
-rw-r--r--bgpd/bgp_attr.h23
-rw-r--r--bgpd/bgp_clist.c4
-rw-r--r--bgpd/bgp_common.c2
-rw-r--r--bgpd/bgp_common.h8
-rw-r--r--bgpd/bgp_community.c13
-rw-r--r--bgpd/bgp_community.h2
-rw-r--r--bgpd/bgp_connection.c56
-rw-r--r--bgpd/bgp_connection.h75
-rw-r--r--bgpd/bgp_ecommunity.c33
-rw-r--r--bgpd/bgp_ecommunity.h4
-rw-r--r--bgpd/bgp_fsm.c11
-rw-r--r--bgpd/bgp_msg_read.c4
-rw-r--r--bgpd/bgp_network.c232
-rw-r--r--bgpd/bgp_network.h23
-rw-r--r--bgpd/bgp_nexthop.c3
-rw-r--r--bgpd/bgp_notification.c7
-rw-r--r--bgpd/bgp_packet.c159
-rw-r--r--bgpd/bgp_peer.c24
-rw-r--r--bgpd/bgp_peer.h53
-rw-r--r--bgpd/bgp_route.c160
-rw-r--r--bgpd/bgp_routemap.c27
-rw-r--r--bgpd/bgp_session.c39
-rw-r--r--bgpd/bgp_session.h6
-rw-r--r--bgpd/bgp_vty.c82
-rw-r--r--bgpd/bgp_zebra.c16
-rw-r--r--bgpd/bgpd.c566
-rw-r--r--bgpd/bgpd.h18
31 files changed, 1372 insertions, 981 deletions
diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c
index 495d0fdc..c03546d7 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);
}
@@ -323,7 +323,7 @@ bgp_adj_out_remove (struct bgp_node *rn, struct bgp_adj_out *adj,
assert((rn == adj->rn) && (peer == adj->peer)) ;
if (adj->attr)
- bgp_attr_unintern (adj->attr);
+ bgp_attr_unintern (&adj->attr);
if (adj->adv)
bgp_advertise_clean (peer, adj, afi, safi);
@@ -364,7 +364,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;
@@ -410,7 +410,7 @@ bgp_adj_in_remove (struct bgp_node *rn, struct bgp_adj_in *bai)
assert(rn == bai->rn) ;
/* Done with this copy of attributes */
- bgp_attr_unintern (bai->attr);
+ bgp_attr_unintern (&bai->attr);
/* Unhook from peer */
if (bai->route_next != NULL)
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index 9857501b..dc6ed166 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -341,19 +341,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 (aspath->refcnt)
- aspath->refcnt--;
+ if (asp->refcnt)
+ asp->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;
}
}
@@ -790,7 +792,7 @@ assegments_parse (struct stream *s, size_t length, int use32bit, int as4_path)
* have segments == NULL and str == zero length string (unique).
*/
struct aspath *
-aspath_parse (struct stream *s, size_t length, int use32bit, int as4_path)
+aspath_parse (struct stream *s, size_t length, bool use32bit, bool as4_path)
{
struct aspath as;
struct aspath *find;
@@ -1643,7 +1645,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, true, false); /* 32Bit ;-) not AS4_PATH */
}
struct aspath *
diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h
index c02a84aa..49a3a5be 100644
--- a/bgpd/bgp_aspath.h
+++ b/bgpd/bgp_aspath.h
@@ -67,7 +67,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, bool, bool);
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 *);
@@ -82,7 +82,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 b90fbce8..c5a710c8 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -365,15 +365,9 @@ attrhash_key_make (void *p)
MIX(transit_hash_key_make (attr->extra->transit));
#ifdef HAVE_IPV6
- {
- int i;
-
- MIX(attr->extra->mp_nexthop_len);
- for (i = 0; i < 16; i++)
- key = jhash(&attr->extra->mp_nexthop_global.s6_addr, 16, key);
- for (i = 0; i < 16; i++)
- key = jhash(&attr->extra->mp_nexthop_local.s6_addr, 16, key);
- }
+ MIX(attr->extra->mp_nexthop_len);
+ key = jhash(attr->extra->mp_nexthop_global.s6_addr, 16, key);
+ key = jhash(attr->extra->mp_nexthop_local.s6_addr, 16, key);
#endif /* HAVE_IPV6 */
}
@@ -530,6 +524,7 @@ bgp_attr_intern (struct attr *attr)
attre->ecommunity = ecommunity_intern (attre->ecommunity);
else
attre->ecommunity->refcnt++;
+
}
if (attre->cluster)
{
@@ -593,7 +588,7 @@ bgp_attr_default_intern (u_char origin)
new = bgp_attr_intern (&attr);
bgp_attr_extra_free (&attr);
- aspath_unintern (new->aspath);
+ aspath_unintern (&new->aspath);
return new;
}
@@ -645,10 +640,41 @@ 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 */
+extern void
+bgp_attr_unintern_sub (struct attr *attr, bool free_extra)
+{
+ /* 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);
+
+ if (free_extra)
+ bgp_attr_extra_free (attr) ;
+ }
+}
+
/*------------------------------------------------------------------------------
* Free bgp attribute and aspath.
*
@@ -671,49 +697,36 @@ bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
* reference count SHOULD be zero.
*/
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 ;
+ struct attr_extra tmp_extra ;
- /* Decrement attribute reference. */
- aspath = attr->aspath;
- community = attr->community;
- if (attr->extra)
+ /* Take copy of attributes so that can unintern sub-objects */
+ tmp = *(*attr);
+
+ if ((*attr)->extra)
{
- ecommunity = attr->extra->ecommunity;
- cluster = attr->extra->cluster;
- transit = attr->extra->transit;
+ tmp.extra = &tmp_extra ;
+ 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)
{
- --attr->refcnt ;
- if (attr->refcnt == 0)
+ --(*attr)->refcnt ;
+ if ((*attr)->refcnt == 0)
{
- ret = hash_release (attrhash, attr);
+ struct attr *ret;
+ 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); /* sets *attr = NULL */
} ;
} ;
- /* aspath refcount should be decremented. */
- 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);
+ /* Now the sub-objects */
+ bgp_attr_unintern_sub (&tmp, false) ; /* false => don't free extra */
}
/*------------------------------------------------------------------------------
@@ -733,7 +746,7 @@ bgp_attr_flush (struct attr *attr)
{
struct attr_extra *attre = attr->extra;
if (attre->ecommunity && (attre->ecommunity->refcnt == 0))
- ecommunity_free (attre->ecommunity);
+ ecommunity_free (&attre->ecommunity);
if (attre->cluster && (attre->cluster->refcnt == 0))
cluster_free (attre->cluster);
if (attre->transit && (attre->transit->refcnt == 0))
@@ -741,8 +754,67 @@ bgp_attr_flush (struct attr *attr)
}
}
+/* Implement draft-ietf-idr-optional-transitive behaviour and
+ * avoid resetting sessions for malformed attributes which are
+ * are partial/optional and hence where the error likely was not
+ * introduced by the sending neighbour.
+ */
+static bgp_attr_parse_ret_t
+bgp_attr_malformed (struct peer *peer, u_char attr_type, u_char flag,
+ u_char subcode, u_char *startp, bgp_size_t length)
+{
+ /* Only relax error handling for eBGP peers */
+ if (peer_sort (peer) == BGP_PEER_EBGP)
+ {
+ switch (attr_type)
+ {
+ /* where an optional attribute is inconsequential, e.g. it does not
+ * affect route selection, and can be safely ignored then any such
+ * attributes which are malformed should just be ignored and the
+ * route processed as normal.
+ */
+ case BGP_ATTR_AS4_AGGREGATOR:
+ case BGP_ATTR_AGGREGATOR:
+ case BGP_ATTR_ATOMIC_AGGREGATE:
+ return BGP_ATTR_PARSE_PROCEED;
+
+ /* Core attributes, particularly ones which may influence route
+ * selection should always cause session resets
+ */
+ case BGP_ATTR_ORIGIN:
+ case BGP_ATTR_AS_PATH:
+ case BGP_ATTR_NEXT_HOP:
+ case BGP_ATTR_MULTI_EXIT_DISC:
+ case BGP_ATTR_LOCAL_PREF:
+ case BGP_ATTR_COMMUNITIES:
+ case BGP_ATTR_ORIGINATOR_ID:
+ case BGP_ATTR_CLUSTER_LIST:
+ case BGP_ATTR_MP_REACH_NLRI:
+ case BGP_ATTR_MP_UNREACH_NLRI:
+ case BGP_ATTR_EXT_COMMUNITIES:
+ break ;
+
+ /* 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.
+ */
+ default:
+ if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS) &&
+ CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) &&
+ CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
+ return BGP_ATTR_PARSE_WITHDRAW;
+ break ;
+ } ;
+ } ;
+
+ /* default to reset */
+ bgp_peer_down_error_with_data(peer, BGP_NOTIFY_UPDATE_ERR, subcode,
+ startp, length) ;
+ return BGP_ATTR_PARSE_ERROR;
+} ;
+
/* Get origin attribute of the update message. */
-static int
+static bgp_attr_parse_ret_t
bgp_attr_origin (struct peer *peer, bgp_size_t length,
struct attr *attr, u_char flag, u_char *startp)
{
@@ -760,11 +832,9 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR,
"Origin attribute flag isn't transitive %d", flag);
- bgp_peer_down_error_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
+ return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
startp, total);
- return -1;
}
/* If any recognized attribute has Attribute Length that conflicts
@@ -776,10 +846,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_peer_down_error_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
- startp, total);
- return -1;
+ return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ startp, total);
}
/* Fetch origin attribute. */
@@ -794,64 +863,63 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
attr->origin);
-
- bgp_peer_down_error_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
- startp, total);
- return -1;
+ return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
+ BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
+ startp, total);
}
/* Set oring attribute flag. */
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED ;
}
-/* Parse AS path information. This function is wrapper of aspath_parse.
+/*------------------------------------------------------------------------------
+ * 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
+ * Returns: if valid: BGP_ATTR_PARSE_PROCEED
+ * and sets *p_asp = address of struct aspath in the hash of
+ * known aspaths, with reference count incremented.
+ *
+ * else: whatever bgp_attr_malformed() decides.
*
* 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)
+static bgp_attr_parse_ret_t
+bgp_attr_aspath (struct peer *peer, struct aspath** p_asp, bgp_size_t length,
+ struct attr *attr, u_char flag, u_char *startp,
+ u_char attr_type)
{
u_char require ;
- struct aspath *asp ;
+ bool as4_path = (attr_type == BGP_ATTR_AS4_PATH) ;
/* Check the attribute flags */
- require = as4_path ? BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
- : BGP_ATTR_FLAG_TRANS ;
+ require = as4_path ? BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
+ : 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" ;
+ *p_asp = NULL ;
if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS))
- zlog (peer->log, LOG_ERR,
- "%s attribute flag isn't transitive %d", path_type, flag) ;
+ zlog (peer->log, LOG_ERR, "%s attribute flag isn't transitive 0x%02X",
+ as4_path ? "AS4_PATH" : "AS_PATH", 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) ;
+ zlog (peer->log, LOG_ERR, "%s attribute flag must %sbe optional 0x%02X",
+ as4_path ? "AS4_PATH" : "AS_PATH",
+ (flag & BGP_ATTR_FLAG_OPTIONAL) ? "not " : "", flag) ;
total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
- bgp_peer_down_error_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
- startp, total) ;
-
- return NULL ;
+ return bgp_attr_malformed (peer, attr_type, flag,
+ BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+ startp, total);
} ;
/* Parse the AS_PATH/AS4_PATH body.
@@ -859,28 +927,27 @@ bgp_attr_aspath (struct peer *peer, bgp_size_t length,
* For AS_PATH peer with AS4 => 4Byte ASN otherwise 2Byte ASN
* AS4_PATH 4Byte ASN
*/
- asp = aspath_parse (peer->ibuf, length,
- as4_path || PEER_CAP_AS4_USE(peer), as4_path) ;
-
- if (asp != NULL)
+ *p_asp = aspath_parse (peer->ibuf, length,
+ PEER_CAP_AS4_USE(peer) || as4_path, as4_path) ;
+ if (*p_asp == NULL)
{
- attr->flag |= ATTR_FLAG_BIT (as4_path ? BGP_ATTR_AS4_PATH
- : BGP_ATTR_AS_PATH) ;
- }
- else
- {
- zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
+ zlog (peer->log, LOG_ERR, "Malformed %s from %s, length is %d",
+ as4_path ? "AS4_PATH" : "AS4_PATH", peer->host, length);
- /* TODO: should BGP_NOTIFY_UPDATE_MAL_AS_PATH be sent for AS4_PATH ?? */
- bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_AS_PATH) ;
+ return bgp_attr_malformed (peer, attr_type, flag,
+ BGP_NOTIFY_UPDATE_MAL_AS_PATH,
+ NULL, 0);
} ;
- return asp ;
+ /* Success !
+ */
+ attr->flag |= ATTR_FLAG_BIT (attr_type) ;
+
+ return BGP_ATTR_PARSE_PROCEED;
} ;
-static int bgp_attr_aspath_check( struct peer *peer,
- struct attr *attr)
+static bgp_attr_parse_ret_t
+bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag)
{
/* These checks were part of bgp_attr_aspath, but with
* as4 we should to check aspath things when
@@ -891,30 +958,33 @@ static int bgp_attr_aspath_check( struct peer *peer,
*/
struct bgp *bgp = peer->bgp;
struct aspath *aspath;
+ bgp_peer_sort_t sort = peer_sort(peer) ;
bgp = peer->bgp;
/* Confederation sanity check. */
- if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
- (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
+ if ( ((sort == BGP_PEER_CONFED) && ! aspath_left_confed_check (attr->aspath))
+ || ((sort == BGP_PEER_EBGP) && aspath_confed_check (attr->aspath)) )
{
zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
- bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_AS_PATH);
- return -1;
+
+ return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
+ BGP_NOTIFY_UPDATE_MAL_AS_PATH,
+ NULL, 0);
}
/* First AS check for EBGP. */
if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
{
- if (peer_sort (peer) == BGP_PEER_EBGP
+ if (sort == BGP_PEER_EBGP
&& ! aspath_firstas_check (attr->aspath, peer->as))
{
zlog (peer->log, LOG_ERR,
"%s incorrect first AS (must be %u)", peer->host, peer->as);
- bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_AS_PATH);
- return -1;
+
+ return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
+ BGP_NOTIFY_UPDATE_MAL_AS_PATH,
+ NULL, 0);
}
}
@@ -924,16 +994,15 @@ 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. */
-static int
+static bgp_attr_parse_ret_t
bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
struct attr *attr, u_char flag, u_char *startp)
{
@@ -947,11 +1016,10 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR,
"Origin attribute flag isn't transitive %d", flag);
- bgp_peer_down_error_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
+
+ return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
startp, total);
- return -1;
}
/* Check nexthop attribute length. */
@@ -960,21 +1028,19 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
length);
- bgp_peer_down_error_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
- startp, total);
- return -1;
+ return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ startp, total);
}
attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* MED atrribute. */
-static int
+static bgp_attr_parse_ret_t
bgp_attr_med (struct peer *peer, bgp_size_t length,
struct attr *attr, u_char flag, u_char *startp)
{
@@ -988,22 +1054,20 @@ bgp_attr_med (struct peer *peer, bgp_size_t length,
zlog (peer->log, LOG_ERR,
"MED attribute length isn't four [%d]", length);
- bgp_peer_down_error_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
+ return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
startp, total);
- return -1;
}
attr->med = stream_getl (peer->ibuf);
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Local preference attribute. */
-static int
+static bgp_attr_parse_ret_t
bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
struct attr *attr, u_char flag)
{
@@ -1013,7 +1077,7 @@ bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
if (peer_sort (peer) == BGP_PEER_EBGP)
{
stream_forward_getp (peer->ibuf, length);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
if (length == 4)
@@ -1024,7 +1088,7 @@ bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
/* Set atomic aggregate flag. */
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Atomic aggregate. */
@@ -1036,16 +1100,15 @@ bgp_attr_atomic (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
- bgp_peer_down_error (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
- return -1;
+ return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ NULL, 0);
}
/* Set atomic aggregate flag. */
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Aggregator attribute */
@@ -1065,9 +1128,9 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen,
length);
- bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
- return -1;
+ return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ NULL, 0);
}
if ( PEER_CAP_AS4_USE(peer) )
@@ -1079,35 +1142,35 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
/* Set atomic aggregate flag. */
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* New Aggregator attribute */
-static int
+static bgp_attr_parse_ret_t
bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
- struct attr *attr, as_t *as4_aggregator_as,
+ struct attr *attr, u_char flag,
+ as_t *as4_aggregator_as,
struct in_addr *as4_aggregator_addr)
{
if (length != 8)
{
zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
-
- bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
- return -1;
+ return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ NULL, 0);
}
*as4_aggregator_as = stream_getl (peer->ibuf);
as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
*/
-static int
-bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
+static bgp_attr_parse_ret_t
+bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag,
struct aspath *as4_path, as_t as4_aggregator,
struct in_addr *as4_aggregator_addr)
{
@@ -1133,11 +1196,11 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
peer->host, "AS4 capable peer, yet it sent");
}
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
- if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
- && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
+ if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH))
+ && !(attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))))
{
/* Hu? This is not supposed to happen at all!
* got as4_path and no aspath,
@@ -1149,9 +1212,10 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
zlog (peer->log, LOG_ERR,
"%s BGP not AS4 capable peer sent AS4_PATH but"
" no AS_PATH, cant do anything here", peer->host);
- bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
- return -1;
+
+ return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
+ BGP_NOTIFY_UPDATE_MAL_ATTR,
+ NULL, 0);
}
/* We have a asn16 peer. First, look for AS4_AGGREGATOR
@@ -1159,7 +1223,7 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
*/
if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
{
- if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
+ if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
{
assert (attre);
@@ -1175,7 +1239,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))
@@ -1202,49 +1266,57 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
if ( BGP_DEBUG(as4, AS4))
zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
" AS4_AGGREGATOR but no AGGREGATOR, will take"
- " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
- (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
+ " it as if AGGREGATOR with AS_TRANS had been there",
+ peer->host);
+ attre = bgp_attr_extra_get (attr) ;
+ attre->aggregator_as = as4_aggregator;
/* sweep it under the carpet and simulate a "good" AGGREGATOR */
attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
}
}
/* need to reconcile NEW_AS_PATH and AS_PATH */
- if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
+ if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
{
newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
- aspath_unintern (attr->aspath);
+ aspath_unintern (&attr->aspath);
attr->aspath = aspath_intern (newpath);
}
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Community attribute. */
-static int
+static bgp_attr_parse_ret_t
bgp_attr_community (struct peer *peer, bgp_size_t length,
- struct attr *attr, u_char flag)
+ struct attr *attr, u_char flag, u_char *startp)
{
+ bgp_size_t total
+ = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
+
if (length == 0)
{
attr->community = NULL;
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
attr->community =
- community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
+ community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
+
/* XXX: fix community_parse to use stream API and remove this */
stream_forward_getp (peer->ibuf, length);
if (!attr->community)
- return -1 ;
+ return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag,
+ BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ startp, total);
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Originator ID attribute. */
-static int
+static bgp_attr_parse_ret_t
bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
struct attr *attr, u_char flag)
{
@@ -1252,9 +1324,9 @@ bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
- bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
- return -1;
+ return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ NULL, 0);
}
(bgp_attr_extra_get (attr))->originator_id.s_addr
@@ -1262,11 +1334,11 @@ bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Cluster list attribute. */
-static int
+static bgp_attr_parse_ret_t
bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
struct attr *attr, u_char flag)
{
@@ -1275,23 +1347,24 @@ bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
{
zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
- bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
- return -1;
+ return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ NULL, 0);
}
(bgp_attr_extra_get (attr))->cluster
= cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
- stream_forward_getp (peer->ibuf, length);;
+ /* XXX: Fix cluster_parse to use stream API and then remove this */
+ stream_forward_getp (peer->ibuf, length);
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Multiprotocol reachability information parse. */
-int
+extern bgp_attr_parse_ret_t
bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
struct bgp_nlri *mp_update)
{
@@ -1314,7 +1387,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. */
@@ -1328,7 +1401,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. */
@@ -1363,7 +1436,9 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
char buf2[INET6_ADDRSTRLEN];
if (BGP_DEBUG (update, UPDATE_IN))
- zlog_debug ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host,
+ zlog_debug ("%s got two nexthop %s %s "
+ "but second one is not a link-local nexthop",
+ peer->host,
inet_ntop (AF_INET6, &attre->mp_nexthop_global,
buf1, INET6_ADDRSTRLEN),
inet_ntop (AF_INET6, &attre->mp_nexthop_local,
@@ -1376,14 +1451,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;
}
{
@@ -1399,7 +1474,7 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
{
zlog_info ("%s: (%s) Failed to read NLRI",
__func__, peer->host);
- return -1;
+ return BGP_ATTR_PARSE_ERROR;
}
if (safi != BGP_SAFI_VPNV4)
@@ -1409,7 +1484,7 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
{
zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
__func__, peer->host);
- return -1;
+ return BGP_ATTR_PARSE_ERROR;
}
}
@@ -1420,12 +1495,12 @@ 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
+extern bgp_attr_parse_ret_t
bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
struct bgp_nlri *mp_withdraw)
{
@@ -1439,7 +1514,7 @@ bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
#define BGP_MP_UNREACH_MIN_SIZE 3
if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
- return -1;
+ return BGP_ATTR_PARSE_ERROR;
afi = stream_getw (s);
safi = stream_getc (s);
@@ -1450,7 +1525,7 @@ bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
{
ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
if (ret < 0)
- return -1;
+ return BGP_ATTR_PARSE_ERROR;
}
mp_withdraw->afi = afi;
@@ -1460,38 +1535,43 @@ bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
stream_forward_getp (s, withdraw_len);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Extended Community attribute. */
-static int
+static bgp_attr_parse_ret_t
bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
- struct attr *attr, u_char flag)
+ struct attr *attr, u_char flag, u_char *startp)
{
+ bgp_size_t total
+ = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
+
if (length == 0)
{
if (attr->extra)
attr->extra->ecommunity = NULL;
- /* Empty extcomm doesn't seem to be invalid per se */
- return 0;
+ /* Empty extcomm doesn't seem to be invalid per se */
+ return BGP_ATTR_PARSE_PROCEED;
}
(bgp_attr_extra_get (attr))->ecommunity =
- ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
+ ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
/* XXX: fix ecommunity_parse to use stream API */
stream_forward_getp (peer->ibuf, length);
if (!attr->extra->ecommunity)
- return -1;
+ return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES, flag,
+ BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ startp, total);
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* BGP unknown attribute treatment. */
-static int
+static bgp_attr_parse_ret_t
bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
u_char type, bgp_size_t length, u_char *startp)
{
@@ -1517,20 +1597,17 @@ bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
then the Error Subcode is set to Unrecognized Well-known
Attribute. The Data field contains the unrecognized attribute
(type, length and value). */
- if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
+ if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
{
- /* Adjust startp to do not include flag value. */
- bgp_peer_down_error_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
+ return bgp_attr_malformed (peer, type, flag,
BGP_NOTIFY_UPDATE_UNREC_ATTR,
startp, total);
- return -1;
}
/* 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
@@ -1553,7 +1630,7 @@ 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;
}
/*------------------------------------------------------------------------------
@@ -1575,12 +1652,12 @@ bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
* However, the attr object itself is NOT internalised.
* (So its reference count will be zero.)
*/
-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;
@@ -1611,8 +1688,10 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
(unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
- return -1;
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ if (as4_path != NULL)
+ aspath_unintern (&as4_path);
+ return BGP_ATTR_PARSE_ERROR;
}
/* Fetch attribute flag and type. */
@@ -1630,20 +1709,22 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
(unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
- return -1;
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ if (as4_path != NULL)
+ aspath_unintern (&as4_path);
+ return BGP_ATTR_PARSE_ERROR;
}
- /* Check extended attribue length bit. */
+ /* Check extended attribute length bit. */
if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
length = stream_getw (BGP_INPUT (peer));
else
length = stream_getc (BGP_INPUT (peer));
/* If any attribute appears more than once in the UPDATE
- message, then the Error Subcode is set to Malformed Attribute
- List. */
-
+ * message, then the Error Subcode is set to Malformed Attribute
+ * List.
+ */
if (CHECK_BITMAP (seen, type))
{
zlog (peer->log, LOG_WARNING,
@@ -1651,13 +1732,15 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
peer->host, type);
bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
- return -1;
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
+ if (as4_path != NULL)
+ aspath_unintern (&as4_path);
+ return BGP_ATTR_PARSE_ERROR;
}
/* Set type to bitmap to check duplicate attribute. `type' is
- unsigned char so it never overflow bitmap range. */
-
+ * unsigned char so it never overflow bitmap range.
+ */
SET_BITMAP (seen, type);
/* Overflow check. */
@@ -1666,10 +1749,15 @@ 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_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
- return -1;
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ if (as4_path != NULL)
+ aspath_unintern (&as4_path);
+ return BGP_ATTR_PARSE_ERROR;
}
/* OK check attribute and store it's value. */
@@ -1679,13 +1767,13 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
ret = bgp_attr_origin (peer, length, attr, flag, startp);
break;
case BGP_ATTR_AS_PATH:
- attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0);
- ret = attr->aspath ? 0 : -1 ;
+ ret = bgp_attr_aspath (peer, &attr->aspath, length, attr, flag,
+ startp, BGP_ATTR_AS_PATH);
break;
case BGP_ATTR_AS4_PATH:
- as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1);
- ret = as4_path ? 0 : -1 ;
- break;
+ ret = bgp_attr_aspath (peer, &as4_path, length, attr, flag,
+ startp, BGP_ATTR_AS4_PATH);
+ break;
case BGP_ATTR_NEXT_HOP:
ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
break;
@@ -1702,10 +1790,12 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
ret = bgp_attr_aggregator (peer, length, attr, flag);
break;
case BGP_ATTR_AS4_AGGREGATOR:
- ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
+ ret = bgp_attr_as4_aggregator (peer, length, attr, flag,
+ &as4_aggregator,
+ &as4_aggregator_addr);
break;
case BGP_ATTR_COMMUNITIES:
- ret = bgp_attr_community (peer, length, attr, flag);
+ ret = bgp_attr_community (peer, length, attr, flag, startp);
break;
case BGP_ATTR_ORIGINATOR_ID:
ret = bgp_attr_originator_id (peer, length, attr, flag);
@@ -1720,23 +1810,38 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
break;
case BGP_ATTR_EXT_COMMUNITIES:
- ret = bgp_attr_ext_communities (peer, length, attr, flag);
+ ret = bgp_attr_ext_communities (peer, length, attr, flag, startp);
break;
default:
ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
break;
}
- /* If error occured immediately return to the caller. */
- if (ret < 0)
+ /* If hard error occured immediately return to the caller. */
+ if (ret == BGP_ATTR_PARSE_ERROR)
{
zlog (peer->log, LOG_WARNING,
"%s: Attribute %s, parse error",
peer->host,
LOOKUP (attr_str, type));
+
bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
- return ret;
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
+ if (as4_path != NULL)
+ 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 != NULL)
+ aspath_unintern (&as4_path);
+ return ret;
}
/* Check the fetched length. */
@@ -1755,8 +1860,10 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
} ;
bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
- return -1;
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ if (as4_path != NULL)
+ aspath_unintern (&as4_path);
+ return BGP_ATTR_PARSE_ERROR;
}
}
@@ -1766,9 +1873,12 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
zlog (peer->log, LOG_WARNING,
"%s BGP attribute %s, length mismatch",
peer->host, LOOKUP (attr_str, type));
+
bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
- return -1;
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ if (as4_path != NULL)
+ aspath_unintern (&as4_path);
+ return BGP_ATTR_PARSE_ERROR;
}
/*
@@ -1778,41 +1888,43 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
* the as4 handling does not say whether AS4_PATH has to be sent
* after AS_PATH or not - and when AS4_AGGREGATOR will be send
* in relationship to AGGREGATOR.
+ *
* So, to be defensive, we are not relying on any order and read
* all attributes first, including these 32bit ones, and now,
* afterwards, we look what and if something is to be done for as4.
*/
- if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
- as4_aggregator, &as4_aggregator_addr))
- return -1;
+ ret = bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path,
+ as4_aggregator, &as4_aggregator_addr) ;
/* 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 )
- {
- aspath_unintern( as4_path ); /* unintern - it is in the hash */
- as4_path = NULL;
- /* The flag that we got this is still there, but that does not
- * do any trouble
- */
- }
- /*
+ *
* The "rest" of the code does nothing with as4_aggregator.
* there is no memory attached specifically which is not part
* of the attr.
* so ignoring just means do nothing.
*/
- /*
- * Finally do the checks on the aspath we did not do yet
+ if (as4_path != NULL)
+ {
+ /* The flag that we got this is still there, but that does not
+ * do any trouble
+ */
+ aspath_unintern (&as4_path);
+ as4_path = NULL ;
+ } ;
+
+ if (ret != BGP_ATTR_PARSE_PROCEED)
+ return ret;
+
+ /* Finally do the checks on the aspath we did not do yet
* because we waited for a potentially synthesized aspath.
*/
- if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
+ if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
{
- ret = bgp_attr_aspath_check( peer, attr );
- if ( ret < 0 )
+ ret = bgp_attr_aspath_check (peer, attr, flag);
+ if (ret != BGP_ATTR_PARSE_PROCEED)
return ret;
}
@@ -1820,7 +1932,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. */
@@ -1847,13 +1959,13 @@ bgp_attr_check (struct peer *peer, struct attr *attr)
zlog (peer->log, LOG_WARNING,
"%s Missing well-known attribute %d.",
peer->host, type);
- bgp_peer_down_error_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MISS_ATTR,
- &type, 1);
- return -1;
+
+ bgp_peer_down_error_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MISS_ATTR,
+ &type, 1);
+ return BGP_ATTR_PARSE_ERROR;
}
- return 0;
+ return BGP_ATTR_PARSE_PROCEED;
}
int stream_put_prefix (struct stream *, struct prefix *);
@@ -1871,6 +1983,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
int send_as4_path = 0;
int send_as4_aggregator = 0;
int use32bit = PEER_CAP_AS4_USE(peer) ;
+ bgp_peer_sort_t sort ;
if (! bgp)
bgp = bgp_get_default ();
@@ -1887,7 +2000,9 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
/* AS path attribute. */
/* If remote-peer is EBGP */
- if (peer_sort (peer) == BGP_PEER_EBGP
+ sort = peer_sort(peer) ;
+
+ if (sort == BGP_PEER_EBGP
&& (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
|| attr->aspath->segments == NULL)
&& (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
@@ -1908,7 +2023,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
aspath = aspath_add_seq (aspath, peer->change_local_as);
}
}
- else if (peer_sort (peer) == BGP_PEER_CONFED)
+ else if (sort == BGP_PEER_CONFED)
{
/* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
aspath = aspath_dup (attr->aspath);
@@ -1965,8 +2080,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
}
/* Local preference. */
- if (peer_sort (peer) == BGP_PEER_IBGP ||
- peer_sort (peer) == BGP_PEER_CONFED)
+ if ((sort == BGP_PEER_IBGP) || (sort == BGP_PEER_CONFED))
{
stream_putc (s, BGP_ATTR_FLAG_TRANS);
stream_putc (s, BGP_ATTR_LOCAL_PREF);
@@ -2025,13 +2139,14 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
{
if (attr->community->size * 4 > 255)
{
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
+ | BGP_ATTR_FLAG_EXTLEN);
stream_putc (s, BGP_ATTR_COMMUNITIES);
stream_putw (s, attr->community->size * 4);
}
else
{
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
stream_putc (s, BGP_ATTR_COMMUNITIES);
stream_putc (s, attr->community->size * 4);
}
@@ -2039,9 +2154,8 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
}
/* Route Reflector. */
- if (peer_sort (peer) == BGP_PEER_IBGP
- && from
- && peer_sort (from) == BGP_PEER_IBGP)
+ if ( (sort == BGP_PEER_IBGP) && (from != NULL)
+ && (peer_sort (from) == BGP_PEER_IBGP) )
{
/* Originator ID. */
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
@@ -2177,18 +2291,18 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
assert (attre);
- if (peer_sort (peer) == BGP_PEER_IBGP
- || peer_sort (peer) == BGP_PEER_CONFED)
+ if ((sort == BGP_PEER_IBGP) || (sort == BGP_PEER_CONFED))
{
if (attre->ecommunity->size * 8 > 255)
{
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
+ | BGP_ATTR_FLAG_EXTLEN);
stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
stream_putw (s, attre->ecommunity->size * 8);
}
else
{
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
stream_putc (s, attre->ecommunity->size * 8);
}
@@ -2216,13 +2330,14 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
{
if (ecom_tr_size * 8 > 255)
{
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
+ | BGP_ATTR_FLAG_EXTLEN);
stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
stream_putw (s, ecom_tr_size * 8);
}
else
{
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
stream_putc (s, ecom_tr_size * 8);
}
@@ -2257,7 +2372,8 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
*/
aspath = aspath_delete_confed_seq (aspath);
- stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
+ stream_putc (s, BGP_ATTR_FLAG_TRANS |BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_EXTLEN);
stream_putc (s, BGP_ATTR_AS4_PATH);
aspath_sizep = stream_get_endp (s);
stream_putw (s, 0);
@@ -2434,7 +2550,7 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
{
assert (attr->extra);
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
stream_putc (s, BGP_ATTR_AGGREGATOR);
stream_putc (s, 8);
stream_putl (s, attr->extra->aggregator_as);
@@ -2446,7 +2562,8 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
{
if (attr->community->size * 4 > 255)
{
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
+ | BGP_ATTR_FLAG_EXTLEN);
stream_putc (s, BGP_ATTR_COMMUNITIES);
stream_putw (s, attr->community->size * 4);
}
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 1017a035..8cca316d 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -21,6 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#ifndef _QUAGGA_BGP_ATTR_H
#define _QUAGGA_BGP_ATTR_H
+#include <stdbool.h>
+
#include "bgpd/bgp_common.h"
#include "bgpd/bgpd.h"
@@ -135,17 +137,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 *attr, bool free_extra) ;
+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);
@@ -175,8 +185,9 @@ extern void cluster_unintern (struct cluster_list *);
void transit_unintern (struct transit *);
/* Exported for unit-test purposes only */
-extern int bgp_mp_reach_parse (struct peer *, bgp_size_t, struct attr *,
- struct bgp_nlri *);
-extern int bgp_mp_unreach_parse (struct peer *, bgp_size_t, struct bgp_nlri *);
+extern bgp_attr_parse_ret_t bgp_mp_reach_parse (struct peer *,
+ bgp_size_t, struct attr *, struct bgp_nlri *);
+extern bgp_attr_parse_ret_t bgp_mp_unreach_parse (struct peer *, bgp_size_t,
+ struct bgp_nlri *);
#endif /* _QUAGGA_BGP_ATTR_H */
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index 0df34bb0..ecf1a526 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -87,7 +87,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:
@@ -732,7 +732,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_common.c b/bgpd/bgp_common.c
index c1ac7120..8a3a57ff 100644
--- a/bgpd/bgp_common.c
+++ b/bgpd/bgp_common.c
@@ -110,7 +110,7 @@ const iSAFI_t iSAFI_map[] =
[qafx_num_other] = iSAFI_Reserved,
} ;
-const pAF_t pAF_map[] =
+const sa_family_t sa_family_map[] =
{
[qafx_ipv4_unicast] = AF_INET,
[qafx_ipv4_multicast] = AF_INET,
diff --git a/bgpd/bgp_common.h b/bgpd/bgp_common.h
index fb695125..e115bfd5 100644
--- a/bgpd/bgp_common.h
+++ b/bgpd/bgp_common.h
@@ -329,14 +329,14 @@ get_iSAFI(qafx_num_t num)
* NB: it is a mistake to try to map qafx_num_undef (FATAL unless NDEBUG).
*/
-extern const pAF_t pAF_map[] ;
+extern const sa_family_t sa_family_map[] ;
-Inline pAF_t
-get_pAF(qafx_num_t num)
+Inline sa_family_t
+get_sa_family(qafx_num_t num)
{
dassert((num >= qafx_num_min) && (num <= qafx_num_max)) ;
- return pAF_map[num] ;
+ return sa_family_map[num] ;
} ;
/*==============================================================================
diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c
index 68383adf..9cbf5f4a 100644
--- a/bgpd/bgp_community.c
+++ b/bgpd/bgp_community.c
@@ -328,21 +328,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 78cbfe2b..5643e285 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_connection.c b/bgpd/bgp_connection.c
index cdd37848..24c86230 100644
--- a/bgpd/bgp_connection.c
+++ b/bgpd/bgp_connection.c
@@ -18,6 +18,7 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+#include <zebra.h>
#include "misc.h"
@@ -130,6 +131,7 @@ bgp_connection_init_new(bgp_connection connection, bgp_session session,
* * notification NULL -- none received or sent
* * err no error, so far
* * cap_suppress do not suppress capabilities
+ * * gtsm false -- no minttl set, yet
* * su_local NULL -- no address, yet
* * su_remote NULL -- no address, yet
* * hold_timer_interval none -- set when connection is opened
@@ -156,8 +158,6 @@ bgp_connection_init_new(bgp_connection connection, bgp_session session,
connection->p_mutex = session->mutex ;
connection->lock_count = 0 ; /* no question about it */
- connection->paf = AF_UNSPEC ;
-
connection->ordinal = ordinal ;
connection->accepted = (ordinal == bgp_connection_secondary) ;
@@ -317,7 +317,7 @@ bgp_connection_make_primary(bgp_connection connection)
extern void
bgp_connection_exit(bgp_connection connection)
{
- bgp_connection_close_down(connection) ; /* make sure */
+ bgp_connection_close(connection, false) ; /* false => not keep timers */
assert(connection->state == bgp_fsm_sStopping) ;
@@ -343,7 +343,7 @@ bgp_connection_free(bgp_connection connection)
/* Make sure is closed, so no active file, no timers, pending queue is empty,
* not on the connection queue, etc.
*/
- bgp_connection_close_down(connection) ;
+ bgp_connection_close(connection, false) ; /* false => not keep timers */
/* Free any components which still exist */
connection->qf = qps_file_free(connection->qf) ;
@@ -586,7 +586,7 @@ bgp_connection_add_pending(bgp_connection connection, mqueue_block mqb,
* Sets:
*
* * if secondary connection, turn off accept()
- * * sets the qfile and fd ready for use -- disabled in all modes
+ * * sets the qfile and sock_fd ready for use -- disabled in all modes
* * clears err -- must be OK so far
* * discards any open_state
* * copies hold_timer_interval and keep_alive_timer_interval from session
@@ -609,28 +609,23 @@ bgp_connection_add_pending(bgp_connection connection, mqueue_block mqb,
* NB: requires the session to be LOCKED.
*/
extern void
-bgp_connection_open(bgp_connection connection, int fd, int family)
+bgp_connection_open(bgp_connection connection, int sock_fd)
{
bgp_session session = connection->session ;
- /* Make sure that there is no file and that buffers are clear, etc. */
- /* If this is the secondary connection, do not accept any more. */
- bgp_connection_close(connection) ; /* FSM deals with timers */
+ /* Make sure that there is no file and that buffers are clear, etc.
+ * If this is the secondary connection, do not accept any more.
+ * The FSM deals with the timers.
+ */
+ bgp_connection_close(connection, true) ; /* true => keep timers */
/* Set the file going */
- qps_add_file(bgp_nexus->selection, connection->qf, fd, connection) ;
+ qps_add_file(bgp_nexus->selection, connection->qf, sock_fd, connection) ;
connection->err = 0 ; /* so far, so good */
bgp_open_state_unset(&connection->open_recv) ;
- /* Note the address family for the socket.
- *
- * This is the real family -- so is IPv6 independent of whether one or
- * both addresses are actually mapped IPv4.
- */
- connection->paf = family ;
-
/* Copy the original hold_timer_interval and keepalive_timer_interval
* Assume these have sensible initial values.
*
@@ -758,7 +753,7 @@ bgp_connection_query_accept(bgp_session session)
/*------------------------------------------------------------------------------
* Close connection.
*
- * * if there is an fd, close it
+ * * if there is an sock_fd, close it
* * if qfile is active, remove it
* * forget any addresses
* * reset all stream buffers to empty
@@ -774,7 +769,7 @@ bgp_connection_query_accept(bgp_session session)
*
* * state of the connection
* * links to and from the session
- * * the timers remain initialised (but may have been unset)
+ * * the timers remain initialised -- and remain on or are unset
* * the buffers remain (but reset)
* * logging and host string
* * any open_state that has been received
@@ -792,19 +787,19 @@ bgp_connection_query_accept(bgp_session session)
* NB: requires the session to be LOCKED.
*/
extern void
-bgp_connection_full_close(bgp_connection connection, int unset_timers)
+bgp_connection_close(bgp_connection connection, bool keep_timers)
{
- int fd ;
+ int sock_fd ;
/* Close connection's file, if any. */
qps_remove_file(connection->qf) ;
- fd = qps_file_unset_fd(connection->qf) ;
- if (fd != fd_undef)
- close(fd) ;
+ sock_fd = qps_file_unset_fd(connection->qf) ;
+ if (sock_fd != fd_undef)
+ close(sock_fd) ;
/* If required, unset the timers. */
- if (unset_timers)
+ if (!keep_timers)
{
qtimer_unset(connection->hold_timer) ;
qtimer_unset(connection->keepalive_timer) ;
@@ -830,7 +825,8 @@ bgp_connection_full_close(bgp_connection connection, int unset_timers)
* This is done when the connection is about to be fully closed, but need to
* send a NOTIFICATION message before finally closing.
*
- * * if there is an fd, shutdown(, SHUT_RD) and disable the qfile for reading
+ * * if there is an sock_fd, shutdown(, SHUT_RD) and disable the qfile for
+ * reading
* * reset all read buffering to empty
* * discard all output except any partially written message
* * empty the pending queue
@@ -851,18 +847,18 @@ extern bool
bgp_connection_part_close(bgp_connection connection)
{
bgp_wbuffer wb = &connection->wbuff ;
- int fd ;
+ int sock_fd ;
uint8_t* p ;
bgp_size_t mlen ;
/* Check that have a usable file descriptor */
- fd = qps_file_fd(connection->qf) ;
+ sock_fd = qps_file_fd(connection->qf) ;
- if (fd == fd_undef)
+ if (sock_fd == fd_undef)
return false ;
/* Shutdown the read side of this connection */
- shutdown(fd, SHUT_RD) ;
+ shutdown(sock_fd, SHUT_RD) ;
qps_disable_modes(connection->qf, qps_read_mbit) ;
/* Stop all buffering activity, except for write buffer. */
diff --git a/bgpd/bgp_connection.h b/bgpd/bgp_connection.h
index 8c5e00d4..4df1fbca 100644
--- a/bgpd/bgp_connection.h
+++ b/bgpd/bgp_connection.h
@@ -166,7 +166,7 @@ struct bgp_connection
bgp_open_state open_recv ; /* the open received. */
qps_file qf ; /* qpselect file structure */
- pAF_t paf ; /* address family */
+ bool gtsm ; /* minttl has been set */
union sockunion* su_local ; /* address of the near end */
union sockunion* su_remote ; /* address of the far end */
@@ -206,56 +206,24 @@ struct bgp_connection
* The functions
*/
-extern bgp_connection
-bgp_connection_init_new(bgp_connection connection, bgp_session session,
- bgp_connection_ord_t ordinal) ;
-extern void
-bgp_connection_open(bgp_connection connection, int fd, int family) ;
-
-extern void
-bgp_connection_start(bgp_connection connection, union sockunion* su_local,
- union sockunion* su_remote) ;
-extern void
-bgp_connection_enable_accept(bgp_connection connection) ;
-
-extern void
-bgp_connection_disable_accept(bgp_connection connection) ;
-
-extern bgp_connection
-bgp_connection_query_accept(bgp_session session) ;
-
-extern bgp_connection
-bgp_connection_get_sibling(bgp_connection connection) ;
-
-extern void
-bgp_connection_make_primary(bgp_connection connection) ;
-
-extern void
-bgp_connection_full_close(bgp_connection connection, int unset_timers) ;
-
-#define bgp_connection_close(conn) bgp_connection_full_close(conn, false)
-#define bgp_connection_close_down(conn) bgp_connection_full_close(conn, true)
-
-extern bool
-bgp_connection_part_close(bgp_connection connection) ;
-
-extern void
-bgp_connection_exit(bgp_connection connection) ;
-
-extern void
-bgp_connection_read_enable(bgp_connection connection) ;
-
-extern int
-bgp_connection_write(bgp_connection connection, struct stream* s) ;
-
-extern void
-bgp_connection_queue_add(bgp_connection connection) ;
-
-extern void
-bgp_connection_queue_del(bgp_connection connection) ;
-
-extern int
-bgp_connection_queue_process(void) ;
+extern bgp_connection bgp_connection_init_new(bgp_connection connection,
+ bgp_session session, bgp_connection_ord_t ordinal) ;
+extern void bgp_connection_open(bgp_connection connection, int sock_fd) ;
+extern void bgp_connection_start(bgp_connection connection, sockunion su_local,
+ sockunion su_remote) ;
+extern void bgp_connection_enable_accept(bgp_connection connection) ;
+extern void bgp_connection_disable_accept(bgp_connection connection) ;
+extern bgp_connection bgp_connection_query_accept(bgp_session session) ;
+extern bgp_connection bgp_connection_get_sibling(bgp_connection connection) ;
+extern void bgp_connection_make_primary(bgp_connection connection) ;
+extern void bgp_connection_close(bgp_connection connection, bool keep_timers) ;
+extern bool bgp_connection_part_close(bgp_connection connection) ;
+extern void bgp_connection_exit(bgp_connection connection) ;
+extern void bgp_connection_read_enable(bgp_connection connection) ;
+extern int bgp_connection_write(bgp_connection connection, struct stream* s) ;
+extern void bgp_connection_queue_add(bgp_connection connection) ;
+extern void bgp_connection_queue_del(bgp_connection connection) ;
+extern int bgp_connection_queue_process(void) ;
Inline bool
bgp_connection_no_pending(bgp_connection connection, bgp_connection* is_pending)
@@ -264,9 +232,8 @@ bgp_connection_no_pending(bgp_connection connection, bgp_connection* is_pending)
|| (*is_pending != NULL) ) ;
} ;
-extern void
-bgp_connection_add_pending(bgp_connection connection, mqueue_block mqb,
- bgp_connection* is_pending) ;
+extern void bgp_connection_add_pending(bgp_connection connection,
+ mqueue_block mqb, bgp_connection* is_pending) ;
/*------------------------------------------------------------------------------
* Set buffer *unwritable* (buffer appears full, but nothing pending).
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 605875a9..c107b031 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -42,13 +42,14 @@ ecommunity_new (void)
/* Allocate ecommunities. */
void
-ecommunity_free (struct ecommunity *ecom)
+ecommunity_free (struct ecommunity **ecom)
{
- if (ecom->val)
- XFREE (MTYPE_ECOMMUNITY_VAL, ecom->val);
- if (ecom->str)
- XFREE (MTYPE_ECOMMUNITY_STR, ecom->str);
- XFREE (MTYPE_ECOMMUNITY, ecom);
+ if ((*ecom)->val)
+ XFREE (MTYPE_ECOMMUNITY_VAL, (*ecom)->val);
+ if ((*ecom)->str)
+ XFREE (MTYPE_ECOMMUNITY_STR, (*ecom)->str);
+ XFREE (MTYPE_ECOMMUNITY, *ecom);
+ ecom = NULL;
}
/* Add a new Extended Communities value to Extended Communities
@@ -197,7 +198,7 @@ ecommunity_intern (struct ecommunity *ecom)
find = (struct ecommunity *) hash_get (ecomhash, ecom, hash_alloc_intern);
if (find != ecom)
- ecommunity_free (ecom);
+ ecommunity_free (&ecom);
find->refcnt++;
@@ -209,18 +210,18 @@ ecommunity_intern (struct ecommunity *ecom)
/* Unintern Extended Communities Attribute. */
void
-ecommunity_unintern (struct ecommunity *ecom)
+ecommunity_unintern (struct ecommunity **ecom)
{
struct ecommunity *ret;
- if (ecom->refcnt)
- ecom->refcnt--;
-
+ if ((*ecom)->refcnt)
+ (*ecom)->refcnt--;
+
/* Pull off from hash. */
- if (ecom->refcnt == 0)
+ if ((*ecom)->refcnt == 0)
{
/* Extended community must be in the hash. */
- ret = (struct ecommunity *) hash_release (ecomhash, ecom);
+ ret = (struct ecommunity *) hash_release (ecomhash, *ecom);
assert (ret != NULL);
ecommunity_free (ecom);
@@ -516,7 +517,7 @@ ecommunity_str2com (const char *str, int type, int keyword_included)
if (! keyword_included || keyword)
{
if (ecom)
- ecommunity_free (ecom);
+ ecommunity_free (&ecom);
return NULL;
}
keyword = 1;
@@ -536,7 +537,7 @@ ecommunity_str2com (const char *str, int type, int keyword_included)
if (! keyword)
{
if (ecom)
- ecommunity_free (ecom);
+ ecommunity_free (&ecom);
return NULL;
}
keyword = 0;
@@ -549,7 +550,7 @@ ecommunity_str2com (const char *str, int type, int keyword_included)
case ecommunity_token_unknown:
default:
if (ecom)
- ecommunity_free (ecom);
+ ecommunity_free (&ecom);
return NULL;
}
}
diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h
index 942fdc73..2f59dc40 100644
--- a/bgpd/bgp_ecommunity.h
+++ b/bgpd/bgp_ecommunity.h
@@ -67,13 +67,13 @@ struct ecommunity_val
extern void ecommunity_init (void);
extern void ecommunity_finish (void);
-extern void ecommunity_free (struct ecommunity *);
+extern void ecommunity_free (struct ecommunity **);
extern struct ecommunity *ecommunity_parse (u_int8_t *, u_short);
extern struct ecommunity *ecommunity_dup (struct ecommunity *);
extern struct ecommunity *ecommunity_merge (struct ecommunity *, struct ecommunity *);
extern struct ecommunity *ecommunity_intern (struct ecommunity *);
extern int ecommunity_cmp (const void *, const void *);
-extern void ecommunity_unintern (struct ecommunity *);
+extern void ecommunity_unintern (struct ecommunity **);
extern unsigned int ecommunity_hash_make (void *);
extern struct ecommunity *ecommunity_str2com (const char *, int, int);
extern char *ecommunity_ecom2str (struct ecommunity *, int);
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 3ce8cc19..a03f1b2c 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -1795,7 +1795,8 @@ static bgp_fsm_action(bgp_fsm_fatal)
*/
static bgp_fsm_action(bgp_fsm_retry)
{
- bgp_connection_close(connection) ; /* FSM does timers */
+ bgp_connection_close(connection, true) ; /* true => keep timers, the
+ * FSM handles them. */
bgp_fsm_throw(connection, bgp_session_eRetry, NULL, 0,
bgp_fsm_eBGP_Start) ;
@@ -1830,8 +1831,8 @@ static bgp_fsm_action(bgp_fsm_expire)
/* The process of sending a NOTIFICATION comes to an end here. */
if (connection->notification_pending)
{
- bgp_connection_close(connection) ; /* FSM deals with timers */
-
+ bgp_connection_close(connection, true) ; /* true => keep timers, the
+ * FSM handles them. */
return next_state ;
} ;
@@ -2176,8 +2177,8 @@ bgp_fsm_catch(bgp_connection connection, bgp_fsm_state_t next_state)
}
else
{
- bgp_connection_close(connection) ; /* FSM deals with timers */
-
+ bgp_connection_close(connection, true) ; /* true => keep timers, the
+ * FSM handles them. */
if (next_state == bgp_fsm_sStopping) /* can exit if sStopping */
bgp_fsm_event(connection, bgp_fsm_eBGP_Stop) ;
} ;
diff --git a/bgpd/bgp_msg_read.c b/bgpd/bgp_msg_read.c
index 5eef4d1f..ed49f535 100644
--- a/bgpd/bgp_msg_read.c
+++ b/bgpd/bgp_msg_read.c
@@ -1716,11 +1716,11 @@ bgp_msg_orf_recv(bgp_connection connection, bgp_route_refresh rr,
static int
bgp_msg_orf_prefix_recv(orf_prefix orfpe, qafx_bit_t qb, sucker sr)
{
- pAF_t paf ;
+ sa_family_t paf ;
int left ;
assert(qb != 0) ;
- paf = get_pAF(qafx_num(qb)) ;
+ paf = get_sa_family(qafx_num(qb)) ;
/* Must have the minimum Prefix ORF entry, less the common byte, left */
left = suck_left(sr) - (BGP_ORF_E_P_MIN_L - BGP_ORF_E_COM_L) ;
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 87f4f953..405fc62d 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -49,21 +49,15 @@ extern struct zebra_privs_t bgpd_privs;
*/
/* Forward references. */
-static void
-bgp_connect_action(qps_file qf, void* file_info) ;
-
-static void
-bgp_accept_action(qps_file qf, void* file_info) ;
-
-static int
-bgp_get_names(int sock_fd, union sockunion* su_local,
+static void bgp_connect_action(qps_file qf, void* file_info) ;
+static void bgp_accept_action(qps_file qf, void* file_info) ;
+static int bgp_get_names(int sock_fd, union sockunion* su_local,
union sockunion* su_remote) ;
-
-static int
-bgp_socket_set_common_options(int sock_fd, union sockunion* su, int ttl,
- const char* password) ;
-static int
-bgp_md5_set_listeners(union sockunion* su, const char* password) ;
+static int bgp_socket_set_common_options(int sock_fd, union sockunion* su,
+ bgp_connection connection) ;
+static int bgp_set_ttl(int sock_fd, bgp_connection connnection,
+ int ttl, bool gtsm) ;
+static int bgp_md5_set_listeners(union sockunion* su, const char* password) ;
/*==============================================================================
* Open and close the listeners.
@@ -333,7 +327,7 @@ bgp_open_listener(sockunion su, unsigned short port,
int sock_fd ;
/* Construct socket and set the common options. */
- sock_fd = socket (sockunion_family(su), sock_type, sock_protocol) ;
+ sock_fd = sockunion_socket(su, sock_type, sock_protocol) ;
if (sock_fd < 0)
{
err = errno ;
@@ -342,7 +336,7 @@ bgp_open_listener(sockunion su, unsigned short port,
return errno = err ;
}
- err = bgp_socket_set_common_options(sock_fd, su, 0, NULL) ;
+ err = bgp_socket_set_common_options(sock_fd, su, NULL) ;
/* Want only IPV6 on ipv6 socket (not mapped addresses)
*
@@ -352,18 +346,10 @@ bgp_open_listener(sockunion su, unsigned short port,
* Also, for all the apparent utility of IPv4-mapped addresses, the semantics
* are simpler if IPv6 sockets speak IPv6 and IPv4 sockets speak IPv4.
*/
-#if defined(HAVE_IPV6) && defined(IPV6_V6ONLY)
+#ifdef HAVE_IPV6
if ((err == 0) && (sockunion_family(su) == AF_INET6))
- {
- int on = 1;
- ret = setsockopt (sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
- if (ret < 0)
- {
- err = errno ;
- zlog_err("%s: could not set IPV6_V6ONLY: %s", __func__,
- errtoa(err, 0).str) ;
- }
- } ;
+ if (setsockopt_ipv6_v6only(sock_fd) < 0)
+ err = errno ;
#endif
/* Bind to port and address (if any) */
@@ -575,9 +561,17 @@ bgp_accept_action(qps_file qf, void* file_info)
bool exists ;
int sock_fd ;
int err ;
- int family ;
- /* Accept client connection. */
+ /* Accept client connection.
+ *
+ * We arrange for an IPv4 listener *and* an IPv6 one (assuming have IPv6),
+ * and we arrange for AF_INET6 listener to be IPV6_V6ONLY. This means that
+ * should NOT get an IPv4 mapped address. However, should we get such an
+ * address, the su_remote will be set to the actual IPv4 address.
+ *
+ * This means: the address family of su_remote is the address family of the
+ * underlying connection, NOT NECESSARILY the socket -- should that matter.
+ */
sock_fd = sockunion_accept(qps_file_fd(qf), &su_remote) ;
if (sock_fd < 0)
{
@@ -620,19 +614,11 @@ bgp_accept_action(qps_file qf, void* file_info)
/* Set the common socket options.
* Does not set password -- that is inherited from the listener.
*
- * At this point, su_remote is the value returned by accept(), so is the
- * actual address (which may be IPv6 mapped IPv4).
+ * At this point, su_remote is the value returned by sockunion_accept(), so
+ * if we have an AF_INET6 socket with an IPv4 mapped address, then su_remote
+ * is an AF_INET.
*/
- err = bgp_socket_set_common_options(sock_fd, &su_remote,
- connection->session->ttl, NULL) ;
-
- /* Get the actual socket family. */
- if (err == 0)
- {
- family = sockunion_getsockfamily(sock_fd) ;
- if (family < 0)
- err = errno ;
- } ;
+ err = bgp_socket_set_common_options(sock_fd, &su_remote, connection) ;
/* Get the local and remote addresses -- noting that IPv6 mapped IPv4
* addresses are rendered as IPv4 addresses.
@@ -644,7 +630,7 @@ bgp_accept_action(qps_file qf, void* file_info)
* to go. Set session not to accept further inbound connections.
*/
if (err == 0)
- bgp_connection_open(connection, sock_fd, family) ;
+ bgp_connection_open(connection, sock_fd) ;
else
close(sock_fd) ;
@@ -658,6 +644,7 @@ bgp_accept_action(qps_file qf, void* file_info)
* Open BGP Connection -- connect() to the other end
*/
+static int bgp_md5_set_socket(int sock_fd, sockunion su, const char *password) ;
static int bgp_bind_ifname(bgp_connection connection, int sock_fd) ;
static int bgp_bind_ifaddress(bgp_connection connection, int sock_fd) ;
@@ -676,23 +663,31 @@ static int bgp_bind_ifaddress(bgp_connection connection, int sock_fd) ;
extern void
bgp_open_connect(bgp_connection connection)
{
- int sock_fd ;
- int err ;
- int family ;
- union sockunion* su = connection->session->su_peer ;
+ int sock_fd ;
+ int err ;
+
+ sockunion su = connection->session->su_peer ;
err = 0 ;
/* Make socket for the connect connection. */
- family = sockunion_family(su) ;
- sock_fd = sockunion_socket(family, SOCK_STREAM, 0) ;
+ sock_fd = sockunion_socket(su, SOCK_STREAM, 0) ;
if (sock_fd < 0)
err = errno ;
+ if (BGP_DEBUG(events, EVENTS))
+ plog_debug(connection->log, "%s [Event] Connect start to %s socket %d%s",
+ connection->host, connection->host, sock_fd,
+ (sock_fd < 0) ? " -- failed" : "" ) ;
+
/* Set the common options. */
if (err == 0)
- err = bgp_socket_set_common_options(sock_fd, su, connection->session->ttl,
- connection->session->password) ;
+ err = bgp_socket_set_common_options(sock_fd, su, connection) ;
+
+ /* Set the TCP MD5 "password", if required. */
+ if (err== 0)
+ if (connection->session->password != NULL)
+ err = bgp_md5_set_socket(sock_fd, su, connection->session->password) ;
/* Bind socket. */
if (err == 0)
@@ -702,10 +697,6 @@ bgp_open_connect(bgp_connection connection)
if (err == 0)
err = bgp_bind_ifaddress(connection, sock_fd) ;
- if (BGP_DEBUG(events, EVENTS))
- plog_debug(connection->log, "%s [Event] Connect start to %s socket %d",
- connection->host, connection->host, sock_fd);
-
/* Connect to the remote peer. */
if (err == 0)
{
@@ -742,7 +733,7 @@ bgp_open_connect(bgp_connection connection)
* in any case, this will be handled by the qpselect action.
*/
- bgp_connection_open(connection, sock_fd, family) ;
+ bgp_connection_open(connection, sock_fd) ;
qps_enable_mode(connection->qf, qps_read_mnum, bgp_connect_action) ;
qps_enable_mode(connection->qf, qps_write_mnum, bgp_connect_action) ;
@@ -830,7 +821,7 @@ bgp_connect_action(qps_file qf, void* file_info)
* Set the TTL for the given connection (if any), if there is an sock_fd.
*/
extern void
-bgp_set_ttl(bgp_connection connection, int ttl)
+bgp_set_new_ttl(bgp_connection connection, int ttl, bool gtsm)
{
int sock_fd ;
@@ -841,8 +832,50 @@ bgp_set_ttl(bgp_connection connection, int ttl)
if (sock_fd < 0)
return ;
- if (ttl != 0)
- sockopt_ttl(sock_fd, ttl) ;
+ bgp_set_ttl(sock_fd, connection, ttl, gtsm) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * BGP set minttl (GTSM) and/or ttl.
+ *
+ * A ttl of <= 0 is treated as "turn off" -- effectively MAXTTL, forcing gtsm
+ * *off*.
+ *
+ * If GTSM is not supported, then sets ttl.
+ *
+ * Returns: 0 : OK (so far so good)
+ * != 0 : error number (from errno or otherwise)
+ */
+static int
+bgp_set_ttl(int sock_fd, bgp_connection connection, int ttl, bool gtsm)
+{
+ int ret ;
+
+ if (gtsm && (ttl > 0))
+ {
+ ret = setsockopt_minttl(sock_fd, ttl) ;
+
+ if (ret >= 0)
+ {
+ ttl = MAXTTL ;
+ connection->gtsm = true ;
+ }
+ else if (errno != EOPNOTSUPP)
+ return errno ;
+ }
+ else if (connection->gtsm)
+ {
+ ret = setsockopt_minttl(sock_fd, 0) ; /* turn off */
+
+ if (ret < 0) /* must have turned it on, so should not fail */
+ return errno ;
+
+ connection->gtsm = false ;
+ } ;
+
+ ret = setsockopt_ttl(sock_fd, ttl) ;
+
+ return (ret >= 0) ? 0 : errno ;
} ;
/*==============================================================================
@@ -927,7 +960,9 @@ bgp_bind_ifname(bgp_connection connection, int sock_fd)
} ;
/*------------------------------------------------------------------------------
- * Update source selection.
+ * Update source selection -- if connection specifies an IP address.
+ *
+ * If required, tries to bind the given socket to the given address.
*
* Returns: 0 : OK (so far so good)
* != 0 : error number (from errno or otherwise)
@@ -937,27 +972,11 @@ bgp_bind_ifaddress(bgp_connection connection, int sock_fd)
{
if (connection->session->ifaddress != NULL)
{
- union sockunion su ;
+ union sockunion su[1] ;
int ret ;
- int family ;
- sockunion_new_sockaddr(&su, &connection->session->ifaddress->sa) ;
-
- family = sockunion_getsockfamily(sock_fd) ;
- if (family < 0)
- return errno ;
-
-#ifdef HAVE_IPV6
- if (family != sockunion_family(&su))
- {
- if (family == AF_INET)
- sockunion_unmap_ipv4(&su) ;
- if (family == AF_INET6)
- sockunion_map_ipv4(&su) ;
- } ;
-#endif
-
- ret = sockunion_bind (sock_fd, &su, 0, &su) ;
+ sockunion_new_sockaddr(su, &connection->session->ifaddress->sa) ;
+ ret = sockunion_bind (sock_fd, su, 0, false) ;
if (ret < 0)
return errno ;
@@ -969,29 +988,28 @@ bgp_bind_ifaddress(bgp_connection connection, int sock_fd)
* BGP Socket Option handling
*/
-static int
-bgp_md5_set_socket(int sock_fd, union sockunion *su, const char *password) ;
-
/*------------------------------------------------------------------------------
* Common socket options:
*
* * non-blocking -- at all times
* * reuseaddr
* * reuseport
- * * set TTL if given ttl != 0
- * * set password if given password != NULL
+ * * set security ttl (GTSM) and/or ttl -- if connection given.
* * for IPv4, set TOS if required
*
- * These options are set on all sockets: connect/listen/accept
+ * These options are set on all sockets: listen/connect/accept
+ * (except either form of ttl, which is not set on listen).
+ *
+ * Note that the family of the given sockunion is the *protocol*, not the
+ * *socket* family.
*
* Returns: 0 => OK
* != 0 == errno -- not that we really expect any errors here
*/
static int
-bgp_socket_set_common_options(int sock_fd, union sockunion* su, int ttl,
- const char* password)
+bgp_socket_set_common_options(int sock_fd, union sockunion* su,
+ bgp_connection connection)
{
- int err ;
int val ;
/* Make socket non-blocking */
@@ -1002,23 +1020,27 @@ bgp_socket_set_common_options(int sock_fd, union sockunion* su, int ttl,
return errno ;
/* Reuse addr and port */
- if (sockopt_reuseaddr(sock_fd) < 0)
+ if (setsockopt_reuseaddr(sock_fd) < 0)
return errno ;
- if (sockopt_reuseport(sock_fd) < 0)
+ if (setsockopt_reuseport(sock_fd) < 0)
return errno ;
/* Adjust ttl if required */
- if (ttl != 0)
- if (sockopt_ttl(sock_fd, ttl) != 0)
- return errno ;
-
- /* Set the TCP MD5 "password", if required. */
- if (password != NULL)
- if ((err = bgp_md5_set_socket(sock_fd, su, password)) != 0)
- return err ;
+ if (connection != NULL)
+ {
+ int err ;
+ err = bgp_set_ttl(sock_fd, connection, connection->session->ttl,
+ connection->session->gtsm) ;
+ if (err != 0)
+ return err ;
+ } ;
#ifdef IPTOS_PREC_INTERNETCONTROL
- /* set IPPROTO_IP/IP_TOS -- if is AF_INET */
+ /* set IPPROTO_IP/IP_TOS -- if is AF_INET
+ *
+ * We assume that if the socket is an AF_INET6 with an IPv4 mapped address,
+ * then can still set IP_PROTOCOL/IP_TOS.
+ */
if (sockunion_family(su) == AF_INET)
if (setsockopt_ipv4_tos(sock_fd, IPTOS_PREC_INTERNETCONTROL) < 0)
return errno ;
@@ -1035,13 +1057,13 @@ bgp_socket_set_common_options(int sock_fd, union sockunion* su, int ttl,
* Returns: 0 => OK
* otherwise: errno
*
- * NB: if MD5 is not supported, returns ENOSYS error (but it should not come
- * to this !).
+ * NB: if MD5 is not supported, returns EOPNOTSUPP error (but it should not
+ * come to this !).
*
* NB: has to change up privileges, which can fail (if things are badly set up)
*/
static int
-bgp_md5_set_socket(int sock_fd, union sockunion *su, const char *password)
+bgp_md5_set_socket(int sock_fd, sockunion su, const char *password)
{
int err, ret ;
@@ -1055,9 +1077,9 @@ bgp_md5_set_socket(int sock_fd, union sockunion *su, const char *password)
zlog_err("%s: could not raise privs: %s", __func__, errtoa(errno, 0).str);
} ;
- ret = sockopt_tcp_signature(sock_fd, su, password) ;
+ ret = setsockopt_tcp_signature(sock_fd, su, password) ;
- if (ret != 0) /* TODO: error already logged as zlog_err() */
+ if (ret != 0)
err = errno ;
if (bgpd_privs.change(ZPRIVS_LOWER))
@@ -1066,10 +1088,6 @@ bgp_md5_set_socket(int sock_fd, union sockunion *su, const char *password)
err = errno ;
zlog_err("%s: could not lower privs: %s", __func__, errtoa(errno, 0).str);
} ;
-
- if (err != 0)
- zlog (NULL, LOG_WARNING, "cannot set TCP_MD5SIG option on socket %d: %s",
- sock_fd, errtoa(err, 0).str) ;
return err ;
} ;
diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h
index 4aa62aac..d05fa3a0 100644
--- a/bgpd/bgp_network.h
+++ b/bgpd/bgp_network.h
@@ -24,22 +24,11 @@
#include "bgpd/bgp_connection.h"
-extern int
-bgp_open_listeners(const char *address, unsigned short port) ;
-
-extern void
-bgp_close_listeners(void) ;
-
-extern void
-bgp_open_connect(bgp_connection connection) ;
-
-extern void
-bgp_prepare_to_accept(bgp_connection connection) ;
-
-extern void
-bgp_not_prepared_to_accept(bgp_connection connection) ;
-
-extern void
-bgp_set_ttl(bgp_connection connection, int ttl) ;
+extern int bgp_open_listeners(const char *address, unsigned short port) ;
+extern void bgp_close_listeners(void) ;
+extern void bgp_open_connect(bgp_connection connection) ;
+extern void bgp_prepare_to_accept(bgp_connection connection) ;
+extern void bgp_not_prepared_to_accept(bgp_connection connection) ;
+extern void bgp_set_new_ttl(bgp_connection connection, int ttl, bool gtsm) ;
#endif /* _QUAGGA_BGP_NETWORK_H */
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index de745007..6c21c247 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -461,7 +461,8 @@ bgp_scan (afi_t afi, safi_t safi)
changed = 0;
metricchanged = 0;
- if (peer_sort (bi->peer) == BGP_PEER_EBGP && bi->peer->ttl == 1)
+ if ((peer_sort (bi->peer) == BGP_PEER_EBGP)
+ && (bi->peer->ttl == 1))
valid = bgp_nexthop_check_ebgp (afi, bi->attr);
else
valid = bgp_nexthop_lookup (afi, bi->peer, bi,
diff --git a/bgpd/bgp_notification.c b/bgpd/bgp_notification.c
index 64228ddb..d70491c9 100644
--- a/bgpd/bgp_notification.c
+++ b/bgpd/bgp_notification.c
@@ -106,7 +106,8 @@ bgp_notify_new_expect(bgp_nom_code_t code, bgp_nom_subcode_t subcode,
/*------------------------------------------------------------------------------
* Allocate and initialise new notification, complete with data
*
- * Can specify an expected amount of data.
+ * Can specify an expected amount of data -- copes with len == 0 (and data may
+ * be NULL iff len == 0).
*
* NB: returns a 'NOT received' notification.
*/
@@ -260,7 +261,7 @@ bgp_notify_reset(bgp_notify notification, bgp_nom_code_t code,
/*==============================================================================
* Append data to given notification
*
- * Copes with zero length append.
+ * Copes with zero length append (and data may be NULL if len == 0).
*
* NB: returns possibly NEW ADDRESS of the notification.
*/
@@ -268,7 +269,7 @@ extern void
bgp_notify_append_data(bgp_notify notification, const void* data,
bgp_size_t len)
{
- bgp_size_t new_length = notification->length + len ;
+ bgp_size_t new_length = notification->length + len ; /* unsigned */
if (new_length > notification->size)
{
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index ec2c0ade..3052eeba 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -175,9 +175,9 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
prd = (struct prefix_rd *) &rn->prn->p;
if (binfo)
{
+ from = binfo->peer;
if (binfo->extra)
tag = binfo->extra->tag;
- from = binfo->peer;
}
bgp_packet_set_marker (s, BGP_MSG_UPDATE);
@@ -202,7 +202,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]++;
@@ -637,7 +637,7 @@ bgp_write (bgp_peer peer, struct stream* s)
static int
bgp_write_notify (struct peer *peer)
{
- int ret;
+ int ret, val;
u_char type;
struct stream *s;
@@ -647,7 +647,10 @@ bgp_write_notify (struct peer *peer)
return 0;
assert (stream_get_endp (s) >= BGP_HEADER_SIZE);
- /* I'm not sure fd is writable. */
+ /* Put socket in blocking mode. */
+ val = fcntl (peer->fd, F_GETFL, 0);
+ fcntl (peer->fd, F_SETFL, val & ~O_NONBLOCK);
+
ret = writen (peer->fd, STREAM_DATA (s), stream_get_endp (s));
if (ret <= 0)
{
@@ -1419,6 +1422,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
struct bgp_nlri mp_update;
struct bgp_nlri mp_withdraw;
char attrstr[BUFSIZ] = "";
+ bgp_attr_parse_ret_t ap_ret ;
/* Status must be Established. */
if (peer->state != bgp_peer_pEstablished)
@@ -1509,22 +1513,42 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
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..
+ */
+ ap_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 (ap_ret != BGP_ATTR_PARSE_WITHDRAW ? &attr : NULL)
+
/* Parse attribute when it exists. */
if (attribute_len)
{
- ret = bgp_attr_parse (peer, &attr, attribute_len,
- &mp_update, &mp_withdraw);
- if (ret < 0)
+ ap_ret = bgp_attr_parse (peer, &attr, attribute_len,
+ &mp_update, &mp_withdraw);
+ if (ap_ret == BGP_ATTR_PARSE_ERROR)
return -1;
}
/* Logging the attribute. */
- if (BGP_DEBUG (update, UPDATE_IN))
+ if ((ap_ret == BGP_ATTR_PARSE_WITHDRAW) || BGP_DEBUG (update, UPDATE_IN))
{
ret= bgp_dump_attr (peer, &attr, attrstr, BUFSIZ);
+ int lvl = (ap_ret == BGP_ATTR_PARSE_WITHDRAW) ? LOG_ERR : LOG_DEBUG ;
+
+ if (ap_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);
}
@@ -1536,7 +1560,10 @@ 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, true) ; /* true => free extra */
+ return -1;
+ }
/* Set NLRI portion to structure. */
update.afi = AFI_IP;
@@ -1559,15 +1586,18 @@ 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, true) ; /* true => free extra */
+ 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
@@ -1595,7 +1625,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
@@ -1626,7 +1656,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
@@ -1657,7 +1687,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
@@ -1686,7 +1716,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
if (mp_update.length
&& mp_update.afi == AFI_IP
&& mp_update.safi == BGP_SAFI_VPNV4)
- bgp_nlri_parse_vpnv4 (peer, &attr, &mp_update);
+ bgp_nlri_parse_vpnv4 (peer, NLRI_ATTR_ARG, &mp_update);
if (mp_withdraw.length
&& mp_withdraw.afi == AFI_IP
@@ -1709,31 +1739,7 @@ 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);
- 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);
- }
-
- /* If peering is stopped due to some reason, do not generate BGP
- event. */
- if (peer->state != bgp_peer_pEstablished)
- return 0;
-
- /* Generate BGP event. */
- /* TODO: is this needed? */
-#if 0
- BGP_EVENT_ADD (peer, Receive_UPDATE_message);
-#endif
+ bgp_attr_unintern_sub (&attr, true) ; /* true => free extra */
return 0;
}
@@ -2013,8 +2019,14 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
while (p_pnt < p_end)
{
+ /* If the ORF entry is malformed, want to read as much of it
+ * as possible without going beyond the bounds of the entry,
+ * to maximise debug information.
+ */
+ int ok;
memset (&orfp, 0, sizeof (struct orf_prefix));
common = *p_pnt++;
+ /* after ++: p_pnt <= p_end */
if (common & ORF_COMMON_PART_REMOVE_ALL)
{
if (BGP_DEBUG (normal, NORMAL))
@@ -2022,34 +2034,60 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
prefix_bgp_orf_remove_all (name);
break;
}
- memcpy (&seq, p_pnt, sizeof (u_int32_t));
- p_pnt += sizeof (u_int32_t);
- orfp.seq = ntohl (seq);
- orfp.ge = *p_pnt++;
- orfp.le = *p_pnt++;
- orfp.p.prefixlen = *p_pnt++;
- orfp.p.family = afi2family (afi);
- psize = PSIZE (orfp.p.prefixlen);
- memcpy (&orfp.p.u.prefix, p_pnt, psize);
+ ok = ((p_end - p_pnt) >= sizeof(u_int32_t)) ;
+ if (!ok)
+ {
+ memcpy (&seq, p_pnt, sizeof (u_int32_t));
+ p_pnt += sizeof (u_int32_t);
+ orfp.seq = ntohl (seq);
+ }
+ else
+ p_pnt = p_end ;
+
+ if ((ok = (p_pnt < p_end)))
+ orfp.ge = *p_pnt++ ; /* value checked in prefix_bgp_orf_set() */
+ if ((ok = (p_pnt < p_end)))
+ orfp.le = *p_pnt++ ; /* value checked in prefix_bgp_orf_set() */
+ if ((ok = (p_pnt < p_end)))
+ orfp.p.prefixlen = *p_pnt++ ;
+ orfp.p.family = afi2family (afi); /* afi checked already */
+
+ psize = PSIZE (orfp.p.prefixlen); /* 0 if not ok */
+ if (psize > prefix_blen(&orfp.p)) /* valid for family ? */
+ {
+ ok = 0 ;
+ psize = prefix_blen(&orfp.p) ;
+ }
+ if (psize > (p_end - p_pnt)) /* valid for packet ? */
+ {
+ ok = 0 ;
+ psize = p_end - p_pnt ;
+ }
+
+ if (psize > 0)
+ memcpy (&orfp.p.u.prefix, p_pnt, psize);
p_pnt += psize;
if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s rcvd %s %s seq %u %s/%d ge %d le %d",
+ zlog_debug ("%s rcvd %s %s seq %u %s/%d ge %d le %d%s",
peer->host,
(common & ORF_COMMON_PART_REMOVE ? "Remove" : "Add"),
(common & ORF_COMMON_PART_DENY ? "deny" : "permit"),
orfp.seq,
inet_ntop (orfp.p.family, &orfp.p.u.prefix, buf, BUFSIZ),
- orfp.p.prefixlen, orfp.ge, orfp.le);
+ orfp.p.prefixlen, orfp.ge, orfp.le,
+ ok ? "" : " MALFORMED");
- ret = prefix_bgp_orf_set (name, afi, &orfp,
- (common & ORF_COMMON_PART_DENY ? 0 : 1 ),
- (common & ORF_COMMON_PART_REMOVE ? 0 : 1));
+ if (ok)
+ ret = prefix_bgp_orf_set (name, afi, &orfp,
+ (common & ORF_COMMON_PART_DENY ? 0 : 1 ),
+ (common & ORF_COMMON_PART_REMOVE ? 0 : 1));
- if (ret != CMD_SUCCESS)
+ if (!ok || (ret != CMD_SUCCESS))
{
if (BGP_DEBUG (normal, NORMAL))
- zlog_debug ("%s Received misformatted prefixlist ORF. Remove All pfxlist", peer->host);
+ zlog_debug ("%s Received misformatted prefixlist ORF."
+ " Remove All pfxlist", peer->host);
prefix_bgp_orf_remove_all (name);
break;
}
@@ -2248,12 +2286,13 @@ bgp_read_packet (struct peer *peer)
return 0;
/* Read packet from fd. */
- nbytes = stream_read_unblock (peer->ibuf, peer->fd, readsize);
+ nbytes = stream_read_try (peer->ibuf, peer->fd, readsize);
/* If read byte is smaller than zero then error occured. */
if (nbytes < 0)
{
- if (errno == EAGAIN)
+ /* Transient error should retry */
+ if (nbytes == -2)
return -1;
plog_err (peer->log, "%s [Error] bgp_read_packet error: %s",
diff --git a/bgpd/bgp_peer.c b/bgpd/bgp_peer.c
index 8af38876..196f0d54 100644
--- a/bgpd/bgp_peer.c
+++ b/bgpd/bgp_peer.c
@@ -772,10 +772,19 @@ bgp_peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
peer->local_id = bgp->router_id;
peer->v_holdtime = bgp->default_holdtime;
peer->v_keepalive = bgp->default_keepalive;
+
if (peer_sort (peer) == BGP_PEER_IBGP)
- peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
- else
- peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+ {
+ peer->ttl = MAXTTL ;
+ peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
+
+ }
+ else /* BGP_PEER_EBGP or BGP_PEER_CONFED */
+ {
+ peer->ttl = 1 ;
+ peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+ } ;
+ peer->gtsm = false ;
SET_FLAG(peer->sflags, PEER_STATUS_REAL_PEER) ;
peer = bgp_peer_lock (peer); /* bgp peer list reference */
@@ -791,9 +800,6 @@ bgp_peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
/* Last reset time set */
peer->resettime = bgp_clock ();
- /* Default TTL set. */
- peer->ttl = (peer_sort (peer) == BGP_PEER_IBGP ? 255 : 1);
-
/* Make peer's address string. */
peer->host = sockunion_su2str (su, MTYPE_BGP_PEER_HOST) ;
@@ -1352,7 +1358,7 @@ bgp_peer_down_error(struct peer* peer,
* session.
*
* Same as above, except that this accepts a data part for the notification
- * message.
+ * message -- but len may be 0 (and data may be null iff len == 0).
*/
extern void
bgp_peer_down_error_with_data (struct peer* peer,
@@ -1888,7 +1894,7 @@ bgp_stop_with_error (struct peer *peer)
* If has a choice, uses address that best matches the peer's address.
*/
extern sockunion
-bgp_peer_get_ifaddress(bgp_peer peer, const char* ifname, pAF_t paf)
+bgp_peer_get_ifaddress(bgp_peer peer, const char* ifname, sa_family_t af)
{
struct interface* ifp ;
struct connected* connected;
@@ -1913,7 +1919,7 @@ bgp_peer_get_ifaddress(bgp_peer peer, const char* ifname, pAF_t paf)
for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
{
- if (connected->address->family != paf)
+ if (connected->address->family != af)
continue ;
this = prefix_common_bits (connected->address, peer_prefix) ;
diff --git a/bgpd/bgp_peer.h b/bgpd/bgp_peer.h
index 37738a63..89708661 100644
--- a/bgpd/bgp_peer.h
+++ b/bgpd/bgp_peer.h
@@ -236,7 +236,9 @@ struct peer
bgp_peer_index_entry index_entry ;
bgp_session session ; /* Current session */
- int ttl; /* TTL of TCP connection to the peer. */
+ int ttl ; /* TTL of TCP connection to the peer. */
+ bool gtsm ; /* ttl set by neighbor xxx ttl_security */
+
char *desc; /* Description of the peer. */
unsigned short port; /* Destination port for peer */
char *host; /* Printable address of the peer. */
@@ -471,44 +473,23 @@ extern const char *peer_down_str[];
*
*/
-extern void
-bgp_session_do_event(mqueue_block mqb, mqb_flag_t flag);
-
-extern void
-bgp_peer_enable(bgp_peer peer);
-
-extern void
-bgp_peer_down(bgp_peer peer, peer_down_t why_down) ;
-
-extern void
-bgp_peer_down_error(struct peer* peer,
- bgp_nom_code_t code, bgp_nom_subcode_t subcode) ;
-extern void
-bgp_peer_down_error_with_data (struct peer* peer,
+extern void bgp_session_do_event(mqueue_block mqb, mqb_flag_t flag);
+extern void bgp_peer_enable(bgp_peer peer);
+extern void bgp_peer_down(bgp_peer peer, peer_down_t why_down) ;
+extern void bgp_peer_down_error(bgp_peer peer,
+ bgp_nom_code_t code, bgp_nom_subcode_t subcode) ;
+extern void bgp_peer_down_error_with_data (bgp_peer peer,
bgp_nom_code_t code, bgp_nom_subcode_t subcode,
const u_int8_t* data, size_t datalen) ;
-
-extern void
-bgp_peer_clearing_completed(struct peer *peer) ;
-
-extern struct peer *
-bgp_peer_new (struct bgp *bgp);
-
-extern struct peer *
-bgp_peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
+extern void bgp_peer_clearing_completed(bgp_peer peer) ;
+extern bgp_peer bgp_peer_new (struct bgp *bgp);
+extern bgp_peer bgp_peer_create (sockunion su, struct bgp *bgp, as_t local_as,
as_t remote_as, afi_t afi, safi_t safi);
-
-extern struct
-peer *bgp_peer_lock (struct peer *) ;
-
-extern struct
-peer *bgp_peer_unlock (struct peer *) ;
-
-extern int
-bgp_peer_delete (struct peer *peer);
-
-extern sockunion
-bgp_peer_get_ifaddress(bgp_peer peer, const char* ifname, pAF_t paf) ;
+extern bgp_peer bgp_peer_lock (bgp_peer peer) ;
+extern bgp_peer bgp_peer_unlock (bgp_peer peer) ;
+extern int bgp_peer_delete (bgp_peer peer);
+extern sockunion bgp_peer_get_ifaddress(bgp_peer peer, const char* ifname,
+ sa_family_t af) ;
#endif /* _QUAGGA_BGP_PEER_H */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index b4f57419..34d580b8 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -140,7 +140,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);
@@ -357,6 +357,7 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist)
int internal_as_route = 0;
int confed_as_route = 0;
int ret;
+ bgp_peer_sort_t new_sort, exist_sort ;
/* 0. Null check. */
if (new == NULL)
@@ -465,18 +466,18 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist)
return 0;
}
- /* 7. Peer type check. */
- if (peer_sort (new->peer) == BGP_PEER_EBGP
- && peer_sort (exist->peer) == BGP_PEER_IBGP)
+ /* 7. Peer type check. CONFED and iBGP rank equal, "internal" (RFC5065)
+ */
+ new_sort = peer_sort(new->peer) ;
+ exist_sort = peer_sort(exist->peer) ;
+
+ if ((new_sort == BGP_PEER_EBGP) && (exist_sort == BGP_PEER_IBGP))
return 1;
- if (peer_sort (new->peer) == BGP_PEER_EBGP
- && peer_sort (exist->peer) == BGP_PEER_CONFED)
+ if ((new_sort == BGP_PEER_EBGP) && (exist_sort == BGP_PEER_CONFED))
return 1;
- if (peer_sort (new->peer) == BGP_PEER_IBGP
- && peer_sort (exist->peer) == BGP_PEER_EBGP)
+ if ((new_sort == BGP_PEER_IBGP) && (exist_sort == BGP_PEER_EBGP))
return 0;
- if (peer_sort (new->peer) == BGP_PEER_CONFED
- && peer_sort (exist->peer) == BGP_PEER_EBGP)
+ if ((new_sort == BGP_PEER_CONFED) && (exist_sort == BGP_PEER_EBGP))
return 0;
/* 8. IGP metric check. */
@@ -498,8 +499,8 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist)
newer path won't displace an older one, even if it was the
preferred route based on the additional decision criteria below. */
if (! bgp_flag_check (bgp, BGP_FLAG_COMPARE_ROUTER_ID)
- && peer_sort (new->peer) == BGP_PEER_EBGP
- && peer_sort (exist->peer) == BGP_PEER_EBGP)
+ && (new_sort == BGP_PEER_EBGP)
+ && (exist_sort == BGP_PEER_EBGP) )
{
if (CHECK_FLAG (new->flags, BGP_INFO_SELECTED))
return 1;
@@ -633,18 +634,19 @@ bgp_community_filter (struct peer *peer, struct attr *attr)
{
if (attr->community)
{
+ bgp_peer_sort_t sort = peer_sort(peer) ;
+
/* NO_ADVERTISE check. */
if (community_include (attr->community, COMMUNITY_NO_ADVERTISE))
return 1;
/* NO_EXPORT check. */
- if (peer_sort (peer) == BGP_PEER_EBGP &&
+ if ((sort == BGP_PEER_EBGP) &&
community_include (attr->community, COMMUNITY_NO_EXPORT))
return 1;
/* NO_EXPORT_SUBCONFED check. */
- if (peer_sort (peer) == BGP_PEER_EBGP
- || peer_sort (peer) == BGP_PEER_CONFED)
+ if ((sort == BGP_PEER_EBGP) || (sort == BGP_PEER_CONFED))
if (community_include (attr->community, COMMUNITY_NO_EXPORT_SUBCONFED))
return 1;
}
@@ -839,7 +841,7 @@ bgp_rs_route_reset(struct rs_route* rt)
{
if (rt->rs_in_attr != NULL)
{
- bgp_attr_unintern(rt->rs_in_attr) ;
+ bgp_attr_unintern(&rt->rs_in_attr) ;
rt->rs_in_attr = NULL ;
} ;
@@ -972,7 +974,7 @@ bgp_export_modifier (struct peer *rsclient, struct rs_route* rt,
*/
bgp_attr_flush (rmap_attr);
- bgp_attr_unintern(client_attr) ;
+ bgp_attr_unintern(&client_attr) ;
client_attr = NULL ;
}
@@ -988,7 +990,7 @@ bgp_export_modifier (struct peer *rsclient, struct rs_route* rt,
old_attr = client_attr ;
client_attr = bgp_attr_intern(rmap_attr) ;
- bgp_attr_unintern(old_attr) ;
+ bgp_attr_unintern(&old_attr) ;
} ;
/* Discard any "extra" part of the duplicated attributes. */
@@ -1061,7 +1063,7 @@ bgp_import_modifier (struct peer *rsclient, struct rs_route* rt,
bgp_attr_flush (rmap_attr);
bgp_attr_extra_free (rmap_attr);
- bgp_attr_unintern(client_attr) ;
+ bgp_attr_unintern(&client_attr) ;
return NULL ;
}
@@ -1080,7 +1082,7 @@ bgp_import_modifier (struct peer *rsclient, struct rs_route* rt,
old_attr = client_attr ;
client_attr = bgp_attr_intern(rmap_attr) ;
- bgp_attr_unintern(old_attr) ;
+ bgp_attr_unintern(&old_attr) ;
bgp_attr_extra_free (rmap_attr) ;
} ;
@@ -1098,6 +1100,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
struct bgp *bgp;
int transparent;
int reflect;
+ bgp_peer_sort_t sort, from_sort ;
from = ri->peer;
filter = &peer->filter[afi][safi];
@@ -1216,7 +1219,10 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
}
/* Route-Reflect check. */
- if (peer_sort (from) == BGP_PEER_IBGP && peer_sort (peer) == BGP_PEER_IBGP)
+ from_sort = peer_sort (from) ;
+ sort = peer_sort (peer) ;
+
+ if ((from_sort == BGP_PEER_IBGP) && (sort == BGP_PEER_IBGP))
reflect = 1;
else
reflect = 0;
@@ -1248,8 +1254,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
bgp_attr_dup (attr, ri->attr);
/* If local-preference is not set. */
- if ((peer_sort (peer) == BGP_PEER_IBGP
- || peer_sort (peer) == BGP_PEER_CONFED)
+ if (((sort == BGP_PEER_IBGP) || (sort == BGP_PEER_CONFED))
&& (! (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))))
{
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
@@ -1257,7 +1262,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
}
/* Remove MED if its an EBGP peer - will get overwritten by route-maps */
- if (peer_sort (peer) == BGP_PEER_EBGP
+ if ((sort == BGP_PEER_EBGP)
&& attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
{
if (ri->peer != bgp->peer_self && ! transparent
@@ -1283,7 +1288,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
|| (p->family == AF_INET6 &&
IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global))
#endif /* HAVE_IPV6 */
- || (peer_sort (peer) == BGP_PEER_EBGP
+ || ((sort == BGP_PEER_EBGP)
&& bgp_multiaccess_check_v4 (attr->nexthop, peer->host) == 0))
{
/* Set IPv4 nexthop. */
@@ -1349,7 +1354,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
#endif /* HAVE_IPV6 */
/* If this is EBGP peer and remove-private-AS is set. */
- if (peer_sort (peer) == BGP_PEER_EBGP
+ if ((sort == BGP_PEER_EBGP)
&& peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS)
&& aspath_private_as_check (attr->aspath))
attr->aspath = aspath_empty_get ();
@@ -1367,8 +1372,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
/* The route reflector is not allowed to modify the attributes
of the reflected IBGP routes. */
- if (peer_sort (from) == BGP_PEER_IBGP
- && peer_sort (peer) == BGP_PEER_IBGP)
+ if ((from_sort == BGP_PEER_IBGP) && (sort == BGP_PEER_IBGP))
{
dummy_attr = &dummy_attr_s ;
bgp_attr_dup (dummy_attr, attr);
@@ -2371,7 +2375,7 @@ bgp_update_rsclient (struct peer *rsclient, struct rs_route* rt)
rt->p->prefixlen, rsclient->host);
/* Discard the duplicate interned attributes */
- bgp_attr_unintern (client_attr);
+ bgp_attr_unintern (&client_attr);
/* Unlock node -- locked in bgp_afi_node_get() */
bgp_unlock_node (rn);
@@ -2386,7 +2390,7 @@ bgp_update_rsclient (struct peer *rsclient, struct rs_route* rt)
bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
/* Discard the old attribute */
- bgp_attr_unintern (ri->attr);
+ bgp_attr_unintern (&ri->attr);
}
else
{
@@ -2396,6 +2400,11 @@ bgp_update_rsclient (struct peer *rsclient, struct rs_route* rt)
ri->sub_type = rt->sub_type;
ri->peer = rt->peer;
ri->uptime = bgp_clock ();
+#if 0 /* TODO: do we need this ?? */
+ /* Update MPLS tag. */
+ if (safi == SAFI_MPLS_VPN)
+ memcpy ((bgp_info_extra_get (ri))->tag, tag, 3);
+#endif
/* Register new BGP information. */
bgp_info_add (rn, ri);
@@ -2449,7 +2458,7 @@ bgp_update_rsclient (struct peer *rsclient, struct rs_route* rt)
bgp_rib_remove (rn, ri, rt->peer, rt->afi, rt->safi);
if (client_attr != NULL)
- bgp_attr_unintern (client_attr);
+ bgp_attr_unintern (&client_attr);
bgp_unlock_node (rn);
return;
@@ -2500,12 +2509,15 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
struct bgp_info *new;
const char *reason;
char buf[SU_ADDRSTRLEN];
+ bgp_peer_sort_t sort ;
use_attr = NULL ; /* nothing to use, yet */
bgp = peer->bgp;
rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd);
+ sort = peer_sort(peer) ;
+
/* When peer's soft reconfiguration enabled. Record input packet in
Adj-RIBs-In. */
if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)
@@ -2575,7 +2587,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
{
/* If the peer is EBGP and nexthop is not on connected route,
discard it. */
- if ((peer_sort (peer) == BGP_PEER_EBGP) && (peer->ttl == 1)
+ if ((sort == BGP_PEER_EBGP) && (peer->ttl == 1)
&& ! bgp_nexthop_check_ebgp (afi, use_attr)
&& ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
{
@@ -2606,7 +2618,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
bgp_info_unset_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
- && peer_sort (peer) == BGP_PEER_EBGP
+ && (sort == BGP_PEER_EBGP)
&& CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
{
if (BGP_DEBUG (update, UPDATE_IN))
@@ -2638,7 +2650,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
}
}
- bgp_attr_unintern (use_attr);
+ bgp_attr_unintern (&use_attr);
bgp_unlock_node (rn);
return 0;
@@ -2677,7 +2689,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
/* Update bgp route dampening information. */
if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
- && peer_sort (peer) == BGP_PEER_EBGP)
+ && (sort == BGP_PEER_EBGP))
{
/* This is implicit withdraw so we should update dampening
information. */
@@ -2686,7 +2698,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 = use_attr ;
/* Update MPLS tag. */
@@ -2695,7 +2707,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
/* Update bgp route dampening information. */
if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
- && peer_sort (peer) == BGP_PEER_EBGP)
+ && (sort == BGP_PEER_EBGP))
{
int ret ;
/* Now we do normal update dampening. */
@@ -2710,9 +2722,9 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
/* Nexthop reachability check. */
if ((afi == AFI_IP || afi == AFI_IP6)
&& safi == SAFI_UNICAST
- && (peer_sort (peer) == BGP_PEER_IBGP
- || peer_sort (peer) == BGP_PEER_CONFED
- || (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1)
+ && ( (sort == BGP_PEER_IBGP)
+ || (sort == BGP_PEER_CONFED)
+ || ((sort == BGP_PEER_EBGP) && (peer->ttl != 1))
|| CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)))
{
if (bgp_nexthop_lookup (afi, peer, ri, NULL, NULL))
@@ -2756,9 +2768,9 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
/* Nexthop reachability check. */
if ((afi == AFI_IP || afi == AFI_IP6)
&& safi == SAFI_UNICAST
- && (peer_sort (peer) == BGP_PEER_IBGP
- || peer_sort (peer) == BGP_PEER_CONFED
- || (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1)
+ && ( (sort == BGP_PEER_IBGP)
+ || (sort == BGP_PEER_CONFED)
+ || ((sort == BGP_PEER_EBGP) && (peer->ttl != 1))
|| CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)))
{
if (bgp_nexthop_lookup (afi, peer, new, NULL, NULL))
@@ -2805,7 +2817,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
bgp_rib_remove (rn, ri, peer, afi, safi);
if (use_attr != NULL)
- bgp_attr_unintern (use_attr);
+ bgp_attr_unintern (&use_attr);
bgp_unlock_node (rn);
return 0;
@@ -2995,7 +3007,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
@@ -3983,7 +3995,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
bgp_attr_extra_free (rmap_attr);
/* Unintern original. */
- aspath_unintern (static_attr->aspath);
+ aspath_unintern (&static_attr->aspath);
bgp_attr_extra_free (static_attr);
bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi);
@@ -3998,7 +4010,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
client_attr = bgp_attr_intern (static_attr) ;
/* Have now finished with the static_attr */
- aspath_unintern (static_attr->aspath);
+ aspath_unintern (&static_attr->aspath);
bgp_attr_extra_free (static_attr);
/* run the import route-map for the rsclient. */
@@ -4041,7 +4053,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
!CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
{
/* No point duplicating */
- bgp_attr_unintern (client_attr);
+ bgp_attr_unintern (&client_attr);
}
else
{
@@ -4052,8 +4064,8 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
bgp_info_restore(rn, ri);
- bgp_attr_unintern (ri->attr);
- ri->attr = client_attr ;
+ bgp_attr_unintern (&ri->attr);
+ ri->attr = client_attr ;
ri->uptime = bgp_clock ();
/* Process change. */
@@ -4131,7 +4143,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;
@@ -4152,8 +4164,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;
}
@@ -4167,7 +4179,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 ();
@@ -4175,7 +4187,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;
}
@@ -4203,7 +4215,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);
}
@@ -4224,8 +4236,8 @@ bgp_static_update (struct bgp *bgp, struct prefix *p,
}
static void
-bgp_static_update_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi,
- u_char safi, struct prefix_rd *prd, u_char *tag)
+bgp_static_update_vpnv4 (struct bgp *bgp, struct prefix *p, afi_t afi,
+ safi_t safi, struct prefix_rd *prd, u_char *tag)
{
struct bgp_node *rn;
struct bgp_info *new;
@@ -4661,7 +4673,7 @@ DEFUN (bgp_network,
"Specify a network to announce via BGP\n"
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
{
- return bgp_static_set (vty, vty->index, argv[0],
+ return bgp_static_set (vty, vty->index, argv[0],
AFI_IP, bgp_node_safi (vty), NULL, 0);
}
@@ -6081,7 +6093,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;
@@ -6104,8 +6116,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;
@@ -6120,7 +6132,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 ();
@@ -6128,7 +6140,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;
}
@@ -6150,7 +6162,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);
}
@@ -7176,6 +7188,7 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
SAFI_MPLS_VPN);
}
}
+
bgp_unlock_node (rm);
}
}
@@ -7200,6 +7213,7 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
route_vty_out_detail (vty, bgp, &rn->p, ri, afi, safi);
}
}
+
bgp_unlock_node (rn);
}
}
@@ -8324,19 +8338,19 @@ bgp_show_community (struct vty *vty, const char *view_name,
{
bgp = bgp_lookup_by_name (view_name);
if (bgp == NULL)
- {
- vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE);
- return CMD_WARNING;
- }
+ {
+ vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
}
else
{
bgp = bgp_get_default ();
if (bgp == NULL)
- {
- vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
}
b = buffer_new (1024);
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 042620cf..f9bf2844 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -1549,10 +1549,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);
}
@@ -1568,7 +1568,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. */
@@ -1576,7 +1576,7 @@ static void
route_set_ecommunity_rt_free (void *rule)
{
struct ecommunity *ecom = rule;
- ecommunity_free (ecom);
+ ecommunity_unintern (&ecom);
}
/* Set community rule structure. */
@@ -1595,7 +1595,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)
@@ -1606,8 +1606,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;
}
@@ -1622,7 +1633,7 @@ route_set_ecommunity_soo_compile (const char *arg)
if (! ecom)
return NULL;
- return ecom;
+ return ecommunity_intern (ecom);
}
/* Free function for set community. */
@@ -1630,7 +1641,7 @@ static void
route_set_ecommunity_soo_free (void *rule)
{
struct ecommunity *ecom = rule;
- ecommunity_free (ecom);
+ ecommunity_unintern (&ecom);
}
/* Set community rule structure. */
diff --git a/bgpd/bgp_session.c b/bgpd/bgp_session.c
index d09fe217..7e04e216 100644
--- a/bgpd/bgp_session.c
+++ b/bgpd/bgp_session.c
@@ -324,11 +324,12 @@ bgp_session_enable(bgp_peer peer)
session->open_send = bgp_peer_open_state_init_new(session->open_send, peer) ;
bgp_open_state_unset(&session->open_recv) ;
- session->connect = (peer->flags & PEER_FLAG_PASSIVE) == 0 ;
- session->listen = 1 ;
+ session->connect = (peer->flags & PEER_FLAG_PASSIVE) == 0 ;
+ session->listen = true ;
- session->ttl = peer->ttl ;
- session->port = peer->port ;
+ session->ttl = peer->ttl ;
+ session->gtsm = peer->gtsm ;
+ session->port = peer->port ;
if (session->ifname != NULL)
free(session->ifname) ;
@@ -952,23 +953,26 @@ bgp_session_do_XON(mqueue_block mqb, mqb_flag_t flag)
}
/*==============================================================================
- * Routing Engine: send set ttl message to BGP Engine
- *
- */
+ * Routing Engine: send set ttl message to BGP Engine, if session is active.
+ */
void
-bgp_session_set_ttl(bgp_session session, int ttl)
+bgp_session_set_ttl(bgp_session session, int ttl, bool gtsm)
{
mqueue_block mqb ;
struct bgp_session_ttl_args *args;
- mqb = mqb_init_new(NULL, bgp_session_do_set_ttl, session) ;
+ if (bgp_session_is_active(session))
+ {
+ mqb = mqb_init_new(NULL, bgp_session_do_set_ttl, session) ;
- args = mqb_get_args(mqb) ;
- args->ttl = ttl ;
+ args = mqb_get_args(mqb) ;
+ args->ttl = ttl ;
+ args->gtsm = gtsm ;
- ++bgp_engine_queue_stats.event ;
+ ++bgp_engine_queue_stats.event ;
- bgp_to_bgp_engine(mqb, mqb_ordinary) ;
+ bgp_to_bgp_engine(mqb, mqb_ordinary) ;
+ } ;
}
/*------------------------------------------------------------------------------
@@ -985,10 +989,13 @@ bgp_session_do_set_ttl(mqueue_block mqb, mqb_flag_t flag)
BGP_SESSION_LOCK(session) ; /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
- session->ttl = args->ttl ;
+ session->ttl = args->ttl ;
+ session->gtsm = args->gtsm ;
- bgp_set_ttl(session->connections[bgp_connection_primary], session->ttl);
- bgp_set_ttl(session->connections[bgp_connection_secondary], session->ttl);
+ bgp_set_new_ttl(session->connections[bgp_connection_primary],
+ session->ttl, session->gtsm) ;
+ bgp_set_new_ttl(session->connections[bgp_connection_secondary],
+ session->ttl, session->gtsm) ;
BGP_SESSION_UNLOCK(session) ; /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
}
diff --git a/bgpd/bgp_session.h b/bgpd/bgp_session.h
index cc8acc19..f8cfa547 100644
--- a/bgpd/bgp_session.h
+++ b/bgpd/bgp_session.h
@@ -157,6 +157,7 @@ struct bgp_session
match */
int ttl ; /* TTL to set, if not zero */
+ bool gtsm ; /* ttl set by ttl-security */
unsigned short port ; /* destination port for peer */
/* TODO: ifindex and ifaddress should be rebound if the peer hears any
@@ -294,7 +295,8 @@ enum { BGP_XON_REFRESH = 40,
struct bgp_session_ttl_args /* to bgp Engine */
{
- int ttl ; /* time to live */
+ int ttl ;
+ bool gtsm ;
} ;
MQB_ARGS_SIZE_OK(bgp_session_ttl_args) ;
@@ -357,7 +359,7 @@ extern int
bgp_session_dec_flow_count(bgp_peer peer) ;
extern void
-bgp_session_set_ttl(bgp_session session, int ttl);
+bgp_session_set_ttl(bgp_session session, int ttl, bool gtsm);
extern void
bgp_session_get_stats(bgp_session session, struct bgp_session_stats *stats);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 0015e043..40efd6b8 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -217,6 +217,11 @@ bgp_vty_return (struct vty *vty, int ret)
break;
case BGP_ERR_PEER_EXISTS:
str = "Cannot have the same neighbor in different bgp views";
+ case BGP_ERR_NO_EBGP_MULTIHOP_WITH_GTSM:
+ str = "ebgp-multihop and ttl-security cannot be configured together";
+ break;
+ case BGP_ERR_NO_IBGP_WITH_TTLHACK:
+ str = "ttl-security only allowed for EBGP peers";
break;
}
if (str)
@@ -2683,13 +2688,11 @@ peer_ebgp_multihop_set_vty (struct vty *vty, const char *ip_str,
return CMD_WARNING;
if (! ttl_str)
- ttl = TTL_MAX;
+ ttl = MAXTTL;
else
- VTY_GET_INTEGER_RANGE ("TTL", ttl, ttl_str, 1, 255);
-
- peer_ebgp_multihop_set (peer, ttl);
+ VTY_GET_INTEGER_RANGE ("TTL", ttl, ttl_str, 1, MAXTTL);
- return CMD_SUCCESS;
+ return bgp_vty_return (vty, peer_ebgp_multihop_set (peer, ttl));
}
static int
@@ -2701,9 +2704,7 @@ peer_ebgp_multihop_unset_vty (struct vty *vty, const char *ip_str)
if (! peer)
return CMD_WARNING;
- peer_ebgp_multihop_unset (peer);
-
- return CMD_SUCCESS;
+ return bgp_vty_return (vty, peer_ebgp_multihop_unset (peer));
}
/* neighbor ebgp-multihop. */
@@ -4011,6 +4012,43 @@ DEFUN (no_neighbor_allowas_in,
return bgp_vty_return (vty, ret);
}
+
+DEFUN (neighbor_ttl_security,
+ neighbor_ttl_security_cmd,
+ NEIGHBOR_CMD2 "ttl-security hops <1-254>",
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Specify the maximum number of hops to the BGP peer\n")
+{
+ struct peer *peer;
+ int gtsm_hops;
+
+ peer = peer_and_group_lookup_vty (vty, argv[0]);
+ if (! peer)
+ return CMD_WARNING;
+
+ VTY_GET_INTEGER_RANGE ("", gtsm_hops, argv[1], 1, 254);
+
+ return bgp_vty_return (vty, peer_ttl_security_hops_set (peer, gtsm_hops));
+}
+
+DEFUN (no_neighbor_ttl_security,
+ no_neighbor_ttl_security_cmd,
+ NO_NEIGHBOR_CMD2 "ttl-security hops <1-254>",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Specify the maximum number of hops to the BGP peer\n")
+{
+ struct peer *peer;
+
+ peer = peer_and_group_lookup_vty (vty, argv[0]);
+ if (! peer)
+ return CMD_WARNING;
+
+ return bgp_vty_return (vty, peer_ttl_security_hops_unset (peer));
+}
+
/* Address family configuration. */
DEFUN_ATTR (address_family_ipv4,
address_family_ipv4_cmd,
@@ -4126,14 +4164,14 @@ DEFUN_ATTR (exit_address_family,
} ;
/* BGP clear sort. */
-enum clear_sort
+typedef enum
{
clear_all,
clear_peer,
clear_group,
clear_external,
clear_as
-};
+} clear_sort_t ;
static void
bgp_clear_vty_error (struct vty *vty, struct peer *peer, afi_t afi,
@@ -4159,7 +4197,7 @@ bgp_clear_vty_error (struct vty *vty, struct peer *peer, afi_t afi,
/* `clear ip bgp' functions. */
static int
bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
- enum clear_sort sort,enum bgp_clear_type stype, const char *arg)
+ clear_sort_t sort, bgp_clear_type_t stype, const char *arg)
{
int ret;
struct peer *peer;
@@ -4301,8 +4339,7 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
static int
bgp_clear_vty (struct vty *vty, const char *name, afi_t afi, safi_t safi,
- enum clear_sort sort, enum bgp_clear_type stype,
- const char *arg)
+ clear_sort_t sort, bgp_clear_type_t stype, const char *arg)
{
struct bgp *bgp;
@@ -7713,10 +7750,17 @@ bgp_show_peer (struct vty *vty, struct peer *p)
p->host, VTY_NEWLINE);
}
- /* EBGP Multihop */
- if (peer_sort (p) != BGP_PEER_IBGP && p->ttl > 1)
- vty_out (vty, " External BGP neighbor may be up to %d hops away.%s",
- p->ttl, VTY_NEWLINE);
+ /* EBGP Multihop and GTSM */
+ if (peer_sort (p) != BGP_PEER_IBGP)
+ {
+ if (p->gtsm)
+ vty_out (vty, " External BGP neighbor may be up to %d hops away"
+ " -- using GTSM.%s",
+ p->ttl, VTY_NEWLINE);
+ else if (p->ttl > 1)
+ vty_out (vty, " External BGP neighbor may be up to %d hops away.%s",
+ p->ttl, VTY_NEWLINE);
+ }
/* Local address. */
if (p->su_local)
@@ -10185,6 +10229,10 @@ bgp_vty_init (void)
install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_rmap_cmd);
#endif /* HAVE_IPV6 */
+ /* ttl_security commands */
+ install_element (BGP_NODE, &neighbor_ttl_security_cmd);
+ install_element (BGP_NODE, &no_neighbor_ttl_security_cmd);
+
/* "show bgp memory" commands. */
install_element (VIEW_NODE, &show_bgp_memory_cmd);
install_element (RESTRICTED_NODE, &show_bgp_memory_cmd);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 195ccaef..fd7cd39e 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -646,6 +646,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp)
int flags;
u_char distance;
struct peer *peer;
+ bgp_peer_sort_t sort ;
if (zclient->sock < 0)
return;
@@ -654,15 +655,16 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp)
return;
flags = 0;
- peer = info->peer;
+ peer = info->peer;
+ sort = peer_sort(peer) ;
- if (peer_sort (peer) == BGP_PEER_IBGP || peer_sort (peer) == BGP_PEER_CONFED)
+ if ((sort == BGP_PEER_IBGP) || (sort == BGP_PEER_CONFED))
{
SET_FLAG (flags, ZEBRA_FLAG_IBGP);
SET_FLAG (flags, ZEBRA_FLAG_INTERNAL);
}
- if ((peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1)
+ if (((sort == BGP_PEER_EBGP) && (peer->ttl != 1))
|| CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
SET_FLAG (flags, ZEBRA_FLAG_INTERNAL);
@@ -780,6 +782,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info)
{
int flags;
struct peer *peer;
+ bgp_peer_sort_t sort ;
if (zclient->sock < 0)
return;
@@ -787,16 +790,17 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info)
if (! zclient->redist[ZEBRA_ROUTE_BGP])
return;
- peer = info->peer;
flags = 0;
+ peer = info->peer;
+ sort = peer_sort(peer) ;
- if (peer_sort (peer) == BGP_PEER_IBGP)
+ if (sort == BGP_PEER_IBGP)
{
SET_FLAG (flags, ZEBRA_FLAG_INTERNAL);
SET_FLAG (flags, ZEBRA_FLAG_IBGP);
}
- if ((peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1)
+ if (((sort == BGP_PEER_EBGP) && (peer->ttl != 1))
|| CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
SET_FLAG (flags, ZEBRA_FLAG_INTERNAL);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 2eee6cae..5a5eab83 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -275,11 +275,12 @@ bgp_confederation_id_set (struct bgp *bgp, as_t as)
were not doing confederation before, reset all EBGP sessions. */
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
+ bgp_peer_sort_t sort = peer_sort (peer) ;
/* We're looking for peers who's AS is not local or part of our
confederation. */
if (already_confed)
{
- if (peer_sort (peer) == BGP_PEER_EBGP)
+ if (sort == BGP_PEER_EBGP)
{
peer->local_as = as;
bgp_peer_down(peer, PEER_DOWN_CONFED_ID_CHANGE) ;
@@ -289,10 +290,10 @@ bgp_confederation_id_set (struct bgp *bgp, as_t as)
{
/* Not doing confederation before, so reset every non-local
session */
- if (peer_sort (peer) != BGP_PEER_IBGP)
+ if (sort != BGP_PEER_IBGP)
{
/* Reset the local_as to be our EBGP one */
- if (peer_sort (peer) == BGP_PEER_EBGP)
+ if (sort == BGP_PEER_EBGP)
peer->local_as = as;
bgp_peer_down(peer, PEER_DOWN_CONFED_ID_CHANGE) ;
@@ -561,7 +562,19 @@ peer_global_config_reset (struct peer *peer)
{
peer->weight = 0;
peer->change_local_as = 0;
- peer->ttl = (peer_sort (peer) == BGP_PEER_IBGP ? 255 : 1);
+
+ if (peer_sort (peer) == BGP_PEER_IBGP)
+ {
+ peer->ttl = MAXTTL ;
+ peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
+ }
+ else /* BGP_PEER_EBGP & BGP_PEER_CONFED */
+ {
+ peer->ttl = 1 ;
+ peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+ } ;
+ peer->gtsm = false ;
+
if (peer->update_source)
{
sockunion_free (peer->update_source);
@@ -573,11 +586,6 @@ peer_global_config_reset (struct peer *peer)
peer->update_if = NULL;
}
- if (peer_sort (peer) == BGP_PEER_IBGP)
- peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
- else
- peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
-
peer->flags = 0;
peer->config = 0;
peer->holdtime = 0;
@@ -586,7 +594,23 @@ peer_global_config_reset (struct peer *peer)
peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
}
-/* Check peer's AS number and determin is this peer IBGP or EBGP */
+/*------------------------------------------------------------------------------
+ * Check peer's AS number and determine is this peer IBGP or EBGP
+ *
+ * peer->as is the ASN heard from the peer at OPEN time (remote ASN)
+ *
+ * peer->local_as is the ASN sent to the peer at OPEN time
+ *
+ * Generally this will be the bgp->as, but for confederations
+ * the bgp->as is the member ASN, so for peers outside the
+ * confederation the local_as is set to the confed_id.
+ *
+ * Returns: BGP_PEER_EBGP
+ * BGP_PEER_IBGP -- including within a confederation member-AS
+ * BGP_PEER_CONFED -- between different confederation member-ASes
+ * BGP_PEER_INTERNAL -- this is group, and remote ASN is not set
+ * or is not group amd local ASN is not set
+ */
int
peer_sort (struct peer *peer)
{
@@ -594,35 +618,58 @@ peer_sort (struct peer *peer)
bgp = peer->bgp;
- /* Peer-group */
+ /* Peer-group
+ *
+ * If the group's ASN (remote ASN) is set, return iBGP or eBGP depending on
+ * the bgp ASN (local ASN).
+ *
+ * Otherwise: look at first peer in group (if any) and return iBGP or eBGP,
+ * depending on that peer's local and remote ASNs.
+ *
+ * Note that all peers in a group which does not specify an ASN,
+ * must all be of the same sort.
+ *
+ * Does not check for peer1->local_as being unset, because that
+ * is not realy possible... TODO ???
+ *
+ * Otherwise: return BGP_PEER_INTERNAL.
+ *
+ * NB: does not trouble itself about CONFEDERATION TODO ????
+ */
if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
if (peer->as)
- return (bgp->as == peer->as ? BGP_PEER_IBGP : BGP_PEER_EBGP);
+ return (bgp->as == peer->as) ? BGP_PEER_IBGP : BGP_PEER_EBGP ;
else
{
struct peer *peer1;
peer1 = listnode_head (peer->group->peer);
if (peer1)
- return (peer1->local_as == peer1->as
- ? BGP_PEER_IBGP : BGP_PEER_EBGP);
+ return (peer1->local_as == peer1->as) ? BGP_PEER_IBGP
+ : BGP_PEER_EBGP ;
}
return BGP_PEER_INTERNAL;
}
- /* Normal peer */
+ /* Normal peer
+ *
+ * If the peer's local ASN is not set, return BGP_PEER_INTERNAL.
+ *
+ * Otherwise: if peer's remote and local ASN are the same, return iBGP unless
+ * it's the confed_id, in which case return eBGP TODO ????
+ *
+ * Otherwise: if this is a confederation peer, return BGP_PEER_CONFED.
+ *
+ * Otherwise: return eBGP
+ */
+ if (peer->local_as == 0) /* not really possible... TODO ??? */
+ return BGP_PEER_INTERNAL;
+
if (bgp && CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
{
- if (peer->local_as == 0)
- return BGP_PEER_INTERNAL;
-
if (peer->local_as == peer->as)
- {
- if (peer->local_as == bgp->confed_id)
- return BGP_PEER_EBGP;
- else
- return BGP_PEER_IBGP;
- }
+ return (peer->local_as != bgp->confed_id) ? BGP_PEER_IBGP
+ : BGP_PEER_EBGP ;
if (bgp_confederation_peers_check (bgp, peer->as))
return BGP_PEER_CONFED;
@@ -631,9 +678,7 @@ peer_sort (struct peer *peer)
}
else
{
- return (peer->local_as == 0
- ? BGP_PEER_INTERNAL : peer->local_as == peer->as
- ? BGP_PEER_IBGP : BGP_PEER_EBGP);
+ return (peer->local_as == peer->as) ? BGP_PEER_IBGP : BGP_PEER_EBGP ;
}
}
@@ -655,10 +700,11 @@ peer_create_accept (struct bgp *bgp)
static void
peer_as_change (struct peer *peer, as_t as)
{
- int type;
+ bgp_peer_sort_t old_sort, new_sort ;
- type = peer_sort (peer);
+ old_sort = peer_sort (peer);
peer->as = as;
+ new_sort = peer_sort (peer);
if (bgp_config_check (peer->bgp, BGP_CONFIG_CONFEDERATION)
&& ! bgp_confederation_peers_check (peer->bgp, as)
@@ -668,16 +714,33 @@ peer_as_change (struct peer *peer, as_t as)
peer->local_as = peer->bgp->as;
/* Advertisement-interval reset */
- if (peer_sort (peer) == BGP_PEER_IBGP)
+ if (new_sort == BGP_PEER_IBGP)
peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
else
peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
- /* TTL reset */
- if (peer_sort (peer) == BGP_PEER_IBGP)
- peer->ttl = 255;
- else if (type == BGP_PEER_IBGP)
- peer->ttl = 1;
+ /* TTL reset
+ *
+ * -------|----------- new -----------|
+ * old | iBGP | eBGP | Confed |
+ * -------|---------|--------|--------|
+ * iBGP | iBGP | eBGP | eBGP | -- sans GTSM
+ * -------|---------|--------|--------|
+ * eBGP | iBGP | stet | stet |
+ * -------|---------|--------|--------|
+ * Confed | iBGP | stet | stet |
+ * -------|---------|--------|--------|
+* */
+ if (new_sort == BGP_PEER_IBGP)
+ {
+ peer->ttl = MAXTTL ;
+ peer->gtsm = false ;
+ }
+ else if (old_sort == BGP_PEER_IBGP)
+ {
+ peer->ttl = 1;
+ peer->gtsm = false ; /* should already be the case ! */
+ } ;
/* reflector-client reset */
if (peer_sort (peer) != BGP_PEER_IBGP)
@@ -988,6 +1051,7 @@ peer_group_get (struct bgp *bgp, const char *name)
group->conf->group = group;
group->conf->as = 0;
group->conf->ttl = 1;
+ group->conf->gtsm = false ;
group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
UNSET_FLAG (group->conf->config, PEER_CONFIG_TIMER);
UNSET_FLAG (group->conf->config, PEER_CONFIG_CONNECT);
@@ -1023,8 +1087,9 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer,
if (conf->change_local_as)
peer->change_local_as = conf->change_local_as;
- /* TTL */
- peer->ttl = conf->ttl;
+ /* TTL & GTSM */
+ peer->ttl = conf->ttl;
+ peer->gtsm = conf->gtsm;
/* Weight */
peer->weight = conf->weight;
@@ -1446,7 +1511,10 @@ peer_group_bind (struct bgp *bgp, union sockunion *su,
/* ebgp-multihop reset */
if (peer_sort (group->conf) == BGP_PEER_IBGP)
- group->conf->ttl = 255;
+ {
+ group->conf->ttl = MAXTTL;
+ group->conf->gtsm = false ;
+ } ;
/* local-as reset */
if (peer_sort (group->conf) != BGP_PEER_EBGP)
@@ -2283,81 +2351,183 @@ peer_af_flag_unset (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag)
return peer_af_flag_modify (peer, afi, safi, flag, false);
}
-/* EBGP multihop configuration. */
+/*------------------------------------------------------------------------------
+ * eBGP multihop configuration set -- Confed is eBGP for this purpose.
+ *
+ * This is simply ignored if iBGP. For iBGP peer->ttl is set to MAXTTL, and
+ * peer->gtsm is always false.
+ *
+ * For eBGP and for Confed, peer->ttl is set to 1, and peer->gtsm is also
+ * set false -- until either ebgp-multihop or ttl-security is seen.
+ *
+ * NB: cannot set ebgp-multihop if ttl-security (GTSM) is set.
+ *
+ * cannot set ebgp-multihop on a group if ttl-security (GTSM) is set on any
+ * group member.
+ *
+ * NB: setting ebgp-multihop of 1 is the same as unsetting it.
+ *
+ * setting any value < 1 also unsets ebgp-multihop (sets ttl = 1)
+ */
int
peer_ebgp_multihop_set (struct peer *peer, int ttl)
{
struct peer_group *group;
struct listnode *node, *nnode;
- bgp_session session = peer->session;
if (peer_sort (peer) == BGP_PEER_IBGP)
return 0;
- peer->ttl = ttl;
+ if (peer->gtsm)
+ return BGP_ERR_NO_EBGP_MULTIHOP_WITH_GTSM;
+
+ if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+ {
+ struct peer *pgm;
+ group = peer->group;
+
+ for (ALL_LIST_ELEMENTS (group->peer, node, nnode, pgm))
+ {
+ if (peer_sort (pgm) == BGP_PEER_IBGP)
+ continue;
+
+ if (pgm->gtsm)
+ return BGP_ERR_NO_EBGP_MULTIHOP_WITH_GTSM;
+ }
+ } ;
+
+ if (ttl <= 0)
+ ttl = 1 ;
+
+ peer->ttl = ttl ;
+//qassert(!peer->gtsm) ;
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- if (bgp_session_is_active(session) && peer_sort (peer) != BGP_PEER_IBGP)
- bgp_session_set_ttl (session, peer->ttl);
+ bgp_session_set_ttl (peer->session, peer->ttl, peer->gtsm);
}
else
{
+ struct peer *pgm;
group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
+ for (ALL_LIST_ELEMENTS (group->peer, node, nnode, pgm))
{
- if (peer_sort (peer) == BGP_PEER_IBGP)
- continue;
-
- peer->ttl = group->conf->ttl;
- session = peer->session;
+ if (peer_sort (pgm) == BGP_PEER_IBGP)
+ continue;
- if (bgp_session_is_active(session))
- bgp_session_set_ttl (session, peer->ttl);
+ pgm->ttl = ttl;
+// qassert(!pgm->gtsm) ;
+ bgp_session_set_ttl (pgm->session, pgm->ttl, pgm->gtsm);
}
}
return 0;
}
+/*------------------------------------------------------------------------------
+ * eBGP multihop configuration unset -- Confed is eBGP for this purpose.
+ *
+ * Implemented by setting the ttl to 0 !
+ */
int
peer_ebgp_multihop_unset (struct peer *peer)
{
+ return peer_ebgp_multihop_set (peer, 0) ;
+}
+
+/*------------------------------------------------------------------------------
+ * eBGP ttl-security hops configuration set -- Confed is eBGP for this purpose.
+ *
+ * Setting ttl-security hops is equivalent to setting eBGP multi-hop, except
+ * that it also enables the GTSM -- if available.
+ *
+ * This is simply ignored if iBGP. For iBGP peer->ttl is set to MAXTTL, and
+ * peer->gtsm is always false.
+ *
+ * For eBGP and for Confed, peer->ttl is set to 1, and peer->gtsm is also
+ * set false -- until either ebgp-multihop or ttl-security is seen.
+ *
+ * NB: cannot set ttl-security (GTSM) if eBGP multi-hop is set.
+ *
+ * cannot set ttl-security (GTSM) on a group if eBGP multi-hop is set on any
+ * group member.
+ *
+ * NB: setting ebgp-multihop of < 1 is unsets it (sets ttl = 1, and gtsm false)
+ */
+int
+peer_ttl_security_hops_set (struct peer *peer, int ttl)
+{
struct peer_group *group;
struct listnode *node, *nnode;
- bgp_session session = peer->session;
+ bool gtsm ;
+
+ zlog_debug ("peer_ttl_security_hops_set: set gtsm_hops to %d for %s",
+ ttl, peer->host) ;
if (peer_sort (peer) == BGP_PEER_IBGP)
- return 0;
+ return BGP_ERR_NO_IBGP_WITH_TTLHACK ;
- if (peer_group_active (peer))
- peer->ttl = peer->group->conf->ttl;
+ if (!peer->gtsm && (peer->ttl > 1))
+ return BGP_ERR_NO_EBGP_MULTIHOP_WITH_GTSM;
+
+ if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+ {
+ struct peer *pgm;
+ group = peer->group;
+
+ for (ALL_LIST_ELEMENTS (group->peer, node, nnode, pgm))
+ {
+ if (peer_sort (pgm) == BGP_PEER_IBGP)
+ continue;
+
+ if (!pgm->gtsm && (pgm->ttl > 1))
+ return BGP_ERR_NO_EBGP_MULTIHOP_WITH_GTSM;
+ }
+ } ;
+
+ if (ttl > 0)
+ gtsm = true ;
else
- peer->ttl = 1;
+ {
+ gtsm = false ;
+ ttl = 1 ;
+ } ;
+
+ peer->ttl = ttl ;
+ peer->gtsm = gtsm ;
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- if (bgp_session_is_active(session) && peer_sort (peer) != BGP_PEER_IBGP)
- bgp_session_set_ttl (session, peer->ttl);
+ bgp_session_set_ttl (peer->session, peer->ttl, peer->gtsm);
}
else
{
+ struct peer *pgm;
group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- if (peer_sort (peer) == BGP_PEER_IBGP)
- continue;
-
- peer->ttl = 1;
- session = peer->session;
+ for (ALL_LIST_ELEMENTS (group->peer, node, nnode, pgm))
+ {
+ if (peer_sort (pgm) == BGP_PEER_IBGP)
+ continue;
- if (bgp_session_is_active(session))
- bgp_session_set_ttl (session, peer->ttl);
- }
+ pgm->ttl = ttl;
+ pgm->gtsm = gtsm ;
+ bgp_session_set_ttl (pgm->session, pgm->ttl, pgm->gtsm);
+ } ;
}
-
return 0;
}
+/*------------------------------------------------------------------------------
+ * eBGP ttl-security hops configuration unset -- Confed is eBGP for this purpose.
+ *
+ * Implemented by setting the ttl to 0 !
+ */
+int
+peer_ttl_security_hops_unset (struct peer *peer)
+{
+ return peer_ttl_security_hops_set(peer, 0) ;
+}
+
+
/* Neighbor description. */
int
peer_description_set (struct peer *peer, char *desc)
@@ -3835,7 +4005,7 @@ peer_clear (struct peer *peer)
int
peer_clear_soft (struct peer *peer, afi_t afi, safi_t safi,
- enum bgp_clear_type stype)
+ bgp_clear_type_t stype)
{
if (peer->state != bgp_peer_pEstablished)
return 0;
@@ -4043,160 +4213,168 @@ 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;
+ struct peer *g_conf ;
+ bool pgm, agm ;
char *addr;
+ bgp_peer_sort_t sort ;
- filter = &peer->filter[afi][safi];
addr = peer->host;
+ sort = peer_sort(peer) ;
if (peer_group_active (peer))
- g_peer = peer->group->conf;
+ g_conf = peer->group->conf ;
+ else
+ g_conf = NULL ;
+ pgm = (g_conf != NULL) ; /* group member for >= 1 address families */
- /************************************
- ****** Global to the neighbor ******
- ************************************/
- if (afi == AFI_IP && safi == SAFI_UNICAST)
+ filter = &peer->filter[afi][safi];
+ agm = (peer->af_group[afi][safi] != 0) ;
+
+ if ((afi == AFI_IP) && (safi == SAFI_UNICAST))
{
- /* remote-as. */
- if (! peer_group_active (peer))
+ /* First: stuff which is global to the neighbor */
+
+ /* peer group and/or remote-as. */
+ if (!pgm)
{
if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- vty_out (vty, " neighbor %s peer-group%s", addr,
- VTY_NEWLINE);
+ vty_out (vty, " neighbor %s peer-group%s", addr, VTY_NEWLINE);
if (peer->as)
vty_out (vty, " neighbor %s remote-as %u%s", addr, peer->as,
- VTY_NEWLINE);
+ VTY_NEWLINE);
}
else
{
- if (! g_peer->as)
+ if (g_conf->as == 0)
vty_out (vty, " neighbor %s remote-as %u%s", addr, peer->as,
- VTY_NEWLINE);
- if (peer->af_group[AFI_IP][SAFI_UNICAST])
+ VTY_NEWLINE);
+ if (agm)
vty_out (vty, " neighbor %s peer-group %s%s", addr,
- peer->group->name, VTY_NEWLINE);
+ peer->group->name, VTY_NEWLINE);
}
- /* local-as. */
+ /* local-as. */
if (peer->change_local_as)
- if (! peer_group_active (peer))
+ if (!pgm)
vty_out (vty, " neighbor %s local-as %u%s%s", addr,
- peer->change_local_as,
- CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) ?
- " no-prepend" : "", VTY_NEWLINE);
+ peer->change_local_as,
+ CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)
+ ? " no-prepend" : "", VTY_NEWLINE);
- /* Description. */
+ /* Description. */
if (peer->desc)
vty_out (vty, " neighbor %s description %s%s", addr, peer->desc,
- VTY_NEWLINE);
+ VTY_NEWLINE);
- /* Shutdown. */
+ /* Shutdown. */
if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN))
- if (! peer_group_active (peer) ||
- ! CHECK_FLAG (g_peer->flags, PEER_FLAG_SHUTDOWN))
+ if (!pgm || ! CHECK_FLAG (g_conf->flags, PEER_FLAG_SHUTDOWN))
vty_out (vty, " neighbor %s shutdown%s", addr, VTY_NEWLINE);
- /* Password. */
+ /* Password. */
if (peer->password)
- if (!peer_group_active (peer)
- || ! g_peer->password
- || strcmp (peer->password, g_peer->password) != 0)
+ if (!pgm || (g_conf->password == NULL)
+ || (strcmp (peer->password, g_conf->password) != 0))
vty_out (vty, " neighbor %s password %s%s", addr, peer->password,
- VTY_NEWLINE);
+ VTY_NEWLINE);
- /* BGP port. */
+ /* BGP port. */
if (peer->port != BGP_PORT_DEFAULT)
- vty_out (vty, " neighbor %s port %d%s", addr, peer->port,
- VTY_NEWLINE);
+ vty_out (vty, " neighbor %s port %d%s", addr, peer->port, VTY_NEWLINE);
- /* Local interface name. */
+ /* Local interface name. */
if (peer->ifname)
vty_out (vty, " neighbor %s interface %s%s", addr, peer->ifname,
- VTY_NEWLINE);
+ VTY_NEWLINE);
- /* Passive. */
+ /* Passive. */
if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE))
- if (! peer_group_active (peer) ||
- ! CHECK_FLAG (g_peer->flags, PEER_FLAG_PASSIVE))
+ if (!pgm || ! CHECK_FLAG (g_conf->flags, PEER_FLAG_PASSIVE))
vty_out (vty, " neighbor %s passive%s", addr, VTY_NEWLINE);
- /* EBGP multihop. */
- if (peer_sort (peer) != BGP_PEER_IBGP && peer->ttl != 1)
- if (! peer_group_active (peer) ||
- g_peer->ttl != peer->ttl)
- vty_out (vty, " neighbor %s ebgp-multihop %d%s", addr, peer->ttl,
- VTY_NEWLINE);
+ /* EBGP multihop and ttl-security hops. */
+ if (sort != BGP_PEER_IBGP)
+ {
+ if (peer->gtsm)
+ {
+ /* ttl-security hops */
+ if (!pgm || ! g_conf->gtsm)
+ vty_out (vty, " neighbor %s ttl-security hops %d%s", addr,
+ peer->ttl, VTY_NEWLINE) ;
+ }
+ else if (peer->ttl != 1)
+ {
+ /* eBGP multihop */
+ if (!pgm || (g_conf->ttl != peer->ttl))
+ vty_out (vty, " neighbor %s ebgp-multihop %d%s", addr,
+ peer->ttl, VTY_NEWLINE) ;
+ } ;
+ } ;
- /* disable-connected-check. */
+ /* disable-connected-check. */
if (CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
- if (! peer_group_active (peer) ||
- ! CHECK_FLAG (g_peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
- vty_out (vty, " neighbor %s disable-connected-check%s", addr, VTY_NEWLINE);
+ if (!pgm ||
+ ! CHECK_FLAG (g_conf->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
+ vty_out (vty, " neighbor %s disable-connected-check%s", addr,
+ VTY_NEWLINE);
- /* Update-source. */
+ /* Update-source. */
if (peer->update_if)
- if (! peer_group_active (peer) || ! g_peer->update_if
- || strcmp (g_peer->update_if, peer->update_if) != 0)
+ if (!pgm || ! g_conf->update_if
+ || (strcmp (g_conf->update_if, peer->update_if) != 0))
vty_out (vty, " neighbor %s update-source %s%s", addr,
- peer->update_if, VTY_NEWLINE);
+ peer->update_if, VTY_NEWLINE);
if (peer->update_source)
- if (! peer_group_active (peer) || ! g_peer->update_source
- || sockunion_cmp (g_peer->update_source,
- peer->update_source) != 0)
+ if (!pgm || ! g_conf->update_source
+ || (sockunion_cmp (g_conf->update_source, peer->update_source) != 0))
vty_out (vty, " neighbor %s update-source %s%s", addr,
sutoa(peer->update_source).str,
VTY_NEWLINE);
- /* advertisement-interval */
+ /* advertisement-interval */
if (CHECK_FLAG (peer->config, PEER_CONFIG_ROUTEADV))
vty_out (vty, " neighbor %s advertisement-interval %d%s",
addr, peer->v_routeadv, VTY_NEWLINE);
- /* timers. */
- if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)
- && ! peer_group_active (peer))
- vty_out (vty, " neighbor %s timers %d %d%s", addr,
- peer->keepalive, peer->holdtime, VTY_NEWLINE);
+ /* timers. */
+ if (!pgm && CHECK_FLAG (peer->config, PEER_CONFIG_TIMER))
+ vty_out (vty, " neighbor %s timers %d %d%s", addr,
+ peer->keepalive, peer->holdtime, VTY_NEWLINE);
if (CHECK_FLAG (peer->config, PEER_CONFIG_CONNECT))
- vty_out (vty, " neighbor %s timers connect %d%s", addr,
- peer->connect, VTY_NEWLINE);
+ vty_out (vty, " neighbor %s timers connect %d%s", addr,
+ peer->connect, VTY_NEWLINE);
- /* Default weight. */
+ /* Default weight. */
if (CHECK_FLAG (peer->config, PEER_CONFIG_WEIGHT))
- if (! peer_group_active (peer) ||
- g_peer->weight != peer->weight)
+ if (!pgm || g_conf->weight != peer->weight)
vty_out (vty, " neighbor %s weight %d%s", addr, peer->weight,
- VTY_NEWLINE);
+ VTY_NEWLINE);
- /* Dynamic capability. */
+ /* Dynamic capability. */
if (CHECK_FLAG (peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY))
- if (! peer_group_active (peer) ||
- ! CHECK_FLAG (g_peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY))
+ if (!pgm || ! CHECK_FLAG (g_conf->flags, PEER_FLAG_DYNAMIC_CAPABILITY))
vty_out (vty, " neighbor %s capability dynamic%s", addr,
- VTY_NEWLINE);
+ VTY_NEWLINE);
- /* dont capability negotiation. */
+ /* dont capability negotiation. */
if (CHECK_FLAG (peer->flags, PEER_FLAG_DONT_CAPABILITY))
- if (! peer_group_active (peer) ||
- ! CHECK_FLAG (g_peer->flags, PEER_FLAG_DONT_CAPABILITY))
- vty_out (vty, " neighbor %s dont-capability-negotiate%s", addr,
- VTY_NEWLINE);
+ if (!pgm || ! CHECK_FLAG (g_conf->flags, PEER_FLAG_DONT_CAPABILITY))
+ vty_out (vty, " neighbor %s dont-capability-negotiate%s", addr,
+ VTY_NEWLINE);
- /* override capability negotiation. */
+ /* override capability negotiation. */
if (CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
- if (! peer_group_active (peer) ||
- ! CHECK_FLAG (g_peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
- vty_out (vty, " neighbor %s override-capability%s", addr,
- VTY_NEWLINE);
+ if (!pgm || ! CHECK_FLAG (g_conf->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
+ vty_out (vty, " neighbor %s override-capability%s", addr,
+ VTY_NEWLINE);
- /* strict capability negotiation. */
+ /* strict capability negotiation. */
if (CHECK_FLAG (peer->flags, PEER_FLAG_STRICT_CAP_MATCH))
- if (! peer_group_active (peer) ||
- ! CHECK_FLAG (g_peer->flags, PEER_FLAG_STRICT_CAP_MATCH))
- vty_out (vty, " neighbor %s strict-capability-match%s", addr,
- VTY_NEWLINE);
+ if (!pgm || ! CHECK_FLAG (g_conf->flags, PEER_FLAG_STRICT_CAP_MATCH))
+ vty_out (vty, " neighbor %s strict-capability-match%s", addr,
+ VTY_NEWLINE);
- if (! peer_group_active (peer))
+ if (!pgm)
{
if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4))
{
@@ -4210,25 +4388,25 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
}
}
}
-
-
- /************************************
- ****** Per AF to the neighbor ******
- ************************************/
-
- if (! (afi == AFI_IP && safi == SAFI_UNICAST))
+ else
{
- if (peer->af_group[afi][safi])
+ /* Per AF for the neighbor */
+
+ if (agm)
vty_out (vty, " neighbor %s peer-group %s%s", addr,
- peer->group->name, VTY_NEWLINE);
+ peer->group->name, VTY_NEWLINE);
else
vty_out (vty, " neighbor %s activate%s", addr, VTY_NEWLINE);
}
+ /*--------------------------------------------------------------------
+ * From now on we are dealing with the particular address family.
+ */
+
/* ORF capability. */
if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)
|| CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM))
- if (! peer->af_group[afi][safi])
+ if (!agm)
{
vty_out (vty, " neighbor %s capability orf prefix-list", addr);
@@ -4243,24 +4421,20 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
}
/* Route reflector client. */
- if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REFLECTOR_CLIENT)
- && ! peer->af_group[afi][safi])
+ if (!agm && peer_af_flag_check (peer, afi, safi, PEER_FLAG_REFLECTOR_CLIENT))
vty_out (vty, " neighbor %s route-reflector-client%s", addr,
VTY_NEWLINE);
/* Nexthop self. */
- if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_NEXTHOP_SELF)
- && ! peer->af_group[afi][safi])
+ if (!agm && peer_af_flag_check (peer, afi, safi, PEER_FLAG_NEXTHOP_SELF))
vty_out (vty, " neighbor %s next-hop-self%s", addr, VTY_NEWLINE);
/* Remove private AS. */
- if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS)
- && ! peer->af_group[afi][safi])
- vty_out (vty, " neighbor %s remove-private-AS%s",
- addr, VTY_NEWLINE);
+ if (!agm && peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS))
+ vty_out (vty, " neighbor %s remove-private-AS%s", addr, VTY_NEWLINE);
/* send-community print. */
- if (! peer->af_group[afi][safi])
+ if (!agm)
{
if (bgp_option_check (BGP_OPT_CONFIG_CISCO))
{
@@ -4288,9 +4462,8 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
}
}
- /* Default information */
- if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_DEFAULT_ORIGINATE)
- && ! peer->af_group[afi][safi])
+ /* Default information */
+ if (!agm && peer_af_flag_check (peer, afi, safi, PEER_FLAG_DEFAULT_ORIGINATE))
{
vty_out (vty, " neighbor %s default-originate", addr);
if (peer->default_rmap[afi][safi].name)
@@ -4298,19 +4471,19 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
vty_out (vty, "%s", VTY_NEWLINE);
}
- /* Soft reconfiguration inbound. */
+ /* Soft reconfiguration inbound. */
if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG))
- if (! peer->af_group[afi][safi] ||
- ! CHECK_FLAG (g_peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG))
+ if (!agm ||
+ ! CHECK_FLAG (g_conf->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG))
vty_out (vty, " neighbor %s soft-reconfiguration inbound%s", addr,
- VTY_NEWLINE);
+ VTY_NEWLINE);
- /* maximum-prefix. */
+ /* maximum-prefix. */
if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX))
- if (! peer->af_group[afi][safi]
- || g_peer->pmax[afi][safi] != peer->pmax[afi][safi]
- || g_peer->pmax_threshold[afi][safi] != peer->pmax_threshold[afi][safi]
- || CHECK_FLAG (g_peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING)
+ if (!agm
+ || g_conf->pmax[afi][safi] != peer->pmax[afi][safi]
+ || g_conf->pmax_threshold[afi][safi] != peer->pmax_threshold[afi][safi]
+ || CHECK_FLAG (g_conf->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING)
!= CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING))
{
vty_out (vty, " neighbor %s maximum-prefix %ld", addr, peer->pmax[afi][safi]);
@@ -4324,15 +4497,14 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
}
/* Route server client. */
- if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)
- && ! peer->af_group[afi][safi])
+ if (!agm && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))
vty_out (vty, " neighbor %s route-server-client%s", addr, VTY_NEWLINE);
/* Allow AS in. */
if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_ALLOWAS_IN))
- if (! peer_group_active (peer)
- || ! peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_ALLOWAS_IN)
- || peer->allowas_in[afi][safi] != g_peer->allowas_in[afi][safi])
+ if (!pgm
+ || ! peer_af_flag_check (g_conf, afi, safi, PEER_FLAG_ALLOWAS_IN)
+ || peer->allowas_in[afi][safi] != g_conf->allowas_in[afi][safi])
{
if (peer->allowas_in[afi][safi] == 3)
vty_out (vty, " neighbor %s allowas-in%s", addr, VTY_NEWLINE);
@@ -4345,10 +4517,10 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
bgp_config_write_filter (vty, peer, afi, safi);
/* atribute-unchanged. */
- if ((CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
+ if (!agm &&
+ ( CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
|| CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)
- || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED))
- && ! peer->af_group[afi][safi])
+ || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED) ))
{
if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
&& CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 3a657456..f20d8315 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -195,8 +195,6 @@ struct bgp_rd
-
-
#define PEER_PASSWORD_MINLEN (1)
#define PEER_PASSWORD_MAXLEN (80)
@@ -342,16 +340,16 @@ struct bgp_nlri
/* IBGP/EBGP identifier. We also have a CONFED peer, which is to say,
a peer who's AS is part of our Confederation. */
-enum
+typedef enum
{
BGP_PEER_IBGP,
BGP_PEER_EBGP,
BGP_PEER_INTERNAL,
BGP_PEER_CONFED
-};
+} bgp_peer_sort_t ;
/* Flag for peer_clear_soft(). */
-enum bgp_clear_type
+typedef enum
{
BGP_CLEAR_SOFT_NONE,
BGP_CLEAR_SOFT_OUT,
@@ -359,7 +357,7 @@ enum bgp_clear_type
BGP_CLEAR_SOFT_BOTH,
BGP_CLEAR_SOFT_IN_ORF_PREFIX,
BGP_CLEAR_SOFT_RSCLIENT
-};
+} bgp_clear_type_t ;
/* Macros. */
#define BGP_INPUT(P) ((P)->ibuf)
@@ -400,7 +398,9 @@ enum bgp_clear_type
#define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS -28
#define BGP_ERR_TCPSIG_FAILED -29
#define BGP_ERR_PEER_EXISTS -30
-#define BGP_ERR_MAX -31
+#define BGP_ERR_NO_EBGP_MULTIHOP_WITH_GTSM -31
+#define BGP_ERR_NO_IBGP_WITH_TTLHACK -32
+#define BGP_ERR_MAX -33
/*------------------------------------------------------------------------------
* Globals.
@@ -600,8 +600,10 @@ extern int peer_maximum_prefix_set (struct peer *, afi_t, safi_t, u_int32_t, u_c
extern int peer_maximum_prefix_unset (struct peer *, afi_t, safi_t);
extern int peer_clear (struct peer *);
-extern int peer_clear_soft (struct peer *, afi_t, safi_t, enum bgp_clear_type);
+extern int peer_clear_soft (struct peer *, afi_t, safi_t, bgp_clear_type_t);
extern void program_terminate_if_all_disabled(void);
+extern int peer_ttl_security_hops_set (struct peer *, int);
+extern int peer_ttl_security_hops_unset (struct peer *);
#endif /* _QUAGGA_BGPD_H */