summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Hall <chris.hall@highwayman.com>2011-08-12 15:06:06 +0100
committerChris Hall <chris.hall@highwayman.com>2011-08-12 15:06:06 +0100
commitcec1fae79110dffa900c0c5f38c3d3b48f5b0db6 (patch)
tree408055322e19098b98766168624f1b96865ac73b
parent228e06bad624a33090da4a09f32f8fed84a7e15c (diff)
parent7bd8653ef788a6395b07583d6766be8950598342 (diff)
downloadquagga-ex18p.tar.bz2
quagga-ex18p.tar.xz
Merge branch 'euro_ix' of /git/quagga.euro-ix into pipeworkex18p
Merge with euro_ix branch v0.99.18ex17. Update version to: 0.99.18ex18p Of particular note: * includes support for GTSM: neighbor ... ttl-security hops X no neighbor ... ttl-security hops X where X is 1-254. For usual case of immediately connected peer, X == 1. Cannot set ttl-security while ebgp-multihop is set, and vice-versa. If underlying O/S does not support GTSM, then will set ttl as per ebgp-multihop. In passing, have fixed various bugs in the main Quagga branch. * initial support for draft-ietf-idr-optional-transitive Does not yet support "neighbor-complete" flag. * main Quagga now uses TCP_CORK and permanent non-blocking Do not beleive TCP_CORK to be necessary for euro_ix code... which has a different buffering strategy. The euro_ix code already runs sockets permanently non-blocking. * various fixes to attribute intern/unintern Trying to remove memory leaks. Nobody seems convinced that this has been perfected, yet. * fixes for ospfd and ospf6d issues. Up to date with master branch up to: commit 538cb284864c17de66152a5236db4cd80e3e7639 Merge: 036a6e6 8ced4e8 Author: Paul Jakma <paul@quagga.net> Date: Fri Jul 29 18:21:50 2011 +0100
-rw-r--r--HACKING.pending4
-rwxr-xr-xREADME.NetBSD4
-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
-rwxr-xr-xconfigure.ac2
-rw-r--r--doc/Makefile.am2
l---------doc/texinfo.tex1
-rw-r--r--lib/prefix.h52
-rw-r--r--lib/qafi_safi.h5
-rw-r--r--lib/qfstring.c234
-rw-r--r--lib/qfstring.h11
-rw-r--r--lib/smux.c9
-rw-r--r--lib/sockopt.c1145
-rw-r--r--lib/sockopt.h41
-rw-r--r--lib/sockunion.c403
-rw-r--r--lib/sockunion.h47
-rw-r--r--lib/thread.c8
-rw-r--r--lib/vty_io.c1
-rw-r--r--lib/vty_io_term.c38
-rw-r--r--ospf6d/ospf6_interface.c58
-rw-r--r--ospf6d/ospf6_interface.h3
-rw-r--r--ospf6d/ospf6_message.c2
-rw-r--r--ospf6d/ospf6_network.c2
-rw-r--r--ospf6d/ospf6_zebra.c3
-rw-r--r--ospfd/ospf_api.c2
-rw-r--r--ospfd/ospf_apiserver.c18
-rw-r--r--ospfd/ospf_apiserver.h6
-rw-r--r--ospfd/ospf_ase.c6
-rw-r--r--ospfd/ospf_network.c2
-rw-r--r--ospfd/ospf_packet.c16
-rw-r--r--ospfd/ospf_te.c15
-rw-r--r--ripd/ripd.c404
-rw-r--r--tests/aspath_test.c329
-rw-r--r--tests/ecommunity_test.c4
-rw-r--r--tools/multiple-bgpd.sh9
-rw-r--r--zebra/irdp_main.c4
-rw-r--r--zebra/zebra_routemap.c11
-rw-r--r--zebra/zserv.c4
67 files changed, 3347 insertions, 1911 deletions
diff --git a/HACKING.pending b/HACKING.pending
index 25ea0bd4..80c8cb45 100644
--- a/HACKING.pending
+++ b/HACKING.pending
@@ -28,7 +28,11 @@ the list have been stored.
Tom Henderson of Boeing has created a repository to work on
multi-topology routing support for OSPF. Work on this repository
+<<<<<<< HEAD
takes place on the branch mtr, which has a branch poing of 0.99.17
+=======
+takes place on the branch mtr, which has a branch point of 0.99.17
+>>>>>>> 538cb284864c17de66152a5236db4cd80e3e7639
* posted patches
diff --git a/README.NetBSD b/README.NetBSD
index 9aac4c35..6bbc680b 100755
--- a/README.NetBSD
+++ b/README.NetBSD
@@ -20,13 +20,15 @@ PREFIX=/usr/pkg
case $1 in
build)
+ # Omitted because it is now default:
+ # --enable-opaque-lsa
./bootstrap.sh
LDFLAGS="-L/usr/pkg/lib -R/usr/pkg/lib" CPPFLAGS="-I/usr/pkg/include" \
./configure --prefix=${PREFIX} \
--sysconfdir=/etc/zebra --localstatedir=/var/run/zebra \
--enable-exampledir=${PREFIX}/share/examples/zebra \
--enable-pkgsrcrcdir=${PREFIX}/etc/rc.d \
- --enable-opaque-lsa --enable-vtysh
+ --enable-vtysh
${MAKE}
;;
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 */
diff --git a/configure.ac b/configure.ac
index c2670fb7..01dc36bb 100755
--- a/configure.ac
+++ b/configure.ac
@@ -8,7 +8,7 @@
## $Id$
AC_PREREQ(2.53)
-AC_INIT(Quagga, 0.99.18ex16p, [http://bugzilla.quagga.net])
+AC_INIT(Quagga, 0.99.18ex18p, [http://bugzilla.quagga.net])
AC_CONFIG_SRCDIR(lib/zebra.h)
AC_CONFIG_MACRO_DIR([m4])
diff --git a/doc/Makefile.am b/doc/Makefile.am
index c3016b2b..cd4d71bd 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -43,7 +43,7 @@ info_TEXINFOS = quagga.texi
# us to have a generic automatic .pdf rule to build the figure sources
# because it cant just work from the png's directly it seems - contrary
# to the documentation...
-quagga.pdf: $(info_TEXINFOS) $(figures_pdf)
+quagga.pdf: $(info_TEXINFOS) $(figures_pdf) $(quagga_TEXINFOS)
$(TEXI2PDF) -o "$@" $<
quagga_TEXINFOS = appendix.texi basic.texi bgpd.texi filter.texi install.texi \
diff --git a/doc/texinfo.tex b/doc/texinfo.tex
deleted file mode 120000
index 19501744..00000000
--- a/doc/texinfo.tex
+++ /dev/null
@@ -1 +0,0 @@
-/usr/share/automake-1.11/texinfo.tex \ No newline at end of file
diff --git a/lib/prefix.h b/lib/prefix.h
index bc44244c..7944fd69 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -40,8 +40,8 @@ typedef const union sockunion* const_sockunion ;
/* IPv4 and IPv6 unified prefix structure. */
struct prefix
{
- u_char family;
- u_char prefixlen;
+ sa_family_t family;
+ u_char prefixlen;
union
{
u_char prefix;
@@ -61,36 +61,66 @@ struct prefix
/* IPv4 prefix structure. */
struct prefix_ipv4
{
- u_char family;
- u_char prefixlen;
+ sa_family_t family;
+ u_char prefixlen;
struct in_addr prefix __attribute__ ((aligned (8)));
};
+CONFIRM(offsetof(struct prefix_ipv4, family)
+ == offsetof(struct prefix, family)) ;
+CONFIRM(offsetof(struct prefix_ipv4, prefixlen)
+ == offsetof(struct prefix, prefixlen)) ;
+CONFIRM(offsetof(struct prefix_ipv4, prefix)
+ == offsetof(struct prefix, u.prefix4)) ;
+CONFIRM(sizeof(struct prefix_ipv4) <= sizeof(struct prefix)) ;
/* IPv6 prefix structure. */
#ifdef HAVE_IPV6
struct prefix_ipv6
{
- u_char family;
- u_char prefixlen;
+ sa_family_t family;
+ u_char prefixlen;
struct in6_addr prefix __attribute__ ((aligned (8)));
};
+CONFIRM(offsetof(struct prefix_ipv6, family)
+ == offsetof(struct prefix, family)) ;
+CONFIRM(offsetof(struct prefix_ipv6, prefixlen)
+ == offsetof(struct prefix, prefixlen)) ;
+CONFIRM(offsetof(struct prefix_ipv6, prefix)
+ == offsetof(struct prefix, u.prefix6)) ;
+CONFIRM(sizeof(struct prefix_ipv6) <= sizeof(struct prefix)) ;
#endif /* HAVE_IPV6 */
struct prefix_ls
{
- u_char family;
- u_char prefixlen;
+ sa_family_t family;
+ u_char prefixlen;
struct in_addr id __attribute__ ((aligned (8)));
struct in_addr adv_router;
};
+CONFIRM(offsetof(struct prefix_ls, family)
+ == offsetof(struct prefix, family)) ;
+CONFIRM(offsetof(struct prefix_ls, prefixlen)
+ == offsetof(struct prefix, prefixlen)) ;
+CONFIRM(offsetof(struct prefix_ls, id)
+ == offsetof(struct prefix, u.lp.id)) ;
+CONFIRM(offsetof(struct prefix_ls, adv_router)
+ == offsetof(struct prefix, u.lp.adv_router)) ;
+CONFIRM(sizeof(struct prefix_ls) <= sizeof(struct prefix)) ;
/* Prefix for routing distinguisher. */
struct prefix_rd
{
- u_char family;
- u_char prefixlen;
- u_char val[8] __attribute__ ((aligned (8)));
+ sa_family_t family;
+ u_char prefixlen;
+ u_char val[8] __attribute__ ((aligned (8)));
};
+CONFIRM(offsetof(struct prefix_rd, family)
+ == offsetof(struct prefix, family)) ;
+CONFIRM(offsetof(struct prefix_rd, prefixlen)
+ == offsetof(struct prefix, prefixlen)) ;
+CONFIRM(offsetof(struct prefix_rd, val)
+ == offsetof(struct prefix, u.val)) ;
+CONFIRM(sizeof(struct prefix_rd) <= sizeof(struct prefix)) ;
#ifndef INET_ADDRSTRLEN
#define INET_ADDRSTRLEN 16
diff --git a/lib/qafi_safi.h b/lib/qafi_safi.h
index c93b741e..5559097d 100644
--- a/lib/qafi_safi.h
+++ b/lib/qafi_safi.h
@@ -139,11 +139,6 @@ typedef struct qAFI_SAFI qAFI_SAFI_t ;
typedef struct qAFI_SAFI* qAFI_SAFI ;
/*==============================================================================
- * POSIX address family type
- */
-typedef int pAF_t ;
-
-/*==============================================================================
* Quagga AFI/SAFI values -- original macro definitions
*/
diff --git a/lib/qfstring.c b/lib/qfstring.c
index 9f2e2e9c..eda2aa9a 100644
--- a/lib/qfstring.c
+++ b/lib/qfstring.c
@@ -20,6 +20,8 @@
*/
#include "misc.h"
+#include <stdio.h>
+
#include "qfstring.h"
/*==============================================================================
@@ -397,7 +399,9 @@ qfs_pointer(qf_str qfs, void* p_val, enum pf_flags flags,
* pf_plus -- requires '+' or '-'
* pf_space -- requires space or '-'
* pf_zeros -- zero fill to width
- * pf_alt -- add '0x' or '0X' if hex (no effect on decimal)
+ * pf_alt -- add '0x' or '0X' if hex -- depending on pf_uc
+ * add '0' if octal and not zero.
+ * no effect otherwise
*
* pf_precision -- explicit precision (needed if precision == 0)
*
@@ -430,7 +434,11 @@ qfs_pointer(qf_str qfs, void* p_val, enum pf_flags flags,
*
* * pf_unsigned or sign == 0 takes precedence over pf_plus and pf_space.
*
- * For hex output, pf_commas groups digits in 4's, separated by '_'.
+ * For decimal output, pf_commas groups digits in 3's, separated by ','.
+ * For hex output, pf_commas groups digits in 4's, separated by '_'.
+ * For oct output, pf_commas is ignored.
+ *
+ * Note that pf_commas is a glibc extension, which does not apply to hex !
*
* For hex output if precision is:
*
@@ -521,6 +529,9 @@ qfs_number(qf_str qfs, uintmax_t val, int sign, enum pf_flags flags,
if ((flags & pf_precision) || (width <= 0))
flags &= ~pf_zeros ; /* turn off zero fill */
+ if (flags & pf_oct)
+ flags &= ~pf_commas ; /* turn off commas */
+
/* Set up any required sign and radix prefix */
if ((flags & pf_unsigned) || (sign == 0))
{
@@ -548,15 +559,22 @@ qfs_number(qf_str qfs, uintmax_t val, int sign, enum pf_flags flags,
sign_len = 0 ;
} ;
- if ((flags & (pf_hex | pf_alt)) == (pf_hex | pf_alt))
- {
- radix_str = (flags & pf_uc) ? "0X" : "0x" ;
- radix_len = 2 ;
- }
- else
+ radix_str = "" ;
+ radix_len = 0 ;
+
+ if (flags & pf_alt)
{
- radix_str = "" ;
- radix_len = 0 ;
+ if (flags & pf_hex)
+ {
+ confirm(pf_uc != 0) ;
+ radix_str = (flags & pf_uc) ? "0X" : "0x" ;
+ radix_len = 2 ;
+ }
+ else if ((flags & pf_oct) && (val != 0))
+ {
+ radix_str = "0" ;
+ radix_len = 1 ;
+ } ;
} ;
/* Turn off zero fill if left justify (width < 0) */
@@ -574,8 +592,14 @@ qfs_number(qf_str qfs, uintmax_t val, int sign, enum pf_flags flags,
} ;
/* Start with the basic digit conversion. */
- base = (flags & pf_hex) ? 16 : 10 ;
+ base = 10 ;
+ if (flags & pf_hex)
+ base = 16 ;
+ else if (flags & pf_oct)
+ base = 8 ;
+
digits = (flags & pf_uc) ? uc : lc ;
+ confirm(pf_uc != 0) ;
e = p = num + sizeof(num) ;
v = val ;
@@ -734,12 +758,15 @@ enum pf_phase
pfp_flags,
pfp_width,
pfp_precision,
- pfp_num_type,
+ pfp_int_type,
+ pfp_float_type,
pfp_done,
pfp_failed
} ;
+CONFIRM(pfp_float_type > pfp_int_type) ;
+
/* Number types for printing */
enum arg_num_type
{
@@ -750,7 +777,8 @@ enum arg_num_type
ant_long_long, /* ll */
ant_intmax_t, /* j */
ant_size_t, /* z */
- ant_ptr_t, /* %p */
+ ant_ptr_t, /* void* */
+ ant_long_double, /* L for float */
ant_default = ant_int,
};
@@ -759,14 +787,16 @@ static enum pf_phase qfs_arg_string(qf_str qfs, const char* src,
enum pf_flags flags, int width, int precision) ;
static enum pf_phase qfs_arg_char(qf_str qfs, char ch,
enum pf_flags flags, int width, int precision) ;
-static enum pf_phase qfs_arg_number(qf_str qfs, va_list* p_va,
+static enum pf_phase qfs_arg_integer(qf_str qfs, va_list* p_va,
enum pf_flags flags, int width, int precision, enum arg_num_type ant) ;
+static enum pf_phase qfs_arg_float(qf_str qfs, va_list* p_va,
+ const char* start, size_t flen, enum arg_num_type ant) ;
/*------------------------------------------------------------------------------
* Formatted print to qf_str -- cf printf() -- appends to the qf_str.
*
- * This operation is async-signal-safe. Takes into account the offset, and
- * adds up any overflow.
+ * This operation is async-signal-safe -- EXCEPT for floating point values.
+ * Takes into account the offset, and adds up any overflow.
*
* Returns: the resulting length of the qf_str.
*/
@@ -786,8 +816,8 @@ qfs_printf(qf_str qfs, const char* format, ...)
/*------------------------------------------------------------------------------
* Formatted print to qf_str -- cf vprintf() -- appends to the qf_str.
*
- * This operation is async-signal-safe. Takes into account the offset, and
- * adds up any overflow
+ * This operation is async-signal-safe -- EXCEPT for floating point values.
+ * Takes into account the offset, and adds up any overflow.
*
* Operates on a copy of the va_list -- so the original is *unchanged*.
*
@@ -851,6 +881,11 @@ qfs_vprintf(qf_str qfs, const char *format, va_list va)
phase = (phase <= pfp_flags) ? pfp_flags : pfp_failed ;
break ;
+ case '#':
+ flags |= pf_alt ;
+ phase = (phase <= pfp_flags) ? pfp_flags : pfp_failed ;
+ break ;
+
case ' ':
flags |= pf_space ;
phase = (phase <= pfp_flags) ? pfp_flags : pfp_failed ;
@@ -909,13 +944,13 @@ qfs_vprintf(qf_str qfs, const char *format, va_list va)
break ;
case '.':
- phase = (phase <= pfp_precision) ? pfp_precision : pfp_failed;
+ phase = (phase < pfp_precision) ? pfp_precision : pfp_failed ;
flags |= pf_precision ;
precision = 0 ;
break ;
case 'l': /* 1 or 2 'l', not 'h', 'j' or 'z' */
- phase = pfp_num_type ;
+ phase = (phase <= pfp_int_type) ? pfp_int_type : pfp_failed ;
if (ant == ant_default)
ant = ant_long ;
else if (ant == ant_long)
@@ -925,7 +960,7 @@ qfs_vprintf(qf_str qfs, const char *format, va_list va)
break ;
case 'h': /* 1 or 2 'h', not 'l', 'j' or 'z' */
- phase = pfp_num_type ;
+ phase = (phase <= pfp_int_type) ? pfp_int_type : pfp_failed ;
if (ant == ant_default)
ant = ant_short ;
else if (ant == ant_short)
@@ -935,17 +970,22 @@ qfs_vprintf(qf_str qfs, const char *format, va_list va)
break ;
case 'j': /* 1 'j', not 'h', 'l' or 'z' */
- phase = (phase <= pfp_num_type) ? pfp_num_type : pfp_failed ;
+ phase = (phase <= pfp_int_type) ? pfp_int_type : pfp_failed ;
ant = ant_intmax_t ;
break ;
case 'z': /* 1 'z', not 'h', 'l' or 'j' */
- phase = (phase <= pfp_num_type) ? pfp_num_type : pfp_failed ;
+ phase = (phase <= pfp_int_type) ? pfp_int_type : pfp_failed ;
ant = ant_size_t ;
break ;
+ case 'L': /* 1 'L', not for integers ! */
+ phase = (phase < pfp_int_type) ? pfp_float_type : pfp_failed ;
+ ant = ant_long_double ;
+ break ;
+
case 's':
- if (phase == pfp_num_type)
+ if (phase == pfp_int_type)
phase = pfp_failed ; /* don't do 'l' etc. */
else
phase = qfs_arg_string(qfs, va_arg(vac, char*),
@@ -953,7 +993,7 @@ qfs_vprintf(qf_str qfs, const char *format, va_list va)
break ;
case 'c':
- if (phase == pfp_num_type)
+ if (phase == pfp_int_type)
phase = pfp_failed ; /* don't do 'l' etc. */
else
phase = qfs_arg_char(qfs, (char)va_arg(vac, int),
@@ -962,33 +1002,53 @@ qfs_vprintf(qf_str qfs, const char *format, va_list va)
case 'd':
case 'i':
- phase = qfs_arg_number(qfs, &vac, flags, width, precision,
+ phase = qfs_arg_integer(qfs, &vac, flags, width, precision,
ant) ;
break ;
case 'u':
- phase = qfs_arg_number(qfs, &vac, flags | pf_unsigned, width,
+ phase = qfs_arg_integer(qfs, &vac, flags | pf_unsigned, width,
+ precision, ant) ;
+ break ;
+
+ case 'o':
+ phase = qfs_arg_integer(qfs, &vac, flags | pf_oct, width,
precision, ant) ;
break ;
case 'x':
- phase = qfs_arg_number(qfs, &vac, flags | pf_hex_x, width,
+ phase = qfs_arg_integer(qfs, &vac, flags | pf_hex_x, width,
precision, ant) ;
break ;
case 'X':
- phase = qfs_arg_number(qfs, &vac, flags | pf_hex_X, width,
+ phase = qfs_arg_integer(qfs, &vac, flags | pf_hex_X, width,
precision, ant) ;
break ;
case 'p':
- if (phase == pfp_num_type)
+ if (phase == pfp_int_type)
phase = pfp_failed ;
else
- phase = qfs_arg_number(qfs, &vac, flags | pf_void_p, width,
+ phase = qfs_arg_integer(qfs, &vac, flags | pf_void_p, width,
precision, ant_ptr_t) ;
break ;
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ case 'g':
+ case 'G':
+ case 'a':
+ case 'A':
+ if (phase == pfp_int_type)
+ phase = pfp_failed ;
+ else
+ phase = qfs_arg_float(qfs, &vac, start, format - start,
+ ant) ;
+ break ;
+
default: /* unrecognised format */
phase = pfp_failed ;
break ;
@@ -1089,14 +1149,16 @@ qfs_arg_char(qf_str qfs, char ch, enum pf_flags flags, int width, int precision)
} ;
/*------------------------------------------------------------------------------
- * %d, %i, %u, %x, %X and %p handler
+ * %d, %i, %u, %o, %x, %X and %p handler
*
- * Accepts: pf_commas -- format with commas
+ * Accepts: pf_commas -- format with commas or '_' for hex (non-standard)
+ * ignored for octal.
* pf_minus -- left justify (any width will be -ve)
* pf_plus -- requires sign
* pf_space -- requires space or '-'
* pf_zeros -- zero fill to width
* pf_alt -- '0x' or '0X' for hex
+ * '0' for octal
*
* pf_precision -- precision specified
*
@@ -1107,16 +1169,24 @@ qfs_arg_char(qf_str qfs, char ch, enum pf_flags flags, int width, int precision)
*
* and: all the number argument types.
*
+ * Rejects: ant == ant_long_double -- which is how the parser spots an
+ * erroneous %Ld for example.
+ *
* This operation is async-signal-safe. Takes into account the offset, and
* adds up any overflow
*/
static enum pf_phase
-qfs_arg_number(qf_str qfs, va_list* p_va, enum pf_flags flags,
+qfs_arg_integer(qf_str qfs, va_list* p_va, enum pf_flags flags,
int width, int precision, enum arg_num_type ant)
{
uintmax_t u_val ;
intmax_t s_val ;
+ /* Reject if seen an 'L'
+ */
+ if (ant == ant_long_double)
+ return pfp_failed ;
+
/* Special for hex with '0... if no explicit precision, set -1 for byte
* and -2 for everything else -- see qfs_number().
*/
@@ -1208,3 +1278,99 @@ qfs_arg_number(qf_str qfs, va_list* p_va, enum pf_flags flags,
return pfp_done ;
} ;
+/*------------------------------------------------------------------------------
+ * %e, %E, %f, %F, %g, %G, %a and %A handler
+ *
+ * This uses the standard library sprintf() to do the business, so this is
+ * NOT async-signal-safe. This means that we get the full precision supported
+ * by the system ! Attempting to construct async-signal-safe conversion is
+ * doomed to failure, because any floating point operation may affect flags
+ * and other state in the processor :-(
+ *
+ * This operation is *NOT* async-signal-safe. Takes into account the offset,
+ * and adds up any overflow
+ */
+
+union float_value
+{
+ double d ;
+ long double ld ;
+} ;
+
+static int
+qfs_arg_float_snprintf(void* buf, int have, const char* format,
+ union float_value* p_val, enum arg_num_type ant)
+{
+ if (ant == ant_default)
+ return snprintf(buf, have, format, p_val->d) ;
+ else
+ return snprintf(buf, have, format, p_val->ld) ;
+} ;
+
+static enum pf_phase
+qfs_arg_float(qf_str qfs, va_list* p_va, const char* start, size_t flen,
+ enum arg_num_type ant)
+{
+ union float_value val ;
+ char format[flen + 1] ;
+ int want ;
+
+ if (ant == ant_default)
+ val.d = va_arg(*p_va, double) ;
+ else
+ val.ld = va_arg(*p_va, long double) ;
+
+ memcpy(format, start, flen) ;
+ format[flen + 1] = '\0' ;
+
+ if (qfs->offset == 0)
+ {
+ /* No offset, so can use the qfs directly.
+ */
+ int have ;
+
+ have = qfs_left(qfs) ;
+ want = qfs_arg_float_snprintf(qfs->ptr, have + 1, format, &val, ant) ;
+
+ if (want > 0)
+ {
+ if (want <= have)
+ qfs->ptr += want ;
+ else
+ {
+ qfs->ptr = qfs->end ;
+ qfs->overflow += (want - have) ;
+ } ;
+ } ;
+ }
+ else
+ {
+ /* Because the offset is not zero, need to use an intermediate
+ * buffer and then copy part after the offset.
+ *
+ * First, discover full extent of the formatted value, then if that
+ * exceeds the offset, construct buffer and copy what we can to the
+ * qps; otherwise, reduce the offset.
+ */
+ want = qfs_arg_float_snprintf(NULL, 0, format, &val, ant) ;
+
+ if (want > 0)
+ {
+ int take ;
+
+ take = qfs->offset + qfs_left(qfs) ;
+ if (take > want)
+ take = want ;
+
+ {
+ char tmp[take + 1] ;
+ want = qfs_arg_float_snprintf(tmp, take + 1, format, &val, ant) ;
+
+ if (want > 0)
+ qfs_append_n(qfs, tmp, want) ;
+ } ;
+ } ;
+ } ;
+
+ return (want >= 0) ? pfp_done : pfp_failed ;
+} ;
diff --git a/lib/qfstring.h b/lib/qfstring.h
index 03204c3d..be858899 100644
--- a/lib/qfstring.h
+++ b/lib/qfstring.h
@@ -26,11 +26,15 @@
#include "vargs.h"
/*==============================================================================
- * These "qfstrings" address the issues of dealing with *fixed* length
+ * These "qfstring" address the issues of dealing with *fixed* length
* strings, particularly where the string handling must be async-signal-safe.
*
* Are also used to support snprintf() style printing, but to one or more
* fixed length buffers.
+ *
+ * All operations that can possibly be async-signal-safe, are. Notable
+ * exception is anything involving floating point values -- because of the
+ * state contain in floating point status/option registers !
*/
/* When initialised a qf_string is set:
@@ -75,8 +79,9 @@ enum pf_flags
pf_precision = BIT( 7), /* '.' seen */
/* The following signal how to render the value */
- pf_hex = BIT( 8), /* hex */
- pf_uc = BIT( 9), /* upper-case */
+ pf_oct = BIT( 8), /* octal */
+ pf_hex = BIT( 9), /* hex */
+ pf_uc = BIT(10), /* upper-case */
/* The following signal the type of value */
pf_ptr = BIT(14), /* is a pointer */
diff --git a/lib/smux.c b/lib/smux.c
index df02dd44..cd3d2edf 100644
--- a/lib/smux.c
+++ b/lib/smux.c
@@ -38,6 +38,7 @@
#include <lib/version.h>
#include "memory.h"
#include "sockunion.h"
+#include "sockopt.h"
#include "smux.h"
#define min(A,B) ((A) < (B) ? (A) : (B))
@@ -215,8 +216,8 @@ smux_socket (void)
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sock < 0)
continue;
- sockopt_reuseaddr (sock);
- sockopt_reuseport (sock);
+ setsockopt_reuseaddr (sock);
+ setsockopt_reuseport (sock);
ret = connect (sock, res->ai_addr, res->ai_addrlen);
if (ret < 0)
{
@@ -251,8 +252,8 @@ smux_socket (void)
serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
- sockopt_reuseaddr (sock);
- sockopt_reuseport (sock);
+ setsockopt_reuseaddr (sock);
+ setsockopt_reuseport (sock);
ret = connect (sock, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
if (ret < 0)
diff --git a/lib/sockopt.c b/lib/sockopt.c
index aa747429..083cafc2 100644
--- a/lib/sockopt.c
+++ b/lib/sockopt.c
@@ -1,4 +1,4 @@
-/* setsockopt functions
+/* Setting and getting socket options -- utility functions.
* Copyright (C) 1999 Kunihiro Ishiguro
*
* This file is part of GNU Zebra.
@@ -20,218 +20,585 @@
*/
#include <zebra.h>
+
#include "log.h"
#include "sockopt.h"
#include "sockunion.h"
#include "pthread_safe.h"
-int
-setsockopt_so_recvbuf (int sock_fd, int size)
+/*------------------------------------------------------------------------------
+ * Set socket SO_REUSEADDR option
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_WARNING message if fails.
+ */
+extern int
+setsockopt_reuseaddr (int sock_fd)
{
int ret;
+ int on = 1;
- ret = setsockopt (sock_fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) ;
+ ret = setsockopt (sock_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if (ret < 0)
{
int err = errno ;
- zlog_err ("socket %d: cannot setsockopt SO_RCVBUF to %d: %s",
- sock_fd, size, errtoa(err, 0).str) ;
+ zlog_warn ("cannot set sockopt SO_REUSEADDR on socket %d: %s", sock_fd,
+ errtoa(err, 0).str) ;
errno = err ;
} ;
- return ret;
+ return ret ;
}
-int
-setsockopt_so_sendbuf (const int sock_fd, int size)
+/*------------------------------------------------------------------------------
+ * Set socket SO_REUSEPORT option -- if it is locally supported.
+ *
+ * Returns: >= 0 => OK -- or not supported
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_WARNING message if fails.
+ */
+extern int
+setsockopt_reuseport (int sock_fd)
{
- int ret ;
+ int ret;
- ret = setsockopt (sock_fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
+#ifdef SO_REUSEPORT
+ int on = 1;
+ ret = setsockopt (sock_fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
+#else
+ ret = 0 ;
+#endif
if (ret < 0)
{
int err = errno ;
- zlog_err ("socket %d: cannot setsockopt SO_SNDBUF to %d: %s",
- sock_fd, size, errtoa(err, 0).str) ;
+ zlog_warn ("cannot set sockopt SO_REUSEPORT on socket %d: %s", sock_fd,
+ errtoa(err, 0).str) ;
errno = err ;
} ;
- return ret;
+ return ret ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Set socket SO_BROADCAST option
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_WARNING message if fails.
+ */
+extern int
+setsockopt_broadcast (int sock_fd)
+{
+ int ret;
+ int on = 1;
+
+ ret = setsockopt (sock_fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
+ if (ret < 0)
+ {
+ int err = errno ;
+ zlog_warn ("cannot set sockopt SO_BROADCAST on socket %d: %s", sock_fd,
+ errtoa(err, 0).str) ;
+ errno = err ;
+ }
+ return ret ;
}
-int
-getsockopt_so_sendbuf (const int sock_fd)
+/*------------------------------------------------------------------------------
+ * Set TCP_CORK, if available.
+ *
+ * Returns: >= 0 => OK -- or not supported
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_WARNING message if fails.
+ */
+extern int
+setsockopt_cork (int sock_fd, int onoff)
{
- u_int32_t optval;
- socklen_t optlen = sizeof (optval);
+#ifdef TCP_CORK
+ int ret;
- int ret = getsockopt (sock_fd, SOL_SOCKET, SO_SNDBUF, &optval, &optlen);
+ ret = setsockopt (sock_fd, IPPROTO_TCP, TCP_CORK, &onoff, sizeof(onoff));
if (ret < 0)
- {
- int err = errno ;
- zlog_err ("socket %d: cannot getsockopt SO_SNDBUF: %s",
+ {
+ int err = errno ;
+ zlog_warn ("cannot set sockopt TCP_CORK to %d on socket %d: %s", onoff,
sock_fd, errtoa(err, 0).str) ;
- errno = err ;
- return ret;
- }
-
- return optval;
+ errno = err ;
+ }
+ return ret ;
+#else
+ return 0;
+#endif
}
-static void *
-getsockopt_cmsg_data (struct msghdr *msgh, int level, int type)
+/*------------------------------------------------------------------------------
+ * Set IP_TTL/IPV6_UNICAST_HOPS for socket, if available
+ *
+ * The ttl given is the maximum number of hops to allow -- so will generally
+ * be 1 or 255 or some small number.
+ *
+ * NB: This code treats any ttl outside the range 1..MAXTTL as MAXTTL.
+ *
+ * Returns: >= 0 => OK -- or not supported
+ * < 0 => failed, see errno.
+ *
+ * Logs a LOG_WARNING message if fails.
+ *
+ * NB: for AF_INET6 where have: IN6_IS_ADDR_V4MAPPED, there is the question
+ * of whether to use IPPROTO_IP/IP_TTL or IPPROTO_IPV6/IPV6_UNICAST_HOPS.
+ *
+ * Here we try first to use the socket family, and if that fails on
+ * AF_INET6, then if the protocol family is AF_INET, then tries that.
+ */
+extern int
+setsockopt_ttl (int sock_fd, int ttl)
{
- struct cmsghdr *cmsg;
- void *ptr = NULL;
+ const char* name ;
+ int af ;
+ int ret ;
- for (cmsg = ZCMSG_FIRSTHDR(msgh);
- cmsg != NULL;
- cmsg = CMSG_NXTHDR(msgh, cmsg))
- if (cmsg->cmsg_level == level && cmsg->cmsg_type)
- return (ptr = CMSG_DATA(cmsg));
+ af = sockunion_getsockfamily(sock_fd) ;
+ if (af < 0)
+ return af ;
- return NULL;
-}
+ if ((ttl < 1) || (ttl > MAXTTL))
+ ttl = MAXTTL ;
-#ifdef HAVE_IPV6
-/* Set IPv6 packet info to the socket. */
-int
-setsockopt_ipv6_pktinfo (int sock_fd, int val)
-{
- int ret;
+ ret = 0 ;
+ name = NULL ;
-#ifdef IPV6_RECVPKTINFO /*2292bis-01*/
- ret = setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val));
- if (ret < 0)
+ while (1)
{
- int err = errno ;
- zlog_warn ("cannot setsockopt IPV6_RECVPKTINFO: %s", errtoa(err, 0).str);
- errno = err ;
+ switch (af)
+ {
+ case AF_INET:
+#ifdef IP_TTL
+ ret = setsockopt (sock_fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
+ name = "IP_TTL" ;
+#endif /* IP_TTL */
+ break ;
+
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ ret = setsockopt (sock_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
+ &ttl, sizeof(ttl));
+ name = "IPV6_UNICAST_HOPS" ;
+
+ if (ret < 0)
+ {
+ af = sockunion_getprotofamily(sock_fd) ;
+ if (af == AF_INET)
+ continue ;
+ } ;
+ break ;
+#endif
+
+ default: /* ignore unknown family */
+ break ;
+ } ;
+
+ break ;
} ;
-#else /*RFC2292*/
- ret = setsockopt(sock_fd, IPPROTO_IPV6, IPV6_PKTINFO, &val, sizeof(val));
+
if (ret < 0)
{
int err = errno ;
- zlog_warn ("cannot setsockopt IPV6_PKTINFO: %s", errtoa(err, 0).str);
+ zlog_warn("cannot set sockopt %s to %d on socket %d: %s", name, ttl,
+ sock_fd, errtoa(err, 0).str) ;
errno = err ;
} ;
-#endif /* INIA_IPV6 */
- return ret;
-}
-/* Set multicast hops val to the socket. */
-int
-setsockopt_ipv6_checksum (int sock_fd, int val)
+ return ret ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Set IP_MINTTL/IPV6_MINHOPCOUNT (GTSM), if available.
+ *
+ * The ttl given is the maximum number of hops to allow -- so will generally
+ * be 1 -- which is the same as IP_TTL/IPV6_UNICAST_HOPS.
+ *
+ * NB: to turn off GTSM, need to set ttl = MAXTTL. This code treats any ttl
+ * outside the range 1..MAXTTL as MAXTTL.
+ *
+ * The underlying mechanics want MAX_TTL - (ttl - 1) -- and may not
+ * accept a value of zero.
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed or not supported -- see errno
+ * EOPNOTSUPP if not supported
+ *
+ * Logs a LOG_WARNING message if fails (and is supported).
+ *
+ * NB: for AF_INET6 where have: IN6_IS_ADDR_V4MAPPED, there is the question
+ * of whether to use IPPROTO_IP/IP_TTL or IPPROTO_IPV6/IPV6_UNICAST_HOPS.
+ *
+ * Here we try first to use the socket family, and if that fails on
+ * AF_INET6, then if the protocol family is AF_INET, then tries that.
+ */
+extern int
+setsockopt_minttl (int sock_fd, int ttl)
{
- int ret;
+ const char* name ;
+ int af ;
+ int minttl ;
+ int ret ;
-#ifdef GNU_LINUX
- ret = setsockopt(sock_fd, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val));
+ af = sockunion_getsockfamily(sock_fd) ;
+ if (af < 0)
+ return af ;
+
+ ret = 0 ;
+ name = NULL ;
+
+ if ((ttl < 1) || (ttl > MAXTTL))
+ ttl = MAXTTL ;
+
+ minttl = MAXTTL - (ttl - 1) ;
+
+ while (1)
+ {
+ enum
+ {
+#ifdef IP_MINTTL
+ have_ip_minttl = true,
#else
- ret = setsockopt(sock_fd, IPPROTO_IPV6, IPV6_CHECKSUM, &val, sizeof(val));
-#endif /* GNU_LINUX */
+ have_ip_minttl = false,
+#endif
+ ip_minttl = IP_MINTTL + 0
+ } ;
+
+#ifdef HAVE_IPV6
+
+# ifdef GNU_LINUX
+ /* The #include to bring in IPV6_MINHOPCOUNT is buried more or less as
+ * deep as we can get it, because it also redefines a number of things
+ * that we do not want redefined.
+ */
+ #include <linux/in6.h>
+# endif
+
+ enum
+ {
+# ifdef IPV6_MINHOPCOUNT
+ have_ipv6_minhopcount = true,
+# else
+ have_ipv6_minhopcount = false,
+# endif
+ ipv6_minhopcount = IPV6_MINHOPCOUNT + 0
+ } ;
+#endif /* HAVE_IPV6 */
+
+ switch (af)
+ {
+ case AF_INET:
+ name = "IP_MINTTL" ;
+ if (have_ip_minttl)
+ ret = setsockopt (sock_fd, IPPROTO_IP, ip_minttl,
+ &minttl, sizeof(minttl));
+ else
+ {
+ ret = -1 ;
+ errno = EOPNOTSUPP ;
+ } ;
+
+ break ;
+
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ name = "IPV6_MINHOPCOUNT" ;
+ if (have_ipv6_minhopcount)
+ ret = setsockopt (sock_fd, IPPROTO_IPV6, ipv6_minhopcount,
+ &minttl, sizeof(minttl));
+ else
+ {
+ ret = -1 ;
+ errno = EOPNOTSUPP ;
+ } ;
+
+ if (ret < 0)
+ {
+ af = sockunion_getprotofamily(sock_fd) ;
+ if (af == AF_INET)
+ continue ;
+ } ;
+
+ break ;
+#endif /* HAVE_IPV6 */
+
+ default: /* ignore unknown family */
+ break ;
+ } ;
+
+ break ;
+ } ;
+
if (ret < 0)
{
int err = errno ;
- zlog_warn ("cannot setsockopt IPV6_CHECKSUM: %s", errtoa(err, 0).str);
+ zlog_warn("cannot set sockopt %s to %d on socket %d: %s", name, minttl,
+ sock_fd, errtoa(err, 0).str) ;
errno = err ;
} ;
- return ret;
-}
-/* Set multicast hops val to the socket. */
-int
-setsockopt_ipv6_multicast_hops (int sock_fd, int val)
+ return ret ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Set TCP MD5 signature socket option, if available.
+ *
+ * A NULL password or an empty password both signify unsetting the MD5
+ * signature.
+ *
+ * Returns: >= 0 => OK (or not supported, but password NULL or empty)
+ * < 0 => failed or not supported, see errno.
+ *
+ * NB: returns EOPNOTSUPP if TCP MD5 is not supported and password is not NULL
+ * and is not empty.
+ *
+ * Logs a LOG_ERR message if fails (and is supported).
+ */
+extern int
+setsockopt_tcp_signature (int sock_fd, sockunion su, const char *password)
{
- int ret;
+ int ret ;
- ret = setsockopt(sock_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val,
- sizeof(val));
+ if ((password != NULL) && (*password == '\0'))
+ password = NULL ;
+
+ ret = 0 ; /* so far, so good */
+
+#if defined(HAVE_TCP_MD5_LINUX24) && defined(GNU_LINUX)
+ /* Support for the old Linux 2.4 TCP-MD5 patch, taken from Hasso Tepper's
+ * version of the Quagga patch (based on work by Rick Payne, and Bruce
+ * Simpson)
+ */
+#define TCP_MD5_AUTH 13
+#define TCP_MD5_AUTH_ADD 1
+#define TCP_MD5_AUTH_DEL 2
+ struct tcp_rfc2385_cmd {
+ u_int8_t command; /* Command - Add/Delete */
+ u_int32_t address; /* IPV4 address associated */
+ u_int8_t keylen; /* MD5 Key len (do NOT assume 0 terminated ascii) */
+ void *key; /* MD5 Key */
+ } cmd;
+ struct in_addr *addr = &su->sin.sin_addr;
+
+ cmd.command = (password != NULL ? TCP_MD5_AUTH_ADD : TCP_MD5_AUTH_DEL);
+ cmd.address = addr->s_addr;
+ cmd.keylen = (password != NULL ? strlen (password) : 0);
+ cmd.key = password;
+
+ ret = setsockopt (sock_fd, IPPROTO_TCP, TCP_MD5_AUTH, &cmd, sizeof cmd) ;
if (ret < 0)
{
int err = errno ;
- zlog_warn ("cannot setsockopt IPV6_MULTICAST_HOPS: %s",
- errtoa(err, 0).str);
+ zlog_err("sockopt_tcp_signature: setsockopt(%d): %s",
+ sock_fd, errtoa(err, 0).str) ;
errno = err ;
+ }
+
+#elif HAVE_DECL_TCP_MD5SIG
+
+# ifdef GNU_LINUX
+ struct tcp_md5sig md5sig ;
+# ifdef HAVE_IPV6
+ int saf ;
+ union sockunion sux[1] ;
+# endif
+
+ /* Testing reveals that in order to set an MD5 password for an AF_INET6
+ * socket, the address passed in must be AF_INET6, even if what we are
+ * dealing with here is an IN6_IS_ADDR_V4MAPPED socket.
+ */
+# ifdef HAVE_IPV6
+ saf = sockunion_getsockfamily(sock_fd) ;
+ if (saf < 0)
+ return saf ;
+
+ if ((saf == AF_INET6) && (sockunion_family(su) == AF_INET))
+ {
+ sockunion_copy (sux, su) ;
+ sockunion_map_ipv4 (sux) ;
+ su = sux ; /* substitute v4 mapped address */
} ;
- return ret;
-}
+# endif
-/* Set multicast hops val to the socket. */
-int
-setsockopt_ipv6_unicast_hops (int sock_fd, int val)
-{
- int ret;
+ /* Set address to AF_UNSPEC and key length and everything else to zero,
+ * then copy in the address and the key.
+ */
+ memset (&md5sig, 0, sizeof (md5sig)) ;
+ confirm(AF_UNSPEC == 0) ;
- ret = setsockopt(sock_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val));
- if (ret < 0)
+ memcpy (&md5sig.tcpm_addr, &su->sa, sockunion_get_len(su)) ;
+
+ if (password != NULL)
{
- int err = errno ;
- zlog_warn("cannot setsockopt IPV6_UNICAST_HOPS: %s", errtoa(err, 0).str);
- errno = err ;
+ size_t keylen = strlen(password) ;
+
+ if (md5sig.tcpm_keylen <= TCP_MD5SIG_MAXKEYLEN)
+ {
+ md5sig.tcpm_keylen = keylen ;
+ memcpy (md5sig.tcpm_key, password, keylen);
+ }
+ else
+ {
+ errno = EINVAL ; /* manufactured error */
+ ret = -1 ;
+ } ;
} ;
- return ret;
-}
-int
-setsockopt_ipv6_hoplimit (int sock_fd, int val)
-{
- int ret;
+# else
+ /*
+ * XXX Need to do PF_KEY operation here to add/remove an SA entry,
+ * and add/remove an SP entry for this peer's packet flows also.
+ */
+ int md5sig = (password != NULL) ? 1 : 0;
+
+# endif /* GNU_LINUX */
+
+ if (ret >= 0)
+ {
+ ret = setsockopt(sock_fd, IPPROTO_TCP, TCP_MD5SIG,
+ &md5sig, sizeof(md5sig)) ;
+ if (ret < 0)
+ /* ENOENT is harmless. It is returned when we clear a password where
+ * one was not previously set.
+ */
+ if ((errno == ENOENT) && (password == NULL))
+ ret = 0 ;
+ } ;
+
+#else
+
+ /* TCP MD5 is not supported */
+
+ if (password != NULL)
+ {
+ errno = EOPNOTSUPP ; /* manufactured error */
+ ret = -1 ;
+ } ;
+
+#endif /* !HAVE_TCP_MD5SIG */
-#ifdef IPV6_RECVHOPLIMIT /*2292bis-01*/
- ret = setsockopt (sock_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val,
- sizeof(val));
if (ret < 0)
{
int err = errno ;
- zlog_warn("cannot setsockopt IPV6_RECVHOPLIMIT: %s", errtoa(err, 0).str);
+ zlog_err("sockopt_tcp_signature: setsockopt(%d): %s",
+ sock_fd, errtoa(err, 0).str) ;
errno = err ;
} ;
-#else /*RFC2292*/
- ret = setsockopt (sock_fd, IPPROTO_IPV6, IPV6_HOPLIMIT, &val, sizeof(val));
+
+ return ret ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Set SO_RCVBUF option on socket.
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed, see errno.
+ *
+ * Logs a LOG_ERR message if fails
+ */
+extern int
+setsockopt_so_recvbuf (int sock_fd, int size)
+{
+ int ret;
+
+ ret = setsockopt (sock_fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) ;
if (ret < 0)
{
int err = errno ;
- zlog_warn ("cannot setsockopt IPV6_HOPLIMIT: %s", errtoa(err, 0).str);
+ zlog_err ("cannot set sockopt SO_RCVBUF to %d on socket %d: %s",
+ size, sock_fd, errtoa(err, 0).str) ;
errno = err ;
} ;
-#endif
+
return ret;
}
-/* Set multicast loop zero to the socket. */
-int
-setsockopt_ipv6_multicast_loop (int sock_fd, int val)
+/*------------------------------------------------------------------------------
+ * Set SO_SNDBUF option on socket.
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed, see errno.
+ *
+ * Logs a LOG_ERR message if fails
+ */
+extern int
+setsockopt_so_sendbuf (int sock_fd, int size)
{
- int ret;
+ int ret ;
+
+ ret = setsockopt (sock_fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
- ret = setsockopt (sock_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
- sizeof (val));
if (ret < 0)
{
int err = errno ;
- zlog_warn ("cannot setsockopt IPV6_MULTICAST_LOOP: %s",
- errtoa(err, 0).str);
+ zlog_err("cannot set sockopt SO_SNDBUF to %d on socket %d: %s",
+ size, sock_fd, errtoa(err, 0).str) ;
errno = err ;
} ;
+
return ret;
}
-static int
-getsockopt_ipv6_ifindex (struct msghdr *msgh)
+/*------------------------------------------------------------------------------
+ * Get SO_SNDBUF option value from socket.
+ *
+ * Returns: >= 0 => OK == value of option
+ * < 0 => failed, see errno.
+ *
+ * Logs a LOG_ERR message if fails
+ */
+extern int
+getsockopt_so_sendbuf (int sock_fd)
{
- struct in6_pktinfo *pktinfo;
+ u_int32_t optval;
+ socklen_t optlen = sizeof (optval);
- pktinfo = getsockopt_cmsg_data (msgh, IPPROTO_IPV6, IPV6_PKTINFO);
+ int ret = getsockopt (sock_fd, SOL_SOCKET, SO_SNDBUF, &optval, &optlen);
+ if (ret < 0)
+ {
+ int err = errno ;
+ zlog_err ("cannot get sockopt SO_SNDBUF on socket %d: %s",
+ sock_fd, errtoa(err, 0).str) ;
+ errno = err ;
+ return ret;
+ }
- return pktinfo->ipi6_ifindex;
+ return optval;
}
-#endif /* HAVE_IPV6 */
+/*------------------------------------------------------------------------------
+ * Set IP_TOS option for AF_INET socket.
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed, see errno.
+ *
+ * Logs a LOG_ERR message if fails
+ */
+extern int
+setsockopt_ipv4_tos(int sock_fd, int tos)
+{
+ int ret;
-/*
+ ret = setsockopt (sock_fd, IPPROTO_IP, IP_TOS, &tos, sizeof (tos));
+ if (ret < 0)
+ {
+ int err = errno ;
+ zlog_err("cannot set sockopt IP_TOS option %#x on socket %d: %s",
+ tos, sock_fd, errtoa(err, 0).str) ;
+ errno = err ;
+ } ;
+ return ret;
+} ;
+
+/*------------------------------------------------------------------------------
* Process multicast socket options for IPv4 in an OS-dependent manner.
* Supported options are IP_MULTICAST_IF and IP_{ADD,DROP}_MEMBERSHIP.
*
@@ -252,7 +619,7 @@ getsockopt_ipv6_ifindex (struct msghdr *msgh)
* but this behavior should not be harmful if they behave the same way,
* allow leaves, or implicitly leave all groups joined to down interfaces.
*/
-int
+extern int
setsockopt_multicast_ipv4(int sock_fd,
int optname,
struct in_addr if_addr /* required */,
@@ -365,27 +732,83 @@ setsockopt_multicast_ipv4(int sock_fd,
}
+/*==============================================================================
+ * Set pktinfo and get ifindex etc
+ */
+
+static int setsockopt_ipv4_pktinfo (int sock_fd, int val) ;
+static int getsockopt_ipv4_ifindex (struct msghdr *msgh) ;
+
+#ifdef HAVE_IPV6
+static int getsockopt_ipv6_ifindex (struct msghdr *msgh) ;
+#endif
+
+static void * getsockopt_cmsg_data (struct msghdr *msgh, int level, int type) ;
+
+/*------------------------------------------------------------------------------
+ * Set IP_PKTINFO/IP_RECVIF or IPV6_RECVPKTINFO/IPV6_PKTINFO -- if available.
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_ERR message if fails.
+ */
+extern int
+setsockopt_pktinfo (int af, int sock_fd, int val)
+{
+ int ret = -1;
+
+ switch (af)
+ {
+ case AF_INET:
+ ret = setsockopt_ipv4_pktinfo (sock_fd, val);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ ret = setsockopt_ipv6_pktinfo (sock_fd, val);
+ break;
+#endif
+ default:
+ zlog_warn("setsockopt_ifindex: unknown address family %d", af) ;
+ ret = -1 ;
+ errno = EINVAL;
+ break ;
+ }
+ return ret;
+}
+
+/*------------------------------------------------------------------------------
+ * Set IP_PKTINFO or IP_RECVIF -- if available.
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_ERR message if fails.
+ */
static int
-setsockopt_ipv4_ifindex (int sock_fd, int val)
+setsockopt_ipv4_pktinfo (int sock_fd, int val)
{
int ret;
-#if defined (IP_PKTINFO)
- ret = setsockopt (sock_fd, IPPROTO_IP, IP_PKTINFO, &val, sizeof (val)) ;
- if (ret < 0)
- {
- int err = errno ;
- zlog_warn ("Can't set IP_PKTINFO option for fd %d to %d: %s",
- sock_fd, val, errtoa(err, 0).str);
- errno = err ;
- } ;
-#elif defined (IP_RECVIF)
- ret = setsockopt (sock_fd, IPPROTO_IP, IP_RECVIF, &val, sizeof (val)) ;
+#if defined(IP_PKTINFO) || defined(IP_RECVIF)
+
+ int opt ;
+ const char* name ;
+
+# if defined(IP_PKTINFO)
+ opt = IP_PKTINFO ;
+ name = "IP_PKTINFO" ;
+# else
+ opt = IP_RECVIF ;
+ name = "IP_RECVIF" ;
+# endif
+
+ ret = setsockopt (sock_fd, IPPROTO_IP, opt, &val, sizeof (val)) ;
if (ret < 0)
{
int err = errno ;
- zlog_warn ("Can't set IP_RECVIF option for fd %d to %d: %s",
- sock_fd, val, errtoa(err, 0).str);
+ zlog_err("cannot set sockopt %s to %d on socket %d: %s", name,
+ val, sock_fd, errtoa(err, 0).str);
errno = err ;
} ;
#else
@@ -393,53 +816,82 @@ setsockopt_ipv4_ifindex (int sock_fd, int val)
#warning "Will not be able to receive link info."
#warning "Things might be seriously broken.."
/* XXX Does this ever happen? Should there be a zlog_warn message here? */
- ret = -1;
+ ret = -1;
+ errno = EOPNOTSUPP ; /* manufactured error */
#endif
return ret;
}
-int
-setsockopt_ipv4_tos(int sock_fd, int tos)
+/*------------------------------------------------------------------------------
+ * Set IPV6_RECVPKTINFO (RFC3542) or IPV6_RECVIF (RFC2292) -- if available.
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_ERR message if fails.
+ */
+#ifdef HAVE_IPV6
+extern int
+setsockopt_ipv6_pktinfo (int sock_fd, int val)
{
int ret;
+ int opt ;
+ const char* name ;
- ret = setsockopt (sock_fd, IPPROTO_IP, IP_TOS, &tos, sizeof (tos));
+# ifdef IPV6_RECVPKTINFO
+ opt = IPV6_RECVPKTINFO ; /* RFC3542 == RFC2292-bis */
+ name = "IPV6_RECVPKTINFO" ;
+# else
+ opt = IPV6_PKTINFO ; /* RFC2292 */
+ name = "IPV6_PKTINFO" ;
+# endif
+
+ ret = setsockopt(sock_fd, IPPROTO_IPV6, opt, &val, sizeof(val));
if (ret < 0)
{
int err = errno ;
- zlog_warn ("Can't set IP_TOS option for fd %d to %#x: %s",
- sock_fd, tos, errtoa(err, 0).str);
+ zlog_err("cannot set sockopt %s to %d on socket %d: %s", name,
+ val, sock_fd, errtoa(err, 0).str);
errno = err ;
} ;
+
return ret;
}
+#endif
-
-int
-setsockopt_ifindex (int af, int sock_fd, int val)
+/*------------------------------------------------------------------------------
+ * Given a struct msghdr*, extract and return ifindex.
+ *
+ * Returns: > 0 => OK == ifindex
+ * 0 => none found or error
+ *
+ * Note: this is badly named, since it is not really a getsockopt() operation,
+ * but extracting data from a sendmsg/recvmsg struct msghdr.
+ *
+ * To have the ifindex returned, need to have setsockopt_pktinfo().
+ */
+extern int
+getsockopt_ifindex (int af, struct msghdr *msgh)
{
- int ret = -1;
-
switch (af)
{
case AF_INET:
- ret = setsockopt_ipv4_ifindex (sock_fd, val);
- break;
+ return (getsockopt_ipv4_ifindex (msgh));
+
#ifdef HAVE_IPV6
case AF_INET6:
- ret = setsockopt_ipv6_pktinfo (sock_fd, val);
- break;
+ return (getsockopt_ipv6_ifindex (msgh));
#endif
+
default:
- zlog_warn ("setsockopt_ifindex: unknown address family %d", af);
- ret = -1 ;
- errno = EINVAL;
- break ;
+ zlog_warn ("getsockopt_ifindex: unknown address family %d", af);
+ return 0 ;
}
- return ret;
}
-/*
+/*------------------------------------------------------------------------------
+ * AF_INET: extract ifindex from struct msghdr, if can
+ *
* Requires: msgh is not NULL and points to a valid struct msghdr, which
* may or may not have control data about the incoming interface.
*
@@ -449,17 +901,17 @@ setsockopt_ifindex (int af, int sock_fd, int val)
static int
getsockopt_ipv4_ifindex (struct msghdr *msgh)
{
- /* XXX: initialize to zero? (Always overwritten, so just cosmetic.) */
- int ifindex = -1;
+ int ifindex ;
#if defined(IP_PKTINFO)
/* Linux pktinfo based ifindex retrieval */
struct in_pktinfo *pktinfo;
- pktinfo =
- (struct in_pktinfo *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_PKTINFO);
- /* XXX Can pktinfo be NULL? Clean up post 0.98. */
- ifindex = pktinfo->ipi_ifindex;
+ pktinfo = getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_PKTINFO);
+ if (pktinfo != NULL)
+ ifindex = pktinfo->ipi_ifindex ;
+ else
+ ifindex = 0 ;
#elif defined(IP_RECVIF)
@@ -510,34 +962,73 @@ getsockopt_ipv4_ifindex (struct msghdr *msgh)
return ifindex;
}
-/* return ifindex, 0 if none found */
-int
-getsockopt_ifindex (int af, struct msghdr *msgh)
+/*------------------------------------------------------------------------------
+ * AF_INET6: extract ifindex from struct msghdr, if can
+ *
+ * Requires: msgh is not NULL and points to a valid struct msghdr, which
+ * may or may not have control data about the incoming interface.
+ *
+ * Returns the interface index (small integer >= 1) if it can be
+ * determined, or else 0.
+ */
+#ifdef HAVE_IPV6
+static int
+getsockopt_ipv6_ifindex (struct msghdr *msgh)
{
- int ifindex = 0;
+ struct in6_pktinfo *pktinfo;
- switch (af)
- {
- case AF_INET:
- return (getsockopt_ipv4_ifindex (msgh));
- break;
-#ifdef HAVE_IPV6
- case AF_INET6:
- return (getsockopt_ipv6_ifindex (msgh));
- break;
+ pktinfo = getsockopt_cmsg_data (msgh, IPPROTO_IPV6, IPV6_PKTINFO);
+
+ if (pktinfo != NULL)
+ return pktinfo->ipi6_ifindex;
+ else
+ return 0 ;
+}
#endif
- default:
- zlog_warn ("getsockopt_ifindex: unknown address family %d", af);
- return (ifindex = 0);
- }
+
+/*------------------------------------------------------------------------------
+ * Scan msg_control portion of struct msghdr, looking for a cmsg with the given
+ * level and type.
+ *
+ * Requires: msgh is not NULL and points to a valid struct msghdr, which
+ * may or may not have control data about the incoming interface.
+ *
+ * Returns: address of data part of cmsg
+ * or: NULL => not found
+ */
+static void *
+getsockopt_cmsg_data (struct msghdr *msgh, int level, int type)
+{
+ struct cmsghdr *cmsg;
+
+ for (cmsg = ZCMSG_FIRSTHDR(msgh);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(msgh, cmsg))
+ if ((cmsg->cmsg_level == level) && (cmsg->cmsg_type == type))
+ return (void*)CMSG_DATA(cmsg);
+
+ return NULL;
}
-/* swab iph between order system uses for IP_HDRINCL and host order */
-void
+/*------------------------------------------------------------------------------
+ * swab iph between order system uses for IP_HDRINCL and host order
+ *
+ * This is done before handing struct ip to the system.
+ *
+ * There are four u_short fields in the IPv4 header:
+ *
+ * u_short ip_len -- convert to network order, except as noted below
+ * u_short ip_id -- convert to network order
+ * u_short ip_off -- convert to network order, except as noted below
+ * u_short ip_sum -- which we don't touch -- set by kernel
+ */
+extern void
sockopt_iphdrincl_swab_htosys (struct ip *iph)
{
- /* BSD and derived take iph in network order, except for
- * ip_len and ip_off
+ /* BSD and derived take iph in network order, except for ip_len and ip_off.
+ *
+ * So if *not* BSD-like, then need to convert ip_len and ip_off to network
+ * order.
*/
#ifndef HAVE_IP_HDRINCL_BSD_ORDER
iph->ip_len = htons(iph->ip_len);
@@ -547,7 +1038,12 @@ sockopt_iphdrincl_swab_htosys (struct ip *iph)
iph->ip_id = htons(iph->ip_id);
}
-void
+/*------------------------------------------------------------------------------
+ * swab iph between order system uses for IP_HDRINCL and host order
+ *
+ * This is done after receiving struct ip from the system -- see notes above.
+ */
+extern void
sockopt_iphdrincl_swab_systoh (struct ip *iph)
{
#ifndef HAVE_IP_HDRINCL_BSD_ORDER
@@ -559,190 +1055,171 @@ sockopt_iphdrincl_swab_systoh (struct ip *iph)
}
/*==============================================================================
- * Set TCP MD5 signature socket option.
+ * IPv6 Stuff
+ */
+#ifdef HAVE_IPV6
+
+/*------------------------------------------------------------------------------
+ * Set IPV6_V6ONLY.
*
* Returns: >= 0 => OK
- * < 0 => failed, see errno.
+ * < 0 => failed -- see errno
*
- * NB: returns ENOSYS if TCP MD5 is not supported
+ * Logs a LOG_ERR message if fails.
*/
-int
-sockopt_tcp_signature (int sock_fd, union sockunion *su, const char *password)
+extern int
+setsockopt_ipv6_v6only(int sock_fd)
{
-#if defined(HAVE_TCP_MD5_LINUX24) && defined(GNU_LINUX)
- int ret ;
-
- /* Support for the old Linux 2.4 TCP-MD5 patch, taken from Hasso Tepper's
- * version of the Quagga patch (based on work by Rick Payne, and Bruce
- * Simpson)
- */
-#define TCP_MD5_AUTH 13
-#define TCP_MD5_AUTH_ADD 1
-#define TCP_MD5_AUTH_DEL 2
- struct tcp_rfc2385_cmd {
- u_int8_t command; /* Command - Add/Delete */
- u_int32_t address; /* IPV4 address associated */
- u_int8_t keylen; /* MD5 Key len (do NOT assume 0 terminated ascii) */
- void *key; /* MD5 Key */
- } cmd;
- struct in_addr *addr = &su->sin.sin_addr;
-
- cmd.command = (password != NULL ? TCP_MD5_AUTH_ADD : TCP_MD5_AUTH_DEL);
- cmd.address = addr->s_addr;
- cmd.keylen = (password != NULL ? strlen (password) : 0);
- cmd.key = password;
-
- ret = setsockopt (sock_fd, IPPROTO_TCP, TCP_MD5_AUTH, &cmd, sizeof cmd) ;
-
- return (ret >= 0) ? 0 : -1 ;
-
-#elif HAVE_DECL_TCP_MD5SIG
- int ret, err ;
-# ifndef GNU_LINUX
- /*
- * XXX Need to do PF_KEY operation here to add/remove an SA entry,
- * and add/remove an SP entry for this peer's packet flows also.
- */
- int md5sig = password && *password ? 1 : 0;
-# else
- int keylen = password ? strlen (password) : 0 ;
- struct tcp_md5sig md5sig ;
- union sockunion *su2 ;
- union sockunion susock ;
+ int ret;
+ int on = 1 ;
- /* Figure out whether the socket and the sockunion are the same family..
- * adding AF_INET to AF_INET6 needs to be v4 mapped, you'd think..
- */
- ret = sockunion_getsockname(sock_fd, &susock) ;
+ ret = setsockopt (sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
if (ret < 0)
- return ret ;
-
- if (susock.sa.sa_family == su->sa.sa_family)
- su2 = su ;
- else
{
- /* oops.. */
- su2 = &susock ;
-
- if (su2->sa.sa_family == AF_INET)
- return 0 ; /* TODO: find out what this is doing ?? */
-
-# ifdef HAVE_IPV6
- /* If this does not work, then all users of this sockopt will need to
- * differentiate between IPv4 and IPv6, and keep separate sockets for
- * each.
- *
- * Sadly, it doesn't seem to work at present. It's unknown whether
- * this is a bug or not.
- */
- if (su2->sa.sa_family == AF_INET6
- && su->sa.sa_family == AF_INET)
- {
- su2->sin6.sin6_family = AF_INET6;
- /* V4Map the address */
- memset (&su2->sin6.sin6_addr, 0, sizeof (struct in6_addr));
- su2->sin6.sin6_addr.s6_addr[10] = 0xff ;
- su2->sin6.sin6_addr.s6_addr[11] = 0xff ;
-# ifdef s6_addr32
- su2->sin6.sin6_addr.s6_addr32[3] = su->sin.sin_addr.s_addr ;
-# else
- memcpy (&su2->sin6.sin6_addr.s6_addr[12], &su->sin.sin_addr, 4);
-# endif
- }
-# endif
+ int err = errno ;
+ zlog_err ("cannot set sockopt IPV6_V6ONLY on socket %d: %s",
+ sock_fd, errtoa(err, 0).str) ;
+ errno = err ;
}
+ return ret ;
+} ;
- memset (&md5sig, 0, sizeof (md5sig));
- memcpy (&md5sig.tcpm_addr, su2, sizeof (*su2));
- md5sig.tcpm_keylen = keylen;
- if (keylen)
- memcpy (md5sig.tcpm_key, password, keylen);
-
-# endif /* GNU_LINUX */
+/*------------------------------------------------------------------------------
+ * Set IPV6_CHECKSUM
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_ERR message if fails.
+ */
+extern int
+setsockopt_ipv6_checksum (int sock_fd, int val)
+{
+ int ret;
- err = 0 ;
- ret = setsockopt(sock_fd, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof(md5sig)) ;
+#ifdef GNU_LINUX
+ ret = setsockopt(sock_fd, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val));
+#else
+ ret = setsockopt(sock_fd, IPPROTO_IPV6, IPV6_CHECKSUM, &val, sizeof(val));
+#endif /* GNU_LINUX */
if (ret < 0)
{
- err = errno ;
- /* ENOENT is harmless. It is returned when we clear a password for which
- one was not previously set. */
- if (err == ENOENT)
- err = 0 ;
- else
- {
- zlog_err ("sockopt_tcp_signature: setsockopt(%d): %s",
+ int err = errno ;
+ zlog_err("cannot set sockopt IPV6_CHECKSUM to %d on socket %d: %s", val,
sock_fd, errtoa(err, 0).str) ;
- errno = err ;
- } ;
- }
-
- return (err == 0) ? 0 : -1 ;
-
-#else
+ errno = err ;
+ } ;
+ return ret;
+}
- /* TCP MD5 is not supported */
+/*------------------------------------------------------------------------------
+ * Set unicast hops val to the socket (cf IP_TTL).
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_ERR message if fails.
+ */
+extern int
+setsockopt_ipv6_unicast_hops (int sock_fd, int val)
+{
+ int ret;
- if ((password == NULL) || (*password == '\0'))
- return 0 ; /* OK if not required ! */
+ ret = setsockopt(sock_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val));
+ if (ret < 0)
+ {
+ int err = errno ;
+ zlog_err("cannot set sockopt IPV6_UNICAST_HOPS to %d on socket %d: %s",
+ val, sock_fd, errtoa(err, 0).str) ;
+ errno = err ;
+ } ;
+ return ret;
+}
- errno = ENOSYS ; /* manufactured error */
- return -1 ;
+/*------------------------------------------------------------------------------
+ * Set multicast hops val to the socket.
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_ERR message if fails.
+ */
+extern int
+setsockopt_ipv6_multicast_hops (int sock_fd, int val)
+{
+ int ret;
-#endif /* !HAVE_TCP_MD5SIG */
-} ;
+ ret = setsockopt(sock_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val,
+ sizeof(val));
+ if (ret < 0)
+ {
+ int err = errno ;
+ zlog_err("cannot set sockopt IPV6_MULTICAST_HOPS to %d on socket %d: %s",
+ val, sock_fd, errtoa(err, 0).str) ;
+ errno = err ;
+ } ;
+ return ret;
+}
-/*==============================================================================
- * Set TTL for socket
+/*------------------------------------------------------------------------------
+ * Set IPV6_RECVHOPLIMIT option (or IPV6_HOPLIMIT)
*
* Returns: >= 0 => OK
- * < 0 => failed, see errno.
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_ERR message if fails.
*/
-int
-sockopt_ttl (int sock_fd, int ttl)
+extern int
+setsockopt_ipv6_hoplimit (int sock_fd, int val)
{
- const char* msg ;
- int ret ;
- int family ;
-
- ret = 0 ;
- msg = NULL ;
+ int ret;
+ int opt ;
+ const char* name ;
- family = sockunion_getsockfamily(sock_fd) ;
- if (family < 0)
- return -1 ;
+# ifdef IPV6_RECVHOPLIMIT
+ opt = IPV6_RECVHOPLIMIT ; /* RFC3542 == RFC2292-bis */
+ name = "IPV6_RECVHOPLIMIT" ;
+# else
+ opt = IPV6_HOPLIMIT ; /* RFC2292 */
+ name = "IPV6_HOPLIMIT" ;
+# endif
- switch (family)
- {
- case AF_INET:
-#ifdef IP_TTL
- ret = setsockopt (sock_fd, IPPROTO_IP, IP_TTL,(void*)&ttl, sizeof(int));
- msg = "IP_TTL" ;
-#endif /* IP_TTL */
- break ;
+ ret = setsockopt(sock_fd, IPPROTO_IPV6, opt, &val, sizeof(val));
+ if (ret < 0)
+ {
+ int err = errno ;
+ zlog_err("cannot set sockopt %s to %d on socket %d: %s", name,
+ val, sock_fd, errtoa(err, 0).str);
+ errno = err ;
+ } ;
-#ifdef HAVE_IPV6
- case AF_INET6:
- ret = setsockopt (sock_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
- (void*)&ttl, sizeof(int));
- msg = "IPV6_UNICAST_HOPS" ;
- break ;
-#endif
+ return ret;
+}
- default: /* ignore unknown family */
- ret = 0 ;
- break ;
- } ;
+/*------------------------------------------------------------------------------
+ * Set IPV6_MULTICAST_LOOP option
+ *
+ * Returns: >= 0 => OK
+ * < 0 => failed -- see errno
+ *
+ * Logs a LOG_ERR message if fails.
+ */
+extern int
+setsockopt_ipv6_multicast_loop (int sock_fd, int val)
+{
+ int ret;
- if (ret != 0)
+ ret = setsockopt (sock_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
+ sizeof (val));
+ if (ret < 0)
{
int err = errno ;
- zlog (NULL, LOG_WARNING,
- "cannot set sockopt %s %d to socket %d: %s", msg, ttl, sock_fd,
- errtoa(err, 0).str) ;
+ zlog_err("cannot set sockopt IPV6_MULTICAST_LOOP to %d on socket %d: %s",
+ val, sock_fd, errtoa(err, 0).str);
errno = err ;
- return -1 ;
} ;
+ return ret;
+}
+#endif /* HAVE_IPV6 */
+
- return 0 ;
-} ;
diff --git a/lib/sockopt.h b/lib/sockopt.h
index ad86f053..c706a74f 100644
--- a/lib/sockopt.h
+++ b/lib/sockopt.h
@@ -1,4 +1,4 @@
-/* Router advertisement
+/* Setting and getting socket options -- utility functions.
* Copyright (C) 1999 Kunihiro Ishiguro
*
* This file is part of GNU Zebra.
@@ -24,18 +24,20 @@
#include "sockunion.h"
+extern int setsockopt_reuseaddr (int sock_fd) ;
+extern int setsockopt_reuseport (int sock_fd) ;
+extern int setsockopt_broadcast (int sock_fd) ;
+
+extern int setsockopt_ttl (int sock_fd, int ttl);
+extern int setsockopt_minttl (int sock_fd, int ttl);
+extern int setsockopt_cork (int sock_fd, int onoff);
+
extern int setsockopt_so_recvbuf (int sock_fd, int size);
-extern int setsockopt_so_sendbuf (const int sock_fd, int size);
-extern int getsockopt_so_sendbuf (const int sock_fd);
+extern int setsockopt_so_sendbuf (int sock_fd, int size);
+extern int getsockopt_so_sendbuf (int sock_fd);
-#ifdef HAVE_IPV6
-extern int setsockopt_ipv6_pktinfo (int, int);
-extern int setsockopt_ipv6_checksum (int, int);
-extern int setsockopt_ipv6_multicast_hops (int, int);
-extern int setsockopt_ipv6_unicast_hops (int, int);
-extern int setsockopt_ipv6_hoplimit (int, int);
-extern int setsockopt_ipv6_multicast_loop (int, int);
-#endif /* HAVE_IPV6 */
+extern int setsockopt_tcp_signature(int sock_fd, union sockunion *su,
+ const char *password);
/*
* It is OK to reference in6_pktinfo here without a protecting #if
@@ -92,7 +94,7 @@ extern int setsockopt_multicast_ipv4(int sock_fd, int optname,
extern int setsockopt_ipv4_tos(int sock_fd, int tos);
/* Ask for, and get, ifindex, by whatever method is supported. */
-extern int setsockopt_ifindex (int, int, int);
+extern int setsockopt_pktinfo (int, int, int);
extern int getsockopt_ifindex (int, struct msghdr *);
/* swab the fields in iph between the host order and system order expected
@@ -101,7 +103,16 @@ extern int getsockopt_ifindex (int, struct msghdr *);
extern void sockopt_iphdrincl_swab_htosys (struct ip *iph);
extern void sockopt_iphdrincl_swab_systoh (struct ip *iph);
-extern int sockopt_ttl (int sock_fd, int ttl);
-extern int sockopt_tcp_signature(int sock_fd, union sockunion *su,
- const char *password);
+#ifdef HAVE_IPV6
+
+extern int setsockopt_ipv6_v6only(int sock_fd) ;
+extern int setsockopt_ipv6_pktinfo (int, int);
+extern int setsockopt_ipv6_checksum (int, int);
+extern int setsockopt_ipv6_multicast_hops (int, int);
+extern int setsockopt_ipv6_unicast_hops (int, int);
+extern int setsockopt_ipv6_hoplimit (int, int);
+extern int setsockopt_ipv6_multicast_loop (int, int);
+
+#endif /* HAVE_IPV6 */
+
#endif /*_ZEBRA_SOCKOPT_H */
diff --git a/lib/sockunion.c b/lib/sockunion.c
index deac292c..9084c27e 100644
--- a/lib/sockunion.c
+++ b/lib/sockunion.c
@@ -249,11 +249,36 @@ sockunion_init_new(sockunion su, sa_family_t family)
if (family != AF_UNSPEC)
sockunion_set_family(su, family) ;
+ else
+ confirm(AF_UNSPEC == 0) ;
return su ;
} ;
/*------------------------------------------------------------------------------
+ * Get the length of the address in the given sockunion.
+ *
+ * Returns zero if AF_UNSPEC or not any known address family.
+ */
+extern int
+sockunion_get_len(sockunion su)
+{
+ switch (su->sa.sa_family)
+ {
+ case AF_INET:
+ return sizeof(struct sockaddr_in) ;
+
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6) ;
+#endif
+
+ default:
+ return 0 ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
* From the given string, fill in the given sockunion.
*
* Returns: 0 => OK -- sockunion filled in
@@ -357,20 +382,19 @@ sockunion_su2str (union sockunion *su, enum MTYPE type)
* If have an IPv6 mapped IPv4 address, convert it to an IPv4 address.
*/
extern void
-sockunion_unmap_ipv4 (union sockunion *su)
+sockunion_unmap_ipv4 (sockunion su)
{
#ifdef HAVE_IPV6
- union sockunion sux ;
- struct sockaddr_in* su_in = &sux.sin ;
-
- if ( (su->sa.sa_family == AF_INET6)
- && IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr) )
+ if ( (sockunion_family(su) == AF_INET6)
+ && IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr) )
{
- sockunion_init_new(&sux, AF_INET) ;
- memcpy (&su_in->sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4) ;
- su_in->sin_port = su->sin6.sin6_port ;
- memcpy (su, &sux, sizeof(sux)) ;
- confirm(sizeof(*su) == sizeof(sux)) ;
+ union sockunion sux[1] ;
+
+ sockunion_init_new(sux, AF_INET) ;
+ memcpy (&sux->sin.sin_addr, &su->sin6.sin6_addr.s6_addr[12], 4) ;
+ sux->sin.sin_port = su->sin6.sin6_port ;
+ memcpy (su, sux, sizeof(*sux)) ;
+ confirm(sizeof(*su) == sizeof(*sux)) ;
}
#endif /* HAVE_IPV6 */
}
@@ -379,20 +403,19 @@ sockunion_unmap_ipv4 (union sockunion *su)
* If have an IPv4 address, convert it to an IPv6 mapped IPv4 address.
*/
extern void
-sockunion_map_ipv4 (union sockunion *su)
+sockunion_map_ipv4 (sockunion su)
{
#ifdef HAVE_IPV6
- union sockunion sux ;
- struct sockaddr_in6* su_in6 = &sux.sin6 ;
-
- if (su->sa.sa_family == AF_INET)
+ if (sockunion_family(su) == AF_INET)
{
- sockunion_init_new(&sux, AF_INET6) ;
- memset (((char *)&su_in6->sin6_addr) + 10, 0xFF, 2) ;
- memcpy (((char *)&su_in6->sin6_addr) + 12, &su->sin.sin_addr, 4) ;
- su_in6->sin6_port = su->sin.sin_port ;
- memcpy (su, &sux, sizeof(sux)) ;
- confirm(sizeof(*su) == sizeof(sux)) ;
+ union sockunion sux[1] ;
+
+ sockunion_init_new(sux, AF_INET6) ;
+ memset (&sux->sin6.sin6_addr.s6_addr[10], 0xFF, 2) ;
+ memcpy (&sux->sin6.sin6_addr.s6_addr[12], &su->sin.sin_addr, 4) ;
+ sux->sin6.sin6_port = su->sin.sin_port ;
+ memcpy (su, sux, sizeof(*sux)) ;
+ confirm(sizeof(*su) == sizeof(*sux)) ;
}
#endif /* HAVE_IPV6 */
}
@@ -414,7 +437,7 @@ sockunion_map_ipv4 (union sockunion *su)
* -1 -- error -- not one of the above
* -2 -- error -- one of the above
*/
-int
+extern int
sockunion_accept (int sock_fd, union sockunion *su)
{
socklen_t len;
@@ -443,23 +466,22 @@ sockunion_accept (int sock_fd, union sockunion *su)
* Returns: -1 : failed -- see errno
* otherwise : socket
*
- * Logs a LOG_WARNING message if fails.
+ * Logs a LOG_ERR message if fails.
*/
extern int
-sockunion_socket(sa_family_t family, int type, int protocol)
+sockunion_socket(sockunion su, int type, int protocol)
{
int sock_fd ;
int err ;
- sock_fd = socket(family, type, protocol);
+ sock_fd = socket(sockunion_family(su), type, protocol);
if (sock_fd >= 0)
return sock_fd ;
err = errno ;
- zlog (NULL, LOG_WARNING,
- "Cannot make socket family=%d, type=%d, protocol=%d: %s",
- (int)family, type, protocol, errtoa(err, 0).str) ;
+ zlog_err("Cannot make socket family=%d, type=%d, protocol=%d: %s",
+ (int)sockunion_family(su), type, protocol, errtoa(err, 0).str) ;
errno = err ;
return -1;
}
@@ -470,15 +492,15 @@ sockunion_socket(sa_family_t family, int type, int protocol)
* Returns: -1 : failed -- see errno
* otherwise : socket
*
- * Logs a LOG_WARNING message if fails.
+ * Logs a LOG_ERR message if fails.
*/
-int
-sockunion_stream_socket (union sockunion *su)
+extern int
+sockunion_stream_socket (sockunion su)
{
if (su->sa.sa_family == 0)
su->sa.sa_family = AF_INET_UNION;
- return sockunion_socket (su->sa.sa_family, SOCK_STREAM, 0);
+ return sockunion_socket (su, SOCK_STREAM, 0);
}
/*------------------------------------------------------------------------------
@@ -541,25 +563,24 @@ sockunion_connect(int sock_fd, union sockunion* peer_su, unsigned short port,
/*------------------------------------------------------------------------------
* Start listening on given socket
*
- * Returns: 0 : OK (so far so good)
- * < 0 : failed -- see errno
+ * Returns: >= 0 : OK (so far so good)
+ * < 0 : failed -- see errno
*
- * Logs a LOG_WARNING message if fails.
+ * Logs a LOG_ERR message if fails.
*/
extern int
sockunion_listen(int sock_fd, int backlog)
{
- int ret, err ;
+ int ret ;
ret = listen(sock_fd, backlog) ;
- if (ret == 0)
- return 0 ;
-
- err = errno ;
- zlog (NULL, LOG_WARNING, "cannot listen on socket %d: %s",
- sock_fd, errtoa(err, 0).str) ;
- errno = err ;
+ if (ret < 0)
+ {
+ int err = errno ;
+ zlog_err("cannot listen on socket %d: %s", sock_fd, errtoa(err, 0).str) ;
+ errno = err ;
+ } ;
return ret ;
} ;
@@ -567,28 +588,72 @@ sockunion_listen(int sock_fd, int backlog)
/*------------------------------------------------------------------------------
* Bind socket to address/port.
*
- * Sets the given port into the sockunion su.
+ * If the 'any' parameter is true, sets the given sockunion to INADDR_ANY or
+ * the *socket* address family equivalent.
*
- * If the 'any' parameter is NULL, set the address part of sockunion to
- * INADDR_ANY or the family equivalent. Note that for IPv6 this does not
- * affect the flow/scope in the su.
+ * Sets the given port into the sockunion su.
*
* For good measure, sets sin_len or family equivalent if required.
*
+ * If not 'any', and the given su does not have the same address family as the
+ * socket, then attempts to convert the su to the same family as the socket,
+ * by mapping or unmapping IPv4.
+ *
* Performs bind() and logs a LOG_WARNING message if fails.
*
* Returns: >= 0 => OK
* < 0 => failed -- see errno
*/
-int
-sockunion_bind (int sock_fd, union sockunion *su, unsigned short port,
- void* any)
+extern int
+sockunion_bind(int sock_fd, sockunion su, unsigned short port, bool any)
{
int sa_len ;
int ret ;
+ int sock_family ;
- if (any == NULL)
- sockunion_set_addr_any(su) ;
+ sock_family = sockunion_getsockfamily(sock_fd) ;
+
+ if (any)
+ {
+ /* Create an "any" -- of same family as the socket */
+ sockunion_init_new(su, sock_family) ;
+ sockunion_set_addr_any(su) ;
+ }
+ else
+ {
+ /* Want to bind to a specific address.
+ *
+ * We provide bind with an address which matches the address family of
+ * the *socket*.
+ *
+ * If the socket is AF_INET, address may be AF_INET, or an AF_INET6
+ * *provided* it is an IPv4 mapped address.
+ *
+ * If the socket is AF_INET6, address may be AF_INET or AF_NET6, and
+ * will map any IPv4 address.
+ *
+ * If we don't HAVE_IPV6, or we don't recognise an address family,
+ * then do nothing and let bind() return some sort of error.
+ */
+#ifdef HAVE_IPV6
+ if (sock_family != sockunion_family(su))
+ {
+ switch (sock_family)
+ {
+ case AF_INET:
+ sockunion_unmap_ipv4(su) ; /* unmap if AF_INET6 mapped IPv4 */
+ break ;
+
+ case AF_INET6:
+ sockunion_map_ipv4(su) ; /* map if AF_INET */
+ break ;
+
+ default:
+ break ;
+ } ;
+ } ;
+#endif
+ } ;
sa_len = sockunion_set_port(su, port) ;
@@ -596,7 +661,7 @@ sockunion_bind (int sock_fd, union sockunion *su, unsigned short port,
if (ret < 0)
{
int err = errno ;
- zlog (NULL, LOG_WARNING, "cannot bind to %s port %d socket %d: %s",
+ zlog_warn("cannot bind to %s port %d socket %d: %s",
sutoa(su).str, port, sock_fd, errtoa(err, 0).str) ;
errno = err ;
} ;
@@ -605,72 +670,11 @@ sockunion_bind (int sock_fd, union sockunion *su, unsigned short port,
}
/*------------------------------------------------------------------------------
- * Set socket SO_REUSEADDR option
- *
- * Returns: >= 0 => OK
- * < 0 => failed -- see errno
- *
- * Logs a LOG_WARNING message if fails.
- */
-int
-sockopt_reuseaddr (int sock_fd)
-{
- int ret;
- int on = 1;
-
- ret = setsockopt (sock_fd, SOL_SOCKET, SO_REUSEADDR, (void *) &on,
- sizeof (on));
- if (ret < 0)
- {
- int err = errno ;
- zlog (NULL, LOG_WARNING,
- "cannot set sockopt SO_REUSEADDR to socket %d: %s", sock_fd,
- errtoa(err, 0).str) ;
- errno = err ;
- } ;
-
- return ret ;
-}
-
-/*------------------------------------------------------------------------------
- * Set socket SO_REUSEPORT option -- if it is locally supported.
- *
- * Returns: >= 0 => OK
- * < 0 => failed -- see errno
- *
- * Logs a LOG_WARNING message if fails.
- */
-int
-sockopt_reuseport (int sock_fd)
-{
- int ret;
-
-#ifdef SO_REUSEPORT
- int on = 1;
- ret = setsockopt (sock_fd, SOL_SOCKET, SO_REUSEPORT,
- (void *) &on, sizeof (on));
-#else
- ret = 0 ;
-#endif
-
- if (ret < 0)
- {
- int err = errno ;
- zlog (NULL, LOG_WARNING,
- "cannot set sockopt SO_REUSEPORT to socket %d: %s", sock_fd,
- errtoa(err, 0).str) ;
- errno = err ;
- } ;
-
- return ret ;
-} ;
-
-/*------------------------------------------------------------------------------
- * If same family and same prefix return 1.
+ * If same (known) family and same prefix return 1, otherwise return 0.
*
* Returns 0 if same family, but not a known family.
*/
-int
+extern int
sockunion_same (union sockunion *su1, union sockunion *su2)
{
int ret = 0;
@@ -686,7 +690,7 @@ sockunion_same (union sockunion *su1, union sockunion *su2)
#ifdef HAVE_IPV6
case AF_INET6:
ret = memcmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr,
- sizeof (struct in6_addr));
+ sizeof (struct in6_addr));
return (ret == 0) ;
#endif /* HAVE_IPV6 */
@@ -696,125 +700,142 @@ sockunion_same (union sockunion *su1, union sockunion *su2)
} ;
/*------------------------------------------------------------------------------
- * Get the address family the given socket is set to.
+ * Get local (getsockname) or remote (getpeername) address and port.
*
* Returns: >= 0 == the address family (AF_UNSPEC if fd sock_fd < 0)
* < 0 => failed -- see errno
*
- * NB: gets the actual address family -- does NOT look for mapped IPv4.
- */
-extern int
-sockunion_getsockfamily(int sock_fd)
-{
- union sockunion su ;
- int ret ;
- socklen_t len ;
-
- if (sock_fd < 0)
- return AF_UNSPEC ;
-
- sockunion_init_new(&su, AF_UNSPEC) ;
- len = sizeof(su) ;
-
- ret = getsockname(sock_fd, (struct sockaddr *)&su, &len) ;
- if (ret < 0)
- {
- int err = errno ;
- zlog_warn ("Failed in getsockname for socket %d: %s",
- sock_fd, errtoa(err, 0).str) ;
- errno = err ;
- return -1 ;
- } ;
-
- return su.sa.sa_family ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Get local or remote address and port.
- *
- * Returns: >= 0 => OK
- * < 0 => failed (or unknown family) -- see errno
- *
- * If address is an IPv4 mapped IPv6 address, returns the IPv4 address.
+ * If "unmap": if address is an IPv4 mapped IPv6 address, returns AF_INET.
*
* NB: returns EAFNOSUPPORT if don't recognise the address family.
+ *
+ * Logs a LOG_ERR message if fails in getsockname/getpeername.
*/
static int
-sockunion_get_name(int sock_fd, union sockunion* su, int local)
+sockunion_get_name(int sock_fd, union sockunion* su, bool local, bool unmap)
{
int ret ;
-
+ socklen_t len ;
union
{
- struct sockaddr sa;
- struct sockaddr_in sin;
-#ifdef HAVE_IPV6
- struct sockaddr_in6 sin6;
-#endif /* HAVE_IPV6 */
+ union sockunion su ;
char tmp_buffer[128];
} name ;
- socklen_t len = sizeof(name) ;
+ memset(su, 0, sizeof(union sockunion)) ;
+
+ confirm(AF_UNSPEC == 0) ;
+ if (sock_fd < 0)
+ return AF_UNSPEC ;
+
+ len = sizeof(name) ;
memset(&name, 0, len);
- memset(su, 0, sizeof(union sockunion)) ;
- if (local)
- ret = getsockname(sock_fd, (struct sockaddr *)&name, &len) ;
+ if (local)
+ ret = getsockname(sock_fd, &name.su.sa, &len) ;
else
- ret = getpeername(sock_fd, (struct sockaddr *)&name, &len) ;
+ ret = getpeername(sock_fd, &name.su.sa, &len) ;
if (ret < 0)
{
int err = errno ;
- zlog_warn ("Cannot get %s address and port: %s",
- local ? "local" : "remote", errtoa(err, 0).str) ;
+ zlog_err("failed in %s for socket %d: %s",
+ local ? "getsockname" : "getpeername",
+ sock_fd, errtoa(err, 0).str) ;
errno = err ;
- return ret ;
}
+ else
+ {
+ ret = name.su.sa.sa_family ;
- ret = 0 ; /* assume all will be well */
- switch (name.sa.sa_family)
- {
- case AF_INET:
- memcpy(su, &name, sizeof (struct sockaddr_in)) ;
- break ;
+ switch (ret)
+ {
+ case AF_INET:
+ su->sin = name.su.sin ;
+ break ;
#ifdef HAVE_IPV6
- case AF_INET6:
- memcpy(su, &name, sizeof (struct sockaddr_in6)) ;
- sockunion_unmap_ipv4(su) ;
- break ;
+ case AF_INET6:
+ su->sin6 = name.su.sin6 ;
+ if (unmap)
+ sockunion_unmap_ipv4(su) ;
+ break ;
#endif /* HAVE_IPV6 */
- default:
- errno = EAFNOSUPPORT ;
- ret = -1 ;
- } ;
+ default:
+ errno = EAFNOSUPPORT ;
+ ret = -1 ;
+ } ;
+ } ;
return ret ;
} ;
/*------------------------------------------------------------------------------
- * Get local address and port -- ie getsockname().
+ * Get the address family the given socket is set to.
+ *
+ * Returns: >= 0 == the address family (AF_UNSPEC if fd sock_fd < 0)
+ * < 0 => failed -- see errno
+ *
+ * NB: gets the actual address family -- does NOT look for mapped IPv4.
+ */
+extern int
+sockunion_getsockfamily(int sock_fd)
+{
+ union sockunion su[1] ;
+ int ret ;
+
+ ret = sockunion_get_name(sock_fd, su, true, /* true => local */
+ false) ; /* false => don't unmap */
+ return (ret >= 0) ? sockunion_family(su) : ret ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Get the address family the given socket's protocol is set to.
+ *
+ * If this is an AF_INET, that's easy.
+ *
+ * If this is an AF_INET6, then needs to look out for IN6_IS_ADDR_V4MAPPED.
+ *
+ * Returns: >= 0 == the address family (AF_UNSPEC if fd sock_fd < 0)
+ * < 0 => failed -- see errno
+ *
+ * NB: gets the underlying address family -- ie: looks for mapped IPv4.
+ */
+extern int
+sockunion_getprotofamily(int sock_fd)
+{
+ union sockunion su[1] ;
+ int ret ;
+
+ ret = sockunion_get_name(sock_fd, su, true, /* true => local */
+ true) ; /* true => unmap */
+ return (ret >= 0) ? sockunion_family(su) : ret ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Get local address and port -- ie getsockname(), except unmaps IPv4 mapped.
*
* See: sockunion_get_name()
*/
-int
-sockunion_getsockname(int sock_fd, union sockunion* su_local)
+extern int
+sockunion_getsockname(int sock_fd, sockunion su_local)
{
- return sockunion_get_name(sock_fd, su_local, 1) ;
+ return sockunion_get_name(sock_fd, su_local, true, /* true => local */
+ true) ; /* true => unmap */
} ;
/*------------------------------------------------------------------------------
- * Get remote address and port -- ie getpeername().
+ * Get remote address and port -- ie getpeername(), except unmaps IPv4 mapped.
*
* See: sockunion_get_name()
*/
-int
-sockunion_getpeername (int sock_fd, union sockunion* su_remote)
+extern int
+sockunion_getpeername (int sock_fd, sockunion su_remote)
{
- return sockunion_get_name(sock_fd, su_remote, 0) ;
+ return sockunion_get_name(sock_fd, su_remote, false, /* false => remote */
+ true) ; /* true => unmap */
} ;
/*------------------------------------------------------------------------------
diff --git a/lib/sockunion.h b/lib/sockunion.h
index 0b23ae63..eeae72d5 100644
--- a/lib/sockunion.h
+++ b/lib/sockunion.h
@@ -24,6 +24,7 @@
#define _ZEBRA_SOCKUNION_H
#include "zebra.h"
+#include <stdbool.h>
#include "symtab.h"
#include "prefix.h"
#include "memory.h"
@@ -101,36 +102,36 @@ struct sockunion_string
/* Prototypes. */
extern sockunion sockunion_init_new(sockunion su, sa_family_t family) ;
+extern int sockunion_get_len(sockunion su) ;
extern int sockunion_set_port(sockunion su, in_port_t port) ;
-extern int str2sockunion (const char *, union sockunion *);
-extern const char *sockunion2str (union sockunion *, char *, size_t);
+extern int str2sockunion (const char * str, sockunion su);
+extern const char *sockunion2str (sockunion su, char* buf, size_t size);
extern sockunion_string_t sutoa(sockunion su) ;
-extern int sockunion_cmp (union sockunion *, union sockunion *);
-extern int sockunion_same (union sockunion *, union sockunion *);
-
-extern char* sockunion_su2str (union sockunion* su, enum MTYPE type) ;
-extern union sockunion *sockunion_str2su (const char *str);
-extern struct in_addr sockunion_get_in_addr (union sockunion *su);
-extern int sockunion_accept (int sock_fd, union sockunion *);
-extern int sockunion_stream_socket (union sockunion *);
-extern int sockopt_reuseaddr (int);
-extern int sockopt_reuseport (int);
-extern int sockunion_bind (int sock_fd, union sockunion *,
- unsigned short, void* any);
-extern int sockunion_socket (sa_family_t family, int type, int protocol) ;
-extern int sockunion_connect (int sock_fd, union sockunion *su,
- unsigned short port, unsigned int) ;
+extern int sockunion_cmp (sockunion su1, sockunion su2);
+extern int sockunion_same (sockunion su1, sockunion su2);
+
+extern char* sockunion_su2str (sockunion su, enum MTYPE type) ;
+extern sockunion sockunion_str2su (const char *str);
+extern struct in_addr sockunion_get_in_addr (sockunion su);
+extern int sockunion_accept (int sock_fd, sockunion su);
+extern int sockunion_stream_socket (sockunion su);
+extern int sockunion_bind (int sock_fd, sockunion su,
+ unsigned short port, bool any) ;
+extern int sockunion_socket (sockunion su, int type, int protocol) ;
+extern int sockunion_connect (int sock_fd, sockunion su,
+ unsigned short port, unsigned int ifindex) ;
extern int sockunion_listen(int sock_fd, int backlog) ;
extern int sockunion_getsockfamily(int sock_fd) ;
-extern int sockunion_getsockname (int, union sockunion*);
-extern int sockunion_getpeername (int, union sockunion*);
-extern void sockunion_unmap_ipv4 (union sockunion *su) ;
-extern void sockunion_map_ipv4 (union sockunion *su) ;
+extern int sockunion_getprotofamily(int sock_fd) ;
+extern int sockunion_getsockname (int sock_fd, sockunion su);
+extern int sockunion_getpeername (int sock_fd, sockunion su);
+extern void sockunion_unmap_ipv4 (sockunion su) ;
+extern void sockunion_map_ipv4 (sockunion su) ;
-extern union sockunion *sockunion_dup (union sockunion *);
+extern sockunion sockunion_dup (sockunion src);
extern void sockunion_copy (sockunion dst, sockunion src) ;
-extern void sockunion_free (union sockunion *);
+extern void sockunion_free (sockunion su);
extern sockunion sockunion_new_prefix(sockunion su, prefix p) ;
extern sockunion sockunion_new_sockaddr(sockunion su, struct sockaddr* sa) ;
diff --git a/lib/thread.c b/lib/thread.c
index 7f8ff5f6..c130d876 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -438,8 +438,7 @@ DEFUN_CALL(show_thread_cpu,
}
static void
-cpu_record_hash_clear (struct hash_backet *bucket,
- void *args)
+cpu_record_hash_clear (struct hash_backet *bucket, void *args)
{
thread_type *filter = args;
struct cpu_thread_history *a = bucket->data;
@@ -1217,7 +1216,6 @@ thread_timer_process (struct thread_list *list, struct timeval *timenow)
/*------------------------------------------------------------------------------
* Move the given list of threads to the back of the THREAD_READY queue.
*/
-/* process a list en masse, e.g. for event thread lists */
static unsigned int
thread_process (struct thread_list *list)
{
@@ -1246,9 +1244,9 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
fd_set readfd;
fd_set writefd;
fd_set exceptfd;
- struct timeval timer_val;
+ struct timeval timer_val ;
struct timeval timer_val_bg;
- struct timeval *timer_wait;
+ struct timeval *timer_wait ;
struct timeval *timer_wait_bg;
while (1)
diff --git a/lib/vty_io.c b/lib/vty_io.c
index 33947342..81af4e5e 100644
--- a/lib/vty_io.c
+++ b/lib/vty_io.c
@@ -40,6 +40,7 @@
#include "filter.h"
#include "privs.h"
#include "sockunion.h"
+#include "sockopt.h"
#include "network.h"
#include <arpa/telnet.h>
diff --git a/lib/vty_io_term.c b/lib/vty_io_term.c
index 61f35761..0660afb6 100644
--- a/lib/vty_io_term.c
+++ b/lib/vty_io_term.c
@@ -41,6 +41,7 @@
#include "filter.h"
#include "privs.h"
#include "sockunion.h"
+#include "sockopt.h"
#include "network.h"
#include <arpa/telnet.h>
@@ -1173,8 +1174,8 @@ static int
uty_term_listen_open(sa_family_t family, int type, int protocol,
struct sockaddr* sa, unsigned short port)
{
- union sockunion su ;
- int sock ;
+ union sockunion su[1] ;
+ int sock_fd ;
int ret ;
VTY_ASSERT_LOCKED() ;
@@ -1182,55 +1183,52 @@ uty_term_listen_open(sa_family_t family, int type, int protocol,
/* Is there an address and is it for this family ? */
if ((sa != NULL) || (sa->sa_family == family))
/* Set up sockunion containing required family and address */
- sockunion_new_sockaddr(&su, sa) ;
+ sockunion_new_sockaddr(su, sa) ;
else
{
/* no address or wrong family -- set up empty sockunion of
* required family */
- sockunion_init_new(&su, family) ;
+ sockunion_init_new(su, family) ;
sa = NULL ;
} ;
/* Open the socket and set its properties */
- sock = sockunion_socket(family, type, protocol) ;
- if (sock < 0)
+ sock_fd = sockunion_socket(su, type, protocol) ;
+ if (sock_fd < 0)
return -1 ;
- ret = sockopt_reuseaddr (sock);
+ ret = setsockopt_reuseaddr (sock_fd);
if (ret >= 0)
- ret = sockopt_reuseport (sock);
+ ret = setsockopt_reuseport (sock_fd);
if (ret >= 0)
- ret = set_nonblocking(sock);
+ ret = set_nonblocking(sock_fd);
-#if defined(HAVE_IPV6) && defined(IPV6_V6ONLY)
- /* Want only IPV6 on ipv6 socket (not mapped addresses)
+#ifdef HAVE_IPV6
+ /* Want only IPv6 on AF_INET6 socket (not mapped addresses)
*
* This distinguishes 0.0.0.0 from :: -- without this, bind() will reject the
* attempt to bind to :: after binding to 0.0.0.0.
*/
- if ((ret >= 0) && (sa->sa_family == AF_INET6))
- {
- int on = 1;
- ret = setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on));
- }
+ if ((ret >= 0) && (family == AF_INET6))
+ ret = setsockopt_ipv6_v6only(sock_fd) ;
#endif
if (ret >= 0)
- ret = sockunion_bind (sock, &su, port, sa) ;
+ ret = sockunion_bind (sock_fd, su, port, (sa == NULL)) ;
if (ret >= 0)
- ret = sockunion_listen (sock, 3);
+ ret = sockunion_listen (sock_fd, 3);
if (ret < 0)
{
- close (sock);
+ close (sock_fd);
return -1 ;
}
/* Socket is open -- set VTY_TERMINAL listener going */
- uty_add_listener(sock, uty_term_accept) ;
+ uty_add_listener(sock_fd, uty_term_accept) ;
/* Return OK and signal whether used address or not */
return (sa != NULL) ? 1 : 0 ;
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index cb347451..236baf17 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -118,6 +118,7 @@ ospf6_interface_create (struct interface *ifp)
oi->cost = 1;
oi->state = OSPF6_INTERFACE_DOWN;
oi->flag = 0;
+ oi->mtu_ignore = 0;
/* Try to adjust I/O buffer size with IfMtu */
oi->ifmtu = ifp->mtu6;
@@ -784,6 +785,8 @@ ospf6_interface_show (struct vty *vty, struct interface *ifp)
{
vty_out (vty, " Instance ID %d, Interface MTU %d (autodetect: %d)%s",
oi->instance_id, oi->ifmtu, ifp->mtu6, VNL);
+ vty_out (vty, " MTU mismatch detection: %s%s", oi->mtu_ignore ?
+ "disabled" : "enabled", VNL);
inet_ntop (AF_INET, &oi->area->area_id,
strbuf, sizeof (strbuf));
vty_out (vty, " Area ID %s, Cost %hu%s", strbuf, oi->cost,
@@ -1368,6 +1371,55 @@ DEFUN (no_ipv6_ospf6_passive,
return CMD_SUCCESS;
}
+DEFUN (ipv6_ospf6_mtu_ignore,
+ ipv6_ospf6_mtu_ignore_cmd,
+ "ipv6 ospf6 mtu-ignore",
+ IP6_STR
+ OSPF6_STR
+ "Ignore MTU mismatch on this interface\n"
+ )
+{
+ struct ospf6_interface *oi;
+ struct interface *ifp;
+
+ ifp = (struct interface *) vty->index;
+ assert (ifp);
+
+ oi = (struct ospf6_interface *) ifp->info;
+ if (oi == NULL)
+ oi = ospf6_interface_create (ifp);
+ assert (oi);
+
+ oi->mtu_ignore = 1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_ospf6_mtu_ignore,
+ no_ipv6_ospf6_mtu_ignore_cmd,
+ "no ipv6 ospf6 mtu-ignore",
+ NO_STR
+ IP6_STR
+ OSPF6_STR
+ "Ignore MTU mismatch on this interface\n"
+ )
+{
+ struct ospf6_interface *oi;
+ struct interface *ifp;
+
+ ifp = (struct interface *) vty->index;
+ assert (ifp);
+
+ oi = (struct ospf6_interface *) ifp->info;
+ if (oi == NULL)
+ oi = ospf6_interface_create (ifp);
+ assert (oi);
+
+ oi->mtu_ignore = 0;
+
+ return CMD_SUCCESS;
+}
+
DEFUN (ipv6_ospf6_advertise_prefix_list,
ipv6_ospf6_advertise_prefix_list_cmd,
"ipv6 ospf6 advertise prefix-list WORD",
@@ -1495,6 +1547,9 @@ config_write_ospf6_interface (struct vty *vty)
if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE))
vty_out (vty, " ipv6 ospf6 passive%s", VNL);
+ if (oi->mtu_ignore)
+ vty_out (vty, " ipv6 ospf6 mtu-ignore%s", VNL);
+
vty_out (vty, "!%s", VNL);
}
return 0;
@@ -1547,6 +1602,9 @@ ospf6_interface_init (void)
install_element (INTERFACE_NODE, &ipv6_ospf6_passive_cmd);
install_element (INTERFACE_NODE, &no_ipv6_ospf6_passive_cmd);
+ install_element (INTERFACE_NODE, &ipv6_ospf6_mtu_ignore_cmd);
+ install_element (INTERFACE_NODE, &no_ipv6_ospf6_mtu_ignore_cmd);
+
install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_prefix_list_cmd);
install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_prefix_list_cmd);
}
diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h
index 878c29e2..cf758c07 100644
--- a/ospf6d/ospf6_interface.h
+++ b/ospf6d/ospf6_interface.h
@@ -76,6 +76,9 @@ struct ospf6_interface
/* OSPF6 Interface flag */
char flag;
+ /* MTU mismatch check */
+ u_char mtu_ignore;
+
/* Decision of DR Election */
u_int32_t drouter;
u_int32_t bdrouter;
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index d06eba26..51933b76 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -832,7 +832,7 @@ ospf6_dbdesc_recv (struct in6_addr *src, struct in6_addr *dst,
((caddr_t) oh + sizeof (struct ospf6_header));
/* Interface MTU check */
- if (ntohs (dbdesc->ifmtu) != oi->ifmtu)
+ if (!oi->mtu_ignore && ntohs (dbdesc->ifmtu) != oi->ifmtu)
{
if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
zlog_debug ("I/F MTU mismatch");
diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c
index 96b82af3..d9783385 100644
--- a/ospf6d/ospf6_network.c
+++ b/ospf6d/ospf6_network.c
@@ -96,7 +96,7 @@ ospf6_serv_sock (void)
/* set socket options */
#if 1
- sockopt_reuseaddr (ospf6_sock);
+ setsockopt_reuseaddr (ospf6_sock);
#else
ospf6_set_reuseaddr ();
#endif /*1*/
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
index 0a8ac3e4..881771a7 100644
--- a/ospf6d/ospf6_zebra.c
+++ b/ospf6d/ospf6_zebra.c
@@ -132,6 +132,9 @@ ospf6_zebra_if_state_update (int command, struct zclient *zclient,
struct interface *ifp;
ifp = zebra_interface_state_read (zclient->ibuf);
+ if (ifp == NULL)
+ return 0;
+
if (IS_OSPF6_DEBUG_ZEBRA (RECV))
zlog_debug ("Zebra Interface state change: "
"%s index %d flags %llx metric %d mtu %d",
diff --git a/ospfd/ospf_api.c b/ospfd/ospf_api.c
index 77383191..fc3b51dd 100644
--- a/ospfd/ospf_api.c
+++ b/ospfd/ospf_api.c
@@ -219,7 +219,7 @@ msg_print (struct msg *msg)
#else /* ORIGINAL_CODING */
/* API message common header part. */
zlog_debug
- ("API-msg [%s]: type(%d),len(%d),seq(%lu),data(%p),size(%lu)",
+ ("API-msg [%s]: type(%d),len(%d),seq(%lu),data(%p),size(%zd)",
ospf_api_typename (msg->hdr.msgtype), msg->hdr.msgtype,
ntohs (msg->hdr.msglen), (unsigned long) ntohl (msg->hdr.msgseq),
STREAM_DATA (msg->s), STREAM_SIZE (msg->s));
diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c
index 026ae39a..a964e690 100644
--- a/ospfd/ospf_apiserver.c
+++ b/ospfd/ospf_apiserver.c
@@ -38,7 +38,8 @@
#include "log.h"
#include "thread.h"
#include "hash.h"
-#include "sockunion.h" /* for inet_aton() */
+#include "sockunion.h" /* for inet_aton() */
+#include "sockopt.h"
#include "buffer.h"
#include <sys/types.h>
@@ -617,8 +618,7 @@ ospf_apiserver_serv_sock_family (unsigned short port, int family)
int accept_sock;
int rc;
- memset (&su, 0, sizeof (union sockunion));
- su.sa.sa_family = family;
+ sockunion_init_new(&su, family) ;
/* Make new socket */
accept_sock = sockunion_stream_socket (&su);
@@ -626,11 +626,11 @@ ospf_apiserver_serv_sock_family (unsigned short port, int family)
return accept_sock;
/* This is a server, so reuse address and port */
- sockopt_reuseaddr (accept_sock);
- sockopt_reuseport (accept_sock);
+ setsockopt_reuseaddr (accept_sock);
+ setsockopt_reuseport (accept_sock);
/* Bind socket to address and given port. */
- rc = sockunion_bind (accept_sock, &su, port, NULL);
+ rc = sockunion_bind (accept_sock, &su, port, true); /* true => any */
if (rc < 0)
{
close (accept_sock); /* Close socket */
@@ -1831,11 +1831,7 @@ ospf_apiserver_lsa11_originator (void *arg)
/* Periodically refresh opaque LSAs so that they do not expire in
other routers. */
-#if 0
-static void
-#else
extern struct ospf_lsa *
-#endif
ospf_apiserver_lsa_refresher (struct ospf_lsa *lsa)
{
struct ospf_apiserver *apiserv;
@@ -1908,7 +1904,7 @@ ospf_apiserver_lsa_refresher (struct ospf_lsa *lsa)
}
out:
- return NULL;
+ return new;
}
diff --git a/ospfd/ospf_apiserver.h b/ospfd/ospf_apiserver.h
index f1412270..45716d9d 100644
--- a/ospfd/ospf_apiserver.h
+++ b/ospfd/ospf_apiserver.h
@@ -180,11 +180,7 @@ extern void ospf_apiserver_config_write_router (struct vty *vty);
extern void ospf_apiserver_config_write_if (struct vty *vty, struct interface *ifp);
extern void ospf_apiserver_show_info (struct vty *vty, struct ospf_lsa *lsa);
extern int ospf_ospf_apiserver_lsa_originator (void *arg);
-#if 0
-extern void ospf_apiserver_lsa_refresher (struct ospf_lsa *lsa);
-#else
-extern struct ospf_lsa * ospf_apiserver_lsa_refresher (struct ospf_lsa *lsa);
-#endif
+extern struct ospf_lsa *ospf_apiserver_lsa_refresher (struct ospf_lsa *lsa);
extern void ospf_apiserver_flush_opaque_lsa (struct ospf_apiserver *apiserv,
u_char lsa_type, u_char opaque_type);
diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c
index 5bac3448..8ef545c2 100644
--- a/ospfd/ospf_ase.c
+++ b/ospfd/ospf_ase.c
@@ -451,6 +451,8 @@ ospf_ase_calculate_route (struct ospf *ospf, struct ospf_lsa * lsa)
/* if there is a Intra/Inter area route to the N
do not install external route */
if ( (rn = route_node_lookup (ospf->new_table, (struct prefix *) &p)) )
+ if ((rn = route_node_lookup (ospf->new_table,
+ (struct prefix *) &p)))
{
route_unlock_node(rn);
if (rn->info == NULL)
@@ -461,8 +463,8 @@ ospf_ase_calculate_route (struct ospf *ospf, struct ospf_lsa * lsa)
}
/* Find a route to the same dest */
/* If there is no route, create new one. */
- if ( (rn = route_node_lookup (ospf->new_external_route,
- (struct prefix *) &p)) )
+ if ((rn = route_node_lookup (ospf->new_external_route,
+ (struct prefix *) &p)))
route_unlock_node(rn);
if (!rn || (or = rn->info) == NULL)
diff --git a/ospfd/ospf_network.c b/ospfd/ospf_network.c
index 1e2d44e6..dc06cb61 100644
--- a/ospfd/ospf_network.c
+++ b/ospfd/ospf_network.c
@@ -214,7 +214,7 @@ ospf_sock_init (void)
zlog_warn ("IP_HDRINCL option not available");
#endif /* IP_HDRINCL */
- ret = setsockopt_ifindex (AF_INET, ospf_sock, 1);
+ ret = setsockopt_pktinfo (AF_INET, ospf_sock, 1);
if (ret < 0)
zlog_warn ("Can't set pktinfo option for fd %d", ospf_sock);
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index 242a2081..23eae565 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -687,6 +687,13 @@ ospf_write (struct thread *thread)
iph.ip_tos = IPTOS_PREC_INTERNETCONTROL;
iph.ip_len = (iph.ip_hl << OSPF_WRITE_IPHL_SHIFT) + op->length;
+#if defined(__DragonFly__)
+ /*
+ * DragonFly's raw socket expects ip_len/ip_off in network byte order.
+ */
+ iph.ip_len = htons(iph.ip_len);
+#endif
+
#ifdef WANT_OSPF_WRITE_FRAGMENT
/* XXX-MT: not thread-safe at all..
* XXX: this presumes this is only programme sending OSPF packets
@@ -2126,6 +2133,15 @@ ospf_recv_packet (int fd, struct interface **ifp, struct stream *ibuf)
ip_len = ip_len + (iph->ip_hl << 2);
#endif
+#if defined(__DragonFly__)
+ /*
+ * in DragonFly's raw socket, ip_len/ip_off are read
+ * in network byte order.
+ * As OpenBSD < 200311 adjust ip_len to strip IP header size!
+ */
+ ip_len = ntohs(iph->ip_len) + (iph->ip_hl << 2);
+#endif
+
ifindex = getsockopt_ifindex (AF_INET, &msgh);
*ifp = if_lookup_by_index (ifindex);
diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c
index 3467ad71..5970a51f 100644
--- a/ospfd/ospf_te.c
+++ b/ospfd/ospf_te.c
@@ -133,13 +133,7 @@ static void ospf_mpls_te_config_write_router (struct vty *vty);
static void ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp);
static void ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa);
static int ospf_mpls_te_lsa_originate (void *arg);
-
-#if 0
-static void ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa);
-#else
-static struct ospf_lsa * ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa);
-#endif
-
+static struct ospf_lsa *ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa);
static void ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, enum sched_opcode);
static void del_mpls_te_link (void *val);
@@ -1014,11 +1008,8 @@ ospf_mpls_te_lsa_originate (void *arg)
out:
return rc;
}
-#if 0
-static void
-#else
+
static struct ospf_lsa *
-#endif
ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa)
{
struct mpls_te_link *lp;
@@ -1079,7 +1070,7 @@ ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa)
}
out:
- return NULL;
+ return new;
}
static void
diff --git a/ripd/ripd.c b/ripd/ripd.c
index 6a592b0a..9c951bf8 100644
--- a/ripd/ripd.c
+++ b/ripd/ripd.c
@@ -17,7 +17,7 @@
* You should have received a copy of the GNU General Public License
* along with GNU Zebra; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
+ * 02111-1307, USA.
*/
#include <zebra.h>
@@ -66,20 +66,20 @@ long rip_global_queries = 0;
union rip_miyagi_string rip_enabled_string = { .cp = "enabled" } ;
union rip_miyagi_string rip_static_string = { .cp = "static" } ;
-
+
/* Prototypes. */
static void rip_event (enum rip_event, int);
static void rip_output_process (struct connected *, struct sockaddr_in *, int, u_char);
static int rip_triggered_update (struct thread *);
static int rip_update_jitter (unsigned long);
-
+
/* RIP output routes type. */
enum
{
rip_all_route,
rip_changed_route
};
-
+
/* RIP command strings. */
static const struct message rip_msg[] =
{
@@ -91,22 +91,6 @@ static const struct message rip_msg[] =
{RIP_POLL_ENTRY, "POLL ENTRY"},
{0, NULL},
};
-
-/* Utility function to set boradcast option to the socket. */
-static int
-sockopt_broadcast (int sock)
-{
- int ret;
- int on = 1;
-
- ret = setsockopt (sock, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof on);
- if (ret < 0)
- {
- zlog_warn ("can't set sockopt SO_BROADCAST to socket %d", sock);
- return -1;
- }
- return 0;
-}
static int
rip_route_rte (struct rip_info *rinfo)
@@ -138,7 +122,7 @@ rip_garbage_collect (struct thread *t)
/* Off timeout timer. */
RIP_TIMER_OFF (rinfo->t_timeout);
-
+
/* Get route_node pointer. */
rp = rinfo->rp;
@@ -165,7 +149,7 @@ rip_timeout (struct thread *t)
rn = rinfo->rp;
/* - The garbage-collection timer is set for 120 seconds. */
- RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect,
+ RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect,
rip->garbage_time);
rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rn->p, &rinfo->nexthop,
@@ -205,7 +189,7 @@ rip_incoming_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
/* Input distribute-list filtering. */
if (ri->list[RIP_FILTER_IN])
{
- if (access_list_apply (ri->list[RIP_FILTER_IN],
+ if (access_list_apply (ri->list[RIP_FILTER_IN],
(struct prefix *) p) == FILTER_DENY)
{
if (IS_RIP_DEBUG_PACKET)
@@ -216,7 +200,7 @@ rip_incoming_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
}
if (ri->prefix[RIP_FILTER_IN])
{
- if (prefix_list_apply (ri->prefix[RIP_FILTER_IN],
+ if (prefix_list_apply (ri->prefix[RIP_FILTER_IN],
(struct prefix *) p) == PREFIX_DENY)
{
if (IS_RIP_DEBUG_PACKET)
@@ -233,7 +217,7 @@ rip_incoming_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
if (dist->list[DISTRIBUTE_IN])
{
alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
-
+
if (alist)
{
if (access_list_apply (alist,
@@ -249,7 +233,7 @@ rip_incoming_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
if (dist->prefix[DISTRIBUTE_IN])
{
plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
-
+
if (plist)
{
if (prefix_list_apply (plist,
@@ -303,7 +287,7 @@ rip_outgoing_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
if (dist->list[DISTRIBUTE_OUT])
{
alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
-
+
if (alist)
{
if (access_list_apply (alist,
@@ -319,7 +303,7 @@ rip_outgoing_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
if (dist->prefix[DISTRIBUTE_OUT])
{
plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
-
+
if (plist)
{
if (prefix_list_apply (plist,
@@ -351,7 +335,7 @@ rip_nexthop_check (struct in_addr *addr)
for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
{
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, ifc))
- {
+ {
p = ifc->address;
if (p->family == AF_INET
@@ -490,9 +474,9 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from,
/* Only connected routes may have a valid NULL distance */
if (rinfo->type != ZEBRA_ROUTE_CONNECT)
old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT;
- /* If imported route does not have STRICT precedence,
+ /* If imported route does not have STRICT precedence,
mark it as a ghost */
- if (new_dist > old_dist
+ if (new_dist > old_dist
|| rte->metric == RIP_METRIC_INFINITY)
{
route_unlock_node (rp);
@@ -502,10 +486,10 @@ rip_rte_process (struct rte *rte, struct sockaddr_in *from,
{
RIP_TIMER_OFF (rinfo->t_timeout);
RIP_TIMER_OFF (rinfo->t_garbage_collect);
-
+
rp->info = NULL;
if (rip_route_rte (rinfo))
- rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,
+ rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,
&rinfo->nexthop, rinfo->metric);
rip_info_free (rinfo);
rinfo = NULL;
@@ -720,7 +704,7 @@ rip_packet_dump (struct rip_packet *packet, int size, const char *sndrcv)
/* Dump each routing table entry. */
rte = packet->rte;
-
+
for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
{
if (packet->version == RIPv2)
@@ -778,7 +762,7 @@ rip_packet_dump (struct rip_packet *packet, int size, const char *sndrcv)
}
else
{
- zlog_debug (" %s family %d tag %d metric %ld",
+ zlog_debug (" %s family %d tag %d metric %ld",
inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
ntohs (rte->family), ntohs (rte->tag),
(u_long)ntohl (rte->metric));
@@ -837,7 +821,7 @@ rip_auth_simple_password (struct rte *rte, struct sockaddr_in *from,
if (ri->auth_str)
{
auth_str = (char *) &rte->prefix;
-
+
if (strncmp (auth_str, ri->auth_str, 16) == 0)
return 1;
}
@@ -871,7 +855,7 @@ rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from,
u_char digest[RIP_AUTH_MD5_SIZE];
u_int16_t packet_len;
char auth_str[RIP_AUTH_MD5_SIZE];
-
+
if (IS_RIP_DEBUG_EVENT)
zlog_debug ("RIPv2 MD5 authentication from %s",
inet_ntoa (from->sin_addr));
@@ -910,7 +894,7 @@ rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from,
/* retrieve authentication data */
md5data = (struct rip_md5_data *) (((u_char *) packet) + packet_len);
-
+
memset (auth_str, 0, RIP_AUTH_MD5_SIZE);
if (ri->key_chain)
@@ -930,14 +914,14 @@ rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from,
if (auth_str[0] == 0)
return 0;
-
+
/* MD5 digest authentication. */
memset (&ctx, 0, sizeof(ctx));
MD5Init(&ctx);
MD5Update(&ctx, packet, packet_len + RIP_HEADER_SIZE);
MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
MD5Final(digest, &ctx);
-
+
if (memcmp (md5data->digest, digest, RIP_AUTH_MD5_SIZE) == 0)
return packet_len;
else
@@ -953,7 +937,7 @@ rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from,
*
*/
static void
-rip_auth_prepare_str_send (struct rip_interface *ri, struct key *key,
+rip_auth_prepare_str_send (struct rip_interface *ri, struct key *key,
char *auth_str, int len)
{
assert (ri || key);
@@ -969,22 +953,22 @@ rip_auth_prepare_str_send (struct rip_interface *ri, struct key *key,
/* Write RIPv2 simple password authentication information
*
- * auth_str is presumed to be 2 bytes and correctly prepared
+ * auth_str is presumed to be 2 bytes and correctly prepared
* (left justified and zero padded).
*/
static void
rip_auth_simple_write (struct stream *s, char *auth_str, int len)
{
assert (s && len == RIP_AUTH_SIMPLE_SIZE);
-
+
stream_putw (s, RIP_FAMILY_AUTH);
stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD);
stream_put (s, auth_str, RIP_AUTH_SIMPLE_SIZE);
-
+
return;
}
-/* write RIPv2 MD5 "authentication header"
+/* write RIPv2 MD5 "authentication header"
* (uses the auth key data field)
*
* Digest offset field is set to 0.
@@ -993,7 +977,7 @@ rip_auth_simple_write (struct stream *s, char *auth_str, int len)
* length to the auth-data MD5 digest is known.
*/
static size_t
-rip_auth_md5_ah_write (struct stream *s, struct rip_interface *ri,
+rip_auth_md5_ah_write (struct stream *s, struct rip_interface *ri,
struct key *key)
{
size_t doff = 0;
@@ -1018,9 +1002,9 @@ rip_auth_md5_ah_write (struct stream *s, struct rip_interface *ri,
else
stream_putc (s, 1);
- /* Auth Data Len. Set 16 for MD5 authentication data. Older ripds
+ /* Auth Data Len. Set 16 for MD5 authentication data. Older ripds
* however expect RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE so we allow for this
- * to be configurable.
+ * to be configurable.
*/
stream_putc (s, ri->md5_auth_len);
@@ -1029,7 +1013,7 @@ rip_auth_md5_ah_write (struct stream *s, struct rip_interface *ri,
arbitrary, but two suggestions are the time of the
message's creation or a simple message counter. */
stream_putl (s, time (NULL));
-
+
/* Reserved field must be zero. */
stream_putl (s, 0);
stream_putl (s, 0);
@@ -1042,11 +1026,11 @@ rip_auth_md5_ah_write (struct stream *s, struct rip_interface *ri,
* or 0 if this is not required
*/
static size_t
-rip_auth_header_write (struct stream *s, struct rip_interface *ri,
+rip_auth_header_write (struct stream *s, struct rip_interface *ri,
struct key *key, char *auth_str, int len)
{
assert (ri->auth_type != RIP_NO_AUTH);
-
+
switch (ri->auth_type)
{
case RIP_AUTH_SIMPLE_PASSWORD:
@@ -1073,7 +1057,7 @@ rip_auth_md5_set (struct stream *s, struct rip_interface *ri, size_t doff,
authentication. */
assert ((ri->auth_type == RIP_AUTH_MD5) && (authlen == RIP_AUTH_MD5_SIZE));
assert (doff > 0);
-
+
/* Get packet length. */
len = stream_get_endp(s);
@@ -1086,7 +1070,7 @@ rip_auth_md5_set (struct stream *s, struct rip_interface *ri, size_t doff,
/* Set the digest offset length in the header */
stream_putw_at (s, doff, len);
-
+
/* Set authentication data. */
stream_putw (s, RIP_FAMILY_AUTH);
stream_putw (s, RIP_AUTH_DATA);
@@ -1104,7 +1088,7 @@ rip_auth_md5_set (struct stream *s, struct rip_interface *ri, size_t doff,
/* RIP routing information. */
static void
-rip_response_process (struct rip_packet *packet, int size,
+rip_response_process (struct rip_packet *packet, int size,
struct sockaddr_in *from, struct connected *ifc)
{
caddr_t lim;
@@ -1112,7 +1096,7 @@ rip_response_process (struct rip_packet *packet, int size,
struct prefix_ipv4 ifaddr;
struct prefix_ipv4 ifaddrclass;
int subnetted;
-
+
/* We don't know yet. */
subnetted = -1;
ifaddr.prefixlen = 0 ; /* eliminate a compiler warning */
@@ -1130,7 +1114,7 @@ rip_response_process (struct rip_packet *packet, int size,
/* The datagram's IPv4 source address should be checked to see
whether the datagram is from a valid neighbor; the source of the
datagram must be on a directly connected network (RFC2453 - Sec. 3.9.2) */
- if (if_lookup_address(from->sin_addr) == NULL)
+ if (if_lookup_address(from->sin_addr) == NULL)
{
zlog_info ("This datagram doesn't came from a valid neighbor: %s",
inet_ntoa (from->sin_addr));
@@ -1177,7 +1161,7 @@ rip_response_process (struct rip_packet *packet, int size,
zlog_info ("Network is net 0 or net 127 or it is not unicast network");
rip_peer_bad_route (from);
continue;
- }
+ }
/* Convert metric value to host byte order. */
rte->metric = ntohl (rte->metric);
@@ -1253,18 +1237,18 @@ rip_response_process (struct rip_packet *packet, int size,
}
}
- /* For RIPv1, there won't be a valid netmask.
+ /* For RIPv1, there won't be a valid netmask.
This is a best guess at the masks. If everyone was using old
Ciscos before the 'ip subnet zero' option, it would be almost
right too :-)
-
+
Cisco summarize ripv1 advertisments to the classful boundary
(/16 for class B's) except when the RIP packet does to inside
the classful network in question. */
- if ((packet->version == RIPv1 && rte->prefix.s_addr != 0)
- || (packet->version == RIPv2
+ if ((packet->version == RIPv1 && rte->prefix.s_addr != 0)
+ || (packet->version == RIPv2
&& (rte->prefix.s_addr != 0 && rte->mask.s_addr == 0)))
{
u_int32_t destination;
@@ -1315,8 +1299,8 @@ rip_response_process (struct rip_packet *packet, int size,
/* In case of RIPv2, if prefix in RTE is not netmask applied one
ignore the entry. */
- if ((packet->version == RIPv2)
- && (rte->mask.s_addr != 0)
+ if ((packet->version == RIPv2)
+ && (rte->mask.s_addr != 0)
&& ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr))
{
zlog_warn ("RIPv2 address %s is not mask /%d applied one",
@@ -1334,22 +1318,22 @@ rip_response_process (struct rip_packet *packet, int size,
zlog_debug ("Default route with non-zero netmask. Set zero to netmask");
rte->mask.s_addr = 0;
}
-
+
/* Routing table updates. */
rip_rte_process (rte, from, ifc->ifp);
}
}
/* Make socket for RIP protocol. */
-static int
+static int
rip_create_socket (struct sockaddr_in *from)
{
int ret;
int sock;
struct sockaddr_in addr;
-
+
memset (&addr, 0, sizeof (struct sockaddr_in));
-
+
if (!from)
{
addr.sin_family = AF_INET;
@@ -1360,21 +1344,21 @@ rip_create_socket (struct sockaddr_in *from)
} else {
memcpy(&addr, from, sizeof(addr));
}
-
+
/* sending port must always be the RIP port */
addr.sin_port = htons (RIP_PORT_DEFAULT);
-
+
/* Make datagram socket. */
sock = socket (AF_INET, SOCK_DGRAM, 0);
- if (sock < 0)
+ if (sock < 0)
{
zlog_err("Cannot create UDP socket: %s", safe_strerror(errno));
exit (1);
}
- sockopt_broadcast (sock);
- sockopt_reuseaddr (sock);
- sockopt_reuseport (sock);
+ setsockopt_broadcast (sock);
+ setsockopt_reuseaddr (sock);
+ setsockopt_reuseport (sock);
#ifdef RIP_RECVMSG
setsockopt_pktinfo (sock);
#endif /* RIP_RECVMSG */
@@ -1386,24 +1370,24 @@ rip_create_socket (struct sockaddr_in *from)
zlog_err ("rip_create_socket: could not raise privs");
setsockopt_so_recvbuf (sock, RIP_UDP_RCV_BUF);
if ( (ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr))) < 0)
-
+
{
int save_errno = errno;
if (ripd_privs.change (ZPRIVS_LOWER))
zlog_err ("rip_create_socket: could not lower privs");
-
+
zlog_err("%s: Can't bind socket %d to %s port %d: %s", __func__,
- sock, inet_ntoa(addr.sin_addr),
- (int) ntohs(addr.sin_port),
+ sock, inet_ntoa(addr.sin_addr),
+ (int) ntohs(addr.sin_port),
safe_strerror(save_errno));
-
+
close (sock);
return ret;
}
-
+
if (ripd_privs.change (ZPRIVS_LOWER))
zlog_err ("rip_create_socket: could not lower privs");
-
+
return sock;
}
@@ -1417,15 +1401,15 @@ rip_send_packet (u_char * buf, int size, struct sockaddr_in *to,
{
int ret, send_sock;
struct sockaddr_in sin;
-
+
assert (ifc != NULL);
-
+
if (IS_RIP_DEBUG_PACKET)
{
#define ADDRESS_SIZE 20
char dst[ADDRESS_SIZE];
dst[ADDRESS_SIZE - 1] = '\0';
-
+
if (to)
{
strncpy (dst, inet_ntoa(to->sin_addr), ADDRESS_SIZE - 1);
@@ -1440,19 +1424,19 @@ rip_send_packet (u_char * buf, int size, struct sockaddr_in *to,
inet_ntoa(ifc->address->u.prefix4),
dst, ifc->ifp->name);
}
-
+
if ( CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY) )
{
/*
* ZEBRA_IFA_SECONDARY is set on linux when an interface is configured
* with multiple addresses on the same subnet: the first address
* on the subnet is configured "primary", and all subsequent addresses
- * on that subnet are treated as "secondary" addresses.
- * In order to avoid routing-table bloat on other rip listeners,
+ * on that subnet are treated as "secondary" addresses.
+ * In order to avoid routing-table bloat on other rip listeners,
* we do not send out RIP packets with ZEBRA_IFA_SECONDARY source addrs.
* XXX Since Linux is the only system for which the ZEBRA_IFA_SECONDARY
* flag is set, we would end up sending a packet for a "secondary"
- * source address on non-linux systems.
+ * source address on non-linux systems.
*/
if (IS_RIP_DEBUG_PACKET)
zlog_debug("duplicate dropped");
@@ -1476,10 +1460,10 @@ rip_send_packet (u_char * buf, int size, struct sockaddr_in *to,
else
{
struct sockaddr_in from;
-
+
sin.sin_port = htons (RIP_PORT_DEFAULT);
sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
-
+
/* multicast send should bind to local interface address */
from.sin_family = AF_INET;
from.sin_port = htons (RIP_PORT_DEFAULT);
@@ -1487,11 +1471,11 @@ rip_send_packet (u_char * buf, int size, struct sockaddr_in *to,
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
from.sin_len = sizeof (struct sockaddr_in);
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
-
+
/*
* we have to open a new socket for each packet because this
* is the most portable way to bind to a different source
- * ipv4 address for each packet.
+ * ipv4 address for each packet.
*/
if ( (send_sock = rip_create_socket (&from)) < 0)
{
@@ -1505,7 +1489,7 @@ rip_send_packet (u_char * buf, int size, struct sockaddr_in *to,
sizeof (struct sockaddr_in));
if (IS_RIP_DEBUG_EVENT)
- zlog_debug ("SEND to %s.%d", inet_ntoa(sin.sin_addr),
+ zlog_debug ("SEND to %s.%d", inet_ntoa(sin.sin_addr),
ntohs (sin.sin_port));
if (ret < 0)
@@ -1519,7 +1503,7 @@ rip_send_packet (u_char * buf, int size, struct sockaddr_in *to,
/* Add redistributed route to RIP table. */
void
-rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
+rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
unsigned int ifindex, struct in_addr *nexthop,
unsigned int metric, unsigned char distance)
{
@@ -1538,7 +1522,7 @@ rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
if (rinfo)
{
- if (rinfo->type == ZEBRA_ROUTE_CONNECT
+ if (rinfo->type == ZEBRA_ROUTE_CONNECT
&& rinfo->sub_type == RIP_ROUTE_INTERFACE
&& rinfo->metric != RIP_METRIC_INFINITY)
{
@@ -1547,7 +1531,7 @@ rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
}
/* Manually configured RIP route check. */
- if (rinfo->type == ZEBRA_ROUTE_RIP
+ if (rinfo->type == ZEBRA_ROUTE_RIP
&& ((rinfo->sub_type == RIP_ROUTE_STATIC) ||
(rinfo->sub_type == RIP_ROUTE_DEFAULT)) )
{
@@ -1567,12 +1551,12 @@ rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
rinfo->metric);
rp->info = NULL;
rip_info_free (rinfo);
-
- route_unlock_node (rp);
+
+ route_unlock_node (rp);
}
rinfo = rip_info_new ();
-
+
rinfo->type = type;
rinfo->sub_type = sub_type;
rinfo->ifindex = ifindex;
@@ -1606,7 +1590,7 @@ rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p,
/* Delete redistributed route from RIP table. */
void
-rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p,
+rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p,
unsigned int ifindex)
{
int ret;
@@ -1623,13 +1607,13 @@ rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p,
rinfo = rp->info;
if (rinfo != NULL
- && rinfo->type == type
- && rinfo->sub_type == sub_type
+ && rinfo->type == type
+ && rinfo->sub_type == sub_type
&& rinfo->ifindex == ifindex)
{
/* Perform poisoned reverse. */
rinfo->metric = RIP_METRIC_INFINITY;
- RIP_TIMER_ON (rinfo->t_garbage_collect,
+ RIP_TIMER_ON (rinfo->t_garbage_collect,
rip_garbage_collect, rip->garbage_time);
RIP_TIMER_OFF (rinfo->t_timeout);
rinfo->flags |= RIP_RTF_CHANGED;
@@ -1646,7 +1630,7 @@ rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p,
/* Response to request called from rip_read ().*/
static void
-rip_request_process (struct rip_packet *packet, int size,
+rip_request_process (struct rip_packet *packet, int size,
struct sockaddr_in *from, struct connected *ifc)
{
caddr_t lim;
@@ -1668,7 +1652,7 @@ rip_request_process (struct rip_packet *packet, int size,
/* When passive interface is specified, suppress responses */
if (ri->passive)
return;
-
+
/* RIP peer update. */
rip_peer_update (from, packet->version);
@@ -1687,7 +1671,7 @@ rip_request_process (struct rip_packet *packet, int size,
if (lim == ((caddr_t) (rte + 1)) &&
ntohs (rte->family) == 0 &&
ntohl (rte->metric) == RIP_METRIC_INFINITY)
- {
+ {
struct prefix_ipv4 saddr;
/* saddr will be used for determining which routes to split-horizon.
@@ -1718,7 +1702,7 @@ rip_request_process (struct rip_packet *packet, int size,
p.prefix = rte->prefix;
p.prefixlen = ip_masklen (rte->mask);
apply_mask_ipv4 (&p);
-
+
rp = route_node_lookup (rip->table, (struct prefix *) &p);
if (rp)
{
@@ -1743,7 +1727,7 @@ setsockopt_pktinfo (int sock)
{
int ret;
int val = 1;
-
+
ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val));
if (ret < 0)
zlog_warn ("Can't setsockopt IP_PKTINFO : %s", safe_strerror (errno));
@@ -1775,7 +1759,7 @@ rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from,
return ret;
for (ptr = ZCMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr))
- if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO)
+ if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO)
{
struct in_pktinfo *pktinfo;
int i;
@@ -1795,7 +1779,7 @@ rip_read_new (struct thread *t)
char buf[RIP_PACKET_MAXSIZ];
struct sockaddr_in from;
unsigned int ifindex;
-
+
/* Fetch socket then register myself. */
sock = THREAD_FD (t);
rip_event (RIP_READ, sock);
@@ -1840,16 +1824,16 @@ rip_read (struct thread *t)
memset (&from, 0, sizeof (struct sockaddr_in));
fromlen = sizeof (struct sockaddr_in);
- len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0,
+ len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0,
(struct sockaddr *) &from, &fromlen);
- if (len < 0)
+ if (len < 0)
{
zlog_info ("recvfrom failed: %s", safe_strerror (errno));
return len;
}
/* Check is this packet comming from myself? */
- if (if_check_address (from.sin_addr))
+ if (if_check_address (from.sin_addr))
{
if (IS_RIP_DEBUG_PACKET)
zlog_debug ("ignore packet comes from myself");
@@ -1858,7 +1842,7 @@ rip_read (struct thread *t)
/* Which interface is this packet comes from. */
ifp = if_lookup_address (from.sin_addr);
-
+
/* RIP packet received */
if (IS_RIP_DEBUG_EVENT)
zlog_debug ("RECV packet from %s port %d on %s",
@@ -1872,9 +1856,9 @@ rip_read (struct thread *t)
inet_ntoa(from.sin_addr), ntohs (from.sin_port));
return -1;
}
-
+
ifc = connected_lookup_address (ifp, from.sin_addr);
-
+
if (ifc == NULL)
{
zlog_info ("rip_read: cannot find connected address for packet from %s "
@@ -1948,7 +1932,7 @@ rip_read (struct thread *t)
if ((packet->version == RIPv1) && !(vrecv & RIPv1))
{
if (IS_RIP_DEBUG_PACKET)
- zlog_debug (" packet's v%d doesn't fit to if version spec",
+ zlog_debug (" packet's v%d doesn't fit to if version spec",
packet->version);
rip_peer_bad_packet (&from);
return -1;
@@ -1956,27 +1940,27 @@ rip_read (struct thread *t)
if ((packet->version == RIPv2) && !(vrecv & RIPv2))
{
if (IS_RIP_DEBUG_PACKET)
- zlog_debug (" packet's v%d doesn't fit to if version spec",
+ zlog_debug (" packet's v%d doesn't fit to if version spec",
packet->version);
rip_peer_bad_packet (&from);
return -1;
}
-
+
/* RFC2453 5.2 If the router is not configured to authenticate RIP-2
messages, then RIP-1 and unauthenticated RIP-2 messages will be
accepted; authenticated RIP-2 messages shall be discarded. */
- if ((ri->auth_type == RIP_NO_AUTH)
- && rtenum
- && (packet->version == RIPv2)
+ if ((ri->auth_type == RIP_NO_AUTH)
+ && rtenum
+ && (packet->version == RIPv2)
&& (packet->rte->family == htons(RIP_FAMILY_AUTH)))
{
if (IS_RIP_DEBUG_EVENT)
- zlog_debug ("packet RIPv%d is dropped because authentication disabled",
+ zlog_debug ("packet RIPv%d is dropped because authentication disabled",
packet->version);
rip_peer_bad_packet (&from);
return -1;
}
-
+
/* RFC:
If the router is configured to authenticate RIP-2 messages, then
RIP-1 messages and RIP-2 messages which pass authentication
@@ -1985,7 +1969,7 @@ rip_read (struct thread *t)
security, RIP-1 messages should be ignored when authentication is
in use (see section 4.1); otherwise, the routing information from
authenticated messages will be propagated by RIP-1 routers in an
- unauthenticated manner.
+ unauthenticated manner.
*/
/* We make an exception for RIPv1 REQUEST packets, to which we'll
* always reply regardless of authentication settings, because:
@@ -2002,7 +1986,7 @@ rip_read (struct thread *t)
* routing-information freely, while still requiring RIPv2
* authentication for any RESPONSEs might be vaguely useful.
*/
- if (ri->auth_type != RIP_NO_AUTH
+ if (ri->auth_type != RIP_NO_AUTH
&& packet->version == RIPv1)
{
/* Discard RIPv1 messages other than REQUESTs */
@@ -2017,7 +2001,7 @@ rip_read (struct thread *t)
else if (ri->auth_type != RIP_NO_AUTH)
{
const char *auth_desc;
-
+
if (rtenum == 0)
{
/* There definitely is no authentication in the packet. */
@@ -2026,7 +2010,7 @@ rip_read (struct thread *t)
rip_peer_bad_packet (&from);
return -1;
}
-
+
/* First RTE must be an Authentication Family RTE */
if (packet->rte->family != htons(RIP_FAMILY_AUTH))
{
@@ -2035,7 +2019,7 @@ rip_read (struct thread *t)
rip_peer_bad_packet (&from);
return -1;
}
-
+
/* Check RIPv2 authentication. */
switch (ntohs(packet->rte->tag))
{
@@ -2043,14 +2027,14 @@ rip_read (struct thread *t)
auth_desc = "simple";
ret = rip_auth_simple_password (packet->rte, &from, ifp);
break;
-
+
case RIP_AUTH_MD5:
auth_desc = "MD5";
ret = rip_auth_md5 (packet, &from, len, ifp);
/* Reset RIP packet length to trim MD5 data. */
len = ret;
break;
-
+
default:
ret = 0;
auth_desc = "unknown type";
@@ -2058,7 +2042,7 @@ rip_read (struct thread *t)
zlog_debug ("RIPv2 Unknown authentication type %d",
ntohs (packet->rte->tag));
}
-
+
if (ret)
{
if (IS_RIP_DEBUG_PACKET)
@@ -2072,7 +2056,7 @@ rip_read (struct thread *t)
return -1;
}
}
-
+
/* Process each command. */
switch (packet->command)
{
@@ -2085,12 +2069,12 @@ rip_read (struct thread *t)
break;
case RIP_TRACEON:
case RIP_TRACEOFF:
- zlog_info ("Obsolete command %s received, please sent it to routed",
+ zlog_info ("Obsolete command %s received, please sent it to routed",
lookup (rip_msg, packet->command));
rip_peer_bad_packet (&from);
break;
case RIP_POLL_ENTRY:
- zlog_info ("Obsolete command %s received",
+ zlog_info ("Obsolete command %s received",
lookup (rip_msg, packet->command));
rip_peer_bad_packet (&from);
break;
@@ -2138,7 +2122,7 @@ rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p,
/* Send update to the ifp or spcified neighbor. */
void
-rip_output_process (struct connected *ifc, struct sockaddr_in *to,
+rip_output_process (struct connected *ifc, struct sockaddr_in *to,
int route_type, u_char version)
{
int ret;
@@ -2177,7 +2161,7 @@ rip_output_process (struct connected *ifc, struct sockaddr_in *to,
/* Get RIP interface. */
ri = ifc->ifp->info;
-
+
/* If output interface is in simple password authentication mode, we
need space for authentication data. */
if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
@@ -2219,7 +2203,7 @@ rip_output_process (struct connected *ifc, struct sockaddr_in *to,
/* For RIPv1, if we are subnetted, output subnets in our network */
/* that have the same mask as the output "interface". For other */
/* networks, only the classfull version is output. */
-
+
if (version == RIPv1)
{
p = (struct prefix_ipv4 *) &rp->p;
@@ -2247,7 +2231,7 @@ rip_output_process (struct connected *ifc, struct sockaddr_in *to,
zlog_debug("RIPv1 mask check, %s/%d made it through",
inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen);
}
- else
+ else
p = (struct prefix_ipv4 *) &rp->p;
/* Apply output filters. */
@@ -2264,18 +2248,18 @@ rip_output_process (struct connected *ifc, struct sockaddr_in *to,
/* if (split_horizon == rip_split_horizon) */
if (ri->split_horizon == RIP_SPLIT_HORIZON)
{
- /*
- * We perform split horizon for RIP and connected route.
+ /*
+ * We perform split horizon for RIP and connected route.
* For rip routes, we want to suppress the route if we would
* end up sending the route back on the interface that we
* learned it from, with a higher metric. For connected routes,
* we suppress the route if the prefix is a subset of the
- * source address that we are going to use for the packet
+ * source address that we are going to use for the packet
* (in order to handle the case when multiple subnets are
* configured on the same interface).
*/
if (rinfo->type == ZEBRA_ROUTE_RIP &&
- rinfo->ifindex == ifc->ifp->ifindex)
+ rinfo->ifindex == ifc->ifp->ifindex)
continue;
if (rinfo->type == ZEBRA_ROUTE_CONNECT &&
prefix_match((struct prefix *)p, ifc->address))
@@ -2302,8 +2286,8 @@ rip_output_process (struct connected *ifc, struct sockaddr_in *to,
/* Interface route-map */
if (ri->routemap[RIP_FILTER_OUT])
{
- ret = route_map_apply (ri->routemap[RIP_FILTER_OUT],
- (struct prefix *) p, RMAP_RIP,
+ ret = route_map_apply (ri->routemap[RIP_FILTER_OUT],
+ (struct prefix *) p, RMAP_RIP,
rinfo);
if (ret == RMAP_DENYMATCH)
@@ -2314,7 +2298,7 @@ rip_output_process (struct connected *ifc, struct sockaddr_in *to,
continue;
}
}
-
+
/* Apply redistribute route map - continue, if deny */
if (rip->route_map[rinfo->type].name
&& rinfo->sub_type != RIP_ROUTE_INTERFACE)
@@ -2322,7 +2306,7 @@ rip_output_process (struct connected *ifc, struct sockaddr_in *to,
ret = route_map_apply (rip->route_map[rinfo->type].map,
(struct prefix *)p, RMAP_RIP, rinfo);
- if (ret == RMAP_DENYMATCH)
+ if (ret == RMAP_DENYMATCH)
{
if (IS_RIP_DEBUG_PACKET)
zlog_debug ("%s/%d is filtered by route-map",
@@ -2344,7 +2328,7 @@ rip_output_process (struct connected *ifc, struct sockaddr_in *to,
{
/* If the route is not connected or localy generated
one, use default-metric value*/
- if (rinfo->type != ZEBRA_ROUTE_RIP
+ if (rinfo->type != ZEBRA_ROUTE_RIP
&& rinfo->type != ZEBRA_ROUTE_CONNECT
&& rinfo->metric != RIP_METRIC_INFINITY)
rinfo->metric_out = rip->default_metric;
@@ -2358,17 +2342,17 @@ rip_output_process (struct connected *ifc, struct sockaddr_in *to,
if (rinfo->metric_out > RIP_METRIC_INFINITY)
rinfo->metric_out = RIP_METRIC_INFINITY;
- /* Perform split-horizon with poisoned reverse
+ /* Perform split-horizon with poisoned reverse
* for RIP and connected routes.
**/
if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) {
- /*
- * We perform split horizon for RIP and connected route.
+ /*
+ * We perform split horizon for RIP and connected route.
* For rip routes, we want to suppress the route if we would
* end up sending the route back on the interface that we
* learned it from, with a higher metric. For connected routes,
* we suppress the route if the prefix is a subset of the
- * source address that we are going to use for the packet
+ * source address that we are going to use for the packet
* (in order to handle the case when multiple subnets are
* configured on the same interface).
*/
@@ -2379,20 +2363,20 @@ rip_output_process (struct connected *ifc, struct sockaddr_in *to,
prefix_match((struct prefix *)p, ifc->address))
rinfo->metric_out = RIP_METRIC_INFINITY;
}
-
+
/* Prepare preamble, auth headers, if needs be */
if (num == 0)
{
stream_putc (s, RIP_RESPONSE);
stream_putc (s, version);
stream_putw (s, 0);
-
+
/* auth header for !v1 && !no_auth */
if ( (ri->auth_type != RIP_NO_AUTH) && (version != RIPv1) )
- doff = rip_auth_header_write (s, ri, key, auth_str,
+ doff = rip_auth_header_write (s, ri, key, auth_str,
RIP_AUTH_SIMPLE_SIZE);
}
-
+
/* Write RTE to the stream. */
num = rip_write_rte (num, s, p, version, rinfo);
if (num == rtemax)
@@ -2437,7 +2421,7 @@ rip_update_interface (struct connected *ifc, u_char version, int route_type)
struct sockaddr_in to;
/* When RIP version is 2 and multicast enable interface. */
- if (version == RIPv2 && if_is_multicast (ifc->ifp))
+ if (version == RIPv2 && if_is_multicast (ifc->ifp))
{
if (IS_RIP_DEBUG_EVENT)
zlog_debug ("multicast announce on %s ", ifc->ifp->name);
@@ -2445,7 +2429,7 @@ rip_update_interface (struct connected *ifc, u_char version, int route_type)
rip_output_process (ifc, NULL, route_type, version);
return;
}
-
+
/* If we can't send multicast packet, send it with unicast. */
if (if_is_broadcast (ifc->ifp) || if_is_pointopoint (ifc->ifp))
{
@@ -2508,14 +2492,14 @@ rip_update_process (int route_type)
if (ri->running)
{
- /*
+ /*
* If there is no version configuration in the interface,
- * use rip's version setting.
+ * use rip's version setting.
*/
int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ?
rip->version_send : ri->ri_send);
- if (IS_RIP_DEBUG_EVENT)
+ if (IS_RIP_DEBUG_EVENT)
zlog_debug("SEND UPDATE to %s ifindex %d",
(ifp->name ? ifp->name : "_unknown_"), ifp->ifindex);
@@ -2546,14 +2530,14 @@ rip_update_process (int route_type)
inet_ntoa (p->prefix));
continue;
}
-
+
if ( (connected = connected_lookup_address (ifp, p->prefix)) == NULL)
{
zlog_warn ("Neighbor %s doesnt have connected network",
inet_ntoa (p->prefix));
continue;
}
-
+
/* Set destination address and port */
memset (&to, 0, sizeof (struct sockaddr_in));
to.sin_addr = p->prefix;
@@ -2619,7 +2603,7 @@ rip_triggered_interval (struct thread *t)
rip_triggered_update (t);
}
return 0;
-}
+}
/* Execute triggered update. */
static int
@@ -2656,7 +2640,7 @@ rip_triggered_update (struct thread *t)
update is triggered when the timer expires. */
interval = (random () % 5) + 1;
- rip->t_triggered_interval =
+ rip->t_triggered_interval =
thread_add_timer (master, rip_triggered_interval, NULL, interval);
return 0;
@@ -2680,7 +2664,7 @@ rip_redistribute_withdraw (int type)
{
/* Perform poisoned reverse. */
rinfo->metric = RIP_METRIC_INFINITY;
- RIP_TIMER_ON (rinfo->t_garbage_collect,
+ RIP_TIMER_ON (rinfo->t_garbage_collect,
rip_garbage_collect, rip->garbage_time);
RIP_TIMER_OFF (rinfo->t_timeout);
rinfo->flags |= RIP_RTF_CHANGED;
@@ -2748,20 +2732,20 @@ rip_request_send (struct sockaddr_in *to, struct interface *ifp,
rte = rip_packet.rte;
rte->metric = htonl (RIP_METRIC_INFINITY);
- if (connected)
+ if (connected)
{
- /*
+ /*
* connected is only sent for ripv1 case, or when
* interface does not support multicast. Caller loops
* over each connected address for this case.
*/
- if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
+ if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
to, connected) != sizeof (rip_packet))
return -1;
else
return sizeof (rip_packet);
}
-
+
/* send request on each connected network */
for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected))
{
@@ -2772,13 +2756,13 @@ rip_request_send (struct sockaddr_in *to, struct interface *ifp,
if (p->family != AF_INET)
continue;
- if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
+ if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet),
to, connected) != sizeof (rip_packet))
return -1;
}
return sizeof (rip_packet);
}
-
+
static int
rip_update_jitter (unsigned long time)
{
@@ -2788,14 +2772,14 @@ rip_update_jitter (unsigned long time)
The RIPv2 RFC says jitter should be small compared to
update_time. We consider 1/JITTER_BOUND to be small.
*/
-
+
int jitter_input = time;
int jitter;
-
+
if (jitter_input < JITTER_BOUND)
jitter_input = JITTER_BOUND;
-
- jitter = (((rand () % ((jitter_input * 2) + 1)) - jitter_input));
+
+ jitter = (((rand () % ((jitter_input * 2) + 1)) - jitter_input));
return jitter/JITTER_BOUND;
}
@@ -2817,22 +2801,22 @@ rip_event (enum rip_event event, int sock)
rip->t_update = NULL;
}
jitter = rip_update_jitter (rip->update_time);
- rip->t_update =
- thread_add_timer (master, rip_update, NULL,
+ rip->t_update =
+ thread_add_timer (master, rip_update, NULL,
sock ? 2 : rip->update_time + jitter);
break;
case RIP_TRIGGERED_UPDATE:
if (rip->t_triggered_interval)
rip->trigger = 1;
else if (! rip->t_triggered_update)
- rip->t_triggered_update =
+ rip->t_triggered_update =
thread_add_event (master, rip_triggered_update, NULL, 0);
break;
default:
break;
}
}
-
+
DEFUN (router_rip,
router_rip_cmd,
"router rip",
@@ -2888,7 +2872,7 @@ DEFUN (rip_version,
rip->version_recv = version;
return CMD_SUCCESS;
-}
+}
DEFUN (no_rip_version,
no_rip_version_cmd,
@@ -2901,7 +2885,7 @@ DEFUN (no_rip_version,
rip->version_recv = RI_RIP_VERSION_1_AND_2;
return CMD_SUCCESS;
-}
+}
ALIAS (no_rip_version,
no_rip_version_val_cmd,
@@ -3049,21 +3033,21 @@ DEFUN (rip_timers,
unsigned long RIP_TIMER_MIN = 5;
update = strtoul (argv[0], &endptr, 10);
- if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0')
+ if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0')
{
vty_out (vty, "update timer value error%s", VTY_NEWLINE);
return CMD_WARNING;
}
-
+
timeout = strtoul (argv[1], &endptr, 10);
- if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0')
+ if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0')
{
vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
return CMD_WARNING;
}
-
+
garbage = strtoul (argv[2], &endptr, 10);
- if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0')
+ if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0')
{
vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -3108,7 +3092,7 @@ ALIAS (no_rip_timers,
"Routing information timeout timer. Default is 180.\n"
"Garbage collection timer. Default is 120.\n")
-
+
struct route_table *rip_distance_table;
struct rip_distance
@@ -3286,7 +3270,7 @@ rip_distance_show (struct vty *vty)
struct rip_distance *rdistance;
int header = 1;
char buf[BUFSIZ];
-
+
vty_out (vty, " Distance: (default is %d)%s",
rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT,
VTY_NEWLINE);
@@ -3376,7 +3360,7 @@ DEFUN (no_rip_distance_source_access_list,
rip_distance_unset (vty, argv[0], argv[1], argv[2]);
return CMD_SUCCESS;
}
-
+
/* Print out routes update time. */
static void
rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo)
@@ -3442,7 +3426,7 @@ DEFUN (show_ip_rip,
" (i) - interface%s%s"
" Network Next Hop Metric From Tag Time%s",
VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
-
+
for (np = route_top (rip->table); np; np = route_next (np))
if ((rinfo = np->info) != NULL)
{
@@ -3453,20 +3437,20 @@ DEFUN (show_ip_rip,
zebra_route_char(rinfo->type),
rip_route_type_print (rinfo->sub_type),
inet_ntoa (np->p.u.prefix4), np->p.prefixlen);
-
+
len = 24 - len;
if (len > 0)
vty_out (vty, "%*s", len, " ");
- if (rinfo->nexthop.s_addr)
+ if (rinfo->nexthop.s_addr)
vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop),
rinfo->metric);
else
vty_out (vty, "0.0.0.0 %2d ", rinfo->metric);
/* Route which exist in kernel routing table. */
- if ((rinfo->type == ZEBRA_ROUTE_RIP) &&
+ if ((rinfo->type == ZEBRA_ROUTE_RIP) &&
(rinfo->sub_type == RIP_ROUTE_RTE))
{
vty_out (vty, "%-15s ", inet_ntoa (rinfo->from));
@@ -3483,7 +3467,7 @@ DEFUN (show_ip_rip,
{
if (rinfo->external_metric)
{
- len = vty_out (vty, "self (%s:%d)",
+ len = vty_out (vty, "self (%s:%d)",
zebra_route_string(rinfo->type),
rinfo->external_metric);
len = 16 - len;
@@ -3522,7 +3506,7 @@ DEFUN (show_ip_rip_status,
vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE);
vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
rip->update_time);
- vty_out (vty, " next due in %lu seconds%s",
+ vty_out (vty, " next due in %lu seconds%s",
thread_timer_remain_second(rip->t_update),
VTY_NEWLINE);
vty_out (vty, " Timeout after %ld seconds,", rip->timeout_time);
@@ -3531,7 +3515,7 @@ DEFUN (show_ip_rip_status,
/* Filtering status show. */
config_show_distribute (vty);
-
+
/* Default metric information. */
vty_out (vty, " Default redistribution metric is %d%s",
rip->default_metric, VTY_NEWLINE);
@@ -3569,7 +3553,7 @@ DEFUN (show_ip_rip_status,
receive_version = lookup (ri_version_msg, rip->version_recv);
else
receive_version = lookup (ri_version_msg, ri->ri_receive);
-
+
vty_out (vty, " %-17s%-3s %-3s %s%s", ifp->name,
send_version,
receive_version,
@@ -3579,7 +3563,7 @@ DEFUN (show_ip_rip_status,
}
vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
- config_write_rip_network (vty, 0);
+ config_write_rip_network (vty, 0);
{
int found_passive = 0;
@@ -3621,16 +3605,16 @@ config_write_rip (struct vty *vty)
/* Router RIP statement. */
vty_out (vty, "router rip%s", VTY_NEWLINE);
write++;
-
+
/* RIP version statement. Default is RIP version 2. */
if (rip->version_send != RI_RIP_VERSION_2
|| rip->version_recv != RI_RIP_VERSION_1_AND_2)
vty_out (vty, " version %d%s", rip->version_send,
VTY_NEWLINE);
-
+
/* RIP timer configuration. */
- if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT
- || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT
+ if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT
+ || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT
|| rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT)
vty_out (vty, " timers basic %lu %lu %lu%s",
rip->update_time,
@@ -3657,7 +3641,7 @@ config_write_rip (struct vty *vty)
/* RIP enabled network and interface configuration. */
config_write_rip_network (vty, 1);
-
+
/* RIP default metric configuration */
if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT)
vty_out (vty, " default-metric %d%s",
@@ -3684,7 +3668,7 @@ config_write_rip (struct vty *vty)
/* RIP static route configuration. */
for (rn = route_top (rip->route); rn; rn = route_next (rn))
if (rn->info)
- vty_out (vty, " route %s/%d%s",
+ vty_out (vty, " route %s/%d%s",
inet_ntoa (rn->p.u.prefix4),
rn->p.prefixlen,
VTY_NEWLINE);
@@ -3700,7 +3684,7 @@ static struct cmd_node rip_node =
"%s(config-router)# ",
1
};
-
+
/* Distribute-list update functions. */
static void
rip_distribute_update (struct distribute *dist)
@@ -3791,7 +3775,7 @@ rip_distribute_update_all_wrapper(struct access_list *notused)
{
rip_distribute_update_all(NULL);
}
-
+
/* Delete all added rip route. */
void
rip_clean (void)
@@ -3810,7 +3794,7 @@ rip_clean (void)
rinfo->sub_type == RIP_ROUTE_RTE)
rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,
&rinfo->nexthop, rinfo->metric);
-
+
RIP_TIMER_OFF (rinfo->t_timeout);
RIP_TIMER_OFF (rinfo->t_garbage_collect);
@@ -3866,7 +3850,7 @@ rip_clean (void)
XFREE (MTYPE_ROUTE_TABLE, rip->table);
XFREE (MTYPE_ROUTE_TABLE, rip->route);
XFREE (MTYPE_ROUTE_TABLE, rip->neighbor);
-
+
XFREE (MTYPE_RIP, rip);
rip = NULL;
}
@@ -3957,10 +3941,10 @@ rip_routemap_update_redistribute (void)
if (rip)
{
- for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
{
if (rip->route_map[i].name)
- rip->route_map[i].map =
+ rip->route_map[i].map =
route_map_lookup_by_name (rip->route_map[i].name);
}
}
diff --git a/tests/aspath_test.c b/tests/aspath_test.c
index ff9d4d5e..11008b25 100644
--- a/tests/aspath_test.c
+++ b/tests/aspath_test.c
@@ -6,6 +6,7 @@
#include "bgpd/bgpd.h"
#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_attr.h"
#define VT100_RESET "\x1b[0m"
#define VT100_RED "\x1b[31m"
@@ -407,7 +408,7 @@ static struct test_segment {
"#ASNs = 0, data = seq(8466 3 52737 4096 3456)",
{ 0x2,0x0, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x0d,0x80 },
12,
- { "", "",
+ { NULL, NULL,
0, 0, 0, 0, 0, 0 },
},
{ /* 26 */
@@ -417,10 +418,190 @@ static struct test_segment {
0x2,0x2, 0x10,0x00, 0x0d,0x80 },
14
,
- { "", "",
+ { NULL, NULL,
0, 0, 0, 0, 0, 0 },
},
- { NULL, NULL, {0}, 0, { NULL, 0, 0 } }
+ { /* 27 */
+ "invalid segment type",
+ "type=8(4096 3456)",
+ { 0x8,0x2, 0x10,0x00, 0x0d,0x80 },
+ 14
+ ,
+ { NULL, NULL,
+ 0, 0, 0, 0, 0, 0 },
+ }, { NULL, NULL, {0}, 0, { NULL, 0, 0 } }
+};
+
+/* */
+static struct aspath_tests {
+ const char *desc;
+ const struct test_segment *segment;
+ const char *shouldbe; /* String it should evaluate to */
+ const enum as4 { AS4_DATA, AS2_DATA }
+ as4; /* whether data should be as4 or not (ie as2) */
+ const int result; /* expected result for bgp_attr_parse */
+ const int cap; /* capabilities to set for peer */
+ const char attrheader [1024];
+ size_t len;
+} aspath_tests [] =
+{
+ /* 0 */
+ {
+ "basic test",
+ &test_segments[0],
+ "8466 3 52737 4096",
+ AS2_DATA, 0,
+ 0,
+ { BGP_ATTR_FLAG_TRANS,
+ BGP_ATTR_AS_PATH,
+ 10,
+ },
+ 3,
+ },
+ /* 1 */
+ {
+ "length too short",
+ &test_segments[0],
+ "8466 3 52737 4096",
+ AS2_DATA, -1,
+ 0,
+ { BGP_ATTR_FLAG_TRANS,
+ BGP_ATTR_AS_PATH,
+ 8,
+ },
+ 3,
+ },
+ /* 2 */
+ {
+ "length too long",
+ &test_segments[0],
+ "8466 3 52737 4096",
+ AS2_DATA, -1,
+ 0,
+ { BGP_ATTR_FLAG_TRANS,
+ BGP_ATTR_AS_PATH,
+ 12,
+ },
+ 3,
+ },
+ /* 3 */
+ {
+ "incorrect flag",
+ &test_segments[0],
+ "8466 3 52737 4096",
+ AS2_DATA, -1,
+ 0,
+ { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL,
+ BGP_ATTR_AS_PATH,
+ 10,
+ },
+ 3,
+ },
+ /* 4 */
+ {
+ "as4_path, with as2 format data",
+ &test_segments[0],
+ "8466 3 52737 4096",
+ AS2_DATA, -1,
+ 0,
+ { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL,
+ BGP_ATTR_AS4_PATH,
+ 10,
+ },
+ 3,
+ },
+ /* 5 */
+ {
+ "as4, with incorrect attr length",
+ &test_segments[0],
+ "8466 3 52737 4096",
+ AS4_DATA, -1,
+ PEER_CAP_AS4_RCV,
+ { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL,
+ BGP_ATTR_AS4_PATH,
+ 10,
+ },
+ 3,
+ },
+ /* 6 */
+ {
+ "basic 4-byte as-path",
+ &test_segments[0],
+ "8466 3 52737 4096",
+ AS4_DATA, 0,
+ PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV,
+ { BGP_ATTR_FLAG_TRANS,
+ BGP_ATTR_AS_PATH,
+ 18,
+ },
+ 3,
+ },
+ /* 7 */
+ {
+ "4b AS_PATH: too short",
+ &test_segments[0],
+ "8466 3 52737 4096",
+ AS4_DATA, -1,
+ PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV,
+ { BGP_ATTR_FLAG_TRANS,
+ BGP_ATTR_AS_PATH,
+ 16,
+ },
+ 3,
+ },
+ /* 8 */
+ {
+ "4b AS_PATH: too long",
+ &test_segments[0],
+ "8466 3 52737 4096",
+ AS4_DATA, -1,
+ PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV,
+ { BGP_ATTR_FLAG_TRANS,
+ BGP_ATTR_AS_PATH,
+ 20,
+ },
+ 3,
+ },
+ /* 9 */
+ {
+ "4b AS_PATH: too long2",
+ &test_segments[0],
+ "8466 3 52737 4096",
+ AS4_DATA, -1,
+ PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV,
+ { BGP_ATTR_FLAG_TRANS,
+ BGP_ATTR_AS_PATH,
+ 22,
+ },
+ 3,
+ },
+ /* 10 */
+ {
+ "4b AS_PATH: bad flags",
+ &test_segments[0],
+ "8466 3 52737 4096",
+ AS4_DATA, -1,
+ PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV,
+ { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL,
+ BGP_ATTR_AS_PATH,
+ 18,
+ },
+ 3,
+ },
+ /* 11 */
+ {
+ "4b AS_PATH: confed",
+ &test_segments[6],
+ "8466 3 52737 4096",
+ AS4_DATA, -1,
+ PEER_CAP_AS4_ADV,
+ { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL,
+ BGP_ATTR_AS4_PATH,
+ 14,
+ },
+ 3,
+ },
+ { NULL, NULL, NULL, 0, 0, 0, { 0 }, 0 },
};
/* prepending tests */
@@ -430,21 +611,25 @@ static struct tests {
struct test_spec sp;
} prepend_tests[] =
{
+ /* 0 */
{ &test_segments[0], &test_segments[1],
{ "8466 3 52737 4096 8722 4",
"8466 3 52737 4096 8722 4",
6, 0, NOT_ALL_PRIVATE, 4096, 1, 8466 },
},
+ /* 1 */
{ &test_segments[1], &test_segments[3],
{ "8722 4 8482 51457 {5204}",
"8722 4 8482 51457 {5204}",
5, 0, NOT_ALL_PRIVATE, 5204, 1, 8722 }
},
+ /* 2 */
{ &test_segments[3], &test_segments[4],
{ "8482 51457 {5204} 8467 59649 {4196,48658} {17322,30745}",
"8482 51457 {5204} 8467 59649 {4196,48658} {17322,30745}",
7, 0, NOT_ALL_PRIVATE, 5204, 1, 8482 },
},
+ /* 3 */
{ &test_segments[4], &test_segments[5],
{ "8467 59649 {4196,48658} {17322,30745} 6435 59408 21665"
" {2457,4369,61697} 1842 41590 51793",
@@ -452,11 +637,13 @@ static struct tests {
" {2457,4369,61697} 1842 41590 51793",
11, 0, NOT_ALL_PRIVATE, 61697, 1, 8467 }
},
+ /* 4 */
{ &test_segments[5], &test_segments[6],
- { "6435 59408 21665 {2457,4369,61697} 1842 41590 51793 (123 456 789)",
- "6435 59408 21665 {2457,4369,61697} 1842 41590 51793 (123 456 789)",
- 7, 3, NOT_ALL_PRIVATE, 123, 1, 6435 },
+ { "6435 59408 21665 {2457,4369,61697} 1842 41590 51793",
+ "6435 59408 21665 {2457,4369,61697} 1842 41590 51793",
+ 7, 0, NOT_ALL_PRIVATE, 1842, 1, 6435 },
},
+ /* 5 */
{ &test_segments[6], &test_segments[7],
{ "(123 456 789) (123 456 789) (111 222)",
"",
@@ -682,6 +869,12 @@ validate (struct aspath *as, const struct test_spec *sp)
static struct stream *s;
struct aspath *asinout, *asconfeddel, *asstr, *as4;
+ if (as == NULL && sp->shouldbe == NULL)
+ {
+ printf ("Correctly failed to parse\n");
+ return fails;
+ }
+
out = aspath_snmp_pathseg (as, &bytes);
asinout = make_aspath (out, bytes, 0);
@@ -790,8 +983,8 @@ validate (struct aspath *as, const struct test_spec *sp)
printf ("private check: %d %d\n", sp->private_as,
aspath_private_as_check (as));
}
- aspath_unintern (asinout);
- aspath_unintern (as4);
+ aspath_unintern (&asinout);
+ aspath_unintern (&as4);
aspath_free (asconfeddel);
aspath_free (asstr);
@@ -835,7 +1028,9 @@ parse_test (struct test_segment *t)
printf (FAILED "\n");
printf ("\n");
- aspath_unintern (asp);
+
+ if (asp)
+ aspath_unintern (&asp);
}
/* prepend testing */
@@ -851,7 +1046,7 @@ prepend_test (struct tests *t)
asp2 = make_aspath (t->test2->asdata, t->test2->len, 0);
ascratch = aspath_dup (asp2);
- aspath_unintern (asp2);
+ aspath_unintern (&asp2);
asp2 = aspath_prepend (asp1, ascratch);
@@ -863,7 +1058,7 @@ prepend_test (struct tests *t)
printf ("%s!\n", FAILED);
printf ("\n");
- aspath_unintern (asp1);
+ aspath_unintern (&asp1);
aspath_free (asp2);
}
@@ -879,7 +1074,7 @@ empty_prepend_test (struct test_segment *t)
asp2 = aspath_empty ();
ascratch = aspath_dup (asp2);
- aspath_unintern (asp2);
+ aspath_unintern (&asp2);
asp2 = aspath_prepend (asp1, ascratch);
@@ -891,7 +1086,8 @@ empty_prepend_test (struct test_segment *t)
printf (FAILED "!\n");
printf ("\n");
- aspath_unintern (asp1);
+ if (asp1)
+ aspath_unintern (&asp1);
aspath_free (asp2);
}
@@ -915,8 +1111,8 @@ as4_reconcile_test (struct tests *t)
printf (FAILED "!\n");
printf ("\n");
- aspath_unintern (asp1);
- aspath_unintern (asp2);
+ aspath_unintern (&asp1);
+ aspath_unintern (&asp2);
aspath_free (ascratch);
}
@@ -941,8 +1137,8 @@ aggregate_test (struct tests *t)
printf (FAILED "!\n");
printf ("\n");
- aspath_unintern (asp1);
- aspath_unintern (asp2);
+ aspath_unintern (&asp1);
+ aspath_unintern (&asp2);
aspath_free (ascratch);
/* aspath_unintern (ascratch);*/
}
@@ -989,34 +1185,113 @@ cmp_test ()
printf (OK "\n");
printf ("\n");
- aspath_unintern (asp1);
- aspath_unintern (asp2);
+ aspath_unintern (&asp1);
+ aspath_unintern (&asp2);
}
}
+static int
+handle_attr_test (struct aspath_tests *t)
+{
+ struct bgp bgp = { 0 };
+ struct peer peer = { 0 };
+ struct attr attr = { 0 };
+ int ret;
+ int initfail = failed;
+ struct aspath *asp;
+ size_t datalen;
+ char host[] = { "none" } ;
+
+ asp = make_aspath (t->segment->asdata, t->segment->len, 0);
+
+ peer.ibuf = stream_new (BGP_MAX_PACKET_SIZE);
+ peer.obuf = stream_fifo_new ();
+ peer.bgp = &bgp;
+ peer.host = host ;
+#if 0
+ peer.fd = -1;
+#endif
+ peer.cap = t->cap;
+
+ stream_write (peer.ibuf, t->attrheader, t->len);
+ datalen = aspath_put (peer.ibuf, asp, t->as4 == AS4_DATA);
+
+ ret = bgp_attr_parse (&peer, &attr, t->len + datalen, NULL, NULL);
+
+ if (ret != t->result)
+ {
+ printf ("bgp_attr_parse returned %d, expected %d\n", ret, t->result);
+ printf ("datalen %d\n", (int)datalen);
+ failed++;
+ }
+ if (ret != 0)
+ goto out;
+
+ if (attr.aspath == NULL)
+ {
+ printf ("aspath is NULL!\n");
+ failed++;
+ }
+ if (attr.aspath && strcmp (attr.aspath->str, t->shouldbe))
+ {
+ printf ("attr str and 'shouldbe' mismatched!\n"
+ "attr str: %s\n"
+ "shouldbe: %s\n",
+ attr.aspath->str, t->shouldbe);
+ failed++;
+ }
+
+out:
+ if (attr.aspath)
+ aspath_unintern (&attr.aspath);
+ if (asp)
+ aspath_unintern (&asp);
+ return failed - initfail;
+}
+
+static void
+attr_test (struct aspath_tests *t)
+{
+ printf ("%s\n", t->desc);
+ printf ("%s\n\n", handle_attr_test (t) ? FAILED : OK);
+}
+
int
main (void)
{
int i = 0;
- aspath_init();
+ bgp_master_init ();
+ master = bm->master;
+ bgp_attr_init ();
+
while (test_segments[i].name)
{
+ printf ("test %u\n", i);
parse_test (&test_segments[i]);
empty_prepend_test (&test_segments[i++]);
}
i = 0;
while (prepend_tests[i].test1)
- prepend_test (&prepend_tests[i++]);
+ {
+ printf ("prepend test %u\n", i);
+ prepend_test (&prepend_tests[i++]);
+ }
i = 0;
while (aggregate_tests[i].test1)
- aggregate_test (&aggregate_tests[i++]);
+ {
+ printf ("aggregate test %u\n", i);
+ aggregate_test (&aggregate_tests[i++]);
+ }
i = 0;
while (reconcile_tests[i].test1)
- as4_reconcile_test (&reconcile_tests[i++]);
+ {
+ printf ("reconcile test %u\n", i);
+ as4_reconcile_test (&reconcile_tests[i++]);
+ }
i = 0;
@@ -1026,6 +1301,14 @@ main (void)
empty_get_test();
+ i = 0;
+
+ while (aspath_tests[i].desc)
+ {
+ printf ("aspath_attr test %d\n", i);
+ attr_test (&aspath_tests[i++]);
+ }
+
printf ("failures: %d\n", failed);
printf ("aspath count: %ld\n", aspath_count());
diff --git a/tests/ecommunity_test.c b/tests/ecommunity_test.c
index da48865c..3a67228d 100644
--- a/tests/ecommunity_test.c
+++ b/tests/ecommunity_test.c
@@ -98,7 +98,7 @@ validate (struct ecommunity *ecom, const struct test_spec *sp)
str1,
(etmp && str2) ? str2 : "NULL");
}
- ecommunity_free (etmp);
+ ecommunity_free (&etmp);
XFREE (MTYPE_ECOMMUNITY_STR, str1);
XFREE (MTYPE_ECOMMUNITY_STR, str2);
@@ -123,7 +123,7 @@ parse_test (struct test_segment *t)
printf ("failed\n");
printf ("\n");
- ecommunity_unintern (ecom);
+ ecommunity_unintern (&ecom);
}
diff --git a/tools/multiple-bgpd.sh b/tools/multiple-bgpd.sh
index 028ad696..d6a38ed4 100644
--- a/tools/multiple-bgpd.sh
+++ b/tools/multiple-bgpd.sh
@@ -25,13 +25,14 @@ for H in `seq 1 ${NUM}` ; do
NEXTAS=$((${ASBASE} + $NEXT))
PREVADDR="${PREFIX}${PREV}"
PREVAS=$((${ASBASE} + $PREV))
+ ASN=$((64560+${H}))
# Edit config to suit.
cat > "$CONF" <<- EOF
password whatever
service advanced-vty
!
- router bgp $((64560+${H}))
+ router bgp ${ASN}
bgp router-id ${ADDR}
network 10.${H}.1.0/24 pathlimit 1
network 10.${H}.2.0/24 pathlimit 2
@@ -40,6 +41,7 @@ for H in `seq 1 ${NUM}` ; do
neighbor default update-source ${ADDR}
neighbor default capability orf prefix-list both
neighbor default soft-reconfiguration inbound
+ neighbor default route-map test out
neighbor ${NEXTADDR} remote-as ${NEXTAS}
neighbor ${NEXTADDR} peer-group default
neighbor ${PREVADDR} remote-as ${PREVAS}
@@ -53,10 +55,15 @@ for H in `seq 1 ${NUM}` ; do
neighbor default activate
neighbor default capability orf prefix-list both
neighbor default default-originate
+ neighbor default route-map test out
neighbor ${NEXTADDR} peer-group default
neighbor ${PREVADDR} peer-group default
exit-address-family
!
+ route-map test permit 10
+ set extcommunity rt ${ASN}:1
+ set extcommunity soo ${ASN}:2
+ set community ${ASN}:1
line vty
!
end
diff --git a/zebra/irdp_main.c b/zebra/irdp_main.c
index c297979c..0658c397 100644
--- a/zebra/irdp_main.c
+++ b/zebra/irdp_main.c
@@ -29,7 +29,7 @@
*/
/*
- * Thanks to Jens Låås at Swedish University of Agricultural Sciences
+ * Thanks to Jens L��s at Swedish University of Agricultural Sciences
* for reviewing and tests.
*/
@@ -108,7 +108,7 @@ irdp_sock_init (void)
return ret;
};
- ret = setsockopt_ifindex (AF_INET, sock, 1);
+ ret = setsockopt_pktinfo (AF_INET, sock, 1);
if (ret < 0) {
zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno));
close(sock);
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
index 808dcf74..b3111b8e 100644
--- a/zebra/zebra_routemap.c
+++ b/zebra/zebra_routemap.c
@@ -642,17 +642,14 @@ route_set_src (void *rule, struct prefix *prefix,
static void *
route_set_src_compile (const char *arg)
{
- sa_family_t family;
union g_addr src, *psrc;
- if (inet_pton(AF_INET, arg, &src.ipv4) > 0)
- family = AF_INET;
+ if (inet_pton(AF_INET, arg, &src.ipv4) != 1
#ifdef HAVE_IPV6
- else if (inet_pton(AF_INET6, arg, &src.ipv6) > 0)
- family = AF_INET6;
+ && inet_pton(AF_INET6, arg, &src.ipv6) != 1
#endif /* HAVE_IPV6 */
- else
- return NULL;
+ )
+ return NULL;
psrc = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (union g_addr));
*psrc = src;
diff --git a/zebra/zserv.c b/zebra/zserv.c
index dc3d432b..398b74c8 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -1360,8 +1360,8 @@ zebra_serv ()
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
- sockopt_reuseaddr (accept_sock);
- sockopt_reuseport (accept_sock);
+ setsockopt_reuseaddr (accept_sock);
+ setsockopt_reuseport (accept_sock);
if ( zserv_privs.change(ZPRIVS_RAISE) )
zlog (NULL, LOG_ERR, "Can't raise privileges");