diff options
205 files changed, 7357 insertions, 3576 deletions
diff --git a/.cvsignore b/.cvsignore deleted file mode 100644 index a67bba01..00000000 --- a/.cvsignore +++ /dev/null @@ -1,30 +0,0 @@ -config.log -config.h -config.cache -config.status -config.guess -config.sub -ltmain.sh -stamp-h -stamp-h[0-9]* -*-stamp -Makefile -INSTALL -.deps -depcomp -missing -install-sh -autom4te*.cache -configure.lineno -configure -config.h.in -aclocal.m4 -Makefile.in -zebra-[0-9.][0-9.][0-9.]*.tar.gz -quagga-[0-9.][0-9.][0-9.]*.tar.gz -quagga-[0-9.][0-9.][0-9.]*.tar.gz.asc -.nfs* -libtool -.arch-inventory -.arch-ids -{arch} diff --git a/HACKING.pending b/HACKING.pending index 80c8cb45..5e0defd8 100644 --- a/HACKING.pending +++ b/HACKING.pending @@ -28,11 +28,7 @@ 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/INSTALL.quagga.txt b/INSTALL.quagga.txt index f627c922..ec4e799d 100644 --- a/INSTALL.quagga.txt +++ b/INSTALL.quagga.txt @@ -1,5 +1,3 @@ -# $Id$ - -------------------------------------------------------------------------- Building and Installing Quagga from releases or snapshots: diff --git a/bgpd/.cvsignore b/bgpd/.cvsignore deleted file mode 100644 index f4504f62..00000000 --- a/bgpd/.cvsignore +++ /dev/null @@ -1,15 +0,0 @@ -Makefile -Makefile.in -*.o -bgpd -bgp_btoa -bgpd.conf -tags -TAGS -.deps -.nfs* -*.lo -*.la -*.libs -.arch-inventory -.arch-ids @@ -34,7 +34,16 @@ #include "confirm.h" /*############################################################################## - * BGP RFC's we know about -- as of 16-Oct-2009 + * BGP RFC's we know about -- as of 31-Dec-2011 + * + * RFC6472 Recommendation for Not Using AS_SET and AS_CONFED_SET in BGP + * RFC6397 Multi-Threaded Routing Toolkit (MRT) Border Gateway Protocol + * (BGP) Routing Information Export Format with Geo-Location + * Extensions + * RFC6286 Autonomous-System-Wide Unique BGP Identifier for BGP-4 + * RFC6198 Requirements for the Graceful Shutdown of BGP Sessions + * RFC5701 IPv6 Address Specific BGP Extended Community Attribute + * RFC5668 4-Octet AS Specific BGP Extended Community * * RFC5566 BGP IPSec Tunnel Encapsulation Attribute * RFC5543 BGP Traffic Engineering Attribute diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c index c03546d7..7246bab1 100644 --- a/bgpd/bgp_advertise.c +++ b/bgpd/bgp_advertise.c @@ -27,6 +27,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "thread.h" #include "bgpd/bgpd.h" +#include "bgpd/bgp_peer.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_advertise.h" diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index ba3b3e83..185c07b0 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -78,16 +78,16 @@ static struct hash *ashash; /* Stream for SNMP. See aspath_snmp_pathseg */ static struct stream *snmp_stream; -static inline as_t * +static as_t * assegment_data_new (int num) { return (XCALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1))); } -static inline void +static void assegment_data_free (as_t *asdata) { - XFREE (MTYPE_AS_SEG_DATA,asdata); + XFREE (MTYPE_AS_SEG_DATA, asdata); } /* Get a new segment. Note that 0 is an allowed length, @@ -118,7 +118,8 @@ assegment_free (struct assegment *seg) return; if (seg->as) - XFREE (MTYPE_AS_SEG_DATA, seg->as); + assegment_data_free (seg->as) ; + memset (seg, 0xfe, sizeof(struct assegment)); XFREE (MTYPE_AS_SEG, seg); @@ -194,7 +195,7 @@ assegment_prepend_asns (struct assegment *seg, as_t asnum, int num) newas[i] = asnum; memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1)); - XFREE (MTYPE_AS_SEG_DATA, seg->as); + assegment_data_free (seg->as) ; seg->as = newas; seg->length += num; return seg; @@ -832,7 +833,7 @@ assegment_data_put (struct stream *s, as_t *as, int num, bool use32bit) } ; return ASSEGMENT_DATA_SIZE(num, use32bit) ; -} +} ; /* write aspath data to stream */ size_t diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 5e24dc0a..e00be3a0 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -31,6 +31,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "jhash.h" #include "bgpd/bgpd.h" +#include "bgpd/bgp_peer.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_aspath.h" @@ -38,31 +39,105 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_debug.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_names.h" +#if 0 /* Attribute strings for logging. */ static const struct message attr_str [] = { - { BGP_ATTR_ORIGIN, "ORIGIN" }, - { BGP_ATTR_AS_PATH, "AS_PATH" }, - { BGP_ATTR_NEXT_HOP, "NEXT_HOP" }, - { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" }, - { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" }, + { BGP_ATTR_ORIGIN, "ORIGIN" }, + { BGP_ATTR_AS_PATH, "AS_PATH" }, + { BGP_ATTR_NEXT_HOP, "NEXT_HOP" }, + { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" }, + { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" }, { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" }, - { BGP_ATTR_AGGREGATOR, "AGGREGATOR" }, - { BGP_ATTR_COMMUNITIES, "COMMUNITY" }, - { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" }, - { BGP_ATTR_CLUSTER_LIST, "CLUSTERLIST" }, - { BGP_ATTR_DPA, "DPA" }, - { BGP_ATTR_ADVERTISER, "ADVERTISER"} , - { BGP_ATTR_RCID_PATH, "RCID_PATH" }, - { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" }, - { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" }, - { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" }, - { BGP_ATTR_AS4_PATH, "AS4_PATH" }, - { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" }, - { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" }, + { BGP_ATTR_AGGREGATOR, "AGGREGATOR" }, + { BGP_ATTR_COMMUNITIES, "COMMUNITY" }, + { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" }, + { BGP_ATTR_CLUSTER_LIST, "CLUSTER_LIST" }, + { BGP_ATTR_DPA, "DPA" }, + { BGP_ATTR_ADVERTISER, "ADVERTISER" } , + { BGP_ATTR_RCID_PATH, "RCID_PATH" }, + { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" }, + { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" }, + { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" }, + { BGP_ATTR_AS4_PATH, "AS4_PATH" }, + { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" }, + { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" }, }; static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]); +#endif + +static const struct message attr_flag_str[] = +{ + { BGP_ATTR_FLAG_OPTIONAL, "Optional" }, + { BGP_ATTR_FLAG_TRANS, "Transitive" }, + { BGP_ATTR_FLAG_PARTIAL, "Partial" }, + { BGP_ATTR_FLAG_EXTLEN, "Extended Length" }, +}; +static const size_t attr_flag_str_max = + sizeof (attr_flag_str) / sizeof (attr_flag_str[0]); + +/* Flag check table + * + * For each known attribute: mask = flags we care about + * req = state required for those flags + */ +#define BGP_ATTR_FLAGS_WELL_KNOWN \ + .mask = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_PARTIAL,\ + .req = 0 | BGP_ATTR_FLAG_TRANS | 0 + +#define BGP_ATTR_FLAGS_OPTIONAL_NON_TRANS \ + .mask = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_PARTIAL,\ + .req = BGP_ATTR_FLAG_OPTIONAL | 0 | 0 + +#define BGP_ATTR_FLAGS_OPTIONAL_TRANS \ + .mask = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS | 0,\ + .req = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS | 0 + +enum { attr_flags_check_limit = 32 } ; + +typedef const struct +{ + uint8_t mask ; + uint8_t req ; +} attr_flags_check_t ; + +static attr_flags_check_t attr_flags_check_array[attr_flags_check_limit] = +{ + [0 ] = { 0 }, + + [BGP_ATTR_ORIGIN ] = { BGP_ATTR_FLAGS_WELL_KNOWN }, + [BGP_ATTR_AS_PATH ] = { BGP_ATTR_FLAGS_WELL_KNOWN }, + [BGP_ATTR_NEXT_HOP ] = { BGP_ATTR_FLAGS_WELL_KNOWN }, + [BGP_ATTR_MULTI_EXIT_DISC ] = { BGP_ATTR_FLAGS_OPTIONAL_NON_TRANS }, + [BGP_ATTR_LOCAL_PREF ] = { BGP_ATTR_FLAGS_WELL_KNOWN }, + [BGP_ATTR_ATOMIC_AGGREGATE ] = { BGP_ATTR_FLAGS_WELL_KNOWN }, + [BGP_ATTR_AGGREGATOR ] = { BGP_ATTR_FLAGS_OPTIONAL_TRANS }, + + [BGP_ATTR_COMMUNITIES ] = { BGP_ATTR_FLAGS_OPTIONAL_TRANS }, + [BGP_ATTR_ORIGINATOR_ID ] = { BGP_ATTR_FLAGS_OPTIONAL_NON_TRANS }, + [BGP_ATTR_CLUSTER_LIST ] = { BGP_ATTR_FLAGS_OPTIONAL_NON_TRANS }, + [BGP_ATTR_DPA ] = { BGP_ATTR_FLAGS_OPTIONAL_TRANS }, + [BGP_ATTR_ADVERTISER ] = { BGP_ATTR_FLAGS_OPTIONAL_NON_TRANS }, + [BGP_ATTR_RCID_PATH ] = { BGP_ATTR_FLAGS_OPTIONAL_NON_TRANS }, + [BGP_ATTR_MP_REACH_NLRI ] = { BGP_ATTR_FLAGS_OPTIONAL_NON_TRANS }, + [BGP_ATTR_MP_UNREACH_NLRI ] = { BGP_ATTR_FLAGS_OPTIONAL_NON_TRANS }, + [BGP_ATTR_EXT_COMMUNITIES ] = { BGP_ATTR_FLAGS_OPTIONAL_TRANS }, + [BGP_ATTR_AS4_PATH ] = { BGP_ATTR_FLAGS_OPTIONAL_TRANS }, + [BGP_ATTR_AS4_AGGREGATOR ] = { BGP_ATTR_FLAGS_OPTIONAL_TRANS }, + [BGP_ATTR_AS_PATHLIMIT ] = { BGP_ATTR_FLAGS_OPTIONAL_TRANS }, +} ; + +/* For all known attribute types this should collapse to almost nothing each + * time it is compiled. + */ +inline static attr_flags_check_t* +bgp_attr_flags_check_get(uint8_t attr_type) +{ + return &attr_flags_check_array[(attr_type < attr_flags_check_limit) + ? attr_type : 0] ; +} ; static struct hash *cluster_hash; @@ -174,14 +249,12 @@ cluster_intern (struct cluster_list *cluster) void cluster_unintern (struct cluster_list *cluster) { - struct cluster_list *ret; - if (cluster->refcnt) cluster->refcnt--; if (cluster->refcnt == 0) { - ret = hash_release (cluster_hash, cluster); + hash_release (cluster_hash, cluster); cluster_free (cluster); } } @@ -234,14 +307,12 @@ transit_intern (struct transit *transit) void transit_unintern (struct transit *transit) { - struct transit *ret; - if (transit->refcnt) transit->refcnt--; if (transit->refcnt == 0) { - ret = hash_release (transit_hash, transit); + hash_release (transit_hash, transit); transit_free (transit); } } @@ -499,7 +570,7 @@ bgp_attr_intern (struct attr *attr) { struct attr *find; - /* Intern referenced strucutre. */ + /* Intern referenced structure. */ if (attr->aspath) { if (! attr->aspath->refcnt) @@ -578,10 +649,9 @@ bgp_attr_default_intern (u_char origin) { struct attr attr; struct attr *new; - struct attr_extra *attre; memset (&attr, 0, sizeof (struct attr)); - attre = bgp_attr_extra_get (&attr); + bgp_attr_extra_get (&attr); bgp_attr_default_set(&attr, origin); @@ -725,8 +795,9 @@ bgp_attr_unintern (struct attr **attr) } ; } ; - /* Now the sub-objects */ - bgp_attr_unintern_sub (&tmp, false) ; /* false => don't free extra */ + /* Now the sub-objects + */ + bgp_attr_unintern_sub (&tmp, false /* don't free extra */) ; } /*------------------------------------------------------------------------------ @@ -754,15 +825,69 @@ bgp_attr_flush (struct attr *attr) } } +/*------------------------------------------------------------------------------ + * Get address of start of attribute (byte 0 of header) and total length of + * same. + * + * Uses the s->startp planted for this purpose. + * + * NB: if the s->startp is at or beyond s->endp, then it is "unset", and we + * return NULL and zero length. + * + * Otherwise, at this point the entire attribute is expected to be within + * the bounds of the stream. + */ +static byte* +bgp_attr_raw(struct peer *peer, ulen* total) +{ + struct stream* s ; + byte* raw ; + ulen len ; + ulen startp ; + + s = BGP_INPUT(peer) ; + startp = stream_get_startp(s) ; + + if (startp >= stream_get_endp(s)) + { + *total = 0 ; + return NULL ; + } ; + + raw = stream_get_pnt_to(s, startp) ; + + len = raw[2] ; + if (CHECK_FLAG (raw[0], BGP_ATTR_FLAG_EXTLEN)) + len = (len << 8) + 4 ; + else + len = len + 3 ; + + qassert((raw + len) <= stream_get_pnt_to(s, stream_get_endp(s))) ; + + *total = len ; + return raw ; +} ; + /* 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. + * + * NB: if sends a notification, then picks the data to send out of the + * BGP_INPUT(peer), assuming that the s->startp has been set to the start + * of the attribute. + * + * Assumes that the attribute header and the entire length of the attribute + * is within the current stream -- for if not, the attribute would have + * been rejected well before we get to this point. */ 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) + u_char subcode) { + byte* data ; + uint data_len ; + /* Only relax error handling for eBGP peers */ if (peer_sort (peer) == BGP_PEER_EBGP) { @@ -776,7 +901,7 @@ bgp_attr_malformed (struct peer *peer, u_char attr_type, u_char flag, case BGP_ATTR_AS4_AGGREGATOR: case BGP_ATTR_AGGREGATOR: case BGP_ATTR_ATOMIC_AGGREGATE: - return BGP_ATTR_PARSE_PROCEED; + return BGP_ATTR_PARSE_IGNORE; /* Core attributes, particularly ones which may influence route * selection should always cause session resets @@ -807,35 +932,174 @@ bgp_attr_malformed (struct peer *peer, u_char attr_type, u_char flag, } ; } ; - /* default to reset */ + /* default to reset + * + * If notification goes with data, that is generally the entire attribute, + * including the header. + */ + switch(subcode) + { + case BGP_NOTIFY_UPDATE_MAL_ATTR: + case BGP_NOTIFY_UPDATE_MAL_AS_PATH: + case BGP_NOTIFY_UPDATE_AS_ROUTE_LOOP: + case BGP_NOTIFY_UPDATE_INVAL_NETWORK: + default: + data = NULL ; + data_len = 0 ; /* send nothing */ + break ; + + case BGP_NOTIFY_UPDATE_MISS_ATTR: + data = &attr_type ; + data_len = 1 ; /* send just the missing type */ + break ; + + case BGP_NOTIFY_UPDATE_UNREC_ATTR: + case BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR: + case BGP_NOTIFY_UPDATE_ATTR_LENG_ERR: + case BGP_NOTIFY_UPDATE_INVAL_ORIGIN: + case BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP: + case BGP_NOTIFY_UPDATE_OPT_ATTR_ERR: + data = bgp_attr_raw(peer, &data_len) ; + + qassert(flag == (data[0] & 0xF0)) ; + qassert(attr_type == data[1]) ; + + break ; /* send complete attribute */ + } ; + bgp_peer_down_error_with_data(peer, BGP_NOTIFY_UPDATE_ERR, subcode, - startp, length) ; + data, data_len) ; return BGP_ATTR_PARSE_ERROR; } ; -/* Get origin attribute of the update message. */ +/* Reject attribute on basis of its length + * + * Issues a logging message and treats as BGP_NOTIFY_UPDATE_ATTR_LENG_ERR + */ static bgp_attr_parse_ret_t -bgp_attr_origin (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp) +bgp_attr_length_malformed (struct peer *peer, u_char type, u_char flag, + ulen len_has, ulen len_required) { - bgp_size_t total; + zlog (peer->log, LOG_ERR, "%s attribute length is %u -- should be %u", + map_direct(bgp_attr_name_map, type).str, len_has, len_required) ; + + return bgp_attr_malformed (peer, type, flag, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); +} ; + +/* Find out what is wrong with the path attribute flag bits and log the error. + "Flag bits" here stand for Optional, Transitive and Partial, but not for + Extended Length. Checking O/T/P bits at once implies, that the attribute + being diagnosed is defined by RFC as either a "well-known" or an "optional, + non-transitive" attribute. - /* total is entire attribute length include Attribute Flags (1), - Attribute Type code (1) and Attribute length (1 or 2). */ - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + NB: by the time we get to here, the LS 4 bits of the flags have been + zeroised. + Returns: true <=> the flag bits are known to be OK + false => one or more flag bits known to be bad... + ...or unknown attr_code (!) + */ +static bool +bgp_attr_flags_diagnose +( + struct peer * peer, + const uint8_t attr_code, /* BGP_ATTR_XXXX received */ + uint8_t flag /* flags received */ +) +{ + attr_flags_check_t* check ; + uint8_t diff ; + + qassert((flag & 0x0F) == 0) ; + + check = bgp_attr_flags_check_get(attr_code) ; + + if (check->mask == 0) + { + zlog(peer->log, LOG_ERR, "***BUG: %s() given unknown attribute type 0x%x", + __func__, attr_code) ; + return false ; + } ; + + diff = (flag ^ check->req) & check->mask ; + + if (diff != 0) + { + bool seen ; + uint i ; + + seen = false ; + for (i = 0; i < attr_flag_str_max ; i++) + { + uint8_t bit ; + + bit = attr_flag_str[i].key ; + + if (diff & bit) + { + zlog (peer->log, LOG_ERR, + "%s attribute must%s be flagged as \"%s\"", + map_direct(bgp_attr_name_map, attr_code).str, + (check->req & bit) ? "" : " not", attr_flag_str[i].str) ; + seen = true ; + } ; + } ; + + qassert (seen); + } ; + + return diff == 0 ; +} ; + +/* Check that the flags for the given attribute are OK, and if not, issue + * suitable diagnostic. + * + * Should collapse to next to nothing -- certainly for constant attr_code ! + */ +inline static bool +bgp_attr_flags_check(struct peer * peer, const uint8_t attr_code, uint8_t flag) +{ + attr_flags_check_t* check ; + + check = bgp_attr_flags_check_get(attr_code) ; + + if (((flag & check->mask) == check->req) && (check->mask != 0)) + return true ; + + return bgp_attr_flags_diagnose(peer, attr_code, flag) ; +} ; + + +/* This is actually an internal error -- at some point has failed to read + * everything that was expected (underrun) or have tried to read more than + * is available (overrun) ! + */ +static bgp_attr_parse_ret_t +bgp_attr_over_or_underrun(struct peer *peer, uint8_t type, bgp_size_t length) +{ + zlog (peer->log, LOG_ERR, + "%s: BGP attribute %s, parser error: %srun %u bytes (BUG)", + peer->host, map_direct(bgp_attr_name_map, type).str, + stream_has_overrun(peer->ibuf) ? "over" : "under", + length) ; + + bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_SUBCODE_UNSPECIFIC); + return BGP_ATTR_PARSE_ERROR; +} ; + +/* Get origin attribute of the update message. */ +static bgp_attr_parse_ret_t +bgp_attr_origin (struct peer *peer, bgp_size_t length, + struct attr *attr, u_char flag) +{ /* If any recognized attribute has Attribute Flags that conflict with the Attribute Type Code, then the Error Subcode is set to Attribute Flags Error. The Data field contains the erroneous attribute (type, length and value). */ - if (flag != BGP_ATTR_FLAG_TRANS) - { - zlog (peer->log, LOG_ERR, - "Origin attribute flag isn't transitive %d", flag); - return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - } + if (!bgp_attr_flags_check(peer, BGP_ATTR_ORIGIN, flag)) + return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR); /* If any recognized attribute has Attribute Length that conflicts with the expected length (based on the attribute type code), then @@ -843,13 +1107,7 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, field contains the erroneous attribute (type, length and value). */ if (length != 1) - { - zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d", - length); - return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - startp, total); - } + return bgp_attr_length_malformed (peer, BGP_ATTR_ORIGIN, flag, length, 1) ; /* Fetch origin attribute. */ attr->origin = stream_getc (BGP_INPUT (peer)); @@ -861,11 +1119,10 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, && (attr->origin != BGP_ORIGIN_EGP) && (attr->origin != BGP_ORIGIN_INCOMPLETE)) { - zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d", - attr->origin); + zlog (peer->log, LOG_ERR, "Origin attribute value %u is invalid", + attr->origin); return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, - BGP_NOTIFY_UPDATE_INVAL_ORIGIN, - startp, total); + BGP_NOTIFY_UPDATE_INVAL_ORIGIN); } /* Set oring attribute flag. */ @@ -880,6 +1137,7 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, * Parses AS_PATH or AS4_PATH. * * 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. * @@ -887,39 +1145,24 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length, * * NB: empty AS path (length == 0) is valid. The returned struct aspath will * have segments == NULL and str == zero length string (unique). + * + * NB: an AS4 speaker should not be sending an AS4_PATH, and we will (later) + * ignore the attribute. We capture it here so that it can be seen in + * any logging/debug stuff. */ 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) + struct attr *attr, u_char flag, u_char type) { - u_char require ; - bool as4_path = (attr_type == BGP_ATTR_AS4_PATH) ; + bool as4_path ; - /* Check the attribute flags */ - require = as4_path ? BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL - : BGP_ATTR_FLAG_TRANS ; + qassert((type == BGP_ATTR_AS_PATH) || (type == BGP_ATTR_AS4_PATH)) ; - if ((flag & (BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS)) != require) + if (!bgp_attr_flags_check(peer,type, flag)) { - bgp_size_t total; - *p_asp = NULL ; - - if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)) - 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 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); - - return bgp_attr_malformed (peer, attr_type, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); + return bgp_attr_malformed (peer, type, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR) ; } ; /* Parse the AS_PATH/AS4_PATH body. @@ -927,27 +1170,35 @@ bgp_attr_aspath (struct peer *peer, struct aspath** p_asp, bgp_size_t length, * For AS_PATH peer with AS4 => 4Byte ASN otherwise 2Byte ASN * AS4_PATH 4Byte ASN */ + as4_path = (type == BGP_ATTR_AS4_PATH) ; + *p_asp = aspath_parse (peer->ibuf, length, PEER_CAP_AS4_USE(peer) || as4_path, as4_path) ; if (*p_asp == NULL) { zlog (peer->log, LOG_ERR, "Malformed %s from %s, length is %d", - as4_path ? "AS4_PATH" : "AS4_PATH", peer->host, length); + map_direct(bgp_attr_name_map, type).str, peer->host, length); - return bgp_attr_malformed (peer, attr_type, flag, - BGP_NOTIFY_UPDATE_MAL_AS_PATH, - NULL, 0); + return bgp_attr_malformed (peer, type, flag, + BGP_NOTIFY_UPDATE_MAL_AS_PATH); } ; /* Success ! */ - attr->flag |= ATTR_FLAG_BIT (attr_type) ; + attr->flag |= ATTR_FLAG_BIT (type) ; + + if (as4_path && PEER_CAP_AS4_USE(peer)) + { + if (BGP_DEBUG(as4, AS4)) + zlog_debug ("[AS4] %s sent AS4_PATH despite being an AS4 speaker", + peer->host); + } return BGP_ATTR_PARSE_PROCEED; } ; static bgp_attr_parse_ret_t -bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag) +bgp_attr_aspath_check (struct peer *peer, struct attr *attr) { /* These checks were part of bgp_attr_aspath, but with * as4 we should to check aspath things when @@ -955,6 +1206,16 @@ bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag) * Otherwise we check ASPATH and use the synthesized thing, and that is * not right. * So do the checks later, i.e. here + * + * NB: if the AS_PATH is malformed, that is reported as problem with the + * AS_PATH attribute, even if the malformation is due to a problem + * with the AS4_PATH. + * + * The AS_PATH is Well-Known Mandatory. So bgp_attr_malformed() will + * not allow much latitude ! + * + * Returns: BGP_ATTR_PARSE_PROCEED -- all well + * BGP_ATTR_PARSE_xxx -- as decided by bgp_attr_malformed() */ struct bgp *bgp = peer->bgp; struct aspath *aspath; @@ -968,9 +1229,8 @@ bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag) { zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host); - return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, - BGP_NOTIFY_UPDATE_MAL_AS_PATH, - NULL, 0); + return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, BGP_ATTR_FLAG_TRANS, + BGP_NOTIFY_UPDATE_MAL_AS_PATH); } /* First AS check for EBGP. */ @@ -982,9 +1242,8 @@ bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag) zlog (peer->log, LOG_ERR, "%s incorrect first AS (must be %u)", peer->host, peer->as); - return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, - BGP_NOTIFY_UPDATE_MAL_AS_PATH, - NULL, 0); + return bgp_attr_malformed(peer, BGP_ATTR_AS_PATH, BGP_ATTR_FLAG_TRANS, + BGP_NOTIFY_UPDATE_MAL_AS_PATH); } } @@ -1004,36 +1263,36 @@ bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag) /* Nexthop attribute. */ static bgp_attr_parse_ret_t bgp_attr_nexthop (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp) + struct attr *attr, u_char flag) { - bgp_size_t total; - - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + in_addr_t nexthop_h, nexthop_n; - /* Flag check. */ - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) - || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) - { - zlog (peer->log, LOG_ERR, - "Origin attribute flag isn't transitive %d", flag); + if (!bgp_attr_flags_check(peer, BGP_ATTR_NEXT_HOP, flag)) + return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR); - return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, - BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, - startp, total); - } - - /* Check nexthop attribute length. */ if (length != 4) - { - zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]", - length); + return bgp_attr_length_malformed (peer, BGP_ATTR_NEXT_HOP, flag, length, 4) ; + /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP + attribute must result in a NOTIFICATION message (this is implemented below). + At the same time, semantically incorrect NEXT_HOP is more likely to be just + logged locally (this is implemented somewhere else). The UPDATE message + gets ignored in any of these cases. + */ + nexthop_n = stream_get_ipv4 (peer->ibuf); + nexthop_h = ntohl (nexthop_n); + if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) + || IPV4_CLASS_DE (nexthop_h)) + { + char buf[INET_ADDRSTRLEN]; + inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN); + zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf); return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - startp, total); + BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP); } - attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf); + attr->nexthop.s_addr = nexthop_n; attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); return BGP_ATTR_PARSE_PROCEED; @@ -1042,22 +1301,15 @@ bgp_attr_nexthop (struct peer *peer, bgp_size_t length, /* MED atrribute. */ static bgp_attr_parse_ret_t bgp_attr_med (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp) + struct attr *attr, u_char flag) { - bgp_size_t total; + if (!bgp_attr_flags_check(peer, BGP_ATTR_MULTI_EXIT_DISC, flag)) + return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR); - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - - /* Length check. */ if (length != 4) - { - zlog (peer->log, LOG_ERR, - "MED attribute length isn't four [%d]", length); - - return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - startp, total); - } + return bgp_attr_length_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag, + length, 4) ; attr->med = stream_getl (peer->ibuf); @@ -1069,8 +1321,16 @@ bgp_attr_med (struct peer *peer, bgp_size_t length, /* Local preference attribute. */ static bgp_attr_parse_ret_t bgp_attr_local_pref (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag) + struct attr *attr, u_char flag) { + if (!bgp_attr_flags_check(peer, BGP_ATTR_LOCAL_PREF, flag)) + return bgp_attr_malformed (peer, BGP_ATTR_LOCAL_PREF, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR); + + if (length != 4) + return bgp_attr_length_malformed (peer, BGP_ATTR_LOCAL_PREF, flag, + length, 4) ; + /* If it is contained in an UPDATE message that is received from an external peer, then this attribute MUST be ignored by the receiving speaker. */ @@ -1080,10 +1340,7 @@ bgp_attr_local_pref (struct peer *peer, bgp_size_t length, return BGP_ATTR_PARSE_PROCEED; } - if (length == 4) - attr->local_pref = stream_getl (peer->ibuf); - else - attr->local_pref = 0; + attr->local_pref = stream_getl (peer->ibuf); /* Set atomic aggregate flag. */ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); @@ -1094,16 +1351,15 @@ bgp_attr_local_pref (struct peer *peer, bgp_size_t length, /* Atomic aggregate. */ static int bgp_attr_atomic (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag) + struct attr *attr, u_char flag) { - if (length != 0) - { - zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length); + if (!bgp_attr_flags_check(peer, BGP_ATTR_ATOMIC_AGGREGATE, flag)) + return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR); - return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - NULL, 0); - } + if (length != 0) + return bgp_attr_length_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag, + length, 0) ; /* Set atomic aggregate flag. */ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); @@ -1111,32 +1367,34 @@ bgp_attr_atomic (struct peer *peer, bgp_size_t length, return BGP_ATTR_PARSE_PROCEED; } -/* Aggregator attribute */ +/* Aggregator attribute + */ static int bgp_attr_aggregator (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag) + struct attr *attr, u_char flag) { - int wantedlen = 6; - struct attr_extra *attre = bgp_attr_extra_get (attr); + bgp_size_t wantedlen ; + struct attr_extra *attre ; - /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */ - if ( PEER_CAP_AS4_USE(peer) ) - wantedlen = 8; + if (!bgp_attr_flags_check(peer, BGP_ATTR_AGGREGATOR, flag)) + return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR); + + /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte + */ + wantedlen = PEER_CAP_AS4_USE(peer) ? 4 + 4 : 2 + 4 ; if (length != wantedlen) - { - zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, - length); + return bgp_attr_length_malformed (peer, BGP_ATTR_AGGREGATOR, flag, + length, wantedlen) ; - return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - NULL, 0); - } + attre = bgp_attr_extra_get (attr); if ( PEER_CAP_AS4_USE(peer) ) attre->aggregator_as = stream_getl (peer->ibuf); else attre->aggregator_as = stream_getw (peer->ibuf); + attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf); /* Set atomic aggregate flag. */ @@ -1145,154 +1403,241 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length, return BGP_ATTR_PARSE_PROCEED; } -/* New Aggregator attribute */ +/* New Aggregator attribute + * + * NB: an AS4 speaker should not be sending an AS4_AGGREGATOR, and we will + * (later) ignore the attribute. We capture it here so that it can be seen + * in any logging/debug stuff. + */ static bgp_attr_parse_ret_t bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, - as_t *as4_aggregator_as, - struct in_addr *as4_aggregator_addr) + struct attr *attr, u_char flag, + as_t *as4_aggregator_as, + struct in_addr *as4_aggregator_addr) { + if (!bgp_attr_flags_check(peer, BGP_ATTR_AS4_AGGREGATOR, flag)) + return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR); + if (length != 8) - { - zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length); - return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - NULL, 0); - } + return bgp_attr_length_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag, + length, 8) ; + *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); + if (PEER_CAP_AS4_USE(peer)) + { + if (BGP_DEBUG(as4, AS4)) + zlog_debug ("[AS4] %s sent AS4_AGGREGATOR despite being an" + " AS4 speaker", peer->host); + } + return BGP_ATTR_PARSE_PROCEED; } -/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH. +/* Process AS4_PATH attribute, if any -- assuming peer is NOT an AS4 speaker + * + * This is done once all attributes have been processed, so that we can mash + * the AS_PATH and the AS4_PATH together, if required. + * + * NB: this MUST be done *after* bgp_attr_munge_as4_aggr() -- see there. + * + * Returns: BGP_ATTR_PARSE_PROCEED -- all is well + * + * NB: we quietly ignore AS4_PATH if no AS_PATH -- same like AS4_AGGREGATOR. */ 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) +bgp_attr_munge_as4_path (struct peer *peer, struct attr *attr, + struct aspath *as4_path) { - int ignore_as4_path = 0; struct aspath *newpath; - struct attr_extra *attre = attr->extra; - if ( PEER_CAP_AS4_USE(peer) ) - { - /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR - * if given. - * It is worth a warning though, because the peer really - * should not send them - */ - if (BGP_DEBUG(as4, AS4)) - { - if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH))) - zlog_debug ("[AS4] %s %s AS4_PATH", - peer->host, "AS4 capable peer, yet it sent"); + if (! (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH))) + return BGP_ATTR_PARSE_PROCEED ; /* Do nothing if no AS4_PATH ! */ + + if (!(attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))) + /* The lack of an AS_PATH is likely to become a serious issue in the + * near future. + * + * In the meantime, we ignore the AS4_PATH. If it were ever the case that + * an AS_PATH is optional... then it would be perfectly possible for the + * non-AS4 speaker to send the AS4_PATH. So this is not the place to + * decide whether the lack of AS_PATH is a problem -- but certainly we + * can do nothing with the AS4_PATH ! + */ + { + if ( BGP_DEBUG(as4, AS4)) + zlog_debug ("[AS4] %s BGP not AS4 capable peer" + " sent AS4_PATH but no AS_PATH," + " so ignore the AS4_PATH", peer->host); + + return BGP_ATTR_PARSE_PROCEED ; /* Easy(-ish) if no AS_PATH */ + } ; - if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR))) - zlog_debug ("[AS4] %s %s AS4_AGGREGATOR", - peer->host, "AS4 capable peer, yet it sent"); - } + /* need to reconcile NEW_AS_PATH and AS_PATH + */ + newpath = aspath_reconcile_as4 (attr->aspath, as4_path); + aspath_unintern (&attr->aspath); + attr->aspath = aspath_intern (newpath); - return BGP_ATTR_PARSE_PROCEED; - } + return BGP_ATTR_PARSE_PROCEED; +} - if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH)) - && !(attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))) - { - /* Hu? This is not supposed to happen at all! - * got as4_path and no aspath, - * This should already - * have been handled by 'well known attributes missing' - * But... yeah, paranoia - * Take this as a "malformed attribute" - */ - zlog (peer->log, LOG_ERR, - "%s BGP not AS4 capable peer sent AS4_PATH but" - " no AS_PATH, cant do anything here", peer->host); +/* Process AS4_AGGREGATOR attribute -- assuming peer is NOT an AS4 speaker + * + * This is done once all attributes have been processed, so that we can mash + * any AGGREGATOR and the AS4_AGGREGATOR together, if required. + * + * NB: this must be done *before* processing the AS4_PATH, because RFC4893 + * says: + * + * "A NEW BGP speaker should also be prepared to receive the + * AS4_AGGREGATOR attribute along with the AGGREGATOR attribute from an + * OLD BGP speaker. When both the attributes are received, if the AS + * number in the AGGREGATOR attribute is not AS_TRANS, then: + * + * - the AS4_AGGREGATOR attribute and the AS4_PATH attribute SHALL + * be ignored, + * + * - the AGGREGATOR attribute SHALL be taken as the information + * about the aggregating node, and + * + * - the AS_PATH attribute SHALL be taken as the AS path + * information. + * + * Otherwise, + * + * - the AGGREGATOR attribute SHALL be ignored, + * + * - the AS4_AGGREGATOR attribute SHALL be taken as the information + * about the aggregating node, and + * + * - the AS path information would need to be constructed, as in all + * other cases. + * + * There are two reasons for the AGGREGATOR to not be AS_TRANS: + * + * 1. Some AS2 speaker since the last AS4 speaker has aggregated + * + * Aggregation has possibly unfortunate effects on the relationship + * between the AS_PATH and the AS4_PATH, so the latter is discarded. + * + * In any case, it is likely that the AS2 aggregator could lose the + * AS4_PATH entirely in the process ! + * + * 2. The last AS4 speaker was bonkers, and may not be trustworthy ! + * + * But (1) is probably the reason for this behaviour. + * + * Returns: BGP_ATTR_PARSE_PROCEED -- all is well + * BGP_ATTR_PARSE_IGNORE => ignore this AND any AS4_PATH + * NB: this is not, strictly, and error + */ +static bgp_attr_parse_ret_t +bgp_attr_munge_as4_aggr (struct peer *peer, struct attr *attr, + as_t as4_aggregator, + struct in_addr *as4_aggregator_addr) +{ + struct attr_extra *attre ; - return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, - BGP_NOTIFY_UPDATE_MAL_ATTR, - NULL, 0); - } + /* We have a AS2 peer. Worry about AGGREGATOR and AS4_AGGREGATOR. + */ + if (!(attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR))) + return BGP_ATTR_PARSE_PROCEED ; /* Easy if no AS4_AGGREGATOR */ - /* We have a asn16 peer. First, look for AS4_AGGREGATOR - * because that may override AS4_PATH + /* AGGREGATOR is Optional Transitive. + * + * RFC4893 says: + * + * "... if the NEW speaker has to send the AGGREGATOR attribute, + * and if the aggregating Autonomous System's AS number is truly 4- + * octets, then the speaker constructs the AS4_AGGREGATOR attributes by + * taking the attribute length and attribute value from the AGGREGATOR + * attribute and placing them into the attribute length and attribute + * value of the AS4_AGGREGATOR attribute, and sets the AS number field + * in the existing AGGREGATOR attribute to the reserved AS number, + * AS_TRANS. Note that if the AS number is 2-octets only, then the + * AS4_AGGREGATOR attribute SHOULD NOT be sent." + * + * So, expect the AS4 speaker to generate an AS4_AGGREGATOR iff there is an + * AGGREGATOR, and the iff the ASN involved requires it. + * + * Do not expect any AS in between to drop the AGGREGATOR attribute. + * + * As noted above the RFC also says: + * + * "A NEW BGP speaker should also be prepared to receive the + * AS4_AGGREGATOR attribute along with the AGGREGATOR attribute..." + * + * It is silent on the case where an AS4_AGGREGATOR appears on its own !! + * In this case we suppose: + * + * (a) an AS4 speaker has issued an AS4_AGGREGATOR *without* sending the + * matching AGGREGATOR -- which is a mistake ! + * + * In this case, one could treat this as if the AS4 speaker had failed + * to use AS_TRANS in the AGGREGATOR attribute. + * + * (b) an AS of either sex has dropped the AGGREGATOR , but not the + * AS4_AGGREGATOR. + * + * An AS2 speaker may have deliberately discarded the AGGREGATOR + * information, but (of course) not known enough to drop the + * AS4 version ! + * + * We cannot really distinguish the case of deliberately dropping the + * AGGREGATOR (however naughty that might be) from a failure to issue + * both AGGREGATOR and AS4_AGGREGATOR together. BUT, if we were to resurrect + * an AGGREGATOR from a lone AS4_AGGREGATOR, then some poor AS2 speaker + * will find that BGP is no longer working as it did before !!! */ - 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); - - /* received both. - * if the as_number in aggregator is not AS_TRANS, - * then AS4_AGGREGATOR and AS4_PATH shall be ignored - * and the Aggregator shall be taken as - * info on the aggregating node, and the AS_PATH - * shall be taken as the AS_PATH - * otherwise - * the Aggregator shall be ignored and the - * AS4_AGGREGATOR shall be taken as the - * Aggregating node and the AS_PATH is to be - * constructed "as in all other cases" - */ - if (attre->aggregator_as != BGP_AS_TRANS) - { - /* ignore */ - if ( BGP_DEBUG(as4, AS4)) - zlog_debug ("[AS4] %s BGP not AS4 capable peer" - " send AGGREGATOR != AS_TRANS and" - " AS4_AGGREGATOR, so ignore" - " AS4_AGGREGATOR and AS4_PATH", peer->host); - ignore_as4_path = 1; - } - else - { - /* "New_aggregator shall be taken as aggregator" */ - attre->aggregator_as = as4_aggregator; - attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr; - } - } - else - { - /* We received a AS4_AGGREGATOR but no AGGREGATOR. - * That is bogus - but reading the conditions - * we have to handle AS4_AGGREGATOR as if it were - * AGGREGATOR in that case - */ - 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) ; - attre->aggregator_as = as4_aggregator; - /* sweep it under the carpet and simulate a "good" AGGREGATOR */ - attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)); - } - } + if ( BGP_DEBUG(as4, AS4)) + zlog_debug ("[AS4] %s BGP not AS4 capable peer" + " sent AS4_AGGREGATOR but no AGGREGATOR," + " so ignore the AS4_AGGREGATOR", peer->host); + + return BGP_ATTR_PARSE_PROCEED ; /* Easy(-ish) if no AGGREGATOR */ + } ; + + /* received both AGGREGATOR and AS4_AGGREGATOR. + */ + attre = attr->extra ; + assert (attre); - /* need to reconcile NEW_AS_PATH and AS_PATH */ - if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH)))) + if (attre->aggregator_as != BGP_AS_TRANS) { - newpath = aspath_reconcile_as4 (attr->aspath, as4_path); - aspath_unintern (&attr->aspath); - attr->aspath = aspath_intern (newpath); - } - return BGP_ATTR_PARSE_PROCEED; + /* ignore */ + if ( BGP_DEBUG(as4, AS4)) + zlog_debug ("[AS4] %s BGP not AS4 capable peer" + " sent AGGREGATOR %u != AS_TRANS and" + " AS4_AGGREGATOR, so ignore" + " AS4_AGGREGATOR and AS4_PATH", peer->host, + attre->aggregator_as); + + return BGP_ATTR_PARSE_IGNORE ; + } ; + + /* Finally -- set the aggregator information from the AS4_AGGREGATOR ! + */ + attre->aggregator_as = as4_aggregator; + attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr; + + return BGP_ATTR_PARSE_PROCEED ; } /* Community attribute. */ static bgp_attr_parse_ret_t bgp_attr_community (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp) + struct attr *attr, u_char flag) { - bgp_size_t total - = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - + if (!bgp_attr_flags_check(peer, BGP_ATTR_COMMUNITIES, flag)) + return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR); if (length == 0) { attr->community = NULL; @@ -1306,9 +1651,13 @@ bgp_attr_community (struct peer *peer, bgp_size_t length, stream_forward_getp (peer->ibuf, length); if (!attr->community) - return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag, - BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, - startp, total); + { + zlog (peer->log, LOG_ERR, "Malformed COMMUNITIES (length is %u)", + length) ; + + return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); + } ; attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); @@ -1318,16 +1667,15 @@ bgp_attr_community (struct peer *peer, bgp_size_t length, /* Originator ID attribute. */ static bgp_attr_parse_ret_t bgp_attr_originator_id (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag) + struct attr *attr, u_char flag) { - if (length != 4) - { - zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length); + if (!bgp_attr_flags_check(peer, BGP_ATTR_ORIGINATOR_ID, flag)) + return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR); - return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - NULL, 0); - } + if (length != 4) + return bgp_attr_length_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag, + length, 4) ; (bgp_attr_extra_get (attr))->originator_id.s_addr = stream_get_ipv4 (peer->ibuf); @@ -1340,16 +1688,18 @@ bgp_attr_originator_id (struct peer *peer, bgp_size_t length, /* Cluster list attribute. */ static bgp_attr_parse_ret_t bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag) + struct attr *attr, u_char flag) { - /* Check length. */ + if (!bgp_attr_flags_check(peer, BGP_ATTR_CLUSTER_LIST, flag)) + return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR); + if (length % 4) { zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length); return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, - NULL, 0); + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); } (bgp_attr_extra_get (attr))->cluster @@ -1365,50 +1715,66 @@ bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, /* Multiprotocol reachability information parse. */ 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) +bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length, + struct attr *attr, const u_char flag, + struct bgp_nlri *mp_update) { - afi_t afi; + afi_t afi; safi_t safi; size_t nlri_len ; byte* nlri ; - size_t attr_endp, nexthop_endp ; + ulen nexthop_endp ; + u_char reserved ; + int ret; struct stream *s; struct attr_extra *attre = bgp_attr_extra_get(attr); - s = BGP_INPUT(peer); + if (!bgp_attr_flags_check(peer, BGP_ATTR_MP_REACH_NLRI, flag)) + return bgp_attr_malformed (peer, BGP_ATTR_MP_REACH_NLRI, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR); /* Require the given length to be: within what is left to read in the stream * at least the minimum required * - * If OK, set "limit", so that provided s->getp <= limit, we are within the - * attribute and within the stream. + * If OK, sets s->endp to the end of the attribute. */ - if (!stream_push_endp(s, length, &attr_endp) || (length < BGP_ATT_MPR_MIN_L)) - { - zlog_info ("%s: %s sent invalid length, %lu", - __func__, peer->host, (ulong)length); - goto parse_error ; - } ; + s = BGP_INPUT(peer); - /* Load AFI, SAFI. + /* Load AFI, SAFI and Next Hop Length */ afi = stream_getw (s); safi = stream_getc (s); + attre->mp_nexthop_len = stream_getc (s); + + if (stream_has_overrun(s)) + { + zlog (peer->log, LOG_ERR, + "%s attribute length is %u -- should be at least 5", + map_direct(bgp_attr_name_map, BGP_ATTR_MP_REACH_NLRI).str, length) ; + + return bgp_attr_malformed (peer, BGP_ATTR_MP_REACH_NLRI, flag, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + } ; /* Get nexthop length and check */ - attre->mp_nexthop_len = stream_getc (s); + nexthop_endp = stream_push_endp(s, attre->mp_nexthop_len + 1) ; - if (!stream_push_endp(s, attre->mp_nexthop_len, &nexthop_endp)) + if (stream_has_overrun(s)) { - zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute", + stream_pop_endp(s, nexthop_endp) ; /* as you was */ + + zlog_info ("%s: %s, MP nexthop length %u + reserved byte" + " overruns end of attribute", __func__, peer->host, attre->mp_nexthop_len); - goto parse_error ; - } - /* Nexthop length check. */ + return bgp_attr_malformed (peer, BGP_ATTR_MP_REACH_NLRI, flag, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); + } ; + + /* Nexthop length check. + */ switch (attre->mp_nexthop_len) { case 4: @@ -1419,14 +1785,9 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, break; case 12: - { - u_int32_t rd_high; - u_int32_t rd_low; - - rd_high = stream_getl (s); - rd_low = stream_getl (s); - stream_get (&attre->mp_nexthop_global_in, s, 4); - } + stream_getl (s); /* RD high */ + stream_getl (s); /* RD low */ + stream_get (&attre->mp_nexthop_global_in, s, 4); break; #ifdef HAVE_IPV6 @@ -1457,107 +1818,147 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, #endif /* HAVE_IPV6 */ default: - zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d", + stream_pop_endp(s, nexthop_endp) ; /* as you was */ + + zlog_info ("%s: (%s) unknown multiprotocol next hop length: %d", __func__, peer->host, attre->mp_nexthop_len) ; - goto parse_error ; + + return bgp_attr_malformed (peer, BGP_ATTR_MP_REACH_NLRI, flag, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); } + /* Eat the reserved byte + */ + reserved = stream_getc (s) ; + + /* We should now have read up to the recorded endp, and not beyond + * + * This is an internal error, really. + */ if (!stream_pop_endp(s, nexthop_endp)) - { - zlog_info ("%s: (%s) Failed to read next hop (length %d)", - __func__, peer->host, attre->mp_nexthop_len) ; - goto parse_error ; - } ; + return bgp_attr_over_or_underrun(peer, BGP_ATTR_MP_REACH_NLRI, length) ; - { - u_char val; - if ((val = stream_getc (s))) - zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field", - peer->host, val) ; - } + /* Check the reserved byte value + */ + if (reserved != 0) + zlog_warn("%s sent non-zero value, %u, for defunct SNPA-length field" + " in MP_REACH_NLRI for AFI/SAFI %u/%u", + peer->host, reserved, afi, safi) ; /* must have nrli_len, what is left of the attribute + * + * RFC 4760 says (section 5, NLRI Encoding) that the NLRI "...is encoded as + * one or more 2-tuples..." which indicates that zero length NLRI would + * be wrong -- except, of course, for End-of-RIB !! + * + * Accepting zero bytes of NLRI does not appear to do harm. But we whine + * about it in the logging. */ - nlri = stream_get_bytes_left(s, &nlri_len) ; + nlri = stream_get_bytes_left(s, &nlri_len) ; /* steps past */ if (nlri_len == 0) + zlog_warn("%s sent zero length NLRI in MP_REACH_NLRI for AFI/SAFI %u/%u", + peer->host, afi, safi) ; + else if (safi != SAFI_MPLS_LABELED_VPN) { - zlog_info ("%s: (%s) zero length NLRI", __func__, peer->host); - goto parse_error ; - } - - if (safi != BGP_SAFI_VPNV4) - { + /* If the nlri are not valid, bgp_nlri_sanity_check() drops the session + */ ret = bgp_nlri_sanity_check (peer, afi, nlri, nlri_len); if (ret < 0) { - zlog_info ("%s: (%s) NLRI doesn't pass sanity check", - __func__, peer->host); - goto parse_error ; + zlog_info ("%s %s NLRI in MP_REACH_NLRI doesn't pass sanity check", + peer->host, map_direct(bgp_afi_name_map, afi).str) ; + return BGP_ATTR_PARSE_ERROR ; } } + /* Record the MP_REACH_NLRI + */ mp_update->afi = afi; mp_update->safi = safi; mp_update->nlri = nlri ; mp_update->length = nlri_len; - stream_pop_endp(s, attr_endp) ; - return BGP_ATTR_PARSE_PROCEED; - -parse_error: - stream_pop_endp(s, attr_endp) ; - return BGP_ATTR_PARSE_ERROR; } ; -/* Multiprotocol unreachable parse */ +/* Multiprotocol unreachable parse + * + * Sets mp_eor iff all is well, and attribute is empty. + */ extern bgp_attr_parse_ret_t -bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length, - struct bgp_nlri *mp_withdraw) +bgp_mp_unreach_parse (struct peer *peer, const bgp_size_t length, + const u_char flag, struct bgp_nlri *mp_withdraw, + bool* mp_eor) { struct stream *s; - afi_t afi; + afi_t afi; safi_t safi; - u_int16_t withdraw_len; + size_t nlri_len ; + byte* nlri ; int ret; - s = peer->ibuf; + if (!bgp_attr_flags_check(peer, BGP_ATTR_MP_UNREACH_NLRI, flag)) + return bgp_attr_malformed (peer, BGP_ATTR_MP_UNREACH_NLRI, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR); -#define BGP_MP_UNREACH_MIN_SIZE 3 - if ((length > stream_get_read_left(s)) || (length < BGP_MP_UNREACH_MIN_SIZE)) - return BGP_ATTR_PARSE_ERROR; + s = BGP_INPUT(peer); - afi = stream_getw (s); + /* Load AFI, SAFI. + */ + afi = stream_getw (s); safi = stream_getc (s); - withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE; + if (stream_has_overrun(s)) + { + zlog (peer->log, LOG_ERR, + "%s attribute length is %u -- should be at least 3", + map_direct(bgp_attr_name_map, BGP_ATTR_MP_UNREACH_NLRI).str, + length) ; - if (safi != BGP_SAFI_VPNV4) + return bgp_attr_malformed (peer, BGP_ATTR_MP_UNREACH_NLRI, flag, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + } ; + + /* must have nrli_len, what is left of the attribute + */ + nlri = stream_get_bytes_left(s, &nlri_len) ; /* steps past */ + + if (nlri_len == 0) + *mp_eor = true ; + else if (safi != SAFI_MPLS_LABELED_VPN) { - ret = bgp_nlri_sanity_check (peer, afi, stream_get_pnt (s), withdraw_len); + /* If the nlri are not valid, bgp_nlri_sanity_check() drops the session + */ + ret = bgp_nlri_sanity_check (peer, afi, nlri, nlri_len); if (ret < 0) - return BGP_ATTR_PARSE_ERROR; + { + zlog_info ("%s %s NLRI in MP_UNREACH_NLRI doesn't pass sanity check", + peer->host, map_direct(bgp_afi_name_map, afi).str) ; + return BGP_ATTR_PARSE_ERROR ; + } } - mp_withdraw->afi = afi; - mp_withdraw->safi = safi; - mp_withdraw->nlri = stream_get_pnt (s); - mp_withdraw->length = withdraw_len; - - stream_forward_getp (s, withdraw_len); + /* Record the MP_UNREACH_NLRI + */ + mp_withdraw->afi = afi; + mp_withdraw->safi = safi; + mp_withdraw->nlri = nlri ; + mp_withdraw->length = nlri_len ; - return BGP_ATTR_PARSE_PROCEED; + return BGP_ATTR_PARSE_PROCEED ; } /* Extended Community attribute. */ static bgp_attr_parse_ret_t bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, - struct attr *attr, u_char flag, u_char *startp) + struct attr *attr, u_char flag) { - bgp_size_t total - = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + if (!bgp_attr_flags_check(peer, BGP_ATTR_EXT_COMMUNITIES, flag)) + return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES, flag, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR); + /* Basic length check. */ if (length == 0) { if (attr->extra) @@ -1574,8 +1975,7 @@ bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, if (!attr->extra->ecommunity) return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES, flag, - BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, - startp, total); + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); @@ -1585,15 +1985,16 @@ bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, /* BGP unknown attribute treatment. */ static bgp_attr_parse_ret_t bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag, - u_char type, bgp_size_t length, u_char *startp) + u_char type, bgp_size_t length) { - bgp_size_t total; struct transit *transit; struct attr_extra *attre; + byte* raw_attr ; + ulen raw_len ; if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s Unknown attribute is received (type %d, length %d)", - peer->host, type, length); + zlog_debug ("%s Unknown attribute is received (type %d, length %d)", + peer->host, type, length); if (BGP_DEBUG (events, EVENTS)) zlog (peer->log, LOG_DEBUG, @@ -1602,18 +2003,17 @@ bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag, /* Forward read pointer of input stream. */ stream_forward_getp (peer->ibuf, length); - /* Adjest total length to include type and length. */ - total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - /* If any of the mandatory well-known attributes are not recognized, then the Error Subcode is set to Unrecognized Well-known Attribute. The Data field contains the unrecognized attribute (type, length and value). */ - if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) + if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) { + zlog (peer->log, LOG_ERR, + "Unknown attribute type %d has flags 0x%x -- ie NOT Optional", + type, flag); return bgp_attr_malformed (peer, type, flag, - BGP_NOTIFY_UPDATE_UNREC_ATTR, - startp, total); + BGP_NOTIFY_UPDATE_UNREC_ATTR); } /* Unrecognized non-transitive optional attributes must be quietly @@ -1621,13 +2021,19 @@ bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag, if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) return BGP_ATTR_PARSE_PROCEED; + /* Get the address and total length of the attribute + */ + raw_attr = bgp_attr_raw(peer, &raw_len) ; + /* If a path with recognized transitive optional attribute is accepted and passed along to other BGP peers and the Partial bit in the Attribute Flags octet is set to 1 by some previous AS, it - is not set back to 0 by the current AS. */ - SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL); + is not set back to 0 by the current AS. + */ + SET_FLAG (raw_attr[0], BGP_ATTR_FLAG_PARTIAL); - /* Store transitive attribute to the end of attr->transit. */ + /* Store transitive attribute to the end of attr->transit. + */ if (! ((attre = bgp_attr_extra_get(attr))->transit) ) attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit)); @@ -1635,12 +2041,12 @@ bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag, if (transit->val) transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val, - transit->length + total); + transit->length + raw_len); else - transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total); + transit->val = XMALLOC (MTYPE_TRANSIT_VAL, raw_len); - memcpy (transit->val + transit->length, startp, total); - transit->length += total; + memcpy (transit->val + transit->length, raw_attr, raw_len); + transit->length += raw_len; return BGP_ATTR_PARSE_PROCEED; } @@ -1663,17 +2069,29 @@ 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.) + * + * The peer->ibuf stream is set so that the getp is the start of the attributes, + * and the endp is the end of same. + * + * NB: uses the stream->startp. + * + * Returns: BGP_ATTR_PARSE_IGNORE -- OK, ignoring one or more bad, but + * trivial, attributes + * BGP_ATTR_PARSE_PROCEED -- all well + * + * BGP_ATTR_PARSE_WITHDRAW -- not good, but keep going, treating + * all prefixes as being withdrawn. + * + * BGP_ATTR_PARSE_ERROR -- not good at all: session dropped */ 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) +bgp_attr_parse (struct peer *peer, struct attr *attr, + struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw, + bool* mp_eor) { - int ret; - u_char flag = 0; - u_char type = 0; - bgp_size_t length; - u_char *startp, *endp; - u_char *attr_endp; + bgp_attr_parse_ret_t aret; + struct stream *s; + ulen attr_count ; u_char seen[BGP_ATTR_BITMAP_SIZE]; /* we need the as4_path only until we have synthesized the as_path with it */ /* same goes for as4_aggregator */ @@ -1684,54 +2102,79 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, /* Initialize bitmap. */ memset (seen, 0, BGP_ATTR_BITMAP_SIZE); - /* End pointer of BGP attribute. */ - endp = BGP_INPUT_PNT (peer) + size; + /* We are going to read size bytes of attributes from the current stream + * position. + */ + *mp_eor = false ; + attr_count = 0 ; - /* Get attributes to the end of attribute length. */ - while (BGP_INPUT_PNT (peer) < endp) + aret = BGP_ATTR_PARSE_PROCEED ; /* So far, so good ! */ + + s = BGP_INPUT(peer) ; + while (stream_get_read_left(s) > 0) { - /* Check remaining length check.*/ - if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN) - { - /* XXX warning: long int format, int arg (arg 5) */ - zlog (peer->log, LOG_WARNING, - "%s error BGP attribute length %lu is smaller than min len", - peer->host, - (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer)))); + bgp_attr_parse_ret_t ret ; + ulen header_length, length, attr_endp ; + u_char flag ; + u_char type ; - bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); - if (as4_path != NULL) - aspath_unintern (&as4_path); - return BGP_ATTR_PARSE_ERROR; - } + ++attr_count ; - /* Fetch attribute flag and type. */ - startp = BGP_INPUT_PNT (peer); - flag = stream_getc (BGP_INPUT (peer)); - type = stream_getc (BGP_INPUT (peer)); + /* Remember the start of the attribute -- used in bgp_attr_malformed() + * and other error handling. + */ + stream_set_startp(s, stream_get_getp(s)) ; + + /* Fetch attribute flag, type and length. + * + * Note that stream_getx() return zero if overrun the end. + * + * "The lower-order four bits of the Attribute Flags octet are + * unused. They MUST be zero when sent and MUST be ignored when + * received." + */ + flag = stream_getc (s) & 0xF0 ; + type = stream_getc (s); + + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)) + { + header_length = 4 ; + length = stream_getw (s); + } + else + { + header_length = 3 ; + length = stream_getc (s); + } ; - /* Check whether Extended-Length applies and is in bounds */ - if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) - && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1))) + /* Check whether attribute prefix and the length of the attribute body + * are all within the total attribute size. + * + * Sets the s->endp to the end of the current attribute and saves the + * end of all attributes in + */ + attr_endp = stream_push_endp(s, length) ; + if (stream_has_overrun(s)) { - zlog (peer->log, LOG_WARNING, - "%s Extended length set, but just %lu bytes of attr header", - peer->host, - (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer)))); + ulen have = attr_endp - (ulen)stream_get_startp(s) ; + + if (have < header_length) + zlog (peer->log, LOG_WARNING, + "%s: broken BGP attribute [0x%x %u %u] have just %u octets for" + " attribute header", + peer->host, flag, type, length, have) ; + else + zlog (peer->log, LOG_WARNING, + "%s: broken BGP attribute [0x%x %u %u] have just %u octets for" + " attribute body", + peer->host, flag, type, length, (have - header_length)) ; bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); - if (as4_path != NULL) - aspath_unintern (&as4_path); - return BGP_ATTR_PARSE_ERROR; - } - /* 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)); + aret = BGP_ATTR_PARSE_ERROR; + goto attr_parse_exit ; + } ; /* If any attribute appears more than once in the UPDATE * message, then the Error Subcode is set to Malformed Attribute @@ -1740,14 +2183,14 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, if (CHECK_BITMAP (seen, type)) { zlog (peer->log, LOG_WARNING, - "%s error BGP attribute type %d appears twice in a message", - peer->host, type); + "%s: error BGP attribute type %s appears twice in a message", + peer->host, map_direct(bgp_attr_name_map, type).str); bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); - if (as4_path != NULL) - aspath_unintern (&as4_path); - return BGP_ATTR_PARSE_ERROR; + + aret = BGP_ATTR_PARSE_ERROR; + goto attr_parse_exit ; } /* Set type to bitmap to check duplicate attribute. `type' is @@ -1755,42 +2198,37 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, */ SET_BITMAP (seen, type); - /* Overflow check. */ - attr_endp = BGP_INPUT_PNT (peer) + length; - - 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); - - bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, - 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. + * + * NB: have long ago discarded the unused flag bits. + * + * can fetch up to length without running off the end of the stream. + * + * NB: if individual attribute parser returns BGP_ATTR_PARSE_PROCEED, + * then it is assumed that: (a) it will have read the entire + * attribute -- so getp == endp, and (b) no more -- so not overrun ! + */ + qassert((flag & 0x0F) == 0) ; + qassert(stream_has_read_left(s, length)) ; - /* OK check attribute and store it's value. */ switch (type) { case BGP_ATTR_ORIGIN: - ret = bgp_attr_origin (peer, length, attr, flag, startp); + ret = bgp_attr_origin (peer, length, attr, flag); break; case BGP_ATTR_AS_PATH: ret = bgp_attr_aspath (peer, &attr->aspath, length, attr, flag, - startp, BGP_ATTR_AS_PATH); + BGP_ATTR_AS_PATH); break; case BGP_ATTR_AS4_PATH: ret = bgp_attr_aspath (peer, &as4_path, length, attr, flag, - startp, BGP_ATTR_AS4_PATH); + BGP_ATTR_AS4_PATH); break; case BGP_ATTR_NEXT_HOP: - ret = bgp_attr_nexthop (peer, length, attr, flag, startp); + ret = bgp_attr_nexthop (peer, length, attr, flag); break; case BGP_ATTR_MULTI_EXIT_DISC: - ret = bgp_attr_med (peer, length, attr, flag, startp); + ret = bgp_attr_med (peer, length, attr, flag); break; case BGP_ATTR_LOCAL_PREF: ret = bgp_attr_local_pref (peer, length, attr, flag); @@ -1803,11 +2241,11 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, break; case BGP_ATTR_AS4_AGGREGATOR: ret = bgp_attr_as4_aggregator (peer, length, attr, flag, - &as4_aggregator, - &as4_aggregator_addr); + &as4_aggregator, + &as4_aggregator_addr); break; case BGP_ATTR_COMMUNITIES: - ret = bgp_attr_community (peer, length, attr, flag, startp); + ret = bgp_attr_community (peer, length, attr, flag); break; case BGP_ATTR_ORIGINATOR_ID: ret = bgp_attr_originator_id (peer, length, attr, flag); @@ -1816,85 +2254,98 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, ret = bgp_attr_cluster_list (peer, length, attr, flag); break; case BGP_ATTR_MP_REACH_NLRI: - ret = bgp_mp_reach_parse (peer, length, attr, mp_update); + ret = bgp_mp_reach_parse (peer, length, attr, flag, mp_update); break; case BGP_ATTR_MP_UNREACH_NLRI: - ret = bgp_mp_unreach_parse (peer, length, mp_withdraw); + ret = bgp_mp_unreach_parse (peer, length, flag, mp_withdraw, mp_eor); break; case BGP_ATTR_EXT_COMMUNITIES: - ret = bgp_attr_ext_communities (peer, length, attr, flag, startp); + ret = bgp_attr_ext_communities (peer, length, attr, flag); break; default: - ret = bgp_attr_unknown (peer, attr, flag, type, length, startp); + ret = bgp_attr_unknown (peer, attr, flag, type, length); break; } - /* If hard error occured immediately return to the caller. */ - if (ret == BGP_ATTR_PARSE_ERROR) + /* Restore the end of all attributes, and check that has read all of + * the attribute. + * + * If individual attribute parser returns BGP_ATTR_PARSE_PROCEED, and + * has not exactly read the attribute, then we have a potentially serious + * internal error !! + * + * NB: in any case, the getp is now set to the end of the attribute we + * just dealt with, and the endp is the end of all attributes. + */ + if (!stream_pop_endp(s, attr_endp)) { - zlog (peer->log, LOG_WARNING, - "%s: Attribute %s, parse error", - peer->host, - LOOKUP (attr_str, type)); + if (ret == BGP_ATTR_PARSE_PROCEED) + ret = bgp_attr_over_or_underrun(peer, type, length) ; - bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_MAL_ATTR); - if (as4_path != NULL) - aspath_unintern (&as4_path); - return ret; - } + stream_clear_overrun(s) ; /* in case continuing */ + } ; - if (ret == BGP_ATTR_PARSE_WITHDRAW) + /* Now decide what to do with the return code + */ + switch (ret) { - 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; - } + case BGP_ATTR_PARSE_PROCEED: + break ; - /* Check the fetched length. */ - if (BGP_INPUT_PNT (peer) != attr_endp) - { - zlog (peer->log, LOG_WARNING, - "%s: BGP attribute %s, fetch error", - peer->host, LOOKUP (attr_str, type)); + /* If we have chosen to ignore an error in a trivial attribute + */ + case BGP_ATTR_PARSE_IGNORE: + zlog (peer->log, LOG_WARNING, + "%s: Attribute %s invalid, but trivial -- ignoring it", + peer->host, + map_direct(bgp_attr_name_map, type).str); + + if (aret == BGP_ATTR_PARSE_PROCEED) + aret = BGP_ATTR_PARSE_IGNORE ; /* promote */ + break ; - if (type == BGP_ATTR_AS_PATH) - { - zlog (peer->log, LOG_WARNING, - "%s: is %sAS4", - peer->host, - PEER_CAP_AS4_USE(peer) ? "" : "NOT ") ; - } ; + /* If soft-ish error, turn into withdraw + */ + case BGP_ATTR_PARSE_WITHDRAW: + zlog (peer->log, LOG_WARNING, + "%s: Attribute %s invalid -- treating update as withdrawal", + peer->host, + map_direct(bgp_attr_name_map, type).str); - bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); - if (as4_path != NULL) - aspath_unintern (&as4_path); - return BGP_ATTR_PARSE_ERROR; - } - } + aret = ret ; /* promote */ + break ; - /* Check final read pointer is same as end pointer. */ - if (BGP_INPUT_PNT (peer) != endp) - { - zlog (peer->log, LOG_WARNING, - "%s BGP attribute %s, length mismatch", - peer->host, LOOKUP (attr_str, type)); + /* Hard error occurred: drop the session and exit immediately. + * + * NB: may (well) already have downed the peer, in which case the + * bgp_peer_down_error() here is redundant -- but does no harm ! + */ + case BGP_ATTR_PARSE_ERROR: + default: + zlog (peer->log, LOG_WARNING, + "%s: Attribute %s invalid -- session drop", + peer->host, + map_direct(bgp_attr_name_map, type).str); - bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); - if (as4_path != NULL) - aspath_unintern (&as4_path); - return BGP_ATTR_PARSE_ERROR; - } + bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_ATTR); + + aret = BGP_ATTR_PARSE_ERROR ; + goto attr_parse_exit ; + } ; + } ; + + /* We have finished parsing the attributes. Any further bgp_attr_malformed() + * will not refer to a specific attribute, but in any case cannot -- so we + * set s->startp to the absolute limit -- see bgp_attr_raw(). + * + * At this point ret == BGP_ATTR_PARSE_PROCEED + * or BGP_ATTR_PARSE_IGNORE if last attribute parsed + * just happened to be so. + */ + stream_set_startp(s, stream_get_endp(s)) ; - /* - * At this place we can see whether we got AS4_PATH and/or + /* At this place we can see whether we got AS4_PATH and/or * AS4_AGGREGATOR from a 16Bit peer and act accordingly. * We can not do this before we've read all attributes because * the as4 handling does not say whether AS4_PATH has to be sent @@ -1905,82 +2356,152 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, * all attributes first, including these 32bit ones, and now, * afterwards, we look what and if something is to be done for as4. */ - 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 - * - * 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. - */ - if (as4_path != NULL) + if (!PEER_CAP_AS4_USE(peer)) { - /* The flag that we got this is still there, but that does not - * do any trouble + bgp_attr_parse_ret_t ret ; + + /* NB: must deal with AS4_AGGREGATOR first, in case that returns + * BGP_ATTR_PARSE_IGNORE -- which means ignore it *and* and AS4_PATH. + * + * In this case BGP_ATTR_PARSE_IGNORE does not signal an *error*, + * so we do not set "ignored" on the strength of it. */ - aspath_unintern (&as4_path); - as4_path = NULL ; - } ; + ret = bgp_attr_munge_as4_aggr (peer, attr, as4_aggregator, + &as4_aggregator_addr) ; - if (ret != BGP_ATTR_PARSE_PROCEED) - return ret; + if (ret == BGP_ATTR_PARSE_PROCEED) + ret = bgp_attr_munge_as4_path (peer, attr, as4_path) ; + + switch (ret) + { + case BGP_ATTR_PARSE_PROCEED: + case BGP_ATTR_PARSE_IGNORE: + break ; + + case BGP_ATTR_PARSE_WITHDRAW: + aret = ret ; + break ; + + case BGP_ATTR_PARSE_ERROR: + default: + aret = BGP_ATTR_PARSE_ERROR ; + goto attr_parse_exit ; + } ; + } ; /* 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))) { - ret = bgp_attr_aspath_check (peer, attr, flag); - if (ret != BGP_ATTR_PARSE_PROCEED) - return ret; - } + bgp_attr_parse_ret_t ret ; + + ret = bgp_attr_aspath_check (peer, attr); + + switch (ret) + { + case BGP_ATTR_PARSE_PROCEED: + break ; + + case BGP_ATTR_PARSE_IGNORE: + if (aret == BGP_ATTR_PARSE_PROCEED) + aret = ret ; + break ; + + case BGP_ATTR_PARSE_WITHDRAW: + aret = ret ; + break ; + + case BGP_ATTR_PARSE_ERROR: + default: + aret = BGP_ATTR_PARSE_ERROR ; + goto attr_parse_exit ; + } ; + } ; /* Finally intern unknown attribute. */ if (attr->extra && attr->extra->transit) attr->extra->transit = transit_intern (attr->extra->transit); - return BGP_ATTR_PARSE_PROCEED; -} + /* Done everything we are going to do -- return the result. + * + * We are done with any AS4_PATH or AS4_AGGREGATOR, and do not hold on to + * those -- though their (temporary) existence is recorded in the attr->flag. + * Any values we wanted from those attributes have by now been integrated + * into the AS_PATH and the AGGREGATOR attributes. + * + * NB: for all returns other than BGP_ATTR_PARSE_ERROR, will have eaten all + * attributes and the s->getp should be at the current s->endp. + * + * We stop immediately on BGP_ATTR_PARSE_ERROR, so s->getp may be + * almost anywhere. + * + * If we had a BGP_ATTR_PARSE_IGNORE, then we have done that already, but + * return BGP_ATTR_PARSE_IGNORE for information. + * + * mp_eor is set false to start with, and... + * ...set true iff get a valid empty BGP_ATTR_MP_UNREACH_NLRI + * + * Here we force mp_eor false if we have anything other than 1 attribute, + * or if everything is not perfect. + */ + attr_parse_exit: + + if (as4_path != NULL) + aspath_unintern (&as4_path); + + if ((attr_count != 1) || (aret != BGP_ATTR_PARSE_PROCEED)) + *mp_eor = false ; + + return aret ; +} ; /* Well-known attribute check. */ -int -bgp_attr_check (struct peer *peer, struct attr *attr) +extern int +bgp_attr_check (struct peer *peer, struct attr *attr, bool with_next_hop) { - u_char type = 0; + bool first ; + uint8_t type ; - if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN))) - type = BGP_ATTR_ORIGIN; + uint32_t flags = ATTR_FLAG_BIT (BGP_ATTR_ORIGIN) | + ATTR_FLAG_BIT (BGP_ATTR_AS_PATH) ; - if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))) - type = BGP_ATTR_AS_PATH; + if (with_next_hop) + flags |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) ; - if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))) - type = BGP_ATTR_NEXT_HOP; + if (peer_sort (peer) == BGP_PEER_IBGP) + flags |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF) ; - if (peer_sort (peer) == BGP_PEER_IBGP - && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) - type = BGP_ATTR_LOCAL_PREF; + if ((attr->flag & flags) == flags) + return BGP_ATTR_PARSE_PROCEED ; - if (type) + /* Set flags to '1' where we have a *missing* attribute + */ + flags = (attr->flag & flags) ^ flags ; + + first = true ; + type = 1 ; + while (flags != 0) { - zlog (peer->log, LOG_WARNING, - "%s Missing well-known attribute %d.", - peer->host, type); + if (flags & 1) + { + zlog (peer->log, LOG_WARNING, "%s Missing well-known attribute %s.", + peer->host, map_direct(bgp_attr_name_map, type).str); + if (first) + bgp_peer_down_error_with_data (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MISS_ATTR, + &type, 1); + first = false ; + } ; - bgp_peer_down_error_with_data (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_MISS_ATTR, - &type, 1); - return BGP_ATTR_PARSE_ERROR; - } - return BGP_ATTR_PARSE_PROCEED; -} + flags >>= 1 ; + ++type ; + } ; + + qassert(flags == 0) ; -//int stream_put_prefix (struct stream *, struct prefix *); + return BGP_ATTR_PARSE_ERROR ; +} /* Make attribute packet. */ bgp_size_t @@ -2275,7 +2796,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, sizep = stream_get_endp (s); stream_putc (s, 0); /* Length of this attribute. */ stream_putw (s, AFI_IP); /* AFI */ - stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */ + stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */ stream_putc (s, 12); stream_putl (s, 0); @@ -2440,7 +2961,7 @@ bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p, if (safi == SAFI_MPLS_VPN) { /* SAFI */ - stream_putc (s, BGP_SAFI_VPNV4); + stream_putc (s, SAFI_MPLS_LABELED_VPN); /* prefix. */ stream_putc (s, p->prefixlen + 88); diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 8cca316d..6a235d54 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -138,18 +138,21 @@ struct transit #define ATTR_FLAG_BIT(X) (1 << ((X) - 1)) typedef enum { - BGP_ATTR_PARSE_PROCEED = 0, + BGP_ATTR_PARSE_IGNORE = 1, + BGP_ATTR_PARSE_PROCEED = 0, /* NB: value >= BGP_ATTR_PARSE_PROCEED is OK */ BGP_ATTR_PARSE_ERROR = -1, BGP_ATTR_PARSE_WITHDRAW = -2, } bgp_attr_parse_ret_t; +#define BGP_ATTR_PARSE_OK(ret) ((ret) >= BGP_ATTR_PARSE_PROCEED) + /* Prototypes. */ extern void bgp_attr_init (void); extern void bgp_attr_finish (void); 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 *); + struct bgp_nlri *, + struct bgp_nlri *, bool*); +extern int bgp_attr_check (struct peer *, struct attr *, bool); 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 *); @@ -185,9 +188,9 @@ extern void cluster_unintern (struct cluster_list *); void transit_unintern (struct transit *); /* Exported for unit-test purposes only */ -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 *); +extern bgp_attr_parse_ret_t bgp_mp_reach_parse (struct peer *, const bgp_size_t, + struct attr *, const u_char, struct bgp_nlri *); +extern bgp_attr_parse_ret_t bgp_mp_unreach_parse (struct peer *, + const bgp_size_t, const u_char, struct bgp_nlri *, bool*); #endif /* _QUAGGA_BGP_ATTR_H */ diff --git a/bgpd/bgp_common.c b/bgpd/bgp_common.c index 8a3a57ff..a615b4f7 100644 --- a/bgpd/bgp_common.c +++ b/bgpd/bgp_common.c @@ -187,9 +187,9 @@ qafx_num_from_iAFI_iSAFI(iAFI_t afi, iSAFI_t safi) /*------------------------------------------------------------------------------ * qAFI/qSAFI => qafx_num_t * - * NB: qAFI_undef with any qSAFI_xxx => qafx_num_undef - * qSAFI_undef with any qAFI_xxx => qafx_num_undef - * qSAFI_Unused qith any qAFI_xxx => qafx_num_undef + * NB: qAFI_undef with any qSAFI_xxx => qafx_num_undef + * qSAFI_undef with any qAFI_xxx => qafx_num_undef + * qSAFI_Reserved_3 with any qAFI_xxx => qafx_num_undef * * NB: any unrecognised qAFI/qSAFI combinations => FATAL error */ @@ -207,7 +207,7 @@ qafx_num_from_qAFI_qSAFI(qAFI_t afi, qSAFI_t safi) switch(safi) { case qSAFI_undef: - case qSAFI_Unused: + case qSAFI_Reserved_3: return qafx_num_undef ; case qSAFI_Unicast: return qafx_ipv4_unicast ; @@ -224,7 +224,7 @@ qafx_num_from_qAFI_qSAFI(qAFI_t afi, qSAFI_t safi) switch(safi) { case qSAFI_undef: - case qSAFI_Unused: + case qSAFI_Reserved_3: return qafx_num_undef ; case qSAFI_Unicast: return qafx_ipv6_unicast ; diff --git a/bgpd/bgp_common.h b/bgpd/bgp_common.h index 2a6216ca..5828be86 100644 --- a/bgpd/bgp_common.h +++ b/bgpd/bgp_common.h @@ -27,7 +27,6 @@ #include "bgpd/bgp.h" #include "qafi_safi.h" -#include "lib/zassert.h" /*============================================================================== * Here are a number of "incomplete" declarations, which allow a number of @@ -38,13 +37,19 @@ struct bgp ; struct peer ; struct bgp_session ; struct bgp_connection ; +struct bgp_connection_options ; struct bgp_open_state ; +struct bgp_nexthop ; typedef struct bgp* bgp_instance ; typedef struct peer* bgp_peer ; typedef struct bgp_session* bgp_session ; typedef struct bgp_connection* bgp_connection ; +typedef struct bgp_connnection_options* bgp_connection_options ; typedef struct bgp_open_state* bgp_open_state ; +typedef struct bgp_nexthop* bgp_nexthop ; + +typedef struct bgp_connnection_options bgp_connection_options_t ; /*============================================================================== * Some BGP capabilities and messages have RFC and pre-RFC forms. diff --git a/bgpd/bgp_connection.c b/bgpd/bgp_connection.c index efcfb98d..8d17d2b0 100644 --- a/bgpd/bgp_connection.c +++ b/bgpd/bgp_connection.c @@ -361,7 +361,7 @@ bgp_connection_free(bgp_connection connection) XFREE(MTYPE_BGP_PEER_HOST, connection->host) ; stream_free(connection->ibuf) ; stream_free(connection->obuf) ; - bgp_write_buffer_free(&connection->wbuff) ; + bgp_write_buffer_free(connection->wbuff) ; /* Free the body */ sdl_del(bgp_connection_list, connection, exist) ; @@ -376,11 +376,10 @@ bgp_connection_free(bgp_connection connection) * * Problem: can it be assumed that all sessions have been closed ? * - * if not... how are all the connections to be pursuaded to adopt + * if not... how are all the connections to be persuaded to adopt * an appropriate posture ? */ - /*------------------------------------------------------------------------------ * If required, allocate new write buffer. * Initialise pointers empty and writable. @@ -653,7 +652,7 @@ bgp_connection_start(bgp_connection connection, union sockunion* su_local, sockunion_set_dup(&connection->su_local, su_local) ; sockunion_set_dup(&connection->su_remote, su_remote) ; - bgp_write_buffer_init(&connection->wbuff, bgp_wbuff_size) ; + bgp_write_buffer_init(connection->wbuff, bgp_wbuff_size) ; } ; /*------------------------------------------------------------------------------ @@ -687,7 +686,7 @@ bgp_connection_stop(bgp_connection connection, bool stop_writer) /* If required: set write buffer *unwritable* (and empty). */ if (stop_writer) - bgp_write_buffer_unwritable(&connection->wbuff) ; + bgp_write_buffer_unwritable(connection->wbuff) ; } ; /*------------------------------------------------------------------------------ @@ -849,7 +848,7 @@ bgp_connection_close(bgp_connection connection, bool keep_timers) extern bool bgp_connection_part_close(bgp_connection connection) { - bgp_wbuffer wb = &connection->wbuff ; + bgp_wbuffer wb = connection->wbuff ; int sock_fd ; uint8_t* p ; bgp_size_t mlen ; @@ -929,7 +928,7 @@ bgp_connection_write(bgp_connection connection, struct stream* s) uint length ; bool enable_write ; - bgp_wbuffer wb = &connection->wbuff ; + bgp_wbuffer wb = connection->wbuff ; enable_write = bgp_write_buffer_empty(wb) ; @@ -978,7 +977,7 @@ static void bgp_connection_write_action(qps_file qf, void* file_info) { bgp_connection connection = file_info ; - bgp_wbuffer wb = &connection->wbuff ; + bgp_wbuffer wb = connection->wbuff ; int have ; int ret ; diff --git a/bgpd/bgp_connection.h b/bgpd/bgp_connection.h index 625fe592..11839e5a 100644 --- a/bgpd/bgp_connection.h +++ b/bgpd/bgp_connection.h @@ -85,6 +85,55 @@ enum bgp_fsm_events bgp_fsm_last_event = 15, } ; +enum bgp_fsm_events_4271 +{ + bgp_fsm2_eNULL = 0, + + /* 8.1.2 Administrative Events + */ + bgp_fsm2_eManualStart = 1, + bgp_fsm2_eManualStop = 2, + bgp_fsm2_eAutomaticStart = 3, + bgp_fsm2_eManualStart_with_Passive = 4, + bgp_fsm2_eAutomaticStart_with_Passive = 5, + bgp_fsm2_eAutomaticStart_with_Damp = 6, + bgp_fsm2_eAutomaticStart_with_Damp_and_Passive = 7, + bgp_fsm2_eAutomaticStop = 8, + + /* 8.1.3 Timer Events + */ + bgp_fsm2_eConnectRetryTimer_Expires = 9, + bgp_fsm2_eHoldTimer_Expires = 10, + bgp_fsm2_eKeepaliveTimer_Expires = 11, + bgp_fsm2_eDelayOpenTimer_Expires = 12, + bgp_fsm2_eIdleHoldTimer_Expires = 13, + + /* 8.1.4 TCP Connection-Based Events + */ + bgp_fsm2_eTcpConnection_Valid = 14, + bgp_fsm2_eTcp_CR_Invalid = 15, + bgp_fsm2_eTcp_CR_Acked = 16, + bgp_fsm2_eTcpConnectionConfirmed = 17, + bgp_fsm2_eTcpConnectionFails = 18, + + /* 8.1.5 BGP Message-Based Events + */ + bgp_fsm2_eBGPOpen = 19, + bgp_fsm2_eBGPOpen_with_DelayOpenTimer = 20, + bgp_fsm2_eBGPHeaderErr = 21, + bgp_fsm2_eBGPOpenMsgErr = 22, + bgp_fsm2_eOpenCollisionDump = 23, + bgp_fsm2_eNotifyMsgVerErr = 24, + bgp_fsm2_eMotifyMsg = 25, + bgp_fsm2_eKeepAliveMsg = 26, + bgp_fsm2_eUpdateMsg = 27, + bgp_fsm2_eUpdareMsgErr = 28, + + /* Number of events -- including the eNULL + */ + bgp_fsm2_event_count = 29, +} ; + /*============================================================================== * BGP Connection Structures * @@ -106,6 +155,7 @@ enum bgp_fsm_events * "empty but not writable" state. */ typedef struct bgp_wbuffer* bgp_wbuffer ; +typedef struct bgp_wbuffer bgp_wbuffer_t ; struct bgp_wbuffer { uint8_t* p_out ; @@ -119,6 +169,45 @@ struct bgp_wbuffer enum { bgp_wbuff_size = BGP_MSG_MAX_L * 10 } ; /*============================================================================== + * BGP Connection Options Structure + * + * This is a discrete structure so that the accept() handling can handle these + * things without requiring the complete bgp_connection or bgp_session ! + */ +struct bgp_connection_options +{ + /* Flags indicating whether to allow inbound and/or outbound connections. + */ + bool accept ; + bool connect ; + + /* Both connect() and accept() will attempt to set the required ttl/gtsm + * + * The gtsm_set flag reflects what has happened. + */ + int ttl_req ; /* TTL to set, if not zero */ + bool gtsm_req ; /* ttl set by ttl-security */ + + bool gtsm_set ; /* minttl has been set */ + + /* Both connect() and accept() will apply MD5 password to connections. + * + * If the accept flag is true, then the password is set for the peer's + * address in all listeners. + * + * For connect() the password is set when the outbpund connection is + * set up. + */ + char* password ; /* copy of MD5 password */ + + /* Only connect() worries about these. + */ + char* ifname ; /* interface to bind to, if any */ + uint ifindex ; /* and its index, if any */ + sockunion ifaddress ; /* address to bind to, if any */ +} ; + +/*============================================================================== * BGP Connection Structure * * The BGP Connection is the main data structure for the BGP Engine. @@ -197,7 +286,7 @@ struct bgp_connection mqueue_local_queue_t pending_queue ; /* pending write messages */ - struct bgp_wbuffer wbuff ; /* write buffer */ + bgp_wbuffer_t wbuff[1] ; /* write buffer */ } ; /*============================================================================== @@ -317,7 +406,7 @@ bgp_write_buffer_has(bgp_wbuffer wb) Inline bool bgp_connection_write_cannot_max(bgp_connection connection) { - return bgp_write_buffer_cannot_max(&connection->wbuff) ; + return bgp_write_buffer_cannot_max(connection->wbuff) ; } ; /*------------------------------------------------------------------------------ @@ -326,7 +415,7 @@ bgp_connection_write_cannot_max(bgp_connection connection) Inline bool bgp_connection_write_empty(bgp_connection connection) { - return bgp_write_buffer_empty(&connection->wbuff) ; + return bgp_write_buffer_empty(connection->wbuff) ; } ; /*============================================================================== diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c index 79d75a3f..58031fc3 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -28,6 +28,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "thread.h" #include "bgpd/bgpd.h" +#include "bgpd/bgp_peer.h" #include "bgpd/bgp_damp.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 1d3fce89..ac4d48da 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -21,7 +21,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include <zebra.h> #include <stdbool.h> -#include <lib/version.h> +#include "lib/version.h" #include "prefix.h" #include "linklist.h" #include "stream.h" @@ -32,7 +32,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "memory.h" #include "qfstring.h" -#include "bgpd/bgp_common.h" #include "bgpd/bgp_engine.h" #include "bgpd/bgp_session.h" #include "bgpd/bgp_connection.h" diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index a95dd5b0..02876d96 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -36,6 +36,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_dump.h" #include "bgpd/bgpd.h" +#include "bgpd/bgp_peer.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 3d0d2b5a..3dde6dc3 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -622,6 +622,13 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format) for (i = 0; i < ecom->size; i++) { + /* Make it sure size is enough. */ + while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size) + { + str_size *= 2; + str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size); + } + /* Space between each value. */ if (! first) str_buf[str_pnt++] = ' '; @@ -665,13 +672,6 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format) break; } - /* Make it sure size is enough. */ - while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size) - { - str_size *= 2; - str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size); - } - /* Put string into buffer. */ if (encode == ECOMMUNITY_ENCODE_AS4) { diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c index 33275898..ca031f31 100644 --- a/bgpd/bgp_filter.c +++ b/bgpd/bgp_filter.c @@ -26,6 +26,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "buffer.h" #include "bgpd/bgpd.h" +#include "bgpd/bgp_peer.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_regex.h" #include "bgpd/bgp_filter.h" diff --git a/bgpd/bgp_filter.h b/bgpd/bgp_filter.h index 3da76d03..66daec7c 100644 --- a/bgpd/bgp_filter.h +++ b/bgpd/bgp_filter.h @@ -27,6 +27,8 @@ enum as_filter_type AS_FILTER_PERMIT }; +struct as_list ; + extern void bgp_filter_cmd_init (void); extern void bgp_filter_init (void); extern void bgp_filter_reset (void); diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 47d1d449..8cb8181b 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -1490,7 +1490,7 @@ bgp_fsm_event(bgp_connection connection, bgp_fsm_event_t event) map_direct(bgp_fsm_status_map, next_state).str) ; if (BGP_DEBUG(normal, NORMAL)) - zlog_debug ("%s on %s went from %s to %s", + zlog_debug ("%s on %s FSM went from %s to %s", connection->host, bgp_event_str[event], map_direct(bgp_fsm_status_map, prev_state).str, diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index 077d45c3..7f67aa65 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -26,7 +26,6 @@ #define _QUAGGA_BGP_FSM_H #include "bgpd/bgp_common.h" -#include "bgpd/bgp_connection.h" /* Prototypes. */ diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index b3bf744a..58bb0e07 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -86,6 +86,7 @@ static zebra_capabilities_t _caps_p [] = { ZCAP_BIND, ZCAP_NET_RAW, + ZCAP_NET_ADMIN, }; struct zebra_privs_t bgpd_privs = @@ -146,6 +147,7 @@ static const struct option longopts[] = { "int_config", required_argument, NULL, 'F'}, { "integrated", no_argument, NULL, 'Q'}, { "int_boot", no_argument, NULL, 'b'}, + { "socket", required_argument, NULL, 'z'}, { 0 } }; @@ -171,6 +173,7 @@ usage (const char *progname, int status) "-Q, --integrated Use integrated configuration file\n" "-b, --int_boot Expect vtysh to provide configuration\n" "-i, --pid_file Set process identifier file name\n" + "-z, --socket Set path of zebra socket\n" "-p, --bgp_port Set bgp protocol's port number\n" "-l, --listenon Listen on specified address (implies -n)\n" "-A, --vty_addr Set vty's bind address\n" @@ -238,7 +241,7 @@ main (int argc, char **argv) int val ; int opt; - opt = getopt_long (argc, argv, "df:i:hp:l:A:P:rnu:g:vCtI2F:Qb", + opt = getopt_long (argc, argv, "df:i:z:hp:l:A:P:rnu:g:vCtI2F:Qb", longopts, 0); if (opt == EOF) break; @@ -286,6 +289,12 @@ main (int argc, char **argv) pid_file = optarg; break; + /* Set zebra server path. + */ + case 'z': + zclient_serv_path_set (optarg); + break; + /* Set port to listen on for BGP -- 0 => default. */ case 'p': @@ -491,6 +500,8 @@ main (int argc, char **argv) */ qpt_clear_qpthreads_active() ; + zprivs_terminate (&bgpd_privs); + bgp_exit(0); } @@ -615,7 +626,7 @@ static void bgp_in_thread_init(void) { bgp_open_listeners(bm->address, bm->port); -} +} ; /*------------------------------------------------------------------------------ * routing_nexus in-thread initialisation/finish -- for gdb ! diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 193d2d50..d14f8f61 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -27,6 +27,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "stream.h" #include "bgpd/bgpd.h" +#include "bgpd/bgp_peer.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" @@ -233,6 +234,9 @@ str2tag (const char *str, u_char *tag) char *endptr; u_int32_t t; + if (*str == '-') + return 0; + errno = 0 ; l = strtoul (str, &endptr, 10); diff --git a/bgpd/bgp_msg_write.h b/bgpd/bgp_msg_write.h index 1d2385b9..d5667785 100644 --- a/bgpd/bgp_msg_write.h +++ b/bgpd/bgp_msg_write.h @@ -26,7 +26,6 @@ #include "misc.h" -#include "bgpd/bgp_common.h" #include "bgpd/bgp_connection.h" #include "bgpd/bgp_notification.h" #include "bgpd/bgp_open_state.h" diff --git a/bgpd/bgp_names.c b/bgpd/bgp_names.c index 521a0b0d..89623246 100644 --- a/bgpd/bgp_names.c +++ b/bgpd/bgp_names.c @@ -20,10 +20,10 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include <zebra.h> -#include <bgpd/bgp_names.h> +#include "bgpd/bgp_names.h" -#include <bgpd/bgp_connection.h> -#include <bgpd/bgp_notification.h> +#include "bgpd/bgp_connection.h" +#include "bgpd/bgp_notification.h" /*------------------------------------------------------------------------------ * Names of FSM status values @@ -219,3 +219,44 @@ const char* bgp_origin_long_map_body[] = const map_direct_t bgp_origin_long_map = map_direct_s(bgp_origin_long_map_body, "unknown(%d)") ; +/*------------------------------------------------------------------------------ + * Attribute type names + */ +const char* bgp_attr_name_map_body[] = +{ + [BGP_ATTR_ORIGIN] = "ORIGIN", + [BGP_ATTR_AS_PATH] = "AS_PATH", + [BGP_ATTR_NEXT_HOP] = "NEXT_HOP", + [BGP_ATTR_MULTI_EXIT_DISC] = "MULTI_EXIT_DISC", + [BGP_ATTR_LOCAL_PREF] = "LOCAL_PREF", + [BGP_ATTR_ATOMIC_AGGREGATE] = "ATOMIC_AGGREGATE", + [BGP_ATTR_AGGREGATOR] = "AGGREGATOR", + [BGP_ATTR_COMMUNITIES] = "COMMUNITY", + [BGP_ATTR_ORIGINATOR_ID] = "ORIGINATOR_ID", + [BGP_ATTR_CLUSTER_LIST] = "CLUSTER_LIST", + [BGP_ATTR_DPA] = "DPA", + [BGP_ATTR_ADVERTISER] = "ADVERTISER" , + [BGP_ATTR_RCID_PATH] = "RCID_PATH", + [BGP_ATTR_MP_REACH_NLRI] = "MP_REACH_NLRI", + [BGP_ATTR_MP_UNREACH_NLRI] = "MP_UNREACH_NLRI", + [BGP_ATTR_EXT_COMMUNITIES] = "EXT_COMMUNITIES", + [BGP_ATTR_AS4_PATH] = "AS4_PATH", + [BGP_ATTR_AS4_AGGREGATOR] = "AS4_AGGREGATOR", + [BGP_ATTR_AS_PATHLIMIT] = "AS_PATHLIMIT", +}; + +const map_direct_t bgp_attr_name_map = + map_direct_s(bgp_attr_name_map_body, "unknown(%u)") ; + +/*------------------------------------------------------------------------------ + * AFI names + */ +const char* bgp_afi_name_map_body[] = +{ + [AFI_IP] = "AFI_IP", + [AFI_IP6] = "AFI_IP6", +}; + +const map_direct_t bgp_afi_name_map = + map_direct_s(bgp_afi_name_map_body, "unknown AFI(%u)") ; + diff --git a/bgpd/bgp_names.h b/bgpd/bgp_names.h index 24b9e0d4..ab688575 100644 --- a/bgpd/bgp_names.h +++ b/bgpd/bgp_names.h @@ -41,5 +41,7 @@ extern const map_direct_t bgp_notify_unspecific_msg_map ; extern const map_direct_t bgp_notify_unknown_msg_map ; extern const map_direct_t bgp_origin_short_map ; extern const map_direct_t bgp_origin_long_map ; +extern const map_direct_t bgp_attr_name_map ; +extern const map_direct_t bgp_afi_name_map ; #endif /* _QUAGGA_BGP_NAMES_H */ diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index a8193beb..856b7e0e 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -34,10 +34,10 @@ #include "bgpd/bgp_debug.h" #include "bgpd/bgp_network.h" +#include "bgpd/bgp_connection.h" +#include "bgpd/bgp_session.h" #include "bgpd/bgp_peer_index.h" -#include "bgpd/bgp_session.h" -#include "bgpd/bgp_connection.h" #include "bgpd/bgp_fsm.h" #include "qpselect.h" @@ -54,7 +54,7 @@ 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, +static int bgp_socket_set_common_options(int sock_fd, sockunion su, bgp_connection connection) ; static int bgp_set_ttl(int sock_fd, bgp_connection connnection, int ttl, bool gtsm) ; @@ -474,14 +474,10 @@ bgp_prepare_to_accept(bgp_connection connection) { int err ; - if (connection->session->password != NULL) - { - err = bgp_md5_set_listeners(connection->session->su_peer, - connection->session->password) ; - -/* TODO: failure to set password in bgp_prepare_to_accept ? */ - } ; - + /* This logs an error if setting the password fails. + */ + err = bgp_md5_set_listeners(connection->session->su_peer, + connection->session->password) ; return ; } ; @@ -492,6 +488,8 @@ bgp_prepare_to_accept(bgp_connection connection) * listener(s) for the appropriate address family. * * NB: requires the session mutex LOCKED. + * + * TODO -- should do this when peer is stopped or about to be deleted !! */ extern void bgp_not_prepared_to_accept(bgp_connection connection) @@ -501,8 +499,6 @@ bgp_not_prepared_to_accept(bgp_connection connection) if (connection->session->password != NULL) { err = bgp_md5_set_listeners(connection->session->su_peer, NULL) ; - -/* TODO: failure to clear password in bgp_not_prepared_to_accept ? */ } ; return ; @@ -586,8 +582,10 @@ bgp_accept_action(qps_file qf, void* file_info) if (BGP_DEBUG(events, EVENTS)) zlog_debug("[Event] BGP connection from host %s", sutoa(&su_remote).str) ; - /* See if we are ready to accept connections from the connecting party */ + /* See if we are ready to accept connections from the connecting party + */ connection = bgp_peer_index_seek_accept(&su_remote, &exists) ; + if (connection == NULL) { if (BGP_DEBUG(events, EVENTS)) @@ -610,7 +608,6 @@ bgp_accept_action(qps_file qf, void* file_info) * The session is active, so the Routing Engine will not make any changes * except under the mutex, and will not destroy the session. */ - BGP_CONNECTION_SESSION_LOCK(connection) ; /*<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-*/ /* Set the common socket options. @@ -701,17 +698,12 @@ bgp_open_connect(bgp_connection connection) /* Connect to the remote peer. */ if (err == 0) - { - int ret ; - ret = sockunion_connect(sock_fd, su, connection->session->port, - connection->session->ifindex) ; + err = sockunion_connect(sock_fd, su, connection->session->port, + connection->session->ifindex) ; /* does not report EINPROGRESS as an error. */ - if (ret < 0) - err = errno ; - } ; - - /* If not OK now, close the sock_fd and signal the error */ + /* If not OK now, close the sock_fd and signal the error + */ if (err != 0) { if (sock_fd >= 0) @@ -997,7 +989,7 @@ bgp_bind_ifaddress(bgp_connection connection, int sock_fd) * * reuseaddr * * reuseport * * set security ttl (GTSM) and/or ttl -- if connection given. - * * for IPv4, set TOS if required + * * set TOS or equivalent if required * * These options are set on all sockets: listen/connect/accept * (except either form of ttl, which is not set on listen). @@ -1009,9 +1001,11 @@ bgp_bind_ifaddress(bgp_connection connection, int sock_fd) * != 0 == errno -- not that we really expect any errors here */ static int -bgp_socket_set_common_options(int sock_fd, union sockunion* su, +bgp_socket_set_common_options(int sock_fd, sockunion su, bgp_connection connection) { + int err ; + /* Make socket non-blocking and close-on-exec */ if (set_nonblocking(sock_fd) < 0) @@ -1029,25 +1023,44 @@ bgp_socket_set_common_options(int sock_fd, union sockunion* su, /* Adjust ttl if required */ if (connection != NULL) { - int err ; err = bgp_set_ttl(sock_fd, connection, connection->session->ttl, connection->session->gtsm) ; if (err != 0) return errno = err ; } ; -#ifdef IPTOS_PREC_INTERNETCONTROL - /* 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. + /* Worry about TOS etc, as required. */ - if (sockunion_family(su) == AF_INET) - if (setsockopt_ipv4_tos(sock_fd, IPTOS_PREC_INTERNETCONTROL) < 0) - return errno ; + err = 0 ; /* so far, so good */ + +#ifdef IPTOS_PREC_INTERNETCONTROL + if (bgpd_privs.change (ZPRIVS_RAISE)) + zlog_err ("%s: could not raise privs", __func__); + + switch(sockunion_family(su)) + { + case AF_INET: + if (setsockopt_ipv4_tos (sock_fd, IPTOS_PREC_INTERNETCONTROL) < 0) + err = errno ; + break ; + +# ifdef HAVE_IPV6 + case AF_INET6: + if (setsockopt_ipv6_tclass (sock_fd, IPTOS_PREC_INTERNETCONTROL) < 0) + err = errno ; + break ; +# endif + + default: + err = 0 ; + break ; + } + + if (bgpd_privs.change (ZPRIVS_LOWER)) + zlog_err ("%s: could not lower privs", __func__); #endif - return 0 ; + return errno = err ; } ; /*------------------------------------------------------------------------------ diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h index d05fa3a0..30dc9f55 100644 --- a/bgpd/bgp_network.h +++ b/bgpd/bgp_network.h @@ -22,7 +22,7 @@ #ifndef _QUAGGA_BGP_NETWORK_H #define _QUAGGA_BGP_NETWORK_H -#include "bgpd/bgp_connection.h" +#include "bgpd/bgp_common.h" extern int bgp_open_listeners(const char *address, unsigned short port) ; extern void bgp_close_listeners(void) ; diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index cc7e1045..9c308b95 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -30,6 +30,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "memory.h" #include "bgpd/bgpd.h" +#include "bgpd/bgp_peer.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" @@ -146,7 +147,7 @@ bgp_nexthop_same (struct nexthop *next1, struct nexthop *next2) } static int -bgp_nexthop_cache_changed (struct bgp_nexthop_cache *bnc1, +bgp_nexthop_cache_different (struct bgp_nexthop_cache *bnc1, struct bgp_nexthop_cache *bnc2) { int i; @@ -171,7 +172,7 @@ bgp_nexthop_cache_changed (struct bgp_nexthop_cache *bnc1, /* If nexthop exists on connected network return 1. */ int -bgp_nexthop_check_ebgp (afi_t afi, struct attr *attr) +bgp_nexthop_onlink (afi_t afi, struct attr *attr) { struct bgp_node *rn; @@ -253,15 +254,15 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, } else { - bnc = zlookup_query_ipv6 (&attr->extra->mp_nexthop_global); - if (bnc) + if (NULL == (bnc = zlookup_query_ipv6 (&attr->extra->mp_nexthop_global))) + bnc = bnc_new (); + else { - struct bgp_table *old; - struct bgp_node *oldrn; - struct bgp_nexthop_cache *oldbnc; - if (changed) { + struct bgp_table *old; + struct bgp_node *oldrn; + if (bgp_nexthop_cache_table[AFI_IP6] == cache1_table[AFI_IP6]) old = cache2_table[AFI_IP6]; else @@ -270,9 +271,9 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, oldrn = bgp_node_lookup (old, &p); if (oldrn) { - oldbnc = oldrn->info; + struct bgp_nexthop_cache *oldbnc = oldrn->info; - bnc->changed = bgp_nexthop_cache_changed (bnc, oldbnc); + bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc); if (bnc->metric != oldbnc->metric) bnc->metricchanged = 1; @@ -281,11 +282,6 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, } } } - else - { - bnc = bnc_new (); - bnc->valid = 0; - } rn->info = bnc; } @@ -344,15 +340,15 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, } else { - bnc = zlookup_query (addr); - if (bnc) + if (NULL == (bnc = zlookup_query (addr))) + bnc = bnc_new (); + else { - struct bgp_table *old; - struct bgp_node *oldrn; - struct bgp_nexthop_cache *oldbnc; - if (changed) { + struct bgp_table *old; + struct bgp_node *oldrn; + if (bgp_nexthop_cache_table[AFI_IP] == cache1_table[AFI_IP]) old = cache2_table[AFI_IP]; else @@ -361,9 +357,9 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, oldrn = bgp_node_lookup (old, &p); if (oldrn) { - oldbnc = oldrn->info; + struct bgp_nexthop_cache *oldbnc = oldrn->info; - bnc->changed = bgp_nexthop_cache_changed (bnc, oldbnc); + bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc); if (bnc->metric != oldbnc->metric) bnc->metricchanged = 1; @@ -372,11 +368,6 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, } } } - else - { - bnc = bnc_new (); - bnc->valid = 0; - } rn->info = bnc; } @@ -463,7 +454,7 @@ bgp_scan (afi_t afi, safi_t safi) if ((peer_sort (bi->peer) == BGP_PEER_EBGP) && (bi->peer->ttl == 1)) - valid = bgp_nexthop_check_ebgp (afi, bi->attr); + valid = bgp_nexthop_onlink (afi, bi->attr); else valid = bgp_nexthop_lookup (afi, bi->peer, bi, &changed, &metricchanged); @@ -1173,51 +1164,79 @@ ALIAS (no_bgp_scan_time, "Configure background scanner interval\n" "Scanner interval (seconds)\n") -DEFUN (show_ip_bgp_scan, - show_ip_bgp_scan_cmd, - "show ip bgp scan", - SHOW_STR - IP_STR - BGP_STR - "BGP scan status\n") +static int +show_ip_bgp_scan_tables (struct vty *vty, const bool detail) { struct bgp_node *rn; struct bgp_nexthop_cache *bnc; + u_char i; if (bgp_scan_thread) vty_out (vty, "BGP scan is running%s", VTY_NEWLINE); else vty_out (vty, "BGP scan is not running%s", VTY_NEWLINE); + vty_out (vty, "BGP scan interval is %d%s", bgp_scan_interval, VTY_NEWLINE); vty_out (vty, "Current BGP nexthop cache:%s", VTY_NEWLINE); - for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP]); rn; rn = bgp_route_next (rn)) + for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP]); rn; + rn = bgp_route_next (rn)) if ((bnc = rn->info) != NULL) { if (bnc->valid) - vty_out (vty, " %s valid [IGP metric %d]%s", - safe_inet_ntoa (rn->p.u.prefix4), bnc->metric, VTY_NEWLINE); - else - vty_out (vty, " %s invalid%s", - safe_inet_ntoa (rn->p.u.prefix4), VTY_NEWLINE); + { + vty_out (vty, " %s valid [IGP metric %d]\n", + siptoa(AF_INET, &rn->p.u.prefix4).str, bnc->metric); + if (detail) + for (i = 0; i < bnc->nexthop_num; i++) + switch (bnc->nexthop[i].type) + { + case NEXTHOP_TYPE_IPV4: + vty_out (vty, " gate %s\n", + siptoa(AF_INET, &bnc->nexthop[i].gate.ipv4).str); + break; + case NEXTHOP_TYPE_IFINDEX: + vty_out (vty, " ifidx %u\n", bnc->nexthop[i].ifindex); + break; + default: + vty_out (vty, " invalid nexthop type %u\n", + bnc->nexthop[i].type); + } + } + else + vty_out (vty, " %s invalid\n", safe_inet_ntoa (rn->p.u.prefix4)); } #ifdef HAVE_IPV6 { - char buf[BUFSIZ]; for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP6]); rn; rn = bgp_route_next (rn)) if ((bnc = rn->info) != NULL) { if (bnc->valid) - vty_out (vty, " %s valid [IGP metric %d]%s", - inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), - bnc->metric, VTY_NEWLINE); + { + vty_out (vty, " %s valid [IGP metric %d]\n", + siptoa(AF_INET6, &rn->p.u.prefix6).str, bnc->metric); + if (detail) + for (i = 0; i < bnc->nexthop_num; i++) + switch (bnc->nexthop[i].type) + { + case NEXTHOP_TYPE_IPV6: + vty_out (vty, " gate %s\n", + siptoa(AF_INET6, &bnc->nexthop[i].gate.ipv6).str); + break; + case NEXTHOP_TYPE_IFINDEX: + vty_out (vty, " ifidx %u\n", bnc->nexthop[i].ifindex); + break; + default: + vty_out (vty, " invalid nexthop type %u\n", + bnc->nexthop[i].type); + } + } else - vty_out (vty, " %s invalid%s", - inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), - VTY_NEWLINE); + vty_out (vty, " %s invalid\n", + siptoa(AF_INET6, &rn->p.u.prefix6).str); } } #endif /* HAVE_IPV6 */ @@ -1227,27 +1246,42 @@ DEFUN (show_ip_bgp_scan, rn; rn = bgp_route_next (rn)) if (rn->info != NULL) - vty_out (vty, " %s/%d%s", safe_inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, - VTY_NEWLINE); + vty_out (vty, " %s\n", spfxtoa(&rn->p).str); #ifdef HAVE_IPV6 - { - char buf[BUFSIZ]; - - for (rn = bgp_table_top (bgp_connected_table[AFI_IP6]); - rn; - rn = bgp_route_next (rn)) - if (rn->info != NULL) - vty_out (vty, " %s/%d%s", - inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), - rn->p.prefixlen, - VTY_NEWLINE); - } + for (rn = bgp_table_top (bgp_connected_table[AFI_IP6]); + rn; + rn = bgp_route_next (rn)) + if (rn->info != NULL) + vty_out (vty, " %s\n", spfxtoa(&rn->p).str); #endif /* HAVE_IPV6 */ return CMD_SUCCESS; } +DEFUN (show_ip_bgp_scan, + show_ip_bgp_scan_cmd, + "show ip bgp scan", + SHOW_STR + IP_STR + BGP_STR + "BGP scan status\n") +{ + return show_ip_bgp_scan_tables (vty, false /* not detail */); +} + +DEFUN (show_ip_bgp_scan_detail, + show_ip_bgp_scan_detail_cmd, + "show ip bgp scan detail", + SHOW_STR + IP_STR + BGP_STR + "BGP scan status\n" + "More detailed output\n") +{ + return show_ip_bgp_scan_tables (vty, true /* detail */); +} + int bgp_config_write_scan_time (struct vty *vty) { @@ -1265,6 +1299,9 @@ CMD_INSTALL_TABLE(static, bgp_nexthop_cmd_table, BGPD) = { RESTRICTED_NODE, &show_ip_bgp_scan_cmd }, { ENABLE_NODE, &show_ip_bgp_scan_cmd }, + { VIEW_NODE, &show_ip_bgp_scan_detail_cmd }, + { ENABLE_NODE, &show_ip_bgp_scan_detail_cmd }, + CMD_INSTALL_END } ; @@ -1274,7 +1311,6 @@ bgp_scan_cmd_init (void) cmd_install_table(bgp_nexthop_cmd_table) ; } ; - void bgp_scan_init (void) { diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index 6e63fd41..17d44f69 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -55,7 +55,7 @@ extern void bgp_connected_add (struct connected *c); extern void bgp_connected_delete (struct connected *c); extern int bgp_multiaccess_check_v4 (struct in_addr, char *); extern int bgp_config_write_scan_time (struct vty *); -extern int bgp_nexthop_check_ebgp (afi_t, struct attr *); +extern int bgp_nexthop_onlink (afi_t, struct attr *); extern int bgp_nexthop_self (afi_t, struct attr *); #endif /* _QUAGGA_BGP_NEXTHOP_H */ diff --git a/bgpd/bgp_notification.h b/bgpd/bgp_notification.h index 755f431e..1622785d 100644 --- a/bgpd/bgp_notification.h +++ b/bgpd/bgp_notification.h @@ -56,8 +56,7 @@ struct bgp_notify /*============================================================================== * "Legacy" definitions */ - -/* BGP notify message codes. */ +/* BGP notify message codes. */ #define BGP_NOTIFY_HEADER_ERR 1 #define BGP_NOTIFY_OPEN_ERR 2 #define BGP_NOTIFY_UPDATE_ERR 3 @@ -67,13 +66,15 @@ struct bgp_notify #define BGP_NOTIFY_CAPABILITY_ERR 7 #define BGP_NOTIFY_MAX 8 -/* BGP_NOTIFY_HEADER_ERR sub codes. */ +#define BGP_NOTIFY_SUBCODE_UNSPECIFIC 0 + +/* BGP_NOTIFY_HEADER_ERR sub codes. */ #define BGP_NOTIFY_HEADER_NOT_SYNC 1 #define BGP_NOTIFY_HEADER_BAD_MESLEN 2 #define BGP_NOTIFY_HEADER_BAD_MESTYPE 3 #define BGP_NOTIFY_HEADER_MAX 4 -/* BGP_NOTIFY_OPEN_ERR sub codes. */ +/* BGP_NOTIFY_OPEN_ERR sub codes. */ #define BGP_NOTIFY_OPEN_UNSUP_VERSION 1 #define BGP_NOTIFY_OPEN_BAD_PEER_AS 2 #define BGP_NOTIFY_OPEN_BAD_BGP_IDENT 3 @@ -83,7 +84,7 @@ struct bgp_notify #define BGP_NOTIFY_OPEN_UNSUP_CAPBL 7 #define BGP_NOTIFY_OPEN_MAX 8 -/* BGP_NOTIFY_UPDATE_ERR sub codes. */ +/* BGP_NOTIFY_UPDATE_ERR sub codes. */ #define BGP_NOTIFY_UPDATE_MAL_ATTR 1 #define BGP_NOTIFY_UPDATE_UNREC_ATTR 2 #define BGP_NOTIFY_UPDATE_MISS_ATTR 3 @@ -97,7 +98,7 @@ struct bgp_notify #define BGP_NOTIFY_UPDATE_MAL_AS_PATH 11 #define BGP_NOTIFY_UPDATE_MAX 12 -/* BGP_NOTIFY_CEASE sub codes (draft-ietf-idr-cease-subcode-05). */ +/* BGP_NOTIFY_CEASE sub codes (RFC 4486). */ #define BGP_NOTIFY_CEASE_MAX_PREFIX 1 #define BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN 2 #define BGP_NOTIFY_CEASE_PEER_UNCONFIG 3 diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 1bfa40b8..872e12a2 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -100,11 +100,8 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer) case SAFI_MULTICAST: vty_out (vty, "SAFI Multicast"); break; - case SAFI_UNICAST_MULTICAST: - vty_out (vty, "SAFI Unicast Multicast"); - break; - case BGP_SAFI_VPNV4: - vty_out (vty, "SAFI MPLS-VPN"); + case SAFI_MPLS_LABELED_VPN: + vty_out (vty, "SAFI MPLS-labeled VPN"); break; default: vty_out (vty, "SAFI Unknown %d ", mpc.safi); @@ -131,9 +128,13 @@ bgp_capability_mp_data (struct stream *s, struct capability_mp_data *mpc) mpc->safi = stream_getc (s); } +/* TODO there is a lot of recent activity eg commit 1212dc1961... to do with + * AFI/SAFI stuff... Need to fully catch up !! + */ int bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi) { +#if 0 /* TODO BGP_SAFI_VPNV4 and BGP_SAFI_VPNV6 ???? */ /* VPNvX are AFI specific */ if ((afi == AFI_IP6 && *safi == BGP_SAFI_VPNV4) || (afi == AFI_IP && *safi == BGP_SAFI_VPNV6)) @@ -141,6 +142,7 @@ bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi) zlog_warn ("Invalid afi/safi combination (%u/%u)", afi, *safi); return 0; } +#endif switch (afi) { @@ -150,9 +152,8 @@ bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi) #endif switch (*safi) { - /* BGP VPNvX SAFI isn't contigious with others, remap */ - case BGP_SAFI_VPNV4: - case BGP_SAFI_VPNV6: + /* BGP MPLS-labeled VPN SAFI isn't contigious with others, remap */ + case SAFI_MPLS_LABELED_VPN: *safi = SAFI_MPLS_VPN; case SAFI_UNICAST: case SAFI_MULTICAST: @@ -412,7 +413,7 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr) peer->v_gr_restart); } - while (stream_get_getp (s) + 4 < end) + while (stream_get_getp (s) + 4 <= end) { afi_t afi = stream_getw (s); safi_t safi = stream_getc (s); @@ -880,7 +881,7 @@ bgp_open_capability_orf (struct stream *s, struct peer *peer, int number_of_orfs = 0; if (safi == SAFI_MPLS_VPN) - safi = BGP_SAFI_VPNV4; + safi = SAFI_MPLS_LABELED_VPN; stream_putc (s, BGP_OPEN_OPT_CAP); capp = stream_get_endp (s); /* Set Capability Len Pointer */ @@ -988,7 +989,7 @@ bgp_open_capability (struct stream *s, struct peer *peer) stream_putc (s, CAPABILITY_CODE_MP_LEN); stream_putw (s, AFI_IP); stream_putc (s, 0); - stream_putc (s, BGP_SAFI_VPNV4); + stream_putc (s, SAFI_MPLS_LABELED_VPN); } #ifdef HAVE_IPV6 /* IPv6 unicast. */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index cf1fc7b7..fad72c36 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -564,7 +564,7 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi, /* Adjust safi code. */ if (safi == SAFI_MPLS_VPN) - safi = BGP_SAFI_VPNV4; + safi = SAFI_MPLS_LABELED_VPN; rr = bgp_route_refresh_new(afi, safi, 1); rr->defer = (when_to_refresh == REFRESH_DEFER); @@ -631,7 +631,7 @@ bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi, /* Adjust safi code. */ if (safi == SAFI_MPLS_VPN) - safi = BGP_SAFI_VPNV4; + safi = SAFI_MPLS_LABELED_VPN; s = peer->work; stream_reset (s); @@ -671,16 +671,14 @@ int bgp_update_receive (struct peer *peer, bgp_size_t size) { int ret; - u_char *end; struct stream *s; struct attr attr; bgp_size_t attribute_len; - bgp_size_t update_len; - bgp_size_t withdraw_len; struct bgp_nlri update; struct bgp_nlri withdraw; struct bgp_nlri mp_update; struct bgp_nlri mp_withdraw; + bool mp_eor ; char attrstr[BUFSIZ] = ""; bgp_attr_parse_ret_t ap_ret ; @@ -701,75 +699,65 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) memset (&mp_withdraw, 0, sizeof (struct bgp_nlri)); s = peer->ibuf; - end = stream_get_pnt (s) + size; - /* RFC1771 6.3 If the Unfeasible Routes Length or Total Attribute - Length is too large (i.e., if Unfeasible Routes Length + Total - Attribute Length + 23 exceeds the message Length), then the Error - Subcode is set to Malformed Attribute List. */ - if (stream_get_pnt (s) + 2 > end) + /* Unfeasible Route Length. + */ + withdraw.length = stream_getw (s); + if (stream_has_overrun(s)) { zlog_err ("%s [Error] Update packet error" " (packet length is short for unfeasible length)", peer->host); bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_MAL_ATTR); + BGP_NOTIFY_UPDATE_MAL_ATTR); return -1; } - /* Unfeasible Route Length. */ - withdraw_len = stream_getw (s); - - /* Unfeasible Route Length check. */ - if (stream_get_pnt (s) + withdraw_len > end) + /* Unfeasible Route packet format check. + */ + if (withdraw.length > 0) { - zlog_err ("%s [Error] Update packet error" - " (packet unfeasible length overflow %d)", - peer->host, withdraw_len); - bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_MAL_ATTR); - return -1; - } + ulen endp ; - /* Unfeasible Route packet format check. */ - if (withdraw_len > 0) - { - ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_get_pnt (s), withdraw_len); + endp = stream_push_endp(s, withdraw.length) ; + if (stream_has_overrun(s)) + { + zlog_err ("%s [Error] Update packet error" + " (packet unfeasible length overflow %d)", + peer->host, withdraw.length); + bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_ATTR); + return -1; + } + + ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_get_pnt (s), + withdraw.length); if (ret < 0) - return -1; + { + zlog_info ("%s withdraw NLRI doesn't pass sanity check", peer->host) ; + return -1 ; + } ; if (BGP_DEBUG (packet, PACKET_RECV)) zlog_debug ("%s [Update:RECV] Unfeasible NLRI received", peer->host); - withdraw.afi = AFI_IP; - withdraw.safi = SAFI_UNICAST; - withdraw.nlri = stream_get_pnt (s); - withdraw.length = withdraw_len; - stream_forward_getp (s, withdraw_len); - } + withdraw.afi = AFI_IP; + withdraw.safi = SAFI_UNICAST; + withdraw.nlri = stream_get_pnt (s); - /* Attribute total length check. */ - if (stream_get_pnt (s) + 2 > end) - { - zlog_warn ("%s [Error] Packet Error" - " (update packet is short for attribute length)", - peer->host); - bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_MAL_ATTR); - return -1; + stream_pop_endp(s, endp) ; /* steps getp to given endp */ } - /* Fetch attribute total length. */ + /* Fetch attribute total length. + */ attribute_len = stream_getw (s); - - /* Attribute length check. */ - if (stream_get_pnt (s) + attribute_len > end) + if (stream_has_overrun(s)) { zlog_warn ("%s [Error] Packet Error" - " (update packet attribute length overflow %d)", - peer->host, attribute_len); + " (update packet is short for attribute length)", + peer->host); bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_MAL_ATTR); + BGP_NOTIFY_UPDATE_MAL_ATTR); return -1; } @@ -790,48 +778,153 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) /* Parse attribute when it exists. */ if (attribute_len) { - ap_ret = bgp_attr_parse (peer, &attr, attribute_len, - &mp_update, &mp_withdraw); - if (ap_ret == BGP_ATTR_PARSE_ERROR) - return -1; - } + ulen endp ; + /* We have s->getp at the start of the attributes. + * + * Set the s->endp to the end of the attributes, check that is within + * the current endp, and save the current endp. + */ + endp = stream_push_endp(s, attribute_len) ; + if (stream_has_overrun(s)) + { + zlog_warn ("%s [Error] Packet Error" + " (update packet attribute length overflow %d)", + peer->host, attribute_len); + bgp_peer_down_error (peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_MAL_ATTR); + return -1; + } ; - /* Logging the attribute. */ - 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 ; + /* Do the real work of parsing the attributes getp..endp. + */ + ap_ret = bgp_attr_parse (peer, &attr, &mp_update, &mp_withdraw, &mp_eor); - if (ap_ret == BGP_ATTR_PARSE_WITHDRAW) - zlog (peer->log, LOG_ERR, - "%s rcvd UPDATE with errors in attr(s)!! Withdrawing route.", - peer->host); + /* Restore the endp, checking that either the getp is at the end of the + * attributes or we have a serious error and no longer care about the + * stream pointers. + */ + if (!stream_pop_endp(s, endp) && (ap_ret != BGP_ATTR_PARSE_ERROR)) + { + /* This is actually an internal error -- have somehow got out of + * step, without the check inside the loop spotting it ! + */ + zlog_err("%s: BGP attribute parser error" + " (BUG: did not process to end of attributes)", peer->host) ; - if (ret) - zlog (peer->log, lvl, "%s rcvd UPDATE w/ attr: %s", - peer->host, attrstr); - } + bgp_peer_down_error (peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_SUBCODE_UNSPECIFIC); - /* Network Layer Reachability Information. */ - update_len = end - stream_get_pnt (s); + ap_ret = BGP_ATTR_PARSE_ERROR; + } ; - if (update_len) - { - /* Check NLRI packet format and prefix length. */ - ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_get_pnt (s), update_len); - if (ret < 0) + /* Logging the attribute. + */ + if ((ap_ret != BGP_ATTR_PARSE_PROCEED) || BGP_DEBUG (update, UPDATE_IN)) { - bgp_attr_unintern_sub (&attr, true) ; /* true => free extra */ - return -1; - } + int lvl ; + + switch (ap_ret) + { + case BGP_ATTR_PARSE_PROCEED: + lvl = LOG_DEBUG ; + break ; + + case BGP_ATTR_PARSE_IGNORE: + lvl = LOG_ERR ; + + zlog (peer->log, lvl, + "%s rcvd UPDATE with errors in trivial attr(s)!!" + " Ignoring those attributes.", + peer->host); + + ap_ret = BGP_ATTR_PARSE_PROCEED ; /* ignore !! */ + break ; + + case BGP_ATTR_PARSE_WITHDRAW: + lvl = LOG_ERR ; + + zlog (peer->log, lvl, + "%s rcvd UPDATE with errors in attr(s)!!" + " Withdrawing route(s)", + peer->host); + break ; + + case BGP_ATTR_PARSE_ERROR: + default: + lvl = LOG_ERR ; + + zlog (peer->log, lvl, + "%s rcvd UPDATE with fatal errors in attr(s)!!" + " Dropping session", + peer->host); + break ; + } ; + + if (bgp_dump_attr (peer, &attr, attrstr, BUFSIZ)) + zlog (peer->log, lvl, "%s rcvd UPDATE w/ attr: %s", + peer->host, attrstr); + + if (ap_ret == BGP_ATTR_PARSE_ERROR) + { + ret = -1 ; + goto exit_bgp_update_receive ; + } ; + } + } + /* Network Layer Reachability Information. + */ + update.length = stream_get_read_left(s); + + if (update.length) + { /* Set NLRI portion to structure. */ - update.afi = AFI_IP; + update.afi = AFI_IP; update.safi = SAFI_UNICAST; update.nlri = stream_get_pnt (s); - update.length = update_len; - stream_forward_getp (s, update_len); - } + + ret = bgp_nlri_sanity_check (peer, update.afi, update.nlri, + update.length) ; + if (ret < 0) + { + zlog_info ("%s update NLRI doesn't pass sanity check", peer->host) ; + return -1 ; + } ; + + stream_forward_getp (s, update.length); + } ; + + /* Now we check for the "mandatory" attributes -- if we have one, other or + * both update.length and mp_update.length. + * + * Note that mp_update.length is a bit pointless, but we tolerate and ignore + * the attribute state. + */ + if ((update.length != 0) || (mp_update.length != 0)) + { + ret = bgp_attr_check (peer, &attr, update.length != 0 /* with NEXT_HOP */); + if (ret < 0) + { + ret = -1 ; + goto exit_bgp_update_receive ; + } + } ; + + /* Worry about mp_eor + * + * If this is true, then the MP_UNREACH_NLRI was the one and only attribute. + * + * If there are any update.length NLRI, then the check for mandatory updates, + * above, will already have failed. + * + * Rule is that the MP_UNREACH_NLRI should be the *only* thing in the UPDATE + * message. + */ + if (mp_eor) + { + if ((withdraw.length != 0) || (update.length != 0)) + mp_eor = false ; + } ; /* NLRI is processed only when the peer is configured specific Address Family and Subsequent Address Family. */ @@ -841,30 +934,20 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) bgp_nlri_parse (peer, NULL, &withdraw); if (update.length) - { - /* We check well-known attribute only for IPv4 unicast - update. */ - ret = bgp_attr_check (peer, &attr); - if (ret < 0) - { - bgp_attr_unintern_sub (&attr, true) ; /* true => free extra */ - return -1; - } - - bgp_nlri_parse (peer, NLRI_ATTR_ARG, &update); - } + bgp_nlri_parse (peer, NLRI_ATTR_ARG, &update); if (mp_update.length - && mp_update.afi == AFI_IP + && mp_update.afi == AFI_IP && mp_update.safi == SAFI_UNICAST) bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length - && mp_withdraw.afi == AFI_IP + && mp_withdraw.afi == AFI_IP && mp_withdraw.safi == SAFI_UNICAST) bgp_nlri_parse (peer, NULL, &mp_withdraw); - if (! attribute_len && ! withdraw_len) + if ((attribute_len == 0) && (withdraw.length == 0) + && (update.length == 0)) { /* End-of-RIB received */ SET_FLAG (peer->af_sflags[AFI_IP][SAFI_UNICAST], @@ -880,6 +963,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) peer->host); } } + if (peer->afc[AFI_IP][SAFI_MULTICAST]) { if (mp_update.length @@ -892,10 +976,9 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) && mp_withdraw.safi == SAFI_MULTICAST) bgp_nlri_parse (peer, NULL, &mp_withdraw); - if (! withdraw_len + if (mp_eor && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == SAFI_MULTICAST - && mp_withdraw.length == 0) + && mp_withdraw.safi == SAFI_MULTICAST) { /* End-of-RIB received */ SET_FLAG (peer->af_sflags[AFI_IP][SAFI_MULTICAST], @@ -914,19 +997,18 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) if (peer->afc[AFI_IP6][SAFI_UNICAST]) { if (mp_update.length - && mp_update.afi == AFI_IP6 + && mp_update.afi == AFI_IP6 && mp_update.safi == SAFI_UNICAST) bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length - && mp_withdraw.afi == AFI_IP6 + && mp_withdraw.afi == AFI_IP6 && mp_withdraw.safi == SAFI_UNICAST) bgp_nlri_parse (peer, NULL, &mp_withdraw); - if (! withdraw_len - && mp_withdraw.afi == AFI_IP6 - && mp_withdraw.safi == SAFI_UNICAST - && mp_withdraw.length == 0) + if (mp_eor + && mp_withdraw.afi == AFI_IP6 + && mp_withdraw.safi == SAFI_UNICAST) { /* End-of-RIB received */ SET_FLAG (peer->af_sflags[AFI_IP6][SAFI_UNICAST], @@ -954,10 +1036,9 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) && mp_withdraw.safi == SAFI_MULTICAST) bgp_nlri_parse (peer, NULL, &mp_withdraw); - if (! withdraw_len + if (mp_eor && mp_withdraw.afi == AFI_IP6 - && mp_withdraw.safi == SAFI_MULTICAST - && mp_withdraw.length == 0) + && mp_withdraw.safi == SAFI_MULTICAST) { /* End-of-RIB received */ @@ -975,18 +1056,17 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) { if (mp_update.length && mp_update.afi == AFI_IP - && mp_update.safi == BGP_SAFI_VPNV4) + && mp_update.safi == SAFI_MPLS_LABELED_VPN) bgp_nlri_parse_vpnv4 (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == BGP_SAFI_VPNV4) + && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN) bgp_nlri_parse_vpnv4 (peer, NULL, &mp_withdraw); - if (! withdraw_len + if (mp_eor && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == BGP_SAFI_VPNV4 - && mp_withdraw.length == 0) + && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN) { /* End-of-RIB received */ @@ -998,10 +1078,14 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) } /* Everything is done. We unintern temporary structures which - interned in bgp_attr_parse(). */ + * interned in bgp_attr_parse(). + */ + ret = 0 ; + + exit_bgp_update_receive: bgp_attr_unintern_sub (&attr, true) ; /* true => free extra */ - return 0; + return ret ; } /* Process incoming route refresh */ @@ -1018,7 +1102,7 @@ bgp_route_refresh_recv(bgp_peer peer, bgp_route_refresh rr) safi = rr->safi; /* Adjust safi code. */ - if (safi == BGP_SAFI_VPNV4) + if (safi == SAFI_MPLS_LABELED_VPN) safi = SAFI_MPLS_VPN; /* ORF prefix-list name */ diff --git a/bgpd/bgp_peer.c b/bgpd/bgp_peer.c index c4b37de5..2cb58c34 100644 --- a/bgpd/bgp_peer.c +++ b/bgpd/bgp_peer.c @@ -24,8 +24,8 @@ #include "bgpd/bgp_peer.h" -#include "bgpd/bgp_common.h" #include "bgpd/bgp_session.h" +#include "bgpd/bgp_connection.h" #include "bgpd/bgp_engine.h" #include "bgpd/bgp_peer_index.h" #include "bgpd/bgpd.h" @@ -330,7 +330,7 @@ bgp_session_has_established(bgp_session session) nsf_af_count = 0 ; for (afi = AFI_IP ; afi < AFI_MAX ; afi++) - for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++) + for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++) { /* If the afi/safi has been negotiated, and have received Graceful * Restart capability, and is Restarting, and will Gracefully Restart @@ -570,7 +570,7 @@ bgp_peer_clear_all_stale_routes (struct peer *peer) safi_t safi; for (afi = AFI_IP ; afi < AFI_MAX ; afi++) - for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++) + for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++) if (peer->nsf[afi][safi]) bgp_clear_stale_route (peer, afi, safi); @@ -1197,7 +1197,7 @@ bgp_peer_enable(bgp_peer peer) * * - PEER_DOWN_NEIGHBOR_DELETE * - * prevents the peer from restarting. + * causes PEER_DOWN_USER_SHUTDOWN prior to deleting the peer completely. * * If there is an active session, then it must be disabled, sending the given * notification, or one based on the reason for downing the peer. @@ -1223,7 +1223,7 @@ bgp_peer_enable(bgp_peer peer) * The peer will have automatically restarted, if possible. * * Noting that PEER_DOWN_USER_SHUTDOWN and PEER_DOWN_NEIGHBOR_DELETE both - * prevent any restart. + * prevent any restart -- by setting PEER_FLAG_SHUTDOWN. * * 2. bgp_peer_pEstablished * @@ -1264,8 +1264,17 @@ bgp_peer_down(bgp_peer peer, peer_down_t why_down) * * See bgp_peer_down() above. * - * If the notification is NULL and need to send a notification, make one up from - * the given reason for downing the peer. + * If the session is active and has not been downed already, then we now down + * it and with suitable notification. + * + * If the notification is NULL and need to send a notification, make one up + * from the given reason for downing the peer. + * + * NB: once the session has been sent one notification, all further + * notifications are ignored (and discarded, here). + * + * If the session is not in a state to receive a notification, we ignore + * this one (and discard it, here). * * NB: takes responsibility for the notification. */ @@ -1273,25 +1282,49 @@ static void bgp_peer_down_notify(bgp_peer peer, peer_down_t why_down, bgp_notify notification) { - /* Deal with session (if any). */ + /* Deal with session (if any) + */ + if (notification == NULL) + notification = bgp_peer_map_peer_down(why_down) ; - if (bgp_session_is_active(peer->session)) - { - if (notification == NULL) - notification = bgp_peer_map_peer_down(why_down) ; + if (bgp_session_disable(peer, notification)) + bgp_notify_set(&peer->session->notification, notification) ; + else + bgp_notify_free(notification) ; - bgp_notify_set(&peer->session->notification, notification) ; +#if 0 + /* This logging is (more or less) part of commit 1212dc1961... + * + * TODO worry how useful this is and whether is not already done elsewhere. + */ - bgp_session_disable(peer, bgp_notify_dup(notification)) ; - /* The copy of the notification will be discarded either by - * the BGP_Engine, if the notification is not sent, or when - * it is returned in the eDisabled message. - */ + /* Log some */ + switch (why_down) + { + case PEER_DOWN_USER_RESET: + zlog_info ("Notification sent to neighbor %s: User reset", peer->host); + break ; + + case PEER_DOWN_USER_SHUTDOWN: + zlog_info ("Notification sent to neighbor %s: shutdown", peer->host); + break ; + + case PEER_DOWN_NOTIFY_SEND: + zlog_info ("Notification sent to neighbor %s: type %u/%u", + peer->host, code, sub_code); + break ; + + default: + zlog_info ("Notification sent to neighbor %s: configuration change", + peer->host); + break ; } ; +#endif /* Now worry about the state of the peer */ - if (why_down == PEER_DOWN_USER_SHUTDOWN) + if ((why_down == PEER_DOWN_USER_SHUTDOWN) + || (why_down == PEER_DOWN_NEIGHBOR_DELETE)) bgp_peer_shutdown(peer) ; if (why_down != PEER_DOWN_NULL) @@ -1305,8 +1338,7 @@ bgp_peer_down_notify(bgp_peer peer, peer_down_t why_down, bgp_peer_nsf_stop (peer) ; /* flush stale routes, if any */ - if (why_down != PEER_DOWN_NEIGHBOR_DELETE) - bgp_peer_enable(peer) ; /* Restart if possible. */ + bgp_peer_enable(peer) ; /* Restart if possible. */ break ; @@ -1612,7 +1644,7 @@ bgp_peer_change_status (bgp_peer peer, bgp_peer_state_t new_state) peer->state = new_state ; if (BGP_DEBUG (normal, NORMAL)) - zlog_debug ("%s went from %s to %s", peer->host, + zlog_debug ("peer %s went from %s to %s", peer->host, map_direct(bgp_peer_status_map, peer->ostate).str, map_direct(bgp_peer_status_map, peer->state).str) ; diff --git a/bgpd/bgp_peer.h b/bgpd/bgp_peer.h index 89708661..39cb54a5 100644 --- a/bgpd/bgp_peer.h +++ b/bgpd/bgp_peer.h @@ -23,8 +23,9 @@ #define _QUAGGA_BGP_PEER_H #include "bgpd/bgp_common.h" -#include "bgpd/bgp_notification.h" +#include "bgpd/bgp_connection.h" #include "bgpd/bgp_peer_index.h" +#include "bgpd/bgp_notification.h" #include "lib/plist.h" diff --git a/bgpd/bgp_peer_index.c b/bgpd/bgp_peer_index.c index d423cd0a..07132fc2 100644 --- a/bgpd/bgp_peer_index.c +++ b/bgpd/bgp_peer_index.c @@ -22,10 +22,10 @@ #include "lib/zassert.h" -#include "bgpd/bgp_peer_index.h" +#include "bgpd/bgp_peer.h" #include "bgpd/bgp_peer.h" #include "bgpd/bgp_session.h" -#include "bgpd/bgp_connection.h" +#include "bgpd/bgp_peer_index.h" #include "lib/symtab.h" #include "lib/vector.h" @@ -339,6 +339,45 @@ bgp_peer_index_set_session(bgp_peer peer, bgp_session session) BGP_PEER_INDEX_UNLOCK() ; /*->->->->->->->->->->->->->->->->->->->->->->->->*/ } ; +#if 0 +/*------------------------------------------------------------------------------ + * Set the index entry bgp_connection_options, for the next time an accept() + * is required for the entry. + * + * This is done under the Peer Index Mutex, so that the BGP Engine can pick + * this up safely. + */ +extern void +bgp_peer_index_set_accept(bgp_peer peer) +{ + bgp_connection_options opts ; + + BGP_PEER_INDEX_LOCK() ; /*<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-*/ + + opts = peer->index_entry->opts ; + + /* For accept() we need: + * + * accept -- true <=> should accept connections. + * + * so is set false if the peer is TODO TODO TODO + * + * ttl_req -- TTL to set, if not zero + * gtsm_req -- ttl set by ttl-security + * + * password -- MD5 password to be set in the listener + */ + opts->connect = (peer->flags & PEER_FLAG_PASSIVE) == 0 ; + opts->listen = true ; + + opts->ttl_req = peer->ttl ; + opts->gtsm_req = peer->gtsm ; + + + + BGP_PEER_INDEX_UNLOCK() ; /*->->->->->->->->->->->->->->->->->->->->->->->->*/ +} ; +#endif /*------------------------------------------------------------------------------ * Find whether given address is for a known peer, and if so whether it has * an active session which is prepared to accept() a connection. diff --git a/bgpd/bgp_peer_index.h b/bgpd/bgp_peer_index.h index da183580..b730d46f 100644 --- a/bgpd/bgp_peer_index.h +++ b/bgpd/bgp_peer_index.h @@ -33,6 +33,14 @@ * * peer_id (ordinal of peer) * * To the bgp_peer_index_entry. + * + * The bgp_peer_index entry contains enough to allow connections to be accepted + * (or not) completely asynchronously with both the Routeing and the BGP + * Engines... so there need never be a time when a connection is not accepted, + * unless the peer is administratively disabled. + * + * When a BGP session is enabled, it will check to see if an accepted + * connection is pending, and adopt it if it is. */ typedef struct bgp_peer_index_entry* bgp_peer_index_entry ; @@ -43,11 +51,18 @@ struct bgp_peer_index_entry bgp_peer_index_entry next_free ; /* for list of free peer_id's */ /* points to self if entry is in use */ + bgp_peer_id_t id ; /* maps IP address to peer_id */ + bgp_peer peer ; /* NULL if entry is not in use */ sockunion_t su ; /* The "name". */ - bgp_peer_id_t id ; /* maps IP address to peer_id */ +//bgp_connection_options_t opts[1] ; /* for accept() */ +// +//int sock ; /* if accepted */ +//bgp_connection_options_t opts_set[1] ; /* if accepted */ + +//qtimer discard ; /* in case not used, promptly */ } ; enum { bgp_peer_id_null = 0 } ; /* no peer can have id == 0 */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 333960e1..08a10664 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1434,11 +1434,9 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, char buf[SU_ADDRSTRLEN]; struct bgp_filter *filter; struct peer *from; - struct bgp *bgp; from = ri->peer; filter = &rsclient->filter[afi][safi]; - bgp = rsclient->bgp; if (DISABLE_BGP_ANNOUNCE) return 0; @@ -1920,7 +1918,7 @@ bgp_process_main (struct work_queue *wq, work_queue_item item) if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED)) { if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED)) - bgp_zebra_announce (p, old_select, bgp); + bgp_zebra_announce (p, old_select, bgp, safi); goto finish ; /* was return ! */ } @@ -1942,18 +1940,18 @@ bgp_process_main (struct work_queue *wq, work_queue_item item) } /* FIB update. */ - if ((safi == SAFI_UNICAST) && (bgp->name == NULL) && - ! bgp_option_check (BGP_OPT_NO_FIB)) + if ( ((safi == SAFI_UNICAST) || (safi == SAFI_MULTICAST)) + && (bgp->name == NULL) && ! bgp_option_check (BGP_OPT_NO_FIB)) { - if (new_select && (new_select->type == ZEBRA_ROUTE_BGP) + if (new_select && (new_select->type == ZEBRA_ROUTE_BGP) && (new_select->sub_type == BGP_ROUTE_NORMAL)) - bgp_zebra_announce (p, new_select, bgp); + bgp_zebra_announce (p, new_select, bgp, safi); else { /* Withdraw the route from the kernel. */ - if (old_select && (old_select->type == ZEBRA_ROUTE_BGP) + if (old_select && (old_select->type == ZEBRA_ROUTE_BGP) && (old_select->sub_type == BGP_ROUTE_NORMAL)) - bgp_zebra_withdraw (p, old_select); + bgp_zebra_withdraw (p, old_select, safi); } } @@ -2189,7 +2187,7 @@ bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi, u_int8_t ndata[7]; if (safi == SAFI_MPLS_VPN) - safi = BGP_SAFI_VPNV4; + safi = SAFI_MPLS_LABELED_VPN; ndata[0] = (afi >> 8); ndata[1] = afi; @@ -2366,11 +2364,12 @@ bgp_update_rsclient (struct peer *rsclient, struct rs_route* rt) } /* IPv4 unicast next hop check. */ - if (rt->afi == AFI_IP && rt->safi == SAFI_UNICAST) + if ( (rt->afi == AFI_IP) && + ((rt->safi == SAFI_UNICAST) || (rt->safi == SAFI_MULTICAST)) ) { /* Next hop must not be 0.0.0.0 nor Class E address. */ - if (client_attr->nexthop.s_addr == 0 - || ntohl (client_attr->nexthop.s_addr) >= 0xe0000000) + if ((client_attr->nexthop.s_addr == 0) + || IPV4_CLASS_DE(ntohl(client_attr->nexthop.s_addr))) { reason = "martian next-hop;"; goto filtered; @@ -2611,18 +2610,18 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* If the peer is EBGP and nexthop is not on connected route, discard it. */ if ((sort == BGP_PEER_EBGP) && (peer->ttl == 1) - && ! bgp_nexthop_check_ebgp (afi, use_attr) + && ! bgp_nexthop_onlink (afi, use_attr) && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) { reason = "non-connected next-hop;"; goto filtered; } - /* Next hop must not be 0.0.0.0 nor Class E address. Next hop + /* Next hop must not be 0.0.0.0 nor Class D/E address. Next hop must not be my own address. */ if (bgp_nexthop_self (afi, use_attr) || (use_attr->nexthop.s_addr == 0) - || (ntohl (use_attr->nexthop.s_addr) >= 0xe0000000)) + || IPV4_CLASS_DE(ntohl(use_attr->nexthop.s_addr))) { reason = "martian next-hop;"; goto filtered; @@ -3723,7 +3722,7 @@ bgp_cleanup_routes (void) if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->type == ZEBRA_ROUTE_BGP && ri->sub_type == BGP_ROUTE_NORMAL) - bgp_zebra_withdraw (&rn->p, ri); + bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST); table = bgp->rib[AFI_IP6][SAFI_UNICAST]; @@ -3732,7 +3731,7 @@ bgp_cleanup_routes (void) if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->type == ZEBRA_ROUTE_BGP && ri->sub_type == BGP_ROUTE_NORMAL) - bgp_zebra_withdraw (&rn->p, ri); + bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST); } } #endif @@ -3855,62 +3854,68 @@ bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) /* NLRI encode syntax check routine. */ int bgp_nlri_sanity_check (struct peer *peer, int afi, u_char *pnt, - bgp_size_t length) + bgp_size_t length) { - u_char *end; - u_char prefixlen; - int psize; + size_t offset ; + u_char prefixlen_max ; + + switch (afi) + { + case AFI_IP: + prefixlen_max = 32 ; + break ; + + case AFI_IP6: + prefixlen_max = 128 ; + break ; - end = pnt + length; + default: + prefixlen_max = 255 ; /* it's a byte, guys */ + break ; + } ; /* RFC1771 6.3 The NLRI field in the UPDATE message is checked for syntactic validity. If the field is syntactically incorrect, then the Error Subcode is set to Invalid Network Field. */ - while (pnt < end) + offset = 0 ; + while (offset < length) { - prefixlen = *pnt++; - - /* Prefix length check. */ - if ((afi == AFI_IP && prefixlen > 32) - || (afi == AFI_IP6 && prefixlen > 128)) - { - plog_err (peer->log, - "%s [Error] Update packet error (wrong prefix length %d)", - peer->host, prefixlen); - bgp_peer_down_error(peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_INVAL_NETWORK); - return -1; - } + u_char prefixlen; - /* Packet size overflow check. */ - psize = PSIZE (prefixlen); + prefixlen = pnt[offset] ; - if (pnt + psize > end) + /* Prefix length check. + */ + if (prefixlen > prefixlen_max) { plog_err (peer->log, - "%s [Error] Update packet error" - " (prefix data overflow prefix size is %d)", - peer->host, psize); + "%s [Error] Update packet error: prefix length %u > %u " + "for %s NLRI", + peer->host, prefixlen, prefixlen_max, + map_direct(bgp_afi_name_map, afi).str) ; bgp_peer_down_error(peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_INVAL_NETWORK); + BGP_NOTIFY_UPDATE_INVAL_NETWORK); return -1; } - pnt += psize; - } + /* Step and check remains within total length. + */ + offset += PSIZE(prefixlen) + 1 ; + + if (offset > length) + { + plog_err (peer->log, + "%s [Error] Update packet error: prefix length %u overruns" + " total size of %s NLRI", + peer->host, prefixlen, + map_direct(bgp_afi_name_map, afi).str); + bgp_peer_down_error(peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_INVAL_NETWORK); + return -1; + } + } ; - /* Packet length consistency check. */ - if (pnt != end) - { - plog_err (peer->log, - "%s [Error] Update packet error" - " (prefix length mismatch with total length)", - peer->host); - bgp_peer_down_error(peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_INVAL_NETWORK); - return -1; - } return 0; } @@ -4978,7 +4983,7 @@ DEFUN (ipv6_bgp_network, "Specify a network to announce via BGP\n" "IPv6 prefix <network>/<length>\n") { - return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST, + return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, bgp_node_safi(vty), NULL, 0); } @@ -5001,7 +5006,7 @@ DEFUN (no_ipv6_bgp_network, "Specify a network to announce via BGP\n" "IPv6 prefix <network>/<length>\n") { - return bgp_static_unset (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST); + return bgp_static_unset (vty, vty->index, argv[0], AFI_IP6, bgp_node_safi(vty)); } ALIAS (no_ipv6_bgp_network, @@ -6066,7 +6071,8 @@ ALIAS (no_ipv6_aggregate_address_summary_only, /* Redistribute route treatment. */ void -bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop, +bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop, + const struct in6_addr *nexthop6, u_int32_t metric, u_char type) { struct bgp *bgp; @@ -6084,6 +6090,15 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop, if (nexthop) attr.nexthop = *nexthop; +#ifdef HAVE_IPV6 + if (nexthop6) + { + struct attr_extra *extra = bgp_attr_extra_get(&attr); + extra->mp_nexthop_global = *nexthop6; + extra->mp_nexthop_len = 16; + } +#endif + attr.med = metric; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); @@ -10291,10 +10306,8 @@ bgp_table_stats_vty (struct vty *vty, const char *name, safi = SAFI_MULTICAST; else if (strncmp (safi_str, "u", 1) == 0) safi = SAFI_UNICAST; - else if (strncmp (safi_str, "vpnv4", 5) == 0) - safi = BGP_SAFI_VPNV4; - else if (strncmp (safi_str, "vpnv6", 6) == 0) - safi = BGP_SAFI_VPNV6; + else if (strncmp (safi_str, "vpnv4", 5) == 0 || strncmp (safi_str, "vpnv6", 5) == 0) + safi = SAFI_MPLS_LABELED_VPN; else { vty_out (vty, "%% Invalid subsequent address family %s%s", @@ -10309,13 +10322,6 @@ bgp_table_stats_vty (struct vty *vty, const char *name, return CMD_WARNING; } - if ((afi == AFI_IP && safi == BGP_SAFI_VPNV6) - || (afi == AFI_IP6 && safi == BGP_SAFI_VPNV4)) - { - vty_out (vty, "%% Invalid subsequent address family %s for %s%s", - afi_str, safi_str, VTY_NEWLINE); - return CMD_WARNING; - } return bgp_table_stats (vty, bgp, afi, safi); } @@ -13497,6 +13503,9 @@ CMD_INSTALL_TABLE(static, bgp_route_cmd_table, BGPD) = { BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd }, { BGP_IPV6_NODE, &no_ipv6_aggregate_address_summary_only_cmd }, + { BGP_IPV6M_NODE, &ipv6_bgp_network_cmd }, + { BGP_IPV6M_NODE, &no_ipv6_bgp_network_cmd }, + /* Old config IPv6 BGP commands. */ { BGP_NODE, &old_ipv6_bgp_network_cmd }, { BGP_NODE, &old_no_ipv6_bgp_network_cmd }, diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 29b9c05a..07fa350b 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -205,8 +205,9 @@ extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *); extern int bgp_maximum_prefix_overflow (struct peer *, afi_t, safi_t, int); extern void bgp_maximum_prefix_cancel_timer (struct peer *peer) ; -extern void bgp_redistribute_add (struct prefix *, struct in_addr *, u_int32_t, - u_char); +extern void bgp_redistribute_add (struct prefix *, const struct in_addr *, + const struct in6_addr *, + u_int32_t, u_char); extern void bgp_redistribute_delete (struct prefix *, u_char); extern void bgp_redistribute_withdraw (struct bgp *, afi_t, int); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 80af8a0f..c10cfc67 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -41,6 +41,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "sockunion.h" #include "bgpd/bgpd.h" +#include "bgpd/bgp_peer.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_aspath.h" @@ -525,7 +526,11 @@ route_match_metric_compile (const char *arg) char *endptr = NULL; unsigned long tmp; - errno = 0 ; + /* Metric value shoud be integer. */ + if (! all_digit (arg)) + return NULL; + + errno = 0; tmp = strtoul (arg, &endptr, 10); if ((*endptr != '\0') || (errno != 0) || (tmp > UINT32_MAX)) return NULL; @@ -847,6 +852,75 @@ struct route_map_rule_cmd route_match_origin_cmd = route_match_origin_compile, route_match_origin_free }; + +/* match probability { */ + +static route_map_result_t +route_match_probability (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + long r; +#if _SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500 + r = random(); +#else + r = (long) rand(); +#endif + + switch (*(unsigned *) rule) + { + case 0: break; + case RAND_MAX: return RMAP_MATCH; + default: + if (r < *(unsigned *) rule) + { + return RMAP_MATCH; + } + } + + return RMAP_NOMATCH; +} + +static void * +route_match_probability_compile (const char *arg) +{ + unsigned *lobule; + unsigned perc; + +#if _SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500 + srandom (time (NULL)); +#else + srand (time (NULL)); +#endif + + perc = atoi (arg); + lobule = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (unsigned)); + + switch (perc) + { + case 0: *lobule = 0; break; + case 100: *lobule = RAND_MAX; break; + default: *lobule = RAND_MAX / 100 * perc; + } + + return lobule; +} + +static void +route_match_probability_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_probability_cmd = +{ + "probability", + route_match_probability, + route_match_probability_compile, + route_match_probability_free +}; + +/* } */ + /* `set ip next-hop IP_ADDRESS' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ @@ -1003,6 +1077,7 @@ route_set_local_pref_compile (const char *arg) errno = 0 ; tmp = strtoul (arg, &endptr, 10); if ((*endptr != '\0') || (errno != 0) || (tmp > UINT32_MAX)) + return NULL; local_pref = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); @@ -2556,6 +2631,38 @@ ALIAS (no_match_ip_next_hop, "IP access-list number (expanded range)\n" "IP Access-list name\n") +/* match probability { */ + +DEFUN (match_probability, + match_probability_cmd, + "match probability <0-100>", + MATCH_STR + "Match portion of routes defined by percentage value\n" + "Percentage of routes\n") +{ + return bgp_route_match_add (vty, vty->index, "probability", argv[0]); +} + +DEFUN (no_match_probability, + no_match_probability_cmd, + "no match probability", + NO_STR + MATCH_STR + "Match portion of routes defined by percentage value\n") +{ + return bgp_route_match_delete (vty, vty->index, "probability", argc ? argv[0] : NULL); +} + +ALIAS (no_match_probability, + no_match_probability_val_cmd, + "no match probability <1-99>", + NO_STR + MATCH_STR + "Match portion of routes defined by percentage value\n" + "Percentage of routes\n") + +/* } */ + DEFUN (match_ip_route_source, match_ip_route_source_cmd, "match ip route-source (<1-199>|<1300-2699>|WORD)", @@ -3907,6 +4014,10 @@ CMD_INSTALL_TABLE(static, bgp_routemap_cmd_table, BGPD) = { RMAP_NODE, &match_origin_cmd }, { RMAP_NODE, &no_match_origin_cmd }, { RMAP_NODE, &no_match_origin_val_cmd }, + { RMAP_NODE, &match_probability_cmd }, + { RMAP_NODE, &no_match_probability_cmd }, + { RMAP_NODE, &no_match_probability_val_cmd }, + { RMAP_NODE, &set_ip_nexthop_cmd }, { RMAP_NODE, &set_ip_nexthop_peer_cmd }, { RMAP_NODE, &no_set_ip_nexthop_cmd }, @@ -4003,6 +4114,7 @@ bgp_route_map_cmd_init (void) route_map_install_match (&route_match_ecommunity_cmd); route_map_install_match (&route_match_metric_cmd); route_map_install_match (&route_match_origin_cmd); + route_map_install_match (&route_match_probability_cmd); route_map_install_set (&route_set_ip_nexthop_cmd); route_map_install_set (&route_set_local_pref_cmd); @@ -4020,11 +4132,13 @@ bgp_route_map_cmd_init (void) route_map_install_set (&route_set_ecommunity_rt_cmd); route_map_install_set (&route_set_ecommunity_soo_cmd); +#ifdef HAVE_IPV6 route_map_install_match (&route_match_ipv6_address_cmd); route_map_install_match (&route_match_ipv6_next_hop_cmd); route_map_install_match (&route_match_ipv6_address_prefix_list_cmd); route_map_install_set (&route_set_ipv6_nexthop_global_cmd); route_map_install_set (&route_set_ipv6_nexthop_local_cmd); +#endif /* HAVE_IPV6 */ cmd_install_table(bgp_routemap_cmd_table) ; } diff --git a/bgpd/bgp_session.c b/bgpd/bgp_session.c index 9fd67679..41d1adaa 100644 --- a/bgpd/bgp_session.c +++ b/bgpd/bgp_session.c @@ -21,13 +21,10 @@ #include "misc.h" #include "bgpd/bgp_session.h" -#include "bgpd/bgp_common.h" #include "bgpd/bgp_peer.h" #include "bgpd/bgp_engine.h" -#include "bgpd/bgp_peer_index.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_open_state.h" -#include "bgpd/bgp_route_refresh.h" #include "bgpd/bgp_msg_write.h" #include "bgpd/bgp_network.h" @@ -82,7 +79,7 @@ static void bgp_session_do_route_refresh_recv(mqueue_block mqb, mqb_flag_t flag) * change any shared item in the session, except under the mutex. And * even then it may make no sense ! * - * NB: a session reaches eDisabled when the Routing Engine has sent a disable + * NB: a session reaches sDisabled when the Routing Engine has sent a disable * request to the BGP Engine, AND an eDisabled event has come back. * * While the Routing Engine is waiting for the eDisabled event, the session @@ -425,9 +422,10 @@ bgp_session_do_enable(mqueue_block mqb, mqb_flag_t flag) } ; /*============================================================================== - * Routing Engine: disable session for given peer -- if enabled (!). + * Routing Engine: disable session for given peer -- if and and if enabled (!). * - * Does nothing if the session is not sEnabled or sEstablished. + * If there is a session and it is sEnabled or sEstablished, send a copy of the + * given notification to the BGP Engine, and set the session sLimping. * * Passes any bgp_notify to the BGP Engine, which will dispose of it in due * course. @@ -438,10 +436,12 @@ bgp_session_do_enable(mqueue_block mqb, mqb_flag_t flag) * some event in the BGP Engine. In any case, the BGP Engine will respond with * an eDisabled. * - * NB: is taking responsibility for the notification, which is either freed - * here or passed to the BGP Engine. + * Returns: true <=> have sent (copy of) notification to BGP_ENGINE + * false => for whatever reason, the session cannot be disabled + * + * NB: caller is responsible for the original notification, if any */ -extern void +extern bool bgp_session_disable(bgp_peer peer, bgp_notify notification) { bgp_session session ; @@ -449,17 +449,18 @@ bgp_session_disable(bgp_peer peer, bgp_notify notification) struct bgp_session_disable_args* args ; session = peer->session ; - assert((session != NULL) && (session->peer == peer)) ; /* Do nothing if session is not active, or is already limping. */ - if ( (session->state != bgp_session_sEnabled) && - (session->state != bgp_session_sEstablished) ) + if (session == NULL || + ( (session->state != bgp_session_sEnabled) && + (session->state != bgp_session_sEstablished) )) { - bgp_notify_free(notification) ; /* discard any bgp_notify */ - return ; + return false ; } ; + assert(session->peer == peer) ; + /* Can revoke whatever may be queued already. Will revoke again when the * disable is acknowledged to finally clear the session out of the queue. */ @@ -498,11 +499,15 @@ bgp_session_disable(bgp_peer peer, bgp_notify notification) mqb = mqb_init_new(NULL, bgp_session_do_disable, session) ; args = mqb_get_args(mqb) ; - args->notification = notification ; + args->notification = bgp_notify_dup(notification) ; ++bgp_engine_queue_stats.event ; bgp_to_bgp_engine(mqb, mqb_priority) ; + + /* We have just disabled the session, sending (a copy of) any notification. + */ + return true ; } ; /*------------------------------------------------------------------------------ diff --git a/bgpd/bgp_session.h b/bgpd/bgp_session.h index 1f0f0469..b93a24fd 100644 --- a/bgpd/bgp_session.h +++ b/bgpd/bgp_session.h @@ -109,7 +109,7 @@ struct bgp_session * * Only the Routing Engine creates and destroys sessions. The BGP Engine * assumes that a session will not be destroyed while it is sEnabled, - * sEstablished or sStopping. + * sEstablished or sLimping. * * These are private to the Routing Engine. */ @@ -320,7 +320,7 @@ inline static void BGP_SESSION_UNLOCK(bgp_session session) */ extern bgp_session bgp_session_init_new(bgp_peer peer) ; extern void bgp_session_enable(bgp_peer peer) ; -extern void bgp_session_disable(bgp_peer peer, bgp_notify notification) ; +extern bool bgp_session_disable(bgp_peer peer, bgp_notify notification) ; extern void bgp_session_delete(bgp_peer peer); extern void bgp_session_event(bgp_session session, bgp_session_event_t event, bgp_notify notification, diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index 5d1ebf3d..029de900 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -26,6 +26,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "vty.h" #include "bgpd/bgpd.h" +#include "bgpd/bgp_peer.h" #include "bgpd/bgp_table.h" static void bgp_node_delete (struct bgp_node *); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index c7c55425..0ef710c5 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -3778,7 +3778,7 @@ peer_maximum_prefix_set_vty (struct vty *vty, const char *ip_str, afi_t afi, if (! peer) return CMD_WARNING; - VTY_GET_INTEGER ("maxmum number", max, num_str); + VTY_GET_INTEGER ("maximum number", max, num_str); if (threshold_str) threshold = atoi (threshold_str); else @@ -4317,17 +4317,9 @@ bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, if (sort == clear_as) { as_t as; - unsigned long as_ul; int find = 0; - VTY_GET_LONG ("AS", as_ul, arg); - - if (!as_ul) - { - vty_out (vty, "Invalid AS number%s", VTY_NEWLINE); - return CMD_WARNING; - } - as = (as_t) as_ul; + VTY_GET_INTEGER_RANGE ("AS", as, arg, 1, BGP_AS4_MAX); for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { @@ -8520,57 +8512,16 @@ ALIAS (show_bgp_instance_ipv6_safi_rsclient_summary, /* Redistribute VTY commands. */ -/* Utility function to convert user input route type string to route - type. */ -static int -bgp_str2route_type (int afi, const char *str) -{ - if (! str) - return 0; - - if (afi == AFI_IP) - { - if (strncmp (str, "k", 1) == 0) - return ZEBRA_ROUTE_KERNEL; - else if (strncmp (str, "c", 1) == 0) - return ZEBRA_ROUTE_CONNECT; - else if (strncmp (str, "s", 1) == 0) - return ZEBRA_ROUTE_STATIC; - else if (strncmp (str, "r", 1) == 0) - return ZEBRA_ROUTE_RIP; - else if (strncmp (str, "o", 1) == 0) - return ZEBRA_ROUTE_OSPF; - } - if (afi == AFI_IP6) - { - if (strncmp (str, "k", 1) == 0) - return ZEBRA_ROUTE_KERNEL; - else if (strncmp (str, "c", 1) == 0) - return ZEBRA_ROUTE_CONNECT; - else if (strncmp (str, "s", 1) == 0) - return ZEBRA_ROUTE_STATIC; - else if (strncmp (str, "r", 1) == 0) - return ZEBRA_ROUTE_RIPNG; - else if (strncmp (str, "o", 1) == 0) - return ZEBRA_ROUTE_OSPF6; - } - return 0; -} - DEFUN (bgp_redistribute_ipv4, bgp_redistribute_ipv4_cmd, - "redistribute (connected|kernel|ospf|rip|static)", + "redistribute " QUAGGA_IP_REDIST_STR_BGPD, "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n") + QUAGGA_IP_REDIST_HELP_STR_BGPD) { int type; - type = bgp_str2route_type (AFI_IP, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8580,20 +8531,16 @@ DEFUN (bgp_redistribute_ipv4, DEFUN (bgp_redistribute_ipv4_rmap, bgp_redistribute_ipv4_rmap_cmd, - "redistribute (connected|kernel|ospf|rip|static) route-map WORD", + "redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD", "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n" + QUAGGA_IP_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") { int type; - type = bgp_str2route_type (AFI_IP, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8605,21 +8552,17 @@ DEFUN (bgp_redistribute_ipv4_rmap, DEFUN (bgp_redistribute_ipv4_metric, bgp_redistribute_ipv4_metric_cmd, - "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>", + "redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295>", "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n" + QUAGGA_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") { int type; u_int32_t metric; - type = bgp_str2route_type (AFI_IP, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8632,13 +8575,9 @@ DEFUN (bgp_redistribute_ipv4_metric, DEFUN (bgp_redistribute_ipv4_rmap_metric, bgp_redistribute_ipv4_rmap_metric_cmd, - "redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>", + "redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n" + QUAGGA_IP_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" @@ -8647,8 +8586,8 @@ DEFUN (bgp_redistribute_ipv4_rmap_metric, int type; u_int32_t metric; - type = bgp_str2route_type (AFI_IP, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8662,13 +8601,9 @@ DEFUN (bgp_redistribute_ipv4_rmap_metric, DEFUN (bgp_redistribute_ipv4_metric_rmap, bgp_redistribute_ipv4_metric_rmap_cmd, - "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD", + "redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n" + QUAGGA_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" @@ -8677,8 +8612,8 @@ DEFUN (bgp_redistribute_ipv4_metric_rmap, int type; u_int32_t metric; - type = bgp_str2route_type (AFI_IP, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8692,19 +8627,15 @@ DEFUN (bgp_redistribute_ipv4_metric_rmap, DEFUN (no_bgp_redistribute_ipv4, no_bgp_redistribute_ipv4_cmd, - "no redistribute (connected|kernel|ospf|rip|static)", + "no redistribute " QUAGGA_IP_REDIST_STR_BGPD, NO_STR "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n") + QUAGGA_IP_REDIST_HELP_STR_BGPD) { int type; - type = bgp_str2route_type (AFI_IP, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8715,21 +8646,17 @@ DEFUN (no_bgp_redistribute_ipv4, DEFUN (no_bgp_redistribute_ipv4_rmap, no_bgp_redistribute_ipv4_rmap_cmd, - "no redistribute (connected|kernel|ospf|rip|static) route-map WORD", + "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD", NO_STR "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n" + QUAGGA_IP_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") { int type; - type = bgp_str2route_type (AFI_IP, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8741,21 +8668,17 @@ DEFUN (no_bgp_redistribute_ipv4_rmap, DEFUN (no_bgp_redistribute_ipv4_metric, no_bgp_redistribute_ipv4_metric_cmd, - "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>", + "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n" + QUAGGA_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") { int type; - type = bgp_str2route_type (AFI_IP, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8767,14 +8690,10 @@ DEFUN (no_bgp_redistribute_ipv4_metric, DEFUN (no_bgp_redistribute_ipv4_rmap_metric, no_bgp_redistribute_ipv4_rmap_metric_cmd, - "no redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>", + "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n" + QUAGGA_IP_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" @@ -8782,8 +8701,8 @@ DEFUN (no_bgp_redistribute_ipv4_rmap_metric, { int type; - type = bgp_str2route_type (AFI_IP, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8796,14 +8715,10 @@ DEFUN (no_bgp_redistribute_ipv4_rmap_metric, ALIAS (no_bgp_redistribute_ipv4_rmap_metric, no_bgp_redistribute_ipv4_metric_rmap_cmd, - "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD", + "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", NO_STR "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n" + QUAGGA_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" @@ -8812,18 +8727,14 @@ ALIAS (no_bgp_redistribute_ipv4_rmap_metric, #ifdef HAVE_IPV6 DEFUN (bgp_redistribute_ipv6, bgp_redistribute_ipv6_cmd, - "redistribute (connected|kernel|ospf6|ripng|static)", + "redistribute " QUAGGA_IP6_REDIST_STR_BGPD, "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n") + QUAGGA_IP6_REDIST_HELP_STR_BGPD) { int type; - type = bgp_str2route_type (AFI_IP6, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8834,20 +8745,16 @@ DEFUN (bgp_redistribute_ipv6, DEFUN (bgp_redistribute_ipv6_rmap, bgp_redistribute_ipv6_rmap_cmd, - "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD", + "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD", "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n" + QUAGGA_IP6_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") { int type; - type = bgp_str2route_type (AFI_IP6, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8859,21 +8766,17 @@ DEFUN (bgp_redistribute_ipv6_rmap, DEFUN (bgp_redistribute_ipv6_metric, bgp_redistribute_ipv6_metric_cmd, - "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>", + "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295>", "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n" + QUAGGA_IP6_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") { int type; u_int32_t metric; - type = bgp_str2route_type (AFI_IP6, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8886,13 +8789,9 @@ DEFUN (bgp_redistribute_ipv6_metric, DEFUN (bgp_redistribute_ipv6_rmap_metric, bgp_redistribute_ipv6_rmap_metric_cmd, - "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>", + "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n" + QUAGGA_IP6_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" @@ -8901,8 +8800,8 @@ DEFUN (bgp_redistribute_ipv6_rmap_metric, int type; u_int32_t metric; - type = bgp_str2route_type (AFI_IP6, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8916,13 +8815,9 @@ DEFUN (bgp_redistribute_ipv6_rmap_metric, DEFUN (bgp_redistribute_ipv6_metric_rmap, bgp_redistribute_ipv6_metric_rmap_cmd, - "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD", + "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n" + QUAGGA_IP6_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" @@ -8931,8 +8826,8 @@ DEFUN (bgp_redistribute_ipv6_metric_rmap, int type; u_int32_t metric; - type = bgp_str2route_type (AFI_IP6, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8946,19 +8841,15 @@ DEFUN (bgp_redistribute_ipv6_metric_rmap, DEFUN (no_bgp_redistribute_ipv6, no_bgp_redistribute_ipv6_cmd, - "no redistribute (connected|kernel|ospf6|ripng|static)", + "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD, NO_STR "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n") + QUAGGA_IP6_REDIST_HELP_STR_BGPD) { int type; - type = bgp_str2route_type (AFI_IP6, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8969,21 +8860,17 @@ DEFUN (no_bgp_redistribute_ipv6, DEFUN (no_bgp_redistribute_ipv6_rmap, no_bgp_redistribute_ipv6_rmap_cmd, - "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD", + "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD", NO_STR "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n" + QUAGGA_IP6_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") { int type; - type = bgp_str2route_type (AFI_IP6, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -8995,21 +8882,17 @@ DEFUN (no_bgp_redistribute_ipv6_rmap, DEFUN (no_bgp_redistribute_ipv6_metric, no_bgp_redistribute_ipv6_metric_cmd, - "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>", + "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n" + QUAGGA_IP6_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") { int type; - type = bgp_str2route_type (AFI_IP6, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -9021,14 +8904,10 @@ DEFUN (no_bgp_redistribute_ipv6_metric, DEFUN (no_bgp_redistribute_ipv6_rmap_metric, no_bgp_redistribute_ipv6_rmap_metric_cmd, - "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>", + "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n" + QUAGGA_IP6_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" @@ -9036,8 +8915,8 @@ DEFUN (no_bgp_redistribute_ipv6_rmap_metric, { int type; - type = bgp_str2route_type (AFI_IP6, argv[0]); - if (! type) + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -9050,14 +8929,10 @@ DEFUN (no_bgp_redistribute_ipv6_rmap_metric, ALIAS (no_bgp_redistribute_ipv6_rmap_metric, no_bgp_redistribute_ipv6_metric_rmap_cmd, - "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD", + "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", NO_STR "Redistribute information from another routing protocol\n" - "Connected\n" - "Kernel routes\n" - "Open Shurtest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n" + QUAGGA_IP6_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index fd7cd39e..2062b1eb 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -233,12 +233,10 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv4 api; - unsigned long ifindex; struct in_addr nexthop; struct prefix_ipv4 p; s = zclient->ibuf; - ifindex = 0; nexthop.s_addr = 0; /* Type, flags, message. */ @@ -261,7 +259,7 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); - ifindex = stream_getl (s); + stream_getl (s); /* ifindex, unused */ } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); @@ -282,7 +280,8 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), api.metric); } - bgp_redistribute_add((struct prefix *)&p, &nexthop, api.metric, api.type); + bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL, + api.metric, api.type); } else { @@ -310,12 +309,10 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv6 api; - unsigned long ifindex; struct in6_addr nexthop; struct prefix_ipv6 p; s = zclient->ibuf; - ifindex = 0; memset (&nexthop, 0, sizeof (struct in6_addr)); /* Type, flags, message. */ @@ -338,7 +335,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); - ifindex = stream_getl (s); + stream_getl (s); /* ifindex, unused */ } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); @@ -357,23 +354,29 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) { if (BGP_DEBUG(zebra, ZEBRA)) { - char buf[INET6_ADDRSTRLEN]; - zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d metric %u", + char buf[2][INET6_ADDRSTRLEN]; + zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d nexthop %s metric %u", zebra_route_string(api.type), - inet_ntop(AF_INET6, &p.prefix, buf, sizeof(buf)), - p.prefixlen, api.metric); + inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])), + p.prefixlen, + inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), + api.metric); } - bgp_redistribute_add ((struct prefix *)&p, NULL, api.metric, api.type); + bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop, + api.metric, api.type); } else { if (BGP_DEBUG(zebra, ZEBRA)) { - char buf[INET6_ADDRSTRLEN]; - zlog_debug("Zebra rcvd: IPv6 route delete %s %s/%d metric %u", + char buf[2][INET6_ADDRSTRLEN]; + zlog_debug("Zebra rcvd: IPv6 route delete %s %s/%d " + "nexthop %s metric %u", zebra_route_string(api.type), - inet_ntop(AF_INET6, &p.prefix, buf, sizeof(buf)), - p.prefixlen, api.metric); + inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])), + p.prefixlen, + inet_ntop(AF_INET6, &nexthop, buf[1], sizeof(buf[1])), + api.metric); } bgp_redistribute_delete ((struct prefix *) &p, api.type); } @@ -641,7 +644,8 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote, } void -bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp) +bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, + safi_t safi) { int flags; u_char distance; @@ -678,6 +682,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp) api.type = ZEBRA_ROUTE_BGP; api.message = 0; + api.safi = safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; @@ -752,6 +757,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp) api.flags = flags; api.type = ZEBRA_ROUTE_BGP; api.message = 0; + api.safi = safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; @@ -778,7 +784,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp) } void -bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info) +bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) { int flags; struct peer *peer; @@ -814,6 +820,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info) api.type = ZEBRA_ROUTE_BGP; api.message = 0; + api.safi = safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; @@ -869,6 +876,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info) api.flags = flags; api.type = ZEBRA_ROUTE_BGP; api.message = 0; + api.safi = safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index bd953864..532424e4 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -23,10 +23,11 @@ Boston, MA 02111-1307, USA. */ extern void bgp_zebra_init (void); extern int bgp_if_update_all (void); -extern int bgp_config_write_redistribute (struct vty *, struct bgp *, afi_t, safi_t, - int *); -extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *); -extern void bgp_zebra_withdraw (struct prefix *, struct bgp_info *); +extern int bgp_config_write_redistribute (struct vty *, struct bgp *, afi_t, + safi_t, int *); +extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, + struct bgp *, safi_t); +extern void bgp_zebra_withdraw (struct prefix *, struct bgp_info *, safi_t); extern int bgp_redistribute_set (struct bgp *, afi_t, int); extern int bgp_redistribute_rmap_set (struct bgp *, afi_t, int, const char *); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 2af8b78d..76092ec3 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -4218,7 +4218,6 @@ static void bgp_config_write_peer (struct vty *vty, struct bgp *bgp, struct peer *peer, afi_t afi, safi_t safi) { - struct bgp_filter *filter; struct peer *g_conf ; bool pgm, agm ; char *addr; @@ -4232,8 +4231,7 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp, g_conf = NULL ; pgm = (g_conf != NULL) ; /* group member for >= 1 address families */ - filter = &peer->filter[afi][safi]; - agm = (peer->af_group[afi][safi] != 0) ; + agm = (peer->af_group[afi][safi] != 0) ; if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) { @@ -4506,6 +4504,11 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp, 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); + /* Nexthop-local unchanged. */ + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) + && ! peer->af_group[afi][safi]) + vty_out (vty, " neighbor %s nexthop-local unchanged%s", addr, VTY_NEWLINE); + /* Allow AS in. */ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_ALLOWAS_IN)) if (!pgm diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index db60ea95..957293ac 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -27,7 +27,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_common.h" #include "bgpd/bgp_notification.h" -#include "bgpd/bgp_peer.h" #include "plist.h" #include "qtime.h" @@ -323,9 +322,8 @@ struct bgp_nlri #define BGP_DEFAULT_RESTART_TIME 120 #define BGP_DEFAULT_STALEPATH_TIME 360 -/* SAFI which used in open capability negotiation. */ -#define BGP_SAFI_VPNV4 128 -#define BGP_SAFI_VPNV6 129 +/* RFC4364 */ +#define SAFI_MPLS_LABELED_VPN 128 /* Max TTL value. */ #define TTL_MAX 255 diff --git a/configure.ac b/configure.ac index 0238502f..8d79e7d6 100755 --- a/configure.ac +++ b/configure.ac @@ -5,10 +5,9 @@ ## Copyright (c) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro <kunihiro@zebra.org> ## Portions Copyright (c) 2003 Paul Jakma <paul@dishone.st> ## -## $Id$ AC_PREREQ(2.53) -AC_INIT(Quagga, 0.99.18ex20b, [http://bugzilla.quagga.net]) +AC_INIT(Quagga, 0.99.20ex21b, [http://bugzilla.quagga.net]) AC_CONFIG_SRCDIR(lib/zebra.h) AC_CONFIG_MACRO_DIR([m4]) @@ -437,7 +436,7 @@ dnl Check other header files. dnl ------------------------- AC_CHECK_HEADERS([stropts.h sys/ksym.h sys/times.h sys/select.h \ sys/types.h linux/version.h netdb.h asm/types.h \ - sys/param.h limits.h signal.h libutil.h \ + sys/param.h limits.h signal.h \ sys/socket.h netinet/in.h time.h sys/time.h]) dnl Utility macro to avoid retyping includes all the time @@ -484,8 +483,35 @@ m4_define([QUAGGA_INCLUDES], #endif /* TIME_WITH_SYS_TIME */ ])dnl -AC_CHECK_HEADERS([sys/un.h net/if.h netinet/in_systm.h netinet/in_var.h \ - net/if_dl.h net/if_var.h net/netopt.h net/route.h \ +dnl HAVE_NET_IF_H must be discovered by the time the longer AC_CHECK_HEADERS +dnl round below execution begins, otherwise it doesn't properly detect +dnl HAVE_NETINET6_IN6_VAR_H, HAVE_NET_IF_VAR_H and HAVE_STRUCT_IN6_ALIASREQ +dnl on FreeBSD (BZ#408). + +AC_CHECK_HEADERS([net/if.h], [], [], QUAGGA_INCLUDES) + +m4_define([QUAGGA_INCLUDES], +QUAGGA_INCLUDES +[#if HAVE_NET_IF_H +# include <net/if.h> +#endif +])dnl + +dnl Same applies for HAVE_NET_IF_VAR_H, which HAVE_NETINET6_ND6_H and +dnl HAVE_NETINET_IN_VAR_H depend upon. But if_var.h depends on if.h, hence +dnl an additional round for it. + +AC_CHECK_HEADERS([net/if_var.h], [], [], QUAGGA_INCLUDES) + +m4_define([QUAGGA_INCLUDES], +QUAGGA_INCLUDES +[#if HAVE_NET_IF_VAR_H +# include <net/if_var.h> +#endif +])dnl + +AC_CHECK_HEADERS([sys/un.h netinet/in_systm.h netinet/in_var.h \ + net/if_dl.h net/netopt.h net/route.h \ inet/nd.h arpa/inet.h netinet/ip_icmp.h \ fcntl.h stddef.h sys/ioctl.h syslog.h wchar.h wctype.h \ sys/sysctl.h sys/sockio.h kvm.h sys/conf.h], @@ -500,10 +526,7 @@ QUAGGA_INCLUDES m4_define([QUAGGA_INCLUDES], QUAGGA_INCLUDES -[#if HAVE_NET_IF_H -# include <net/if.h> -#endif -#if HAVE_SYS_UN_H +[#if HAVE_SYS_UN_H # include <sys/un.h> #endif #if HAVE_NETINET_IN_SYSTM_H @@ -515,9 +538,6 @@ QUAGGA_INCLUDES #if HAVE_NET_IF_DL_H # include <net/if_dl.h> #endif -#if HAVE_NET_IF_VAR_H -# include <net/if_var.h> -#endif #if HAVE_NET_NETOPT_H # include <net/netopt.h> #endif @@ -637,6 +657,13 @@ AC_SUBST(LIBREADLINE) dnl ---------- dnl PAM module +dnl +dnl Quagga detects the PAM library it is built against by checking for a +dnl functional pam_misc.h (Linux-PAM) or openpam.h (OpenPAM) header. pam_misc.h +dnl is known to #include pam_appl.h, the standard header of a PAM library, and +dnl openpam.h doesn't do that, although depends on the header too. Hence a +dnl little assistance to AC_CHECK_HEADER is necessary for the proper detection +dnl of OpenPAM. dnl ---------- if test "$with_libpam" = "yes"; then AC_CHECK_HEADER([security/pam_misc.h], @@ -650,7 +677,7 @@ if test "$with_libpam" = "yes"; then AC_DEFINE(PAM_CONV_FUNC,openpam_ttyconv,Have openpam_ttyconv) pam_conv_func="openpam_ttyconv" ], - [], QUAGGA_INCLUDES) + [], QUAGGA_INCLUDES[#include <security/pam_appl.h>]) if test -z "$ac_cv_header_security_pam_misc_h$ac_cv_header_security_openpam_h" ; then AC_MSG_WARN([*** pam support will not be built ***]) with_libpam="no" @@ -707,11 +734,9 @@ dnl ---------------------------- AC_FUNC_CHOWN AC_FUNC_FNMATCH AC_FUNC_FORK -AC_FUNC_MALLOC AC_FUNC_MEMCMP AC_FUNC_MKTIME AC_FUNC_STRFTIME -AC_FUNC_REALLOC AC_FUNC_STAT AC_FUNC_SELECT_ARGTYPES AC_FUNC_STRFTIME @@ -958,6 +983,15 @@ AC_TRY_COMPILE([#ifdef HAVE_SYS_PARAM_H AC_DEFINE(HAVE_BSD_STRUCT_IP_MREQ_HACK,,[Can pass ifindex in struct ip_mreq])], AC_MSG_RESULT(no)) +AC_MSG_CHECKING([for RFC3678 protocol-independed API]) +AC_TRY_COMPILE([ +#include <sys/types.h> +#include <netinet/in.h> +], [struct group_req gr; int sock; setsockopt(sock, IPPROTO_IP, MCAST_JOIN_GROUP, (void*)&gr, sizeof(gr)); +], [AC_MSG_RESULT(yes) +AC_DEFINE(HAVE_RFC3678,1,[Have RFC3678 protocol-independed API])], +AC_MSG_RESULT(no)) + dnl --------------------------------------------------------------- dnl figure out how to check link-state dnl --------------------------------------------------------------- @@ -1014,10 +1048,18 @@ dnl ----------------------------- dnl check ipforward detect method dnl ----------------------------- AC_CACHE_CHECK([ipforward method], [quagga_cv_ipforward_method], -[for quagga_cv_ipforward_method in /proc/net/snmp /dev/ip /dev/null; -do - test x`ls $quagga_cv_ipforward_method 2>/dev/null` = x"$quagga_cv_ipforward_method" && break -done +[if test x$cross_compiling = xyes; then + if test x"$opsys" = x"gnu-linux"; then + quagga_cv_ipforward_method=/proc/net/snmp + else + quagga_cv_ipforward_method=/dev/ip + fi +else + for quagga_cv_ipforward_method in /proc/net/snmp /dev/ip /dev/null; + do + test x`ls $quagga_cv_ipforward_method 2>/dev/null` = x"$quagga_cv_ipforward_method" && break + done +fi case $quagga_cv_ipforward_method in "/proc/net/snmp") quagga_cv_ipforward_method="proc";; "/dev/ip") @@ -1445,14 +1487,12 @@ AC_SUBST(LIBCAP) dnl --------------------------- dnl check for glibc 'backtrace' dnl --------------------------- -if test "${glibc}" = "yes"; then - AC_CHECK_HEADER([execinfo.h], - [AC_CHECK_FUNC([backtrace], - [AC_DEFINE(HAVE_GLIBC_BACKTRACE,,[Glibc backtrace]) - AC_DEFINE(HAVE_STACK_TRACE,,[Stack symbol decoding]) - ]) - ]) -fi +AC_CHECK_HEADER([execinfo.h], + [AC_CHECK_FUNC([backtrace], + [AC_DEFINE(HAVE_GLIBC_BACKTRACE,,[Glibc backtrace]) + AC_DEFINE(HAVE_STACK_TRACE,,[Stack symbol decoding]) + ]) +]) dnl ----------------------------------------- dnl check for malloc mallinfo struct and call diff --git a/doc/.cvsignore b/doc/.cvsignore deleted file mode 100644 index 43987b24..00000000 --- a/doc/.cvsignore +++ /dev/null @@ -1,31 +0,0 @@ -Makefile -Makefile.in -mdate-sh -draft-zebra-00.txt -zebra.info-* -zebra.html -defines.texi -version.texi -quagga.html -quagga.info -*.pdf -*.eps -quagga.ps -quagga.dvi -stamp-vti -.nfs* -*.aux -*.cp -*.cps -*.fn -*.fns -*.ky -*.kys -*.log -*.op -*.pg -*.toc -*.tp -*.vr -.arch-inventory -.arch-ids diff --git a/doc/BGP-TypeCode b/doc/BGP-TypeCode index 5663c4d7..b3218079 100644 --- a/doc/BGP-TypeCode +++ b/doc/BGP-TypeCode @@ -3,24 +3,22 @@ Value Attribute References ========================================================================= - 1 ORIGIN [RFC 1771] - 2 AS_PATH [RFC 1771] - 3 NEXT_HOP [RFC 1771] - 4 MULTI_EXIT_DISC [RFC 1771] - 5 LOCAL_PREF [RFC 1771] - 6 ATOMIC_AGGREGATE [RFC 1771] - 7 AGGREGATOR [RFC 1771] + 1 ORIGIN [RFC 4271] + 2 AS_PATH [RFC 4271] + 3 NEXT_HOP [RFC 4271] + 4 MULTI_EXIT_DISC [RFC 4271] + 5 LOCAL_PREF [RFC 4271] + 6 ATOMIC_AGGREGATE [RFC 4271] + 7 AGGREGATOR [RFC 4271] 8 COMMUNITIES [RFC 1997] - 9 ORIGINATOR_ID [RFC 1966] - 10 CLUSTER_LIST [RFC 1966] + 9 ORIGINATOR_ID [RFC 4456] + 10 CLUSTER_LIST [RFC 4456] 11 DPA [draft-ietf-idr-bgp-dpa-05.txt(expired)] - 12 ADVERTISER [Changed from RFC 1863 bgp@ans.net ML?] - 13 RCID_PATH [Changed from RFC 1863 bgp@ans.net ML?] - 14 MP_REACH_NLRI [RFC 2283] - 15 MP_UNREACH_NLRI [RFC 2283] - 16 EXT_COMMUNITIES [draft-ramachandra-bgp-ext-communities-09.txt] + 12 ADVERTISER [RFC 1863] + 13 RCID_PATH [RFC 1863] + 14 MP_REACH_NLRI [RFC 4760] + 15 MP_UNREACH_NLRI [RFC 4760] + 16 EXT_COMMUNITIES [RFC 4360] 17 AS4_PATH [RFC 4893] 18 AS4_AGGREGATOR [RFC 4893] - 254 RCID_PATH [RFC 1863] - 255 ADVERTISER [RFC 1863] ========================================================================= diff --git a/doc/bgpd.texi b/doc/bgpd.texi index e7463300..63834600 100644 --- a/doc/bgpd.texi +++ b/doc/bgpd.texi @@ -85,6 +85,7 @@ so @code{router-id} is set to 0.0.0.0. So please set router-id by hand. @menu * BGP distance:: * BGP decision process:: +* BGP route flap dampening:: @end menu @node BGP distance @@ -123,6 +124,27 @@ sequences should should be taken into account during the BGP best path decision process. @end deffn +@node BGP route flap dampening +@subsection BGP route flap dampening + +@deffn {BGP} {bgp dampening @var{<1-45>} @var{<1-20000>} @var{<1-20000>} @var{<1-255>}} {} +This command enables BGP route-flap dampening and specifies dampening parameters. + +@table @asis +@item @asis{half-life} +Half-life time for the penalty +@item @asis{reuse-threshold} +Value to start reusing a route +@item @asis{suppress-threshold} +Value to start suppressing a route +@item @asis{max-suppress} +Maximum duration to suppress a stable route +@end table + +The route-flap damping algorithm is compatible with @cite{RFC2439}. The use of this command +is not recommended nowadays, see @uref{http://www.ripe.net/ripe/docs/ripe-378,,RIPE-378}. +@end deffn + @node BGP network @section BGP network @@ -930,6 +952,14 @@ Clear peers which have addresses of X.X.X.X Clear peer using soft reconfiguration. @end deffn +@deffn {Command} {show ip bgp dampened-paths} {} +Display paths suppressed due to dampening +@end deffn + +@deffn {Command} {show ip bgp flap-statistics} {} +Display flap statistics of routes +@end deffn + @deffn {Command} {show debug} {} @end deffn diff --git a/doc/ipv6.texi b/doc/ipv6.texi index a78a92fe..d4ef45a3 100644 --- a/doc/ipv6.texi +++ b/doc/ipv6.texi @@ -62,23 +62,24 @@ Default: not set, i.e. hosts do not assume a complete IP address is placed. @end itemize @end deffn -@deffn {Interface Command} {ipv6 nd ra-interval SECONDS} {} -@deffnx {Interface Command} {no ipv6 nd ra-interval} {} +@deffn {Interface Command} {ipv6 nd ra-interval <1-1800>} {} +@deffnx {Interface Command} {no ipv6 nd ra-interval [<1-1800>]} {} The maximum time allowed between sending unsolicited multicast router -advertisements from the interface, in seconds. Must be no less than 3 seconds. +advertisements from the interface, in seconds. Default: @code{600} @end deffn -@deffn {Interface Command} {ipv6 nd ra-interval msec MILLISECONDS} {} -@deffnx {Interface Command} {no ipv6 nd ra-interval msec} {} +@deffn {Interface Command} {ipv6 nd ra-interval msec <70-1800000>} {} +@deffnx {Interface Command} {no ipv6 nd ra-interval [msec <70-1800000>]} {} The maximum time allowed between sending unsolicited multicast router -advertisements from the interface, in milliseconds. Must be no less than 30 milliseconds. +advertisements from the interface, in milliseconds. Default: @code{600000} @end deffn -@deffn {Interface Command} {ipv6 nd ra-lifetime SECONDS} {} -@deffnx {Interface Command} {no ipv6 nd ra-lifetime} {} + +@deffn {Interface Command} {ipv6 nd ra-lifetime <0-9000>} {} +@deffnx {Interface Command} {no ipv6 nd ra-lifetime [<0-9000>]} {} The value to be placed in the Router Lifetime field of router advertisements sent from the interface, in seconds. Indicates the usefulness of the router as a default router on this interface. Setting the value to zero indicates @@ -89,12 +90,12 @@ Must be either zero or between value specified with @var{ipv6 nd ra-interval} Default: @code{1800} @end deffn -@deffn {Interface Command} {ipv6 nd reachable-time MILLISECONDS} {} -@deffnx {Interface Command} {no ipv6 nd reachable-time} {} +@deffn {Interface Command} {ipv6 nd reachable-time <1-3600000>} {} +@deffnx {Interface Command} {no ipv6 nd reachable-time [<1-3600000>]} {} The value to be placed in the Reachable Time field in the Router Advertisement messages sent by the router, in milliseconds. The configured time enables the router to detect unavailable neighbors. The value zero means unspecified (by -this router). Must be no greater than @code{3,600,000} milliseconds (1 hour). +this router). Default: @code{0} @end deffn @@ -126,18 +127,20 @@ the router acts as a Home Agent and includes a Home Agent Option. Default: not set @end deffn -@deffn {Interface Command} {ipv6 nd home-agent-preference} {} -@deffnx {Interface Command} {no ipv6 nd home-agent-preference} {} +@deffn {Interface Command} {ipv6 nd home-agent-preference <0-65535>} {} +@deffnx {Interface Command} {no ipv6 nd home-agent-preference [<0-65535>]} {} The value to be placed in Home Agent Option, when Home Agent config flag is set, -which indicates to hosts Home Agent preference. +which indicates to hosts Home Agent preference. The default value of 0 stands +for the lowest preference possible. Default: 0 @end deffn -@deffn {Interface Command} {ipv6 nd home-agent-lifetime} {} -@deffnx {Interface Command} {no ipv6 nd home-agent-lifetime} {} ++@deffn {Interface Command} {ipv6 nd home-agent-lifetime <0-65520>} {} ++@deffnx {Interface Command} {no ipv6 nd home-agent-lifetime [<0-65520>]} {} The value to be placed in Home Agent Option, when Home Agent config flag is set, -which indicates to hosts Home Agent Lifetime. A value of 0 means to place Router Lifetime value. +which indicates to hosts Home Agent Lifetime. The default value of 0 means to +place the current Router Lifetime value. Default: 0 @end deffn @@ -151,12 +154,21 @@ Default: not set @end deffn @deffn {Interface Command} {ipv6 nd router-preference (high|medium|low)} {} -@deffnx {Interface Command} {no ipv6 nd router-preference} {} +@deffnx {Interface Command} {no ipv6 nd router-preference [(high|medium|low)]} {} Set default router preference in IPv6 router advertisements per RFC4191. Default: medium @end deffn +@deffn {Interface Command} {ipv6 nd mtu <1-65535>} {} +@deffnx {Interface Command} {no ipv6 nd mtu [<1-65535>]} {} +Include an MTU (type 5) option in each RA packet to assist the attached hosts +in proper interface configuration. The announced value is not verified to be +consistent with router interface MTU. + +Default: don't advertise any MTU option +@end deffn + @example @group interface eth0 @@ -166,6 +178,6 @@ interface eth0 @end example For more information see @cite{RFC2462 (IPv6 Stateless Address Autoconfiguration)} -, @cite{RFC2461 (Neighbor Discovery for IP Version 6 (IPv6))} -, @cite{RFC3775 (Mobility Support in IPv6 (Mobile IPv6))} +, @cite{RFC4861 (Neighbor Discovery for IP Version 6 (IPv6))} +, @cite{RFC6275 (Mobility Support in IPv6)} and @cite{RFC4191 (Default Router Preferences and More-Specific Routes)}. diff --git a/doc/mpls/.cvsignore b/doc/mpls/.cvsignore deleted file mode 100644 index 1218df92..00000000 --- a/doc/mpls/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -.arch-ids -.arch-inventory diff --git a/doc/ospfd.texi b/doc/ospfd.texi index f879a986..856a2ba0 100644 --- a/doc/ospfd.texi +++ b/doc/ospfd.texi @@ -99,7 +99,7 @@ behaviors implemented in Cisco and IBM routers." to section G.2 (changes) in section 16.4 a change to the path preference algorithm that prevents possible routing loops that were possible in the old version of OSPFv2. More specifically it demands -that inter-area paths and intra-area path are now of equal preference +that inter-area paths and intra-area backbone path are now of equal preference but still both preferred to external paths. This command should NOT be set normally. @@ -568,10 +568,6 @@ redistributed into OSPF (@pxref{OSPF redistribute}). @deffnx {OSPF Command} {no distance ospf} {} @end deffn -@deffn {Command} {router zebra} {} -@deffnx {Command} {no router zebra} {} -@end deffn - @node Showing OSPF information @section Showing OSPF information diff --git a/doc/ripd.texi b/doc/ripd.texi index 197bc5af..c6f804af 100644 --- a/doc/ripd.texi +++ b/doc/ripd.texi @@ -424,10 +424,10 @@ must be different. Maybe it'd be better to made new matches - say Match if route destination is permitted by access-list. @end deffn -@deffn {Route Map} {match ip next-hop A.B.C.D} {} -Cisco uses here <access-list>, @command{ripd} IPv4 address. Match if -route has this next-hop (meaning next-hop listed in the rip route -table - "show ip rip") +@deffn {Route Map} {match ip next-hop @var{word}} {} +@deffnx {Route Map} {match ip next-hop prefix-list @var{word}} {} +Match if route next-hop (meaning next-hop listed in the rip route-table +as displayed by "show ip rip") is permitted by access-list. @end deffn @deffn {Route Map} {match metric <0-4294967295>} {} diff --git a/guile/.cvsignore b/guile/.cvsignore deleted file mode 100644 index d345fc35..00000000 --- a/guile/.cvsignore +++ /dev/null @@ -1,7 +0,0 @@ -Makefile -*.o -zebra-guile -Makefile.in -.nfs* -.arch-inventory -.arch-ids diff --git a/init/.cvsignore b/init/.cvsignore deleted file mode 100644 index 3c447f5b..00000000 --- a/init/.cvsignore +++ /dev/null @@ -1,3 +0,0 @@ -Makefile -Makefile.in -.nfs* diff --git a/isisd/.cvsignore b/isisd/.cvsignore deleted file mode 100644 index 26aa85cb..00000000 --- a/isisd/.cvsignore +++ /dev/null @@ -1,12 +0,0 @@ -Makefile -Makefile.in -*.o -isisd -.deps -isisd.conf -.nfs* -*.lo -*.la -*.libs -.arch-inventory -.arch-ids diff --git a/isisd/dict.c b/isisd/dict.c index 4d2400f6..aa60d68a 100644 --- a/isisd/dict.c +++ b/isisd/dict.c @@ -13,9 +13,6 @@ * This source code may be translated into executable form and incorporated * into proprietary software; there is no requirement for such software to * contain a copyright notice related to this source. - * - * $Id$ - * $Name$ */ #include "zebra.h" diff --git a/isisd/include-netbsd/.cvsignore b/isisd/include-netbsd/.cvsignore deleted file mode 100644 index 73bcf19d..00000000 --- a/isisd/include-netbsd/.cvsignore +++ /dev/null @@ -1,3 +0,0 @@ -.arch-inventory -.arch-ids - diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index aab8d1a3..de34bea9 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -172,7 +172,7 @@ isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state state, circuit->upadjcount[level - 1]++; if (state == ISIS_ADJ_DOWN) { - isis_delete_adj (adj, adj->circuit->u.bc.adjdb[level - 1]); + listnode_delete (adj->circuit->u.bc.adjdb[level - 1], adj); circuit->upadjcount[level - 1]--; } diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index d2923b57..99e2bf6f 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -142,6 +142,11 @@ isis_circuit_deconfigure (struct isis_circuit *circuit, struct isis_area *area) { + /* destroy adjacencies */ + if (circuit->u.bc.adjdb[0]) + isis_adjdb_iterate (circuit->u.bc.adjdb[0], (void(*) (struct isis_adjacency *, void *)) isis_delete_adj, circuit->u.bc.adjdb[0]); + if (circuit->u.bc.adjdb[1]) + isis_adjdb_iterate (circuit->u.bc.adjdb[1], (void(*) (struct isis_adjacency *, void *)) isis_delete_adj, circuit->u.bc.adjdb[1]); /* Remove circuit from area */ listnode_delete (area->circuit_list, circuit); /* Free the index of SRM and SSN flags */ @@ -602,6 +607,13 @@ isis_circuit_down (struct isis_circuit *circuit) { THREAD_TIMER_OFF (circuit->u.p2p.t_send_p2p_hello); } + + if (circuit->t_send_psnp[0]) { + THREAD_TIMER_OFF (circuit->t_send_psnp[0]); + } + if (circuit->t_send_psnp[1]) { + THREAD_TIMER_OFF (circuit->t_send_psnp[1]); + } /* close the socket */ close (circuit->fd); @@ -818,6 +830,21 @@ isis_interface_config_write (struct vty *vty) } } } + if (c->passwd.type==ISIS_PASSWD_TYPE_HMAC_MD5) + { + vty_out (vty, " isis password md5 %s%s", c->passwd.passwd, + VTY_NEWLINE); + write++; + } + else + { + if (c->passwd.type==ISIS_PASSWD_TYPE_CLEARTXT) + { + vty_out (vty, " isis password clear %s%s", c->passwd.passwd, + VTY_NEWLINE); + write++; + } + } } } @@ -1010,11 +1037,44 @@ DEFUN (no_isis_circuit_type, return CMD_SUCCESS; } -DEFUN (isis_passwd, - isis_passwd_cmd, - "isis password WORD", +DEFUN (isis_passwd_md5, + isis_passwd_md5_cmd, + "isis password md5 WORD", + "IS-IS commands\n" + "Configure the authentication password for interface\n" + "Authentication Type\n" + "Password\n") +{ + struct isis_circuit *circuit; + struct interface *ifp; + int len; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) + { + return CMD_WARNING; + } + + len = strlen (argv[0]); + if (len > 254) + { + vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE); + return CMD_WARNING; + } + circuit->passwd.len = len; + circuit->passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5; + strncpy ((char *)circuit->passwd.passwd, argv[0], 255); + + return CMD_SUCCESS; +} + +DEFUN (isis_passwd_clear, + isis_passwd_clear_cmd, + "isis password clear WORD", "IS-IS commands\n" "Configure the authentication password for interface\n" + "Authentication Type\n" "Password\n") { struct isis_circuit *circuit; @@ -1063,7 +1123,6 @@ DEFUN (no_isis_passwd, return CMD_SUCCESS; } - DEFUN (isis_priority, isis_priority_cmd, "isis priority <0-127>", @@ -2074,7 +2133,8 @@ isis_circuit_init () install_element (INTERFACE_NODE, &isis_circuit_type_cmd); install_element (INTERFACE_NODE, &no_isis_circuit_type_cmd); - install_element (INTERFACE_NODE, &isis_passwd_cmd); + install_element (INTERFACE_NODE, &isis_passwd_clear_cmd); + install_element (INTERFACE_NODE, &isis_passwd_md5_cmd); install_element (INTERFACE_NODE, &no_isis_passwd_cmd); install_element (INTERFACE_NODE, &isis_priority_cmd); diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index a7e719f6..f32d1dda 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -65,6 +65,7 @@ struct isis_p2p_info struct isis_circuit { int state; + int connected; u_char circuit_id; /* l1/l2 p2p/bcast CircuitID */ struct isis_area *area; /* back pointer to the area */ struct interface *interface; /* interface info from z */ diff --git a/isisd/isis_common.h b/isisd/isis_common.h index 26338556..334d3394 100644 --- a/isisd/isis_common.h +++ b/isisd/isis_common.h @@ -35,6 +35,7 @@ struct isis_passwd u_char len; #define ISIS_PASSWD_TYPE_UNUSED 0 #define ISIS_PASSWD_TYPE_CLEARTXT 1 +#define ISIS_PASSWD_TYPE_HMAC_MD5 54 #define ISIS_PASSWD_TYPE_PRIVATE 255 u_char type; /* Authenticate SNPs? */ diff --git a/isisd/isis_csm.c b/isisd/isis_csm.c index e4f8f133..f5e5d683 100644 --- a/isisd/isis_csm.c +++ b/isisd/isis_csm.c @@ -114,6 +114,7 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg) isis_circuit_configure (circuit, (struct isis_area *) arg); isis_circuit_up (circuit); circuit->state = C_STATE_UP; + circuit->connected = 1; isis_event_circuit_state_change (circuit, 1); listnode_delete (isis->init_circ_list, circuit); break; @@ -140,9 +141,12 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg) zlog_warn ("circuit already enabled"); break; case IF_UP_FROM_Z: - isis_circuit_if_add (circuit, (struct interface *) arg); - isis_circuit_up (circuit); + if (!circuit->connected) { + isis_circuit_if_add (circuit, (struct interface *) arg); + isis_circuit_up (circuit); + } circuit->state = C_STATE_UP; + circuit->connected = 1; isis_event_circuit_state_change (circuit, 1); break; case ISIS_DISABLE: @@ -173,7 +177,6 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg) isis_event_circuit_state_change (circuit, 0); break; case IF_DOWN_FROM_Z: - isis_circuit_if_del (circuit); circuit->state = C_STATE_CONF; isis_event_circuit_state_change (circuit, 0); break; diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 545d43e4..4ea8e088 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -353,10 +353,25 @@ isis_lsp_authinfo_check (struct stream *stream, struct isis_area *area, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN, pdulen - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN, &expected, &found, &tlvs); + if (retval || !(found & TLVFLAG_AUTH_INFO)) return 1; /* Auth fail (parsing failed or no auth-tlv) */ - return authentication_check (passwd, &tlvs.auth_info); + switch (tlvs.auth_info.type) + { + case ISIS_PASSWD_TYPE_HMAC_MD5: + zlog_debug("Got LSP with ISIS_PASSWD_TYPE_HMAC_MD5"); + break; + case ISIS_PASSWD_TYPE_CLEARTXT: + zlog_debug("Got LSP with ISIS_PASSWD_TYPE_CLEARTXT"); + break; + default: + zlog_debug("Unknown authentication type in LSP"); + break; + } + + return 0; + /* return authentication_check (passwd, &tlvs.auth_info);*/ } static void @@ -1640,7 +1655,7 @@ lsp_regenerate_schedule (struct isis_area *area) if (diff < MIN_LSP_GEN_INTERVAL) { area->lsp_regenerate_pending[0] = 1; - thread_add_timer (master, lsp_l1_regenerate, area, + area->t_lsp_l1_regenerate=thread_add_timer (master, lsp_l1_regenerate, area, MIN_LSP_GEN_INTERVAL - diff); goto L2; } @@ -1663,7 +1678,7 @@ L2: if (diff < MIN_LSP_GEN_INTERVAL) { area->lsp_regenerate_pending[1] = 1; - thread_add_timer (master, lsp_l2_regenerate, area, + area->t_lsp_l2_regenerate=thread_add_timer (master, lsp_l2_regenerate, area, MIN_LSP_GEN_INTERVAL - diff); return ISIS_OK; } @@ -2037,6 +2052,8 @@ lsp_tick (struct thread *thread) { for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit)) { + if (circuit->state != C_STATE_UP) + continue; for (ALL_LIST_ELEMENTS_RO (lsp_list, lspnode, lsp)) { if (ISIS_CHECK_FLAG (lsp->SRMflags, circuit)) diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h index adbde78e..8d648d05 100644 --- a/isisd/isis_lsp.h +++ b/isisd/isis_lsp.h @@ -58,7 +58,6 @@ struct isis_lsp #endif /* used for 60 second counting when rem_lifetime is zero */ int age_out; - struct isis_adjacency *adj; /* FIXME: For now only topology LSP's use this. Is it helpful for others? */ struct isis_area *area; struct tlvs tlv_data; /* Simplifies TLV access */ diff --git a/isisd/isis_main.c b/isisd/isis_main.c index c5e824c1..15d85d6d 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -34,6 +34,7 @@ #include "privs.h" #include "sigevent.h" #include "filter.h" +#include "zclient.h" #include "isisd/dict.h" #include "include-netbsd/iso.h" @@ -72,16 +73,17 @@ struct zebra_privs_t isisd_privs = { /* isisd options */ struct option longopts[] = { - {"daemon", no_argument, NULL, 'd'}, + {"daemon", no_argument, NULL, 'd'}, {"config_file", required_argument, NULL, 'f'}, - {"pid_file", required_argument, NULL, 'i'}, - {"vty_addr", required_argument, NULL, 'A'}, - {"vty_port", required_argument, NULL, 'P'}, - {"user", required_argument, NULL, 'u'}, - {"group", required_argument, NULL, 'g'}, - {"version", no_argument, NULL, 'v'}, - {"dryrun", no_argument, NULL, 'C'}, - {"help", no_argument, NULL, 'h'}, + {"pid_file", required_argument, NULL, 'i'}, + {"socket", required_argument, NULL, 'z'}, + {"vty_addr", required_argument, NULL, 'A'}, + {"vty_port", required_argument, NULL, 'P'}, + {"user", required_argument, NULL, 'u'}, + {"group", required_argument, NULL, 'g'}, + {"version", no_argument, NULL, 'v'}, + {"dryrun", no_argument, NULL, 'C'}, + {"help", no_argument, NULL, 'h'}, {0} }; @@ -130,6 +132,7 @@ Daemon which manages IS-IS routing\n\n\ -d, --daemon Runs in daemon mode\n\ -f, --config_file Set configuration file name\n\ -i, --pid_file Set process identifier file name\n\ +-z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -u, --user User to run as\n\ @@ -246,7 +249,7 @@ main (int argc, char **argv, char **envp) /* Command line argument treatment. */ while (1) { - opt = getopt_long (argc, argv, "df:i:hA:p:P:u:g:vC", longopts, 0); + opt = getopt_long (argc, argv, "df:i:z:hA:p:P:u:g:vC", longopts, 0); if (opt == EOF) break; @@ -264,6 +267,9 @@ main (int argc, char **argv, char **envp) case 'i': pid_file = optarg; break; + case 'z': + zclient_serv_path_set (optarg); + break; case 'A': vty_addr = optarg; break; diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 0a69dcb6..d47c0023 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -29,10 +29,11 @@ #include "log.h" #include "stream.h" #include "vty.h" -#include "hash.c" +#include "hash.h" #include "prefix.h" #include "if.h" #include "checksum.h" +#include "md5.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" @@ -168,26 +169,40 @@ accept_level (int level, int circuit_t) return retval; } + +/* + * Verify authentication information + * Support cleartext and HMAC MD5 authentication + */ int -authentication_check (struct isis_passwd *one, struct isis_passwd *theother) +authentication_check (struct isis_passwd *remote, struct isis_passwd *local, struct isis_circuit* c) { - if (one->type != theother->type) + unsigned char digest[ISIS_AUTH_MD5_SIZE]; + + if (c->passwd.type) { - zlog_warn ("Unsupported authentication type %d", theother->type); - return 1; /* Auth fail (different authentication types) */ - } - switch (one->type) + switch (c->passwd.type) { + case ISIS_PASSWD_TYPE_HMAC_MD5: + /* HMAC MD5 (RFC 3567) */ + /* MD5 computation according to RFC 2104 */ + hmac_md5(c->rcv_stream->data, stream_get_endp(c->rcv_stream), + (unsigned char *) &(local->passwd), c->passwd.len, + (unsigned char *) &digest); + return memcmp (digest, remote->passwd, ISIS_AUTH_MD5_SIZE); + break; case ISIS_PASSWD_TYPE_CLEARTXT: - if (one->len != theother->len) + /* Cleartext (ISO 10589) */ + if (local->len != remote->len) return 1; /* Auth fail () - passwd len mismatch */ - return memcmp (one->passwd, theother->passwd, one->len); + return memcmp (local->passwd, remote->passwd, local->len); break; default: zlog_warn ("Unsupported authentication type"); break; } - return 0; /* Auth pass */ + } + return 0; /* Authentication pass when no authentication is configured */ } /* @@ -372,7 +387,7 @@ process_p2p_hello (struct isis_circuit *circuit) if (circuit->passwd.type) { if (!(found & TLVFLAG_AUTH_INFO) || - authentication_check (&circuit->passwd, &tlvs.auth_info)) + authentication_check (&tlvs.auth_info, &circuit->passwd, circuit)) { isis_event_auth_failure (circuit->area->area_tag, "P2P hello authentication failure", @@ -754,10 +769,11 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) goto out; } + /* Verify authentication, either cleartext of HMAC MD5 */ if (circuit->passwd.type) { if (!(found & TLVFLAG_AUTH_INFO) || - authentication_check (&circuit->passwd, &tlvs.auth_info)) + authentication_check (&tlvs.auth_info, &circuit->passwd, circuit)) { isis_event_auth_failure (circuit->area->area_tag, "LAN hello authentication failure", @@ -1199,6 +1215,7 @@ dontcheckadj: /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */ if ((!lsp || comp == LSP_NEWER)) { + int regenerate = (lsp == NULL); /* i */ if (lsp) { @@ -1233,7 +1250,6 @@ dontcheckadj: ntohs (hdr->pdu_len), lsp0, circuit->area); lsp->level = level; - lsp->adj = adj; lsp_insert (lsp, circuit->area->lspdb[level - 1]); /* ii */ ISIS_FLAGS_SET_ALL (lsp->SRMflags); @@ -1244,6 +1260,9 @@ dontcheckadj: if (circuit->circ_type != CIRCUIT_T_BROADCAST) ISIS_SET_FLAG (lsp->SSNflags, circuit); /* FIXME: v) */ + if (regenerate && circuit->u.bc.is_dr[level - 1]) { + lsp_l1_pseudo_generate (circuit); + } } /* 7.3.15.1 e) 2) LSP equal to the one in db */ else if (comp == LSP_EQUAL) @@ -1262,8 +1281,7 @@ dontcheckadj: ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); } } - if (lsp) - lsp->adj = adj; + return retval; } @@ -1426,7 +1444,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, if (passwd->type) { if (!(found & TLVFLAG_AUTH_INFO) || - authentication_check (passwd, &tlvs.auth_info)) + authentication_check (&tlvs.auth_info, passwd, circuit)) { isis_event_auth_failure (circuit->area->area_tag, "SNP authentication" " failure", @@ -1793,6 +1811,9 @@ isis_receive (struct thread *thread) circuit = THREAD_ARG (thread); assert (circuit); + if (!circuit->area) + return ISIS_OK; + if (circuit->rcv_stream == NULL) circuit->rcv_stream = stream_new (ISO_MTU (circuit)); else @@ -1920,11 +1941,15 @@ send_hello (struct isis_circuit *circuit, int level) struct isis_fixed_hdr fixed_hdr; struct isis_lan_hello_hdr hello_hdr; struct isis_p2p_hello_hdr p2p_hello_hdr; + char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; u_int32_t interval; - unsigned long len_pointer, length; + unsigned long len_pointer, length, auth_tlv; int retval; + if (circuit->state != C_STATE_UP || circuit->interface == NULL) + return ISIS_WARNING; + if (circuit->interface->mtu == 0) { zlog_warn ("circuit has zero MTU"); @@ -1952,6 +1977,9 @@ send_hello (struct isis_circuit *circuit, int level) memset (&hello_hdr, 0, sizeof (struct isis_lan_hello_hdr)); interval = circuit->hello_multiplier[level - 1] * circuit->hello_interval[level - 1]; + /* If we are the DIS then hello interval is divided by three, as is the hold-timer */ + if (circuit->u.bc.is_dr[level - 1]) + interval=interval/3; if (interval > USHRT_MAX) interval = USHRT_MAX; hello_hdr.circuit_t = circuit->circuit_is_type; @@ -1988,34 +2016,36 @@ send_hello (struct isis_circuit *circuit, int level) /* * Then the variable length part */ + /* add circuit password */ - if (circuit->passwd.type) - if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len, + /* Cleartext */ + if (circuit->passwd.type == ISIS_PASSWD_TYPE_CLEARTXT) + if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, circuit->passwd.len, circuit->passwd.passwd, circuit->snd_stream)) return ISIS_WARNING; - /* Area Addresses TLV */ - assert (circuit->area); - if (circuit->area->area_addrs && circuit->area->area_addrs->count > 0) - if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream)) - return ISIS_WARNING; - /* LAN Neighbors TLV */ - if (circuit->circ_type == CIRCUIT_T_BROADCAST) + /* or HMAC MD5 */ + if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) { - if (level == 1 && circuit->u.bc.lan_neighs[0]->count > 0) - if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0], - circuit->snd_stream)) - return ISIS_WARNING; - if (level == 2 && circuit->u.bc.lan_neighs[1]->count > 0) - if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1], - circuit->snd_stream)) - return ISIS_WARNING; + /* Remember where TLV is written so we can later overwrite the MD5 hash */ + auth_tlv = stream_get_endp (circuit->snd_stream); + memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); + if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE, + hmac_md5_hash, circuit->snd_stream)) + return ISIS_WARNING; } /* Protocols Supported TLV */ if (circuit->nlpids.count > 0) if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream)) return ISIS_WARNING; + + /* Area Addresses TLV */ + assert (circuit->area); + if (circuit->area->area_addrs && circuit->area->area_addrs->count > 0) + if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream)) + return ISIS_WARNING; + /* IP interface Address TLV */ if (circuit->ip_router && circuit->ip_addrs && circuit->ip_addrs->count > 0) if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream)) @@ -2029,6 +2059,22 @@ send_hello (struct isis_circuit *circuit, int level) return ISIS_WARNING; #endif /* HAVE_IPV6 */ + /* Restart signaling, vendor C sends it too */ + retval = add_tlv (211, 3, 0, circuit->snd_stream); + + /* LAN Neighbors TLV */ + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + { + if (level == 1 && circuit->u.bc.lan_neighs[0]->count > 0) + if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0], + circuit->snd_stream)) + return ISIS_WARNING; + if (level == 2 && circuit->u.bc.lan_neighs[1]->count > 0) + if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1], + circuit->snd_stream)) + return ISIS_WARNING; + } + if (circuit->u.bc.pad_hellos) if (tlv_add_padding (circuit->snd_stream)) return ISIS_WARNING; @@ -2037,6 +2083,14 @@ send_hello (struct isis_circuit *circuit, int level) /* Update PDU length */ stream_putw_at (circuit->snd_stream, len_pointer, (u_int16_t) length); + /* For HMAC MD5 we need to compute the md5 hash and store it */ + if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) + { + hmac_md5(circuit->snd_stream->data, stream_get_endp(circuit->snd_stream), (unsigned char *) &circuit->passwd.passwd, circuit->passwd.len, (unsigned char *) &hmac_md5_hash); + /* Copy the hash into the stream */ + memcpy(circuit->snd_stream->data+auth_tlv+3,hmac_md5_hash,ISIS_AUTH_MD5_SIZE); + } + retval = circuit->tx (circuit, level); if (retval) zlog_warn ("sending of LAN Level %d Hello failed", level); @@ -2074,9 +2128,21 @@ send_lan_l1_hello (struct thread *thread) { struct isis_circuit *circuit; int retval; + unsigned long next_hello; circuit = THREAD_ARG (thread); assert (circuit); + + if (!circuit->area) { + return ISIS_OK; + } + + /* Pseudonode sends hellos three times more than the other nodes */ + if (circuit->u.bc.is_dr[0]) + next_hello=circuit->hello_interval[0]/3+1; + else + next_hello=circuit->hello_interval[0]; + circuit->u.bc.t_send_lan_hello[0] = NULL; if (circuit->u.bc.run_dr_elect[0]) @@ -2087,7 +2153,7 @@ send_lan_l1_hello (struct thread *thread) /* set next timer thread */ THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0], send_lan_l1_hello, circuit, - isis_jitter (circuit->hello_interval[0], IIH_JITTER)); + isis_jitter (next_hello, IIH_JITTER)); return retval; } @@ -2097,9 +2163,21 @@ send_lan_l2_hello (struct thread *thread) { struct isis_circuit *circuit; int retval; + unsigned long next_hello; circuit = THREAD_ARG (thread); assert (circuit); + + if (!circuit->area) { + return ISIS_OK; + } + + /* Pseudonode sends hellos three times more than the other nodes */ + if (circuit->u.bc.is_dr[1]) + next_hello=circuit->hello_interval[1]/3+1; + else + next_hello=circuit->hello_interval[1]; + circuit->u.bc.t_send_lan_hello[1] = NULL; if (circuit->u.bc.run_dr_elect[1]) @@ -2110,7 +2188,7 @@ send_lan_l2_hello (struct thread *thread) /* set next timer thread */ THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[1], send_lan_l2_hello, circuit, - isis_jitter (circuit->hello_interval[1], IIH_JITTER)); + isis_jitter (next_hello, IIH_JITTER)); return retval; } @@ -2204,6 +2282,9 @@ send_csnp (struct isis_circuit *circuit, int level) struct listnode *node; struct isis_lsp *lsp; + if (circuit->state != C_STATE_UP || circuit->interface == NULL) + return ISIS_WARNING; + memset (start, 0x00, ISIS_SYS_ID_LEN + 2); memset (stop, 0xff, ISIS_SYS_ID_LEN + 2); @@ -2258,9 +2339,7 @@ send_l1_csnp (struct thread *thread) circuit->t_send_csnp[0] = NULL; if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[0]) - { send_csnp (circuit, 1); - } /* set next timer thread */ THREAD_TIMER_ON (master, circuit->t_send_csnp[0], send_l1_csnp, circuit, isis_jitter (circuit->csnp_interval[0], CSNP_JITTER)); @@ -2280,9 +2359,7 @@ send_l2_csnp (struct thread *thread) circuit->t_send_csnp[1] = NULL; if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[1]) - { send_csnp (circuit, 2); - } /* set next timer thread */ THREAD_TIMER_ON (master, circuit->t_send_csnp[1], send_l2_csnp, circuit, isis_jitter (circuit->csnp_interval[1], CSNP_JITTER)); @@ -2369,6 +2446,9 @@ send_psnp (int level, struct isis_circuit *circuit) struct list *list = NULL; struct listnode *node; + if (circuit->state != C_STATE_UP || circuit->interface == NULL) + return ISIS_WARNING; + if ((circuit->circ_type == CIRCUIT_T_BROADCAST && !circuit->u.bc.is_dr[level - 1]) || circuit->circ_type != CIRCUIT_T_BROADCAST) @@ -2475,85 +2555,85 @@ send_lsp (struct thread *thread) circuit = THREAD_ARG (thread); assert (circuit); - if (circuit->state == C_STATE_UP) + if (circuit->state != C_STATE_UP || circuit->interface == NULL) + return ISIS_WARNING; + + lsp = listgetdata ((node = listhead (circuit->lsp_queue))); + + /* + * Do not send if levels do not match + */ + if (!(lsp->level & circuit->circuit_is_type)) + goto dontsend; + + /* + * Do not send if we do not have adjacencies in state up on the circuit + */ + if (circuit->upadjcount[lsp->level - 1] == 0) + goto dontsend; + /* only send if it needs sending */ + if ((time (NULL) - lsp->last_sent) >= + circuit->area->lsp_gen_interval[lsp->level - 1]) { - lsp = listgetdata ((node = listhead (circuit->lsp_queue))); - /* - * Do not send if levels do not match - */ - if (!(lsp->level & circuit->circuit_is_type)) - goto dontsend; + if (isis->debugs & DEBUG_UPDATE_PACKETS) + { + zlog_debug + ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x," + " lifetime %us on %s", circuit->area->area_tag, lsp->level, + rawlspid_print (lsp->lsp_header->lsp_id), + ntohl (lsp->lsp_header->seq_num), + ntohs (lsp->lsp_header->checksum), + ntohs (lsp->lsp_header->rem_lifetime), + circuit->interface->name); + } + /* copy our lsp to the send buffer */ + stream_copy (circuit->snd_stream, lsp->pdu); + + retval = circuit->tx (circuit, lsp->level); /* - * Do not send if we do not have adjacencies in state up on the circuit + * If the sending succeeded, we can del the lsp from circuits + * lsp_queue */ - if (circuit->upadjcount[lsp->level - 1] == 0) - goto dontsend; - /* only send if it needs sending */ - if ((time (NULL) - lsp->last_sent) >= - circuit->area->lsp_gen_interval[lsp->level - 1]) + if (retval == ISIS_OK) { - - if (isis->debugs & DEBUG_UPDATE_PACKETS) - { - zlog_debug - ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x," - " lifetime %us on %s", circuit->area->area_tag, lsp->level, - rawlspid_print (lsp->lsp_header->lsp_id), - ntohl (lsp->lsp_header->seq_num), - ntohs (lsp->lsp_header->checksum), - ntohs (lsp->lsp_header->rem_lifetime), - circuit->interface->name); - } - /* copy our lsp to the send buffer */ - stream_copy (circuit->snd_stream, lsp->pdu); - - retval = circuit->tx (circuit, lsp->level); + list_delete_node (circuit->lsp_queue, node); /* - * If the sending succeeded, we can del the lsp from circuits - * lsp_queue + * On broadcast circuits also the SRMflag can be cleared */ - if (retval == ISIS_OK) - { - list_delete_node (circuit->lsp_queue, node); + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); + if (flags_any_set (lsp->SRMflags) == 0) + { /* - * On broadcast circuits also the SRMflag can be cleared + * need to remember when we were last sent */ - if (circuit->circ_type == CIRCUIT_T_BROADCAST) - ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); - - if (flags_any_set (lsp->SRMflags) == 0) - { - /* - * need to remember when we were last sent - */ - lsp->last_sent = time (NULL); - } - } - else - { - zlog_debug ("sending of level %d link state failed", lsp->level); + lsp->last_sent = time (NULL); } } else { - /* my belief is that if it wasn't his time, the lsp can be removed - * from the queue - */ - dontsend: - list_delete_node (circuit->lsp_queue, node); + zlog_debug ("sending of level %d link state failed", lsp->level); } -#if 0 - /* - * If there are still LSPs send next one after lsp-interval (33 msecs) + } + else + { + /* my belief is that if it wasn't his time, the lsp can be removed + * from the queue */ - if (listcount (circuit->lsp_queue) > 0) - thread_add_timer (master, send_lsp, circuit, 1); -#endif + dontsend: + list_delete_node (circuit->lsp_queue, node); } +#if 0 + /* + * If there are still LSPs send next one after lsp-interval (33 msecs) + */ + if (listcount (circuit->lsp_queue) > 0) + thread_add_timer (master, send_lsp, circuit, 1); +#endif return retval; } diff --git a/isisd/isis_pdu.h b/isisd/isis_pdu.h index 95c1ee4f..c4c38e22 100644 --- a/isisd/isis_pdu.h +++ b/isisd/isis_pdu.h @@ -258,8 +258,7 @@ int ack_lsp (struct isis_link_state_hdr *hdr, void fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type); int send_hello (struct isis_circuit *circuit, int level); - -int authentication_check (struct isis_passwd *one, - struct isis_passwd *theother); +#define ISIS_AUTH_MD5_SIZE 16U +int authentication_check (struct isis_passwd *remote, struct isis_passwd *local, struct isis_circuit *c); #endif /* _ZEBRA_ISIS_PDU_H */ diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c index 9e4165e3..8a5c3ed0 100644 --- a/isisd/isis_pfpacket.c +++ b/isisd/isis_pfpacket.c @@ -232,6 +232,10 @@ isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa) LLC_LEN, MSG_PEEK, (struct sockaddr *) &s_addr, (socklen_t *) &addr_len); + if (!circuit->area) { + return ISIS_OK; + } + if (bytesread < 0) { zlog_warn ("isis_recv_packet_bcast(): fd %d, recvfrom (): %s", diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 633f0ad1..b183f044 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -407,12 +407,13 @@ isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype, if (adj) listnode_add (vertex->Adj_N, adj); + #ifdef EXTREME_DEBUG zlog_debug ("ISIS-Spf: add to TENT %s %s depth %d dist %d", vtype2string (vertex->type), vid2string (vertex, buff), vertex->depth, vertex->d_N); #endif /* EXTREME_DEBUG */ - listnode_add (spftree->tents, vertex); + if (list_isempty (spftree->tents)) { listnode_add (spftree->tents, vertex); @@ -551,7 +552,8 @@ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id, */ static int isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp, - uint32_t cost, uint16_t depth, int family) + uint32_t cost, uint16_t depth, int family, + struct isis_adjacency *adj) { struct listnode *node, *fragnode = NULL; u_int16_t dist; @@ -565,9 +567,6 @@ isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp, struct ipv6_reachability *ip6reach; #endif /* HAVE_IPV6 */ - - if (!lsp->adj) - return ISIS_WARNING; if (lsp->tlv_data.nlpids == NULL || !speaks (lsp->tlv_data.nlpids, family)) return ISIS_OK; @@ -593,7 +592,7 @@ lspfragloop: vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS : VTYPE_NONPSEUDO_IS; process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist, - depth + 1, lsp->adj, family); + depth + 1, adj, family); } } if (lsp->tlv_data.te_is_neighs) @@ -609,7 +608,7 @@ lspfragloop: vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS : VTYPE_NONPSEUDO_TE_IS; process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist, - depth + 1, lsp->adj, family); + depth + 1, adj, family); } } if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs) @@ -623,7 +622,7 @@ lspfragloop: prefix.u.prefix4 = ipreach->prefix; prefix.prefixlen = ip_masklen (ipreach->mask); process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, - lsp->adj, family); + adj, family); } } @@ -638,7 +637,7 @@ lspfragloop: prefix.u.prefix4 = ipreach->prefix; prefix.prefixlen = ip_masklen (ipreach->mask); process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, - lsp->adj, family); + adj, family); } } if (family == AF_INET && lsp->tlv_data.te_ipv4_reachs) @@ -653,7 +652,7 @@ lspfragloop: te_ipv4_reach->control); prefix.prefixlen = (te_ipv4_reach->control & 0x3F); process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, - lsp->adj, family); + adj, family); } } #ifdef HAVE_IPV6 @@ -670,7 +669,7 @@ lspfragloop: memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix, PSIZE (ip6reach->prefix_len)); process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, - lsp->adj, family); + adj, family); } } #endif /* HAVE_IPV6 */ @@ -693,7 +692,8 @@ lspfragloop: static int isis_spf_process_pseudo_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp, uint16_t cost, - uint16_t depth, int family) + uint16_t depth, int family, + struct isis_adjacency *adj) { struct listnode *node, *fragnode = NULL; struct is_neigh *is_neigh; @@ -717,13 +717,13 @@ pseudofragloop: /* Two way connectivity */ if (!memcmp (is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN)) continue; - if (isis_find_vertex - (spftree->tents, (void *) is_neigh->neigh_id, vtype) == NULL + if ((depth > 0 || isis_find_vertex + (spftree->tents, (void *) is_neigh->neigh_id, vtype) == NULL) && isis_find_vertex (spftree->paths, (void *) is_neigh->neigh_id, vtype) == NULL) { /* C.2.5 i) */ - isis_spf_add2tent (spftree, vtype, is_neigh->neigh_id, lsp->adj, + isis_spf_add2tent (spftree, vtype, is_neigh->neigh_id, adj, cost, depth, family); } } @@ -735,13 +735,13 @@ pseudofragloop: /* Two way connectivity */ if (!memcmp (te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN)) continue; - if (isis_find_vertex - (spftree->tents, (void *) te_is_neigh->neigh_id, vtype) == NULL + if ((depth > 0 || isis_find_vertex + (spftree->tents, (void *) te_is_neigh->neigh_id, vtype) == NULL) && isis_find_vertex (spftree->paths, (void *) te_is_neigh->neigh_id, vtype) == NULL) { /* C.2.5 i) */ - isis_spf_add2tent (spftree, vtype, te_is_neigh->neigh_id, lsp->adj, + isis_spf_add2tent (spftree, vtype, te_is_neigh->neigh_id, adj, cost, depth, family); } } @@ -862,9 +862,6 @@ isis_spf_preload_tent (struct isis_spftree *spftree, lsp = lsp_search (lsp_id, area->lspdb[level - 1]); if (!lsp) zlog_warn ("No lsp found for IS adjacency"); - /* else { - isis_spf_process_lsp (spftree, lsp, vertex->d_N, 1, family); - } */ break; case ISIS_SYSTYPE_UNKNOWN: default: @@ -887,14 +884,14 @@ isis_spf_preload_tent (struct isis_spftree *spftree, { zlog_warn ("ISIS-Spf: No adjacency found for DR"); } - if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0) + else if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0) { zlog_warn ("ISIS-Spf: No lsp found for DR"); } else { isis_spf_process_pseudo_lsp (spftree, lsp, - circuit->te_metric[level - 1], 0, family); + circuit->te_metric[level - 1], 0, family, adj); } } @@ -984,6 +981,7 @@ isis_run_spf (struct isis_area *area, int level, int family) struct isis_spftree *spftree = NULL; u_char lsp_id[ISIS_SYS_ID_LEN + 2]; struct isis_lsp *lsp; + struct isis_adjacency *adj = NULL; struct route_table *table = NULL; struct route_node *rode; struct isis_route_info *rinfo; @@ -1034,16 +1032,28 @@ isis_run_spf (struct isis_area *area, int level, int family) while (listcount (spftree->tents) > 0) { + /* C.2.7 a) 1) */ node = listhead (spftree->tents); vertex = listgetdata (node); - /* Remove from tent list */ + + /* C.2.7 a) 2) */ list_delete_node (spftree->tents, node); + + /* C.2.7 a) 3) */ if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type)) continue; add_to_paths (spftree, vertex, area, level); + if (vertex->type == VTYPE_PSEUDO_IS || - vertex->type == VTYPE_NONPSEUDO_IS) + vertex->type == VTYPE_NONPSEUDO_IS || + vertex->type == VTYPE_PSEUDO_TE_IS || + vertex->type == VTYPE_NONPSEUDO_TE_IS ) { + if (listcount(vertex->Adj_N) == 0) { + continue; + } + adj = listgetdata(vertex->Adj_N->head); + memcpy (lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1); LSP_FRAGMENT (lsp_id) = 0; lsp = lsp_search (lsp_id, area->lspdb[level - 1]); @@ -1052,13 +1062,12 @@ isis_run_spf (struct isis_area *area, int level, int family) if (LSP_PSEUDO_ID (lsp_id)) { isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N, - vertex->depth, family); - + vertex->depth, family, adj); } else { isis_spf_process_lsp (spftree, lsp, vertex->d_N, - vertex->depth, family); + vertex->depth, family, adj); } } else diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c index 94fa65ed..3fc717e3 100644 --- a/isisd/isis_tlv.c +++ b/isisd/isis_tlv.c @@ -446,6 +446,10 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, tlvs->auth_info.len = length-1; pnt++; memcpy (tlvs->auth_info.passwd, pnt, length - 1); + /* Fill authentication with 0 for later computation + * of MD5 (RFC 5304, 2) + */ + memset (pnt, 0, length - 1); pnt += length - 1; } else @@ -741,7 +745,7 @@ add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream) stream_putc (stream, len); /* LENGTH */ stream_put (stream, value, (int) len); /* VALUE */ -#ifdef EXTREME_DEBUG +#ifdef EXTREME_TLV_DEBUG zlog_debug ("Added TLV %d len %d", tag, len); #endif /* EXTREME DEBUG */ return ISIS_OK; @@ -878,7 +882,7 @@ tlv_add_authinfo (char auth_type, char auth_len, u_char *auth_value, { u_char value[255]; u_char *pos = value; - *pos++ = ISIS_PASSWD_TYPE_CLEARTXT; + *pos++ = auth_type; memcpy (pos, auth_value, auth_len); return add_tlv (AUTH_INFO, auth_len + 1, value, stream); diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 94c3f351..d7717245 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -274,6 +274,8 @@ isis_zebra_route_add_ipv4 (struct prefix *prefix, stream_putc (stream, flags); /* message */ stream_putc (stream, message); + /* SAFI */ + stream_putw (stream, SAFI_UNICAST); /* prefix information */ psize = PSIZE (prefix->prefixlen); stream_putc (stream, prefix->prefixlen); @@ -321,6 +323,7 @@ isis_zebra_route_del_ipv4 (struct prefix *prefix, api.type = ZEBRA_ROUTE_ISIS; api.flags = 0; api.message = 0; + api.safi = SAFI_UNICAST; prefix4.family = AF_INET; prefix4.prefixlen = prefix->prefixlen; prefix4.prefix = prefix->u.prefix4; @@ -350,6 +353,7 @@ isis_zebra_route_add_ipv6 (struct prefix *prefix, api.type = ZEBRA_ROUTE_ISIS; api.flags = 0; api.message = 0; + api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); @@ -433,6 +437,7 @@ isis_zebra_route_del_ipv6 (struct prefix *prefix, api.type = ZEBRA_ROUTE_ISIS; api.flags = 0; api.message = 0; + api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); api.nexthop_num = listcount (route_info->nexthops6); diff --git a/isisd/isisd.c b/isisd/isisd.c index 9b07ab88..b18c5a92 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -52,6 +52,7 @@ #include "isisd/isis_route.h" #include "isisd/isis_zebra.h" #include "isisd/isis_events.h" +#include "isisd/isis_csm.h" #ifdef TOPOLOGY_GENERATE #include "spgrid.h" @@ -217,21 +218,31 @@ isis_area_destroy (struct vty *vty, const char *area_tag) for (ALL_LIST_ELEMENTS (area->circuit_list, node, nnode, circuit)) { /* The fact that it's in circuit_list means that it was configured */ + isis_csm_state_change (ISIS_DISABLE, circuit, area); + isis_circuit_down (circuit); isis_circuit_deconfigure (circuit, area); - isis_circuit_del (circuit); } list_delete (area->circuit_list); } listnode_delete (isis->area_list, area); + THREAD_TIMER_OFF (area->t_tick); if (area->t_remove_aged) thread_cancel (area->t_remove_aged); THREAD_TIMER_OFF (area->t_lsp_refresh[0]); THREAD_TIMER_OFF (area->t_lsp_refresh[1]); + THREAD_TIMER_OFF (area->spftree[0]->t_spf); + THREAD_TIMER_OFF (area->spftree[1]->t_spf); + + THREAD_TIMER_OFF (area->t_lsp_l1_regenerate); + THREAD_TIMER_OFF (area->t_lsp_l2_regenerate); + XFREE (MTYPE_ISIS_AREA, area); + isis->sysid_set=0; + return CMD_SUCCESS; } diff --git a/isisd/isisd.h b/isisd/isisd.h index 2277f27c..b17982e2 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -93,6 +93,8 @@ struct isis_area struct flags flags; struct thread *t_tick; /* LSP walker */ struct thread *t_remove_aged; + struct thread *t_lsp_l1_regenerate; + struct thread *t_lsp_l2_regenerate; int lsp_regenerate_pending[ISIS_LEVELS]; struct thread *t_lsp_refresh[ISIS_LEVELS]; diff --git a/isisd/topology/.cvsignore b/isisd/topology/.cvsignore deleted file mode 100644 index b0ae823b..00000000 --- a/isisd/topology/.cvsignore +++ /dev/null @@ -1,9 +0,0 @@ -Makefile -Makefile.in -*.o -tags -TAGS -.deps -.nfs* -.arch-inventory -.arch-ids diff --git a/lib/.cvsignore b/lib/.cvsignore deleted file mode 100644 index 806696d7..00000000 --- a/lib/.cvsignore +++ /dev/null @@ -1,14 +0,0 @@ -Makefile -Makefile.in -*.o -*.lo -*.la -version.c -version.h -.deps -.nfs* -.libs -.arch-inventory -.arch-ids -memtypes.h -route_types.h diff --git a/lib/Makefile.am b/lib/Makefile.am index 24114e9e..b86165fb 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -30,7 +30,7 @@ libzebra_la_DEPENDENCIES = @LIB_REGEX@ libzebra_la_LIBADD = @LIB_REGEX@ pkginclude_HEADERS = \ - avl.h command.h command_common.h command_execute.h \ + avl.h buffer.h command.h command_common.h command_execute.h \ command_local.h command_parse.h command_queue.h confirm.h \ distribute.h elstring.h errno_names.h filter.h getopt.h \ hash.h heap.h if.h if_rmap.h jhash.h keychain.h \ @@ -49,10 +49,10 @@ pkginclude_HEADERS = \ workqueue.h zassert.h zclient.h \ zconfig.h zebra.h -EXTRA_DIST = regex.c regex-gnu.h memtypes.awk route_types.awk route_types.txt +EXTRA_DIST = regex.c regex-gnu.h memtypes.awk route_types.pl route_types.txt memtypes.h: $(srcdir)/memtypes.c $(srcdir)/memtypes.awk ($(GAWK) -f $(srcdir)/memtypes.awk $(srcdir)/memtypes.c > $@) -route_types.h: $(srcdir)/route_types.txt $(srcdir)/route_types.awk - ($(GAWK) -f $(srcdir)/route_types.awk $(srcdir)/route_types.txt > $@) +route_types.h: $(srcdir)/route_types.txt $(srcdir)/route_types.pl + @PERL@ $(srcdir)/route_types.pl < $(srcdir)/route_types.txt > $@ diff --git a/lib/command.c b/lib/command.c index ba81afa8..c23e863d 100644 --- a/lib/command.c +++ b/lib/command.c @@ -1,26 +1,25 @@ -/* - $Id$ - - Command interpreter routine for virtual terminal [aka TeletYpe] - Copyright (C) 1997, 98, 99 Kunihiro Ishiguro - -This file is part of GNU Zebra. - -GNU Zebra is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published -by the Free Software Foundation; either version 2, or (at your -option) any later version. - -GNU Zebra is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -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. */ - +/* Command interpreter routine for virtual terminal [aka TeletYpe] + * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + * + * Revisions: Copyright (C) 2010 Chris Hall (GMCH), Highwayman + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * 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. + */ #include "misc.h" #include "version.h" diff --git a/lib/distribute.c b/lib/distribute.c index 48417d3d..ff4a6141 100644 --- a/lib/distribute.c +++ b/lib/distribute.c @@ -300,7 +300,6 @@ DEFUN (distribute_list_all, "Filter outgoing routing updates\n") { enum distribute_type type; - struct distribute *dist; /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) @@ -315,7 +314,7 @@ DEFUN (distribute_list_all, } /* Get interface name corresponding distribute list. */ - dist = distribute_list_set (NULL, type, argv[0]); + distribute_list_set (NULL, type, argv[0]); return CMD_SUCCESS; } @@ -380,7 +379,6 @@ DEFUN (distribute_list, "Interface name\n") { enum distribute_type type; - struct distribute *dist; /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) @@ -394,7 +392,7 @@ DEFUN (distribute_list, } /* Get interface name corresponding distribute list. */ - dist = distribute_list_set (argv[2], type, argv[0]); + distribute_list_set (argv[2], type, argv[0]); return CMD_SUCCESS; } @@ -408,7 +406,7 @@ ALIAS (distribute_list, "Filter outgoing routing updates\n" "Interface name\n") -DEFUN (no_districute_list, no_distribute_list_cmd, +DEFUN (no_distribute_list, no_distribute_list_cmd, "no distribute-list WORD (in|out) WORD", NO_STR "Filter networks in routing updates\n" @@ -440,7 +438,7 @@ DEFUN (no_districute_list, no_distribute_list_cmd, return CMD_SUCCESS; } -ALIAS (no_districute_list, no_ipv6_distribute_list_cmd, +ALIAS (no_distribute_list, no_ipv6_distribute_list_cmd, "no distribute-list WORD (in|out) WORD", NO_STR "Filter networks in routing updates\n" @@ -449,7 +447,7 @@ ALIAS (no_districute_list, no_ipv6_distribute_list_cmd, "Filter outgoing routing updates\n" "Interface name\n") -DEFUN (districute_list_prefix_all, +DEFUN (distribute_list_prefix_all, distribute_list_prefix_all_cmd, "distribute-list prefix WORD (in|out)", "Filter networks in routing updates\n" @@ -459,7 +457,6 @@ DEFUN (districute_list_prefix_all, "Filter outgoing routing updates\n") { enum distribute_type type; - struct distribute *dist; /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) @@ -474,12 +471,12 @@ DEFUN (districute_list_prefix_all, } /* Get interface name corresponding distribute list. */ - dist = distribute_list_prefix_set (NULL, type, argv[0]); + distribute_list_prefix_set (NULL, type, argv[0]); return CMD_SUCCESS; } -ALIAS (districute_list_prefix_all, +ALIAS (distribute_list_prefix_all, ipv6_distribute_list_prefix_all_cmd, "distribute-list prefix WORD (in|out)", "Filter networks in routing updates\n" @@ -488,7 +485,7 @@ ALIAS (districute_list_prefix_all, "Filter incoming routing updates\n" "Filter outgoing routing updates\n") -DEFUN (no_districute_list_prefix_all, +DEFUN (no_distribute_list_prefix_all, no_distribute_list_prefix_all_cmd, "no distribute-list prefix WORD (in|out)", NO_STR @@ -522,7 +519,7 @@ DEFUN (no_districute_list_prefix_all, return CMD_SUCCESS; } -ALIAS (no_districute_list_prefix_all, +ALIAS (no_distribute_list_prefix_all, no_ipv6_distribute_list_prefix_all_cmd, "no distribute-list prefix WORD (in|out)", NO_STR @@ -532,7 +529,7 @@ ALIAS (no_districute_list_prefix_all, "Filter incoming routing updates\n" "Filter outgoing routing updates\n") -DEFUN (districute_list_prefix, distribute_list_prefix_cmd, +DEFUN (distribute_list_prefix, distribute_list_prefix_cmd, "distribute-list prefix WORD (in|out) WORD", "Filter networks in routing updates\n" "Filter prefixes in routing updates\n" @@ -542,7 +539,6 @@ DEFUN (districute_list_prefix, distribute_list_prefix_cmd, "Interface name\n") { enum distribute_type type; - struct distribute *dist; /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) @@ -557,12 +553,12 @@ DEFUN (districute_list_prefix, distribute_list_prefix_cmd, } /* Get interface name corresponding distribute list. */ - dist = distribute_list_prefix_set (argv[2], type, argv[0]); + distribute_list_prefix_set (argv[2], type, argv[0]); return CMD_SUCCESS; } -ALIAS (districute_list_prefix, ipv6_distribute_list_prefix_cmd, +ALIAS (distribute_list_prefix, ipv6_distribute_list_prefix_cmd, "distribute-list prefix WORD (in|out) WORD", "Filter networks in routing updates\n" "Filter prefixes in routing updates\n" @@ -571,7 +567,7 @@ ALIAS (districute_list_prefix, ipv6_distribute_list_prefix_cmd, "Filter outgoing routing updates\n" "Interface name\n") -DEFUN (no_districute_list_prefix, no_distribute_list_prefix_cmd, +DEFUN (no_distribute_list_prefix, no_distribute_list_prefix_cmd, "no distribute-list prefix WORD (in|out) WORD", NO_STR "Filter networks in routing updates\n" @@ -605,7 +601,7 @@ DEFUN (no_districute_list_prefix, no_distribute_list_prefix_cmd, return CMD_SUCCESS; } -ALIAS (no_districute_list_prefix, no_ipv6_distribute_list_prefix_cmd, +ALIAS (no_distribute_list_prefix, no_ipv6_distribute_list_prefix_cmd, "no distribute-list prefix WORD (in|out) WORD", NO_STR "Filter networks in routing updates\n" diff --git a/lib/filter.c b/lib/filter.c index bc9ccf55..414fc367 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -226,7 +226,7 @@ access_list_free (struct access_list *access) /* Delete access_list from access_master and free it. */ static void -access_list_delete (struct access_list *access) +access_list_delete (struct access_list *access, bool call_hook) { struct filter *filter; struct filter *next; @@ -256,12 +256,22 @@ access_list_delete (struct access_list *access) else list->head = access->next; - if (access->name) - XFREE (MTYPE_ACCESS_LIST_STR, access->name); - if (access->remark) XFREE (MTYPE_TMP, access->remark); + /* If we are to call the delete_hook, then now is the time to do it. + * + * The contents of the access-list have been emptied out, and just the + * name remains. + */ + if (call_hook && (master->delete_hook != NULL)) + master->delete_hook(access) ; + + /* Finish off the job + */ + if (access->name) + XFREE (MTYPE_ACCESS_LIST_STR, access->name); + access_list_free (access); } @@ -493,13 +503,17 @@ access_list_filter_delete (struct access_list *access, struct filter *filter) filter_free (filter); - /* If access_list becomes empty delete it from access_master. */ + /* If access_list becomes empty delete it from access_master and run the + * delete_hook at the right moment. + * + * TODO -- note that this deletes the access list even if a "remark" remains + * + * Otherwise, run the delete hook. + */ if (access_list_empty (access)) - access_list_delete (access); - - /* Run hook function. */ - if (master->delete_hook) - (*master->delete_hook) (access); + access_list_delete (access, true /* run delete_hook */); + else if (master->delete_hook) + master->delete_hook(access); } /* @@ -588,8 +602,8 @@ vty_access_list_remark_unset (struct vty *vty, afi_t afi, const char *name) access->remark = NULL; } - if (access->head == NULL && access->tail == NULL && access->remark == NULL) - access_list_delete (access); + if (access_list_empty (access)) + access_list_delete (access, true /* run delete_hook */); return CMD_SUCCESS; } @@ -1337,15 +1351,10 @@ DEFUN (no_access_list_all, master = access->master; - /* Delete all filter from access-list. */ - access_list_delete (access); - - /* Run hook function. */ - if (master->delete_hook) - (*master->delete_hook) (access); + access_list_delete (access, true /* run delete_hook */); return CMD_SUCCESS; -} +} ; DEFUN (access_list_remark, access_list_remark_cmd, @@ -1508,12 +1517,7 @@ DEFUN (no_ipv6_access_list_all, master = access->master; - /* Delete all filter from access-list. */ - access_list_delete (access); - - /* Run hook function. */ - if (master->delete_hook) - (*master->delete_hook) (access); + access_list_delete (access, true /* run delete_hook */); return CMD_SUCCESS; } @@ -1876,12 +1880,12 @@ access_list_reset_ipv4 (void) for (access = master->num.head; access; access = next) { next = access->next; - access_list_delete (access); + access_list_delete (access, false /* do not delete_hook() TODO ??? */); } for (access = master->str.head; access; access = next) { next = access->next; - access_list_delete (access); + access_list_delete (access, false /* do not delete_hook() TODO ??? */); } assert (master->num.head == NULL); @@ -1965,12 +1969,12 @@ access_list_reset_ipv6 (void) for (access = master->num.head; access; access = next) { next = access->next; - access_list_delete (access); + access_list_delete (access, false /* do not delete_hook() TODO ??? */); } for (access = master->str.head; access; access = next) { next = access->next; - access_list_delete (access); + access_list_delete (access, false /* do not delete_hook() TODO ??? */); } assert (master->num.head == NULL); @@ -428,19 +428,17 @@ if_dump (const struct interface *ifp) struct listnode *node; struct connected *c; - zlog_info ("Interface %s index %d metric %d mtu %d " + for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, c)) + zlog_info ("Interface %s index %d metric %d mtu %d " #ifdef HAVE_IPV6 - "mtu6 %d " + "mtu6 %d " #endif /* HAVE_IPV6 */ "%s", ifp->name, ifp->ifindex, ifp->metric, ifp->mtu, #ifdef HAVE_IPV6 - ifp->mtu6, + ifp->mtu6, #endif /* HAVE_IPV6 */ if_flag_dump (ifp->flags)); - - for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, c)) - ; } /* Interface printing for all interface. */ diff --git a/lib/if_rmap.c b/lib/if_rmap.c index 60fc7ef6..eaf2ab82 100644 --- a/lib/if_rmap.c +++ b/lib/if_rmap.c @@ -208,7 +208,6 @@ DEFUN (if_rmap, "Route map interface name\n") { enum if_rmap_type type; - struct if_rmap *if_rmap; if (strncmp (argv[1], "i", 1) == 0) type = IF_RMAP_IN; @@ -220,7 +219,7 @@ DEFUN (if_rmap, return CMD_WARNING; } - if_rmap = if_rmap_set (argv[2], type, argv[0]); + if_rmap_set (argv[2], type, argv[0]); return CMD_SUCCESS; } @@ -1,6 +1,4 @@ /* - * $Id$ - * * Logging of zebra * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro * @@ -22,6 +20,8 @@ * 02111-1307, USA. */ +#define QUAGGA_DEFINE_DESC_TABLE + #include <zebra.h> #include "log.h" @@ -1539,7 +1539,8 @@ lookup (const struct message *mes, int key) * provided otherwise. */ const char * -mes_lookup (const struct message *meslist, int max, int index, const char *none) +mes_lookup (const struct message *meslist, int max, int index, + const char *none, const char *mesname) { int pos = index - meslist[0].key; @@ -1562,17 +1563,20 @@ mes_lookup (const struct message *meslist, int max, int index, const char *none) { const char *str = (meslist->str ? meslist->str : none); - zlog_debug ("message index %d [%s] found in position %d (max is %d)", - index, str, i, max); + zlog_debug ("message index %d [%s] found in %s at position %d " + "(max is %d)", + index, str, mesname, i, max); return str; } } } - zlog_err("message index %d not found (max is %d)", index, max); + zlog_err("message index %d not found in %s (max is %d)", index, mesname, max); assert (none); return none; } +#ifndef QUAGGA_DEFINE_DESC_TABLE + struct zebra_desc_table { unsigned int type; @@ -1596,6 +1600,8 @@ static const struct zebra_desc_table route_types[] = { }; #undef DESC_ENTRY +#endif + #define DESC_ENTRY(T) [(T)] = { (T), (#T), '\0' } static const struct zebra_desc_table command_types[] = { DESC_ENTRY (ZEBRA_INTERFACE_ADD), @@ -1620,6 +1626,7 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY (ZEBRA_ROUTER_ID_ADD), DESC_ENTRY (ZEBRA_ROUTER_ID_DELETE), DESC_ENTRY (ZEBRA_ROUTER_ID_UPDATE), + DESC_ENTRY (ZEBRA_HELLO), }; #undef DESC_ENTRY @@ -1685,4 +1692,48 @@ proto_name2num(const char *s) return route_types[i].type; return -1; } + #undef RTSIZE + +int +proto_redistnum(int afi, const char *s) +{ + if (! s) + return -1; + + if (afi == AFI_IP) + { + if (strncmp (s, "k", 1) == 0) + return ZEBRA_ROUTE_KERNEL; + else if (strncmp (s, "c", 1) == 0) + return ZEBRA_ROUTE_CONNECT; + else if (strncmp (s, "s", 1) == 0) + return ZEBRA_ROUTE_STATIC; + else if (strncmp (s, "r", 1) == 0) + return ZEBRA_ROUTE_RIP; + else if (strncmp (s, "o", 1) == 0) + return ZEBRA_ROUTE_OSPF; + else if (strncmp (s, "i", 1) == 0) + return ZEBRA_ROUTE_ISIS; + else if (strncmp (s, "b", 1) == 0) + return ZEBRA_ROUTE_BGP; + } + if (afi == AFI_IP6) + { + if (strncmp (s, "k", 1) == 0) + return ZEBRA_ROUTE_KERNEL; + else if (strncmp (s, "c", 1) == 0) + return ZEBRA_ROUTE_CONNECT; + else if (strncmp (s, "s", 1) == 0) + return ZEBRA_ROUTE_STATIC; + else if (strncmp (s, "r", 1) == 0) + return ZEBRA_ROUTE_RIPNG; + else if (strncmp (s, "o", 1) == 0) + return ZEBRA_ROUTE_OSPF6; + else if (strncmp (s, "i", 1) == 0) + return ZEBRA_ROUTE_ISIS; + else if (strncmp (s, "b", 1) == 0) + return ZEBRA_ROUTE_BGP; + } + return -1; +} @@ -1,6 +1,4 @@ /* - * $Id$ - * * Zebra logging funcions. * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro * @@ -103,12 +101,13 @@ struct message /* For message lookup. */ extern const char * zlog_get_proto_name (struct zlog *zl); -#define LOOKUP(x, y) mes_lookup(x, x ## _max, y, "(no item found)") +/* For hackey massage lookup and check */ +#define LOOKUP(x, y) mes_lookup(x, x ## _max, y, "(no item found)", #x) extern const char *lookup (const struct message *, int); extern const char *mes_lookup (const struct message *meslist, int max, int index, - const char *no_item); + const char *no_item, const char *mesname); extern const char *zlog_priority[]; extern const char *zlog_proto_names[]; @@ -130,7 +130,7 @@ static const uint8_t md5_paddat[MD5_BUFLEN] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, }; static void md5_calc (const uint8_t *, md5_ctxt *); @@ -161,7 +161,7 @@ void md5_loop(md5_ctxt *ctxt, const void *vinput, uint len) for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) { md5_calc((input + i), ctxt); } - + ctxt->md5_i = len - i; memcpy (ctxt->md5_buf, (input + i), ctxt->md5_i); } else { @@ -174,10 +174,10 @@ void md5_pad(md5_ctxt *ctxt) { uint gap; - /* Don't count up padding. Keep md5_n. */ + /* Don't count up padding. Keep md5_n. */ gap = MD5_BUFLEN - ctxt->md5_i; if (gap > 8) { - memcpy (ctxt->md5_buf + ctxt->md5_i, md5_paddat, + memcpy (ctxt->md5_buf + ctxt->md5_i, md5_paddat, gap - sizeof(ctxt->md5_n)); } else { /* including gap == 8 */ @@ -187,7 +187,7 @@ void md5_pad(md5_ctxt *ctxt) MD5_BUFLEN - sizeof(ctxt->md5_n)); } - /* 8 byte word */ + /* 8 byte word */ if (BYTE_ORDER == LITTLE_ENDIAN) memcpy (&ctxt->md5_buf[56], &ctxt->md5_n8[0], 8); else @@ -265,7 +265,7 @@ static void md5_calc(const uint8_t *b64, md5_ctxt * ctxt) ROUND1(C, D, A, B, 10, Sc, 11); ROUND1(B, C, D, A, 11, Sd, 12); ROUND1(A, B, C, D, 12, Sa, 13); ROUND1(D, A, B, C, 13, Sb, 14); ROUND1(C, D, A, B, 14, Sc, 15); ROUND1(B, C, D, A, 15, Sd, 16); - + ROUND2(A, B, C, D, 1, Se, 17); ROUND2(D, A, B, C, 6, Sf, 18); ROUND2(C, D, A, B, 11, Sg, 19); ROUND2(B, C, D, A, 0, Sh, 20); ROUND2(A, B, C, D, 5, Se, 21); ROUND2(D, A, B, C, 10, Sf, 22); @@ -283,14 +283,14 @@ static void md5_calc(const uint8_t *b64, md5_ctxt * ctxt) ROUND3(C, D, A, B, 3, Sk, 43); ROUND3(B, C, D, A, 6, Sl, 44); ROUND3(A, B, C, D, 9, Si, 45); ROUND3(D, A, B, C, 12, Sj, 46); ROUND3(C, D, A, B, 15, Sk, 47); ROUND3(B, C, D, A, 2, Sl, 48); - - ROUND4(A, B, C, D, 0, Sm, 49); ROUND4(D, A, B, C, 7, Sn, 50); - ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A, 5, Sp, 52); - ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C, 3, Sn, 54); - ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A, 1, Sp, 56); - ROUND4(A, B, C, D, 8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58); - ROUND4(C, D, A, B, 6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60); - ROUND4(A, B, C, D, 4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62); + + ROUND4(A, B, C, D, 0, Sm, 49); ROUND4(D, A, B, C, 7, Sn, 50); + ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A, 5, Sp, 52); + ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C, 3, Sn, 54); + ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A, 1, Sp, 56); + ROUND4(A, B, C, D, 8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58); + ROUND4(C, D, A, B, 6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60); + ROUND4(A, B, C, D, 4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62); ROUND4(C, D, A, B, 2, So, 63); ROUND4(B, C, D, A, 9, Sp, 64); ctxt->md5_sta += A; @@ -298,3 +298,76 @@ static void md5_calc(const uint8_t *b64, md5_ctxt * ctxt) ctxt->md5_stc += C; ctxt->md5_std += D; } + +/* From RFC 2104 */ +void +hmac_md5(text, text_len, key, key_len, digest) +unsigned char* text; /* pointer to data stream */ +int text_len; /* length of data stream */ +unsigned char* key; /* pointer to authentication key */ +int key_len; /* length of authentication key */ +unsigned char* digest; /* caller digest to be filled in */ + +{ + MD5_CTX context; + unsigned char k_ipad[65]; /* inner padding - + * key XORd with ipad + */ + unsigned char k_opad[65]; /* outer padding - + * key XORd with opad + */ + unsigned char tk[16]; + int i; + /* if key is longer than 64 bytes reset it to key=MD5(key) */ + if (key_len > 64) { + + MD5_CTX tctx; + + MD5Init(&tctx); + MD5Update(&tctx, key, key_len); + MD5Final(tk, &tctx); + + key = tk; + key_len = 16; + } + + /* + * the HMAC_MD5 transform looks like: + * + * MD5(K XOR opad, MD5(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected + */ + + /* start out by storing key in pads */ + bzero( k_ipad, sizeof k_ipad); + bzero( k_opad, sizeof k_opad); + bcopy( key, k_ipad, key_len); + bcopy( key, k_opad, key_len); + + /* XOR key with ipad and opad values */ + for (i=0; i<64; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + /* + * perform inner MD5 + */ + MD5Init(&context); /* init context for 1st + * pass */ + MD5Update(&context, k_ipad, 64); /* start with inner pad */ + MD5Update(&context, text, text_len); /* then text of datagram */ + MD5Final(digest, &context); /* finish up 1st pass */ + /* + * perform outer MD5 + */ + MD5Init(&context); /* init context for 2nd + * pass */ + MD5Update(&context, k_opad, 64); /* start with outer pad */ + MD5Update(&context, digest, 16); /* then results of 1st + * hash */ + MD5Final(digest, &context); /* finish up 2nd pass */ +} @@ -82,4 +82,8 @@ do { \ md5_result((x), (y)); \ } while (0) +/* From RFC 2104 */ +void hmac_md5(unsigned char* text, int text_len, unsigned char* key, + int key_len, unsigned char* digest); + #endif /* ! _LIBZEBRA_MD5_H_*/ diff --git a/lib/memtypes.c b/lib/memtypes.c index 3c502df3..8eddd45a 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -5,8 +5,6 @@ * * The script is sensitive to the format (though not whitespace), see * the top of memtypes.awk for more details. - * - * $Id$ */ #include "zebra.h" @@ -133,6 +133,12 @@ typedef unsigned int uint ; typedef unsigned int usize ; typedef unsigned int ulen ; +enum +{ + USIZE_MAX = UINT_MAX, + ULEN_MAX = UINT_MAX, +} ; + typedef int ssize ; typedef int slen ; diff --git a/lib/prefix.c b/lib/prefix.c index e226ec3e..d8df359a 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -29,9 +29,335 @@ #include "log.h" #include "tstring.h" -/* Maskbit. */ -static const u_char maskbit[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, - 0xf8, 0xfc, 0xfe, 0xff }; +/* Maskbit -- mask for last significant byte of a prefix: maskbit[len % 8] + */ +static const uint8_t maskbit[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, + 0xf8, 0xfc, 0xfe, 0xff }; + +/* IPv4 masks -- address in *host* order + */ +static const uint32_t in_addr_mask_h[] = +{ + 0x00000000, /* /0 0.0.0.0 */ + 0x80000000, /* /1 128.0.0.0 */ + 0xc0000000, /* /2 192.0.0.0 */ + 0xe0000000, /* /3 224.0.0.0 */ + 0xf0000000, /* /4 240.0.0.0 */ + 0xf8000000, /* /5 248.0.0.0 */ + 0xfc000000, /* /6 252.0.0.0 */ + 0xfe000000, /* /7 254.0.0.0 */ + 0xff000000, /* /8 255.0.0.0 */ + 0xff800000, /* /9 255.128.0.0 */ + 0xffc00000, /* /10 255.192.0.0 */ + 0xffe00000, /* /11 255.224.0.0 */ + 0xfff00000, /* /12 255.240.0.0 */ + 0xfff80000, /* /13 255.248.0.0 */ + 0xfffc0000, /* /14 255.252.0.0 */ + 0xfffe0000, /* /15 255.254.0.0 */ + 0xffff0000, /* /16 255.255.0.0 */ + 0xffff8000, /* /17 255.255.128.0 */ + 0xffffc000, /* /18 255.255.192.0 */ + 0xffffe000, /* /19 255.255.224.0 */ + 0xfffff000, /* /20 255.255.240.0 */ + 0xfffff800, /* /21 255.255.248.0 */ + 0xfffffc00, /* /22 255.255.252.0 */ + 0xfffffe00, /* /23 255.255.254.0 */ + 0xffffff00, /* /24 255.255.255.0 */ + 0xffffff80, /* /25 255.255.255.128 */ + 0xffffffc0, /* /26 255.255.255.192 */ + 0xffffffe0, /* /27 255.255.255.224 */ + 0xfffffff0, /* /28 255.255.255.240 */ + 0xfffffff8, /* /29 255.255.255.248 */ + 0xfffffffc, /* /30 255.255.255.252 */ + 0xfffffffe, /* /31 255.255.255.254 */ + 0xffffffff /* /32 255.255.255.255 */ +}; + +/* IPv4 masks -- address in *network* order + */ +#if BYTE_ORDER == BIG_ENDIAN + +#define in_addr_mask_n in_addr_mask_h + +#elif BYTE_ORDER == LITTLE_ENDIAN + +static const u_int32_t in_addr_mask_n[] = +{ + 0x00000000, /* /0 0.0.0.0 */ + 0x00000080, /* /1 128.0.0.0 */ + 0x000000c0, /* /2 192.0.0.0 */ + 0x000000e0, /* /3 224.0.0.0 */ + 0x000000f0, /* /4 240.0.0.0 */ + 0x000000f8, /* /5 248.0.0.0 */ + 0x000000fc, /* /6 252.0.0.0 */ + 0x000000fe, /* /7 254.0.0.0 */ + 0x000000ff, /* /8 255.0.0.0 */ + 0x000080ff, /* /9 255.128.0.0 */ + 0x0000c0ff, /* /10 255.192.0.0 */ + 0x0000e0ff, /* /11 255.224.0.0 */ + 0x0000f0ff, /* /12 255.240.0.0 */ + 0x0000f8ff, /* /13 255.248.0.0 */ + 0x0000fcff, /* /14 255.252.0.0 */ + 0x0000feff, /* /15 255.254.0.0 */ + 0x0000ffff, /* /16 255.255.0.0 */ + 0x0080ffff, /* /17 255.255.128.0 */ + 0x00c0ffff, /* /18 255.255.192.0 */ + 0x00e0ffff, /* /19 255.255.224.0 */ + 0x00f0ffff, /* /20 255.255.240.0 */ + 0x00f8ffff, /* /21 255.255.248.0 */ + 0x00fcffff, /* /22 255.255.252.0 */ + 0x00feffff, /* /23 255.255.254.0 */ + 0x00ffffff, /* /24 255.255.255.0 */ + 0x80ffffff, /* /25 255.255.255.128 */ + 0xc0ffffff, /* /26 255.255.255.192 */ + 0xe0ffffff, /* /27 255.255.255.224 */ + 0xf0ffffff, /* /28 255.255.255.240 */ + 0xf8ffffff, /* /29 255.255.255.248 */ + 0xfcffffff, /* /30 255.255.255.252 */ + 0xfeffffff, /* /31 255.255.255.254 */ + 0xffffffff /* /32 255.255.255.255 */ +}; + +#endif /* BYTE_ORDER == ZZZ */ + +/* IPv6 masks -- address in *network* order + */ +#define FFx1 0xFF +#define FFx2 0xFF, 0xFF +#define FFx3 0xFF, 0xFF, 0xFF +#define FFx4 0xFF, 0xFF, 0xFF, 0xFF +#define FFx5 FFx4, FFx1 +#define FFx6 FFx4, FFx2 +#define FFx7 FFx4, FFx3 +#define FFx8 FFx4, FFx4 +#define FFx9 FFx4, FFx4, FFx1 +#define FFx10 FFx4, FFx4, FFx2 +#define FFx11 FFx4, FFx4, FFx3 +#define FFx12 FFx4, FFx4, FFx4 +#define FFx13 FFx4, FFx4, FFx4, FFx1 +#define FFx14 FFx4, FFx4, FFx4, FFx2 +#define FFx15 FFx4, FFx4, FFx4, FFx3 +#define FFx16 FFx4, FFx4, FFx4, FFx4 + +static const byte in_addr6_mask_n[129][sizeof(struct in6_addr)] = +{ + [ 0] = { 0x00 }, + [ 1] = { 0x80 }, + [ 2] = { 0xc0 }, + [ 3] = { 0xe0 }, + [ 4] = { 0xf0 }, + [ 5] = { 0xf8 }, + [ 6] = { 0xfc }, + [ 7] = { 0xfe }, + + [ 8] = { FFx1, 0x00 }, + [ 9] = { FFx1, 0x80 }, + [ 10] = { FFx1, 0xc0 }, + [ 11] = { FFx1, 0xe0 }, + [ 12] = { FFx1, 0xf0 }, + [ 13] = { FFx1, 0xf8 }, + [ 14] = { FFx1, 0xfc }, + [ 15] = { FFx1, 0xfe }, + + [ 16] = { FFx2, 0x00 }, + [ 17] = { FFx2, 0x80 }, + [ 18] = { FFx2, 0xc0 }, + [ 19] = { FFx2, 0xe0 }, + [ 20] = { FFx2, 0xf0 }, + [ 21] = { FFx2, 0xf8 }, + [ 22] = { FFx2, 0xfc }, + [ 23] = { FFx2, 0xfe }, + [ 24] = { FFx3, 0x00 }, + + [ 25] = { FFx3, 0x80 }, + [ 26] = { FFx3, 0xc0 }, + [ 27] = { FFx3, 0xe0 }, + [ 28] = { FFx3, 0xf0 }, + [ 29] = { FFx3, 0xf8 }, + [ 30] = { FFx3, 0xfc }, + [ 31] = { FFx3, 0xfe }, + + [ 32] = { FFx4, 0x00 }, + [ 33] = { FFx4, 0x80 }, + [ 34] = { FFx4, 0xc0 }, + [ 35] = { FFx4, 0xe0 }, + [ 36] = { FFx4, 0xf0 }, + [ 37] = { FFx4, 0xf8 }, + [ 38] = { FFx4, 0xfc }, + [ 39] = { FFx4, 0xfe }, + + [ 40] = { FFx5, 0x00 }, + [ 41] = { FFx5, 0x80 }, + [ 42] = { FFx5, 0xc0 }, + [ 43] = { FFx5, 0xe0 }, + [ 44] = { FFx5, 0xf0 }, + [ 45] = { FFx5, 0xf8 }, + [ 46] = { FFx5, 0xfc }, + [ 47] = { FFx5, 0xfe }, + + [ 48] = { FFx6, 0x00 }, + [ 49] = { FFx6, 0x80 }, + [ 50] = { FFx6, 0xc0 }, + [ 51] = { FFx6, 0xe0 }, + [ 52] = { FFx6, 0xf0 }, + [ 53] = { FFx6, 0xf8 }, + [ 54] = { FFx6, 0xfc }, + [ 55] = { FFx6, 0xfe }, + + [ 56] = { FFx7, 0x00 }, + [ 57] = { FFx7, 0x80 }, + [ 58] = { FFx7, 0xc0 }, + [ 59] = { FFx7, 0xe0 }, + [ 60] = { FFx7, 0xf0 }, + [ 61] = { FFx7, 0xf8 }, + [ 62] = { FFx7, 0xfc }, + [ 63] = { FFx7, 0xfe }, + + [ 64] = { FFx8, 0x00 }, + [ 65] = { FFx8, 0x80 }, + [ 66] = { FFx8, 0xc0 }, + [ 67] = { FFx8, 0xe0 }, + [ 68] = { FFx8, 0xf0 }, + [ 69] = { FFx8, 0xf8 }, + [ 70] = { FFx8, 0xfc }, + [ 71] = { FFx8, 0xfe }, + + [ 72] = { FFx9, 0x00 }, + [ 73] = { FFx9, 0x80 }, + [ 74] = { FFx9, 0xc0 }, + [ 75] = { FFx9, 0xe0 }, + [ 76] = { FFx9, 0xf0 }, + [ 77] = { FFx9, 0xf8 }, + [ 78] = { FFx9, 0xfc }, + [ 79] = { FFx9, 0xfe }, + + [ 80] = { FFx10, 0x00 }, + [ 81] = { FFx10, 0x80 }, + [ 82] = { FFx10, 0xc0 }, + [ 83] = { FFx10, 0xe0 }, + [ 84] = { FFx10, 0xf0 }, + [ 85] = { FFx10, 0xf8 }, + [ 86] = { FFx10, 0xfc }, + [ 87] = { FFx10, 0xfe }, + + [ 88] = { FFx11, 0x00 }, + [ 89] = { FFx11, 0x80 }, + [ 90] = { FFx11, 0xc0 }, + [ 91] = { FFx11, 0xe0 }, + [ 92] = { FFx11, 0xf0 }, + [ 93] = { FFx11, 0xf8 }, + [ 94] = { FFx11, 0xfc }, + [ 95] = { FFx11, 0xfe }, + + [ 96] = { FFx12, 0x00 }, + [ 97] = { FFx12, 0x80 }, + [ 98] = { FFx12, 0xc0 }, + [ 99] = { FFx12, 0xe0 }, + [100] = { FFx12, 0xf0 }, + [101] = { FFx12, 0xf8 }, + [102] = { FFx12, 0xfc }, + [103] = { FFx12, 0xfe }, + + [104] = { FFx13, 0x00 }, + [105] = { FFx13, 0x80 }, + [106] = { FFx13, 0xc0 }, + [107] = { FFx13, 0xe0 }, + [108] = { FFx13, 0xf0 }, + [109] = { FFx13, 0xf8 }, + [110] = { FFx13, 0xfc }, + [111] = { FFx13, 0xfe }, + + [112] = { FFx14, 0x00 }, + [113] = { FFx14, 0x80 }, + [114] = { FFx14, 0xc0 }, + [115] = { FFx14, 0xe0 }, + [116] = { FFx14, 0xf0 }, + [117] = { FFx14, 0xf8 }, + [118] = { FFx14, 0xfc }, + [119] = { FFx14, 0xfe }, + + [120] = { FFx15, 0x00 }, + [121] = { FFx15, 0x80 }, + [122] = { FFx15, 0xc0 }, + [123] = { FFx15, 0xe0 }, + [124] = { FFx15, 0xf0 }, + [125] = { FFx15, 0xf8 }, + [126] = { FFx15, 0xfc }, + [127] = { FFx15, 0xfe }, + + [128] = { FFx16 }, +}; + +/* Table to map last byte of mask to the number of bits that byte adds + * to the prefix length. + * + * NB: this ignores all bits from the MS '0' bit onwards. + */ +static const u_char masklen_byte[256] = +{ /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ + /* 0x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 1x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 2x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 3x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 4x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 5x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 6x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 7x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 8x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 9x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* Ax */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* Bx */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* Cx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + /* Dx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + /* Ex */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + /* Fx */ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, + /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ +} ; + +/* Table to test for valid mask byte. + * + * Returns: 0 => not a valid prefix byte + * > 0 == number of prefix bits the byte contributes + 1 + */ +static const u_char masklen_byte_valid[256] = +{ + [0x00] = 0 + 1, + [0x80] = 1 + 1, + [0xC0] = 2 + 1, + [0xE0] = 3 + 1, + [0xF0] = 4 + 1, + [0xF8] = 5 + 1, + [0xFC] = 6 + 1, + [0xFE] = 7 + 1, + [0xFF] = 8 + 1, +} ; + +/* Table to count number of leading '0' bits before the ms '1'. + * + * This is the (an) inverse of masklen_byte -- which is the count of leanding + * '1' bits before the ms '0'. + */ +static const u_char masklen_byte_inverse[256] = +{ /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ + /* 0x */ 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + /* 1x */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + /* 2x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + /* 3x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + /* 4x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 5x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 6x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 7x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 8x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 9x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Ax */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Bx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Cx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Dx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Ex */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* Fx */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ +} ; + /* Number of bits in prefix type. */ #ifndef PNBBY @@ -40,84 +366,121 @@ static const u_char maskbit[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, #define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff) +unsigned int +prefix_bit (const u_char *prefix, const u_char prefixlen) +{ + uint offset = prefixlen / PNBBY; + uint shift = (PNBBY - 1) - (prefixlen % PNBBY); + + return (prefix[offset] >> shift) & 1; +} + +#ifdef HAVE_IPV6 + +unsigned int +prefix6_bit (const struct in6_addr *prefix, const u_char prefixlen) +{ + return prefix_bit((const u_char *) &prefix->s6_addr, prefixlen); +} + +#endif /* HAVE_IPV6 */ + /* Address Famiy Identifier to Address Family converter. */ -int +extern sa_family_t afi2family (afi_t afi) { - if (afi == AFI_IP) - return AF_INET; + switch (afi) + { + case AFI_IP: + return AF_INET; + #ifdef HAVE_IPV6 - else if (afi == AFI_IP6) - return AF_INET6; + case AFI_IP6: + return AF_INET6; #endif /* HAVE_IPV6 */ - return 0; + + default: + return AF_UNSPEC; + + confirm(AF_UNSPEC == 0) ; + } ; } -afi_t -family2afi (int family) +extern afi_t +family2afi (sa_family_t family) { - if (family == AF_INET) - return AFI_IP; + switch (family) + { + case AF_INET: + return AFI_IP; + #ifdef HAVE_IPV6 - else if (family == AF_INET6) - return AFI_IP6; + case AF_INET6: + return AFI_IP6; #endif /* HAVE_IPV6 */ - return 0; + + default: + return AFI_RESERVED; + + confirm(AFI_RESERVED == 0) ; + } ; } -/* If n includes p prefix then return 1 else return 0. */ +/* If n includes p prefix then return 1 else return 0. + * + * NB: this takes no notice of the prefixes' families. + */ int prefix_match (const struct prefix *n, const struct prefix *p) { - int offset; - int shift; - const u_char *np, *pp; + uint i, m ; - /* If n's prefix is longer than p's one return 0. */ if (n->prefixlen > p->prefixlen) return 0; - /* Set both prefix's head pointer. */ - np = (const u_char *)&n->u.prefix; - pp = (const u_char *)&p->u.prefix; + i = n->prefixlen / 32 ; + m = n->prefixlen % 32 ; - offset = n->prefixlen / PNBBY; - shift = n->prefixlen % PNBBY; - - if (shift) - if (maskbit[shift] & (np[offset] ^ pp[offset])) + if (m != 0) + if (((n->u.n32[i] ^ p->u.n32[i]) & in_addr_mask_n[m]) != 0) return 0; - while (offset--) - if (np[offset] != pp[offset]) + while (i--) + if (n->u.n32[i] != p->u.n32[i]) return 0; - return 1; + + return 1; /* match */ } /* Copy prefix from src to dest. */ void prefix_copy (struct prefix *dest, const struct prefix *src) { - dest->family = src->family; + dest->family = src->family; dest->prefixlen = src->prefixlen; - if (src->family == AF_INET) - dest->u.prefix4 = src->u.prefix4; + switch (src->family) + { + case AF_INET: + dest->u.prefix4 = src->u.prefix4; + break ; + #ifdef HAVE_IPV6 - else if (src->family == AF_INET6) - dest->u.prefix6 = src->u.prefix6; + case AF_INET6: + dest->u.prefix6 = src->u.prefix6; + break ; #endif /* HAVE_IPV6 */ - else if (src->family == AF_UNSPEC) - { - dest->u.lp.id = src->u.lp.id; - dest->u.lp.adv_router = src->u.lp.adv_router; - } - else - { - zlog (NULL, LOG_ERR, "prefix_copy(): Unknown address family %d", - src->family); - assert (0); - } + + case AF_UNSPEC: + dest->u.lp.id = src->u.lp.id; + dest->u.lp.adv_router = src->u.lp.adv_router; + break ; + + default: + zlog (NULL, LOG_ERR, "prefix_copy(): Unknown address family %d", + src->family); + assert (0); + } ; } /* @@ -127,21 +490,35 @@ prefix_copy (struct prefix *dest, const struct prefix *src) * but also the host part. Thus, 10.0.0.1/8 and 10.0.0.2/8 are not * the same. Note that this routine has the same return value sense * as '==' (which is different from prefix_cmp). + * + * If the Families are the same, they must be either AF_INET or AF_INET6 -- + * otherwise returns 0. + * + * If the Prefix Lengths are different, will return 0. Takes no notice of + * what the Prefix Length is, however. The check for "same" checks the + * address part specified by the Family. */ int prefix_same (const struct prefix *p1, const struct prefix *p2) { - if (p1->family == p2->family && p1->prefixlen == p2->prefixlen) + if ((p1->family == p2->family) && (p1->prefixlen == p2->prefixlen)) { - if (p1->family == AF_INET) - if (IPV4_ADDR_SAME (&p1->u.prefix, &p2->u.prefix)) - return 1; + switch (p1->family) + { + case AF_INET: + return (IPV4_ADDR_SAME (&p1->u.prefix4.s_addr, + &p2->u.prefix4.s_addr)) ? 1 : 0; #ifdef HAVE_IPV6 - if (p1->family == AF_INET6 ) - if (IPV6_ADDR_SAME (&p1->u.prefix, &p2->u.prefix)) - return 1; + case AF_INET6: + return (IPV6_ADDR_SAME (&p1->u.prefix6.s6_addr, + &p2->u.prefix6.s6_addr)) ? 1 : 0; #endif /* HAVE_IPV6 */ + + default: + break ; + } ; } + return 0; } @@ -154,32 +531,31 @@ prefix_same (const struct prefix *p1, const struct prefix *p2) * 10.0.0.2/8 are considered equivalent by this routine. Note that * this routine has the same return sense as strcmp (which is different * from prefix_same). + * + * Does not care what the Family is and does not check that Prefix Length is + * feasible (either for the Family or for the size of the struct prefix !) + * */ int prefix_cmp (const struct prefix *p1, const struct prefix *p2) { - int offset; - int shift; - - /* Set both prefix's head pointer. */ - const u_char *pp1 = (const u_char *)&p1->u.prefix; - const u_char *pp2 = (const u_char *)&p2->u.prefix; + uint i, m ; - if (p1->family != p2->family || p1->prefixlen != p2->prefixlen) + if ((p1->family != p2->family) || (p1->prefixlen != p2->prefixlen)) return 1; - offset = p1->prefixlen / 8; - shift = p1->prefixlen % 8; + i = p1->prefixlen / 32 ; + m = p1->prefixlen % 32 ; - if (shift) - if (maskbit[shift] & (pp1[offset] ^ pp2[offset])) + if (m != 0) + if (((p1->u.n32[i] ^ p2->u.n32[i]) & in_addr_mask_n[m]) != 0) return 1; - while (offset--) - if (pp1[offset] != pp2[offset]) + while (i--) + if (p1->u.n32[i] != p2->u.n32[i]) return 1; - return 0; + return 0; /* equal */ } /* @@ -191,50 +567,83 @@ prefix_cmp (const struct prefix *p1, const struct prefix *p2) int prefix_common_bits (const struct prefix *p1, const struct prefix *p2) { - int pos, bit; - int length = 0; - u_char xor; + uint i, len ; + uint32_t d ; - /* Set both prefix's head pointer. */ - const u_char *pp1 = (const u_char *)&p1->u.prefix; - const u_char *pp2 = (const u_char *)&p2->u.prefix; + if (p1->family != p2->family) + return -1; + + switch (p1->family) + { + case AF_INET: + len = IPV4_MAX_BYTELEN / 4 ; + confirm((IPV4_MAX_BYTELEN % 4) == 0) ; + break ; - if (p1->family == AF_INET) - length = IPV4_MAX_BYTELEN; #ifdef HAVE_IPV6 - if (p1->family == AF_INET6) - length = IPV6_MAX_BYTELEN; + case AF_INET6: + len = IPV6_MAX_BYTELEN / 4 ; + confirm((IPV6_MAX_BYTELEN % 4) == 0) ; + break ; #endif - if (p1->family != p2->family || !length) - return -1; - for (pos = 0; pos < length; pos++) - if (pp1[pos] != pp2[pos]) - break; - if (pos == length) - return pos * 8; + default: + return -1 ; + } ; - xor = pp1[pos] ^ pp2[pos]; - for (bit = 0; bit < 8; bit++) - if (xor & (1 << (7 - bit))) - break; + i = 0 ; - return pos * 8 + bit; -} + while ((d = p1->u.n32[i] ^ p2->u.n32[i]) == 0) + { + ++i ; + if (i == len) + return len * 32 ; + } ; + + d = ntohl(d) ; + + if (d > 0x0000FFFF) + { + if (d > 0x00FFFFFF) + return (i * 32) + 0 + masklen_byte_inverse[(d >> 24) & 0xFF] ; + else + return (i * 32) + 8 + masklen_byte_inverse[(d >> 16) & 0xFF] ; + } + else + { + if (d > 0x000000FF) + return (i * 32) + 16 + masklen_byte_inverse[(d >> 8) & 0xFF] ; + else + return (i * 32) + 24 + masklen_byte_inverse[(d >> 0) & 0xFF] ; + } ; +} ; /* Return prefix family type string. */ const char * prefix_family_str (const struct prefix *p) { - if (p->family == AF_INET) - return "inet"; + switch (p->family) + { + case AF_INET: + return "inet"; + #ifdef HAVE_IPV6 - if (p->family == AF_INET6) - return "inet6"; + case AF_INET6: + return "inet6"; #endif /* HAVE_IPV6 */ - return "unspec"; + + case AF_UNSPEC: + return "unspec"; + + default: + return "unknown" ; + } ; } +/*============================================================================== + * IPv4 Stuff + */ + /* Allocate new prefix_ipv4 structure. */ struct prefix_ipv4 * prefix_ipv4_new () @@ -310,80 +719,77 @@ str2prefix_ipv4 (const char *str, struct prefix_ipv4 *p) return 1 ; } -/* Convert masklen into IP address's netmask. */ -void -masklen2ip (int masklen, struct in_addr *netmask) +/* Convert masklen into IP address's netmask (network byte order). + */ +extern void +masklen2ip (const uint masklen, struct in_addr *netmask) { - u_char *pnt; - int bit; - int offset; - - memset (netmask, 0, sizeof (struct in_addr)); - pnt = (unsigned char *) netmask; - - offset = masklen / 8; - bit = masklen % 8; - - while (offset--) - *pnt++ = 0xff; - - if (bit) - *pnt = maskbit[bit]; -} + netmask->s_addr = in_addr_mask_n[masklen <= IPV4_MAX_BITLEN + ? masklen : IPV4_MAX_BITLEN] ; +} ; -/* Convert IP address's netmask into integer. We assume netmask is - sequential one. Argument netmask should be network byte order. */ +/* Convert IPv4 netmask to prefix length. + * + * If the netmask is invalid, all '1's after the first '0' are ignored. + * + * Argument netmask should be network byte order. + */ u_char ip_masklen (struct in_addr netmask) { - u_char len; - u_char *pnt; - u_char *end; - u_char val; + uint32_t ip_h ; - len = 0; - pnt = (u_char *) &netmask; - end = pnt + 4; + ip_h = ntohl(netmask.s_addr) ; - while ((pnt < end) && (*pnt == 0xff)) - { - len+= 8; - pnt++; - } + if (ip_h > 0xFFFF0000) + if (ip_h > 0xFFFFFF00) + return 24 + masklen_byte[(ip_h >> 0) & 0xFF] ; + else + return 16 + masklen_byte[(ip_h >> 8) & 0xFF] ; + else + if (ip_h > 0xFF000000) + return 8 + masklen_byte[(ip_h >> 16) & 0xFF] ; + else + return 0 + masklen_byte[(ip_h >> 24) & 0xFF] ; +} ; - if (pnt < end) - { - val = *pnt; - while (val) - { - len++; - val <<= 1; - } - } - return len; -} +/* Check whether given IPv4 netmask is valid. + * + * Netmask is valid if there are no '1' bits after the LS '0' (if any) + * + * Argument netmask should be network byte order. + */ +bool +ip_mask_check (struct in_addr netmask) +{ + uint32_t ip_h ; + + ip_h = ntohl(netmask.s_addr) ; + + return (ip_h | (ip_h - 1)) == 0xFFFFFFFF ; + + /* So: where ip_h has at some unknown MS bits, and then '1' followed by + * '0's we have: + * + * 'X..X10..0' - 1 -> 'X..X01..1' + * + * so to be a valid mask: 'X..X10..0' | 'X..X01..1' == '1..1' ! + * + * ip_h is unsigned, so if ip_h == 0 + * + * '0..0' - 1 -> '1..1' and '0..0' | '1..1' == '1..1' + * + * so that's fine too. + */ +} ; -/* Apply mask to IPv4 prefix. */ +/* Apply mask to IPv4 prefix (network byte order). */ void apply_mask_ipv4 (struct prefix_ipv4 *p) { - u_char *pnt; - int index; - int offset; - - index = p->prefixlen / 8; - - if (index < 4) - { - pnt = (u_char *) &p->prefix; - offset = p->prefixlen % 8; - - pnt[index] &= maskbit[offset]; - index++; - - while (index < 4) - pnt[index++] = 0; - } + qassert (p->prefixlen >= 0 && p->prefixlen <= IPV4_MAX_BITLEN); + p->prefix.s_addr &= in_addr_mask_n[ p->prefixlen <= IPV4_MAX_BITLEN + ? p->prefixlen : IPV4_MAX_BITLEN ] ; } /* If prefix is 0.0.0.0/0 then return 1 else return 0. */ @@ -393,6 +799,9 @@ prefix_ipv4_any (const struct prefix_ipv4 *p) return (p->prefix.s_addr == 0 && p->prefixlen == 0); } +/*============================================================================== + * IPv6 Stuff + */ #ifdef HAVE_IPV6 /* Allocate a new ip version 6 route */ @@ -472,53 +881,86 @@ str2prefix_ipv6 (const char *str, struct prefix_ipv6 *p) return 1 ; } -/* Convert struct in6_addr netmask into integer. - * FIXME return u_char as ip_maskleni() does. */ -int +/* Convert IPv6 netmask to prefix length. + * + * If the netmask is invalid, all '1's after the first '0' are ignored. + * + * Argument netmask should be network byte order. + */ +u_char ip6_masklen (struct in6_addr netmask) { - int len = 0; - unsigned char val; - unsigned char *pnt; + uint i ; + byte b ; - pnt = (unsigned char *) & netmask; - - while ((*pnt == 0xff) && len < 128) + i = 0; + while ((b = netmask.s6_addr[i]) == 0xff) { - len += 8; - pnt++; - } + ++i ; - if (len < 128) - { - val = *pnt; - while (val) - { - len++; - val <<= 1; - } - } - return len; + if (i == IPV6_MAX_BYTELEN) + return IPV6_MAX_BITLEN ; + + confirm(IPV6_MAX_BITLEN == (IPV6_MAX_BYTELEN * 8)) ; + } ; + + return (i * 8) + masklen_byte[b] ; } -void -masklen2ip6 (int masklen, struct in6_addr *netmask) +/* Check whether given IPv6 netmask is valid. + * + * Netmask is valid if there are no '1' bits after the LS '0' (if any) + * + * The check does all of the work required to establish the prefix length (plus + * a little. So, unlike ip4_mask_check() -- which returns a bool -- this + * returns the prefix length if is a valid mask. + * + * Returns: -1 <=> *not* valid + * >= 0 == the prefix length + * + * Argument netmask should be network byte order. + */ +int +ip6_mask_check (struct in6_addr netmask) { - unsigned char *pnt; - int bit; - int offset; + uint i, l ; + byte b ; + + i = 0; + while ((b = netmask.s6_addr[i]) == 0xff) + { + ++i ; - memset (netmask, 0, sizeof (struct in6_addr)); - pnt = (unsigned char *) netmask; + if (i == IPV6_MAX_BYTELEN) + return IPV6_MAX_BITLEN ; - offset = masklen / 8; - bit = masklen % 8; + confirm(IPV6_MAX_BITLEN == (IPV6_MAX_BYTELEN * 8)) ; + } ; + + l = masklen_byte_valid[b] ; + + if (l == 0) + return -1 ; + + l += (i * 8) - 1 ; + + while (i < (IPV6_MAX_BYTELEN - 1)) + { + if (netmask.s6_addr[++i] != 0) + return -1 ; + } ; - while (offset--) - *pnt++ = 0xff; + return l ; +} ; - if (bit) - *pnt = maskbit[bit]; +void +masklen2ip6 (const uint masklen, struct in6_addr *netmask) +{ +//assert (masklen >= 0 && masklen <= IPV6_MAX_BITLEN); + memcpy (netmask, + &in_addr6_mask_n[masklen <= IPV6_MAX_BITLEN ? masklen + : IPV6_MAX_BITLEN], + sizeof (struct in6_addr)); } void @@ -558,6 +1000,9 @@ str2in6_addr (const char *str, struct in6_addr *addr) } #endif /* HAVE_IPV6 */ +/*============================================================================== + * General prefix and sockunion stuff + */ void apply_mask (struct prefix *p) { @@ -580,16 +1025,16 @@ apply_mask (struct prefix *p) /* Utility function of convert between struct prefix <=> union sockunion. * FIXME This function isn't used anywhere. */ struct prefix * -sockunion2prefix (const union sockunion *dest, - const union sockunion *mask) +sockunion2prefix (const_sockunion dest, + const_sockunion mask) { if (dest->sa.sa_family == AF_INET) { struct prefix_ipv4 *p; p = prefix_ipv4_new (); - p->family = AF_INET; - p->prefix = dest->sin.sin_addr; + p->family = AF_INET; + p->prefix = dest->sin.sin_addr; p->prefixlen = ip_masklen (mask->sin.sin_addr); return (struct prefix *) p; } @@ -599,7 +1044,7 @@ sockunion2prefix (const union sockunion *dest, struct prefix_ipv6 *p; p = prefix_ipv6_new (); - p->family = AF_INET6; + p->family = AF_INET6; p->prefixlen = ip6_masklen (mask->sin6.sin6_addr); memcpy (&p->prefix, &dest->sin6.sin6_addr, sizeof (struct in6_addr)); return (struct prefix *) p; @@ -610,7 +1055,7 @@ sockunion2prefix (const union sockunion *dest, /* Utility function of convert between struct prefix <=> union sockunion. */ struct prefix * -sockunion2hostprefix (const union sockunion *su) +sockunion2hostprefix (const_sockunion su) { if (su->sa.sa_family == AF_INET) { @@ -638,7 +1083,8 @@ sockunion2hostprefix (const union sockunion *su) } void -prefix2sockunion (const struct prefix *p, union sockunion *su) { +prefix2sockunion (const struct prefix *p, union sockunion *su) +{ memset (su, 0, sizeof (*su)); su->sa.sa_family = p->family; @@ -701,6 +1147,38 @@ prefix2str (const struct prefix *p, char *str, int size) return 0; } +/*------------------------------------------------------------------------------ + * Return str_pfxtoa_t structure containing string representation of given + * prefix. + */ +extern str_pfxtoa_t +spfxtoa(const struct prefix* p) +{ + str_pfxtoa_t QFB_QFS(pfa, qfs) ; + + switch (p->family) + { + case AF_INET: + confirm(sizeof(pfa.str) > (INET_ADDRSTRLEN + 3)) ; +#ifdef HAVE_IPV6 + case AF_INET6: + confirm(sizeof(pfa.str) > (INET6_ADDRSTRLEN + 4)) ; +#endif + inet_ntop(p->family, &p->u.prefix, pfa.str, sizeof(pfa.str)) ; + + qfs_init_as_is(qfs, pfa.str, sizeof(pfa.str)) ; + qfs_printf(qfs, "/%u", p->prefixlen) ; + break; + + default: + qfs_printf(qfs, "?unknown address family=%u?", p->family) ; + break ; + } ; + + qfs_term(qfs) ; + return pfa; +} ; + struct prefix * prefix_new () { @@ -879,7 +1357,7 @@ prefix_to_raw(prefix_raw raw, const struct prefix * p) raw->prefix_len = plen ; if (len != 0) { - memcpy(raw->prefix, p->u.val, len) ; + memcpy(raw->prefix, p->u.b, len) ; raw->prefix[len - 1] &= prefix_last_byte_mask[plen & 0x7] ; } ; @@ -927,8 +1405,9 @@ prefix_from_raw(struct prefix * p, prefix_raw raw, sa_family_t family) p->prefixlen = plen ; if (len != 0) { - memcpy(p->u.val, raw->prefix, len) ; + memcpy(p->u.b, raw->prefix, len) ; - p->u.val[len - 1] &= prefix_last_byte_mask[plen & 0x7] ; + p->u.b[len - 1] &= prefix_last_byte_mask[plen & 0x7] ; } ; } ; + diff --git a/lib/prefix.h b/lib/prefix.h index ba862c08..c7e0c387 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -25,6 +25,7 @@ #include "misc.h" #include "sockunion.h" +#include "qfstring.h" typedef const union sockunion* const_sockunion ; @@ -44,7 +45,12 @@ struct prefix u_char prefixlen; union { + uint64_t n64[2] ; + uint32_t n32[4] ; + uint8_t b[16] ; + u_char prefix ; + struct in_addr prefix4 ; #ifdef HAVE_IPV6 struct in6_addr prefix6; @@ -58,6 +64,20 @@ struct prefix } u __attribute__ ((aligned (8))); }; +/* So we know that the AF_INET, IPv4 prefix address maps to *network order* + * uint32_t. + * + * And that the AF_INET6, IPv6 prefix address maps to Big Endian array of four + * *network order* uint32_t (or two *network order uint64_t !) + */ +CONFIRM(sizeof(struct in_addr) == sizeof(((struct prefix*)0)->u.n32[0])) ; + +#ifdef HAVE_IPV6 +CONFIRM(sizeof(struct in6_addr) == sizeof(((struct prefix*)0)->u.b)) ; +CONFIRM(sizeof(struct in6_addr) == sizeof(((struct prefix*)0)->u.n32)) ; +CONFIRM(sizeof(struct in6_addr) == sizeof(((struct prefix*)0)->u.n64)) ; +#endif + /* Prefix as carried in protocols */ struct prefix_raw @@ -159,6 +179,7 @@ CONFIRM(sizeof(struct prefix_rd) <= sizeof(struct prefix)) ; #define IPV4_NET0(a) ((((u_int32_t) (a)) & 0xff000000) == 0x00000000) #define IPV4_NET127(a) ((((u_int32_t) (a)) & 0xff000000) == 0x7f000000) #define IPV4_LINKLOCAL(a) ((((u_int32_t) (a)) & 0xffff0000) == 0xa9fe0000) +#define IPV4_CLASS_DE(a) ((((u_int32_t) (a)) & 0xe0000000) == 0xe0000000) /* Max bit/byte length of IPv6 address. */ #define IPV6_MAX_BYTELEN 16 @@ -174,26 +195,20 @@ CONFIRM(sizeof(struct prefix_rd) <= sizeof(struct prefix)) ; /* Prefix's family member. */ #define PREFIX_FAMILY(p) ((p)->family) -/* Check bit of the prefix. */ -static inline unsigned int -prefix_bit (const u_char *prefix, const u_char prefixlen) -{ - unsigned int offset = prefixlen / 8; - unsigned int shift = 7 - (prefixlen % 8); - - return (prefix[offset] >> shift) & 1; -} - -static inline unsigned int -prefix6_bit (const struct in6_addr *prefix, const u_char prefixlen) -{ - return prefix_bit((const u_char *) &prefix->s6_addr, prefixlen); -} +QFB_T(60) str_pfxtoa_t ; -/* Prototypes. */ -extern int afi2family (afi_t); -extern afi_t family2afi (int); +/*============================================================================== + * Prototypes. + */ +extern sa_family_t afi2family (afi_t); +extern afi_t family2afi (sa_family_t ); +/* Check bit of the prefix. */ +extern unsigned int prefix_bit (const u_char *prefix, const u_char prefixlen); +#ifdef HAVE_IPV6 +extern unsigned int prefix6_bit (const struct in6_addr *prefix, + const u_char prefixlen); +#endif extern struct prefix *prefix_new (void); extern void prefix_free (struct prefix *); extern const char *prefix_family_str (const struct prefix *); @@ -204,6 +219,7 @@ extern void prefix_from_raw(struct prefix *, prefix_raw, sa_family_t) ; extern int str2prefix (const char *, struct prefix *); extern int prefix2str (const struct prefix *, char *, int); +extern str_pfxtoa_t spfxtoa(const struct prefix* p) ; extern int prefix_match (const struct prefix *, const struct prefix *); extern int prefix_same (const struct prefix *, const struct prefix *); extern int prefix_cmp (const struct prefix *, const struct prefix *); @@ -234,7 +250,8 @@ extern int prefix_ipv4_any (const struct prefix_ipv4 *); extern void apply_classful_mask_ipv4 (struct prefix_ipv4 *); extern u_char ip_masklen (struct in_addr); -extern void masklen2ip (int, struct in_addr *); +extern bool ip_mask_check (struct in_addr netmask) ; +extern void masklen2ip (const uint, struct in_addr *); /* returns the network portion of the host address */ extern in_addr_t ipv4_network_addr (in_addr_t hostaddr, int masklen); /* given the address of a host on a network and the network mask length, @@ -260,8 +277,9 @@ prefix_copy_ipv6(struct prefix* dst, struct prefix* src) *dst = *src ; } ; -extern int ip6_masklen (struct in6_addr); -extern void masklen2ip6 (int, struct in6_addr *); +extern u_char ip6_masklen (struct in6_addr); +extern int ip6_mask_check (struct in6_addr netmask) ; +extern void masklen2ip6 (const uint, struct in6_addr *); extern void str2in6_addr (const char *, struct in6_addr *); extern const char *inet6_ntoa (struct in6_addr); diff --git a/lib/pthread_safe.c b/lib/pthread_safe.c index c90fa4ae..92d63074 100644 --- a/lib/pthread_safe.c +++ b/lib/pthread_safe.c @@ -568,6 +568,36 @@ safe_inet_ntoa (struct in_addr in) } /*------------------------------------------------------------------------------ + * Construct string for given IP family/address. + * + * Requires buffer of at least SU_ADDRSTRLEN characters. + */ +extern str_iptoa_t +siptoa(sa_family_t family, const void* address) +{ + str_iptoa_t QFB_QFS(ipa, qfs) ; + + switch (family) + { + case AF_INET: + confirm(sizeof(ipa.str) >= INET_ADDRSTRLEN) ; +#ifdef HAVE_IPV6 + case AF_INET6: + confirm(sizeof(ipa.str) >= INET6_ADDRSTRLEN) ; +#endif + inet_ntop(family, address, ipa.str, sizeof(ipa.str)); + break; + + default: + qfs_printf(qfs, "?unknown address family=%d?", family) ; + qfs_term(qfs) ; + break ; + } ; + + return ipa; +} ; + +/*------------------------------------------------------------------------------ * Return the thread's buffer, create it if necessary. * (pthread Thread Specific Data) */ diff --git a/lib/pthread_safe.h b/lib/pthread_safe.h index 42dfc923..bda64fef 100644 --- a/lib/pthread_safe.h +++ b/lib/pthread_safe.h @@ -29,6 +29,7 @@ #include "qfstring.h" QFB_T(150) strerror_t ; +QFB_T(50) str_iptoa_t ; extern void safe_init_r(void); extern void safe_finish(void); @@ -45,6 +46,8 @@ extern int getenv_r(const char* name, char* buf, int buf_len) ; extern const char * safe_strerror(int errnum); extern const char * safe_inet_ntoa (struct in_addr in); +extern str_iptoa_t siptoa(sa_family_t family, const void* address) ; + extern int safe_getpwnam(const char* name, struct passwd** p_pwd, void* buf, ulen size); extern int safe_getpwuid(uid_t id, struct passwd** p_pwd, void* buf, ulen size); diff --git a/lib/qafi_safi.h b/lib/qafi_safi.h index 5559097d..4e19bfd1 100644 --- a/lib/qafi_safi.h +++ b/lib/qafi_safi.h @@ -62,7 +62,7 @@ enum iSAFI iSAFI_Unicast = 1, /* unicast forwarding */ iSAFI_Multicast = 2, /* multicast forwarding */ - iSAFI_Unused = 3, /* also Reserved by IANA */ + iSAFI_Reserved_3 = 3, /* Reserved by IANA */ iSAFI_MPLS_VPN = 128 /* MPLS-labeled VPN address */ } ; @@ -108,7 +108,7 @@ enum qSAFI qSAFI_Unicast = 1, qSAFI_Multicast = 2, - qSAFI_Unused = 3, + qSAFI_Reserved_3 = 3, qSAFI_MPLS_VPN = 4, qSAFI_last = 4, /* last real qSAFI */ @@ -143,6 +143,7 @@ typedef struct qAFI_SAFI* qAFI_SAFI ; */ /* Address family numbers from RFC1700. */ +#define AFI_RESERVED 0 #define AFI_IP 1 #define AFI_IP6 2 #define AFI_MAX 3 @@ -156,7 +157,7 @@ CONFIRM(AFI_MAX == qAFI_count) ; /* Subsequent Address Family Identifier. */ #define SAFI_UNICAST 1 #define SAFI_MULTICAST 2 -#define SAFI_UNICAST_MULTICAST 3 +#define SAFI_RESERVED_3 3 #define SAFI_MPLS_VPN 4 #define SAFI_MAX 5 @@ -164,8 +165,8 @@ CONFIRM( (SAFI_UNICAST == qSAFI_Unicast) && (SAFI_UNICAST == iSAFI_Unicast) ) ; CONFIRM( (SAFI_MULTICAST == qSAFI_Multicast) && (SAFI_MULTICAST == iSAFI_Multicast) ) ; -CONFIRM( (SAFI_UNICAST_MULTICAST == qSAFI_Unused) - && (SAFI_UNICAST_MULTICAST == iSAFI_Unused) ) ; +CONFIRM( (SAFI_RESERVED_3 == qSAFI_Reserved_3) + && (SAFI_RESERVED_3 == iSAFI_Reserved_3) ) ; CONFIRM(SAFI_MPLS_VPN == qSAFI_MPLS_VPN) ; CONFIRM(SAFI_MAX == qSAFI_count) ; diff --git a/lib/route_types.awk b/lib/route_types.awk deleted file mode 100644 index eb3d382a..00000000 --- a/lib/route_types.awk +++ /dev/null @@ -1,187 +0,0 @@ -# $Id$ -# -# Scan a file of route-type definitions (see eg route_types.txt) and -# generate a corresponding header file with: -# -# - enum of Zserv route-types -# - redistribute strings for the various Quagga daemons -# -# See route_types.txt for the format. -# -# - -BEGIN { - FS="[,]"; - - # globals - exitret = 0; - tcount = 0; - - # formats for output - ## the define format - redist_def_fmt = "#define QUAGGA_REDIST_STR_%s \\\n"; - ## DEFUN/vty route-type argument - redist_str_fmt = "\"(%s)\"\n"; - redist_help_def_fmt = "#define QUAGGA_REDIST_HELP_STR_%s"; - redist_help_str_fmt = " \\\n \"%s\\n\""; - - # header - header = "/* Auto-generated from route_types.txt by " ARGV[0] ". */\n"; - header = header "/* Do not edit! */\n"; - header = header "\n#ifndef _QUAGGA_ROUTE_TYPES_H\n"; - header = header "#define _QUAGGA_ROUTE_TYPES_H\n"; - footer = "#endif /* _QUAGGA_ROUTE_TYPES_H */\n"; - printf ("%s\n", header); -} - -# Chomp comment lines -($0 ~ /^#/) { - next; -} - -# get rid of the commas, leading/trailling whitespace and -# quotes -{ - for (i = 1; i <= NF; i++) { - #print "before:" $i; - $i = gensub(/^[[:blank:]]*(.*)[,]*.*/, "\\1", "g",$i); - $i = gensub(/^["](.*)["]$/, "\\1", "g", $i); - #print "after :" $i; - } -} - -# 7 field format: -# type cname daemon C 4 6 short help -(NF >= 7) { - #print "7", $1, $0; - - if ($1 in types) { - print "error: attempt to redefine", $1; - exitret = 1; - exit exitret; - } - - typesbynum[tcount] = $1; - types[$1,"num"] = tcount++; - types[$1,"cname"] = $2; - types[$1,"daemon"] = $3; - types[$1,"C"] = $4; - types[$1,"4"] = strtonum($5); - types[$1,"6"] = strtonum($6); - types[$1,"shelp"] = $7; - - #print "num :", types[$1,"num"] - #print "cname :", types[$1,"cname"] - #print "daemon:", types[$1,"daemon"]; - #print "char :", types[$1,"C"]; -}; - -# 2 field: type "long description" -(NF == 2) { - #print "2", $1, $2; - - if (!(($1 SUBSEP "num") in types)) { - print "error: type", $1, "must be defined before help str"; - exitret = 2; - exit exitret; - } - - types[$1,"lhelp"] = $2; -} - -END { - if (exitret) - exit exitret; - - # The enums - # not yet... - #printf("enum\n{\n"); - #for (i = 0; i < tcount; i++) { - # type = typesbynum[i]; - # if (type != "" && types[type,"num"] == i) - # printf (" %s,\n", type); - #} - #printf (" ZEBRA_ROUTE_MAX,\n};\n\n"); - - # the redistribute defines - for (i = 0; i < tcount; i++) { - type = typesbynum[i]; - - # must be a type, and must cross-check against recorded type - if (type == "" || types[type,"num"] != i) - continue; - - # ignore route types that can't be redistributed - if (!(types[type,"4"] || types[type,"6"])) - continue; - - # must have a daemon name - if (!((type SUBSEP "daemon") in types)) - continue; - if (!(daemon = types[type,"daemon"])) - continue; - - # might have done this daemon already? - if (daemon in seen_daemons) - continue; - - cname = types[type,"cname"]; - all = all "|" cname; - rstr = ""; - hstr = ""; - - # add it to the others - for (j = 0; j < tcount; j++) { - # ignore self - if (i == j) - continue; - - type2 = typesbynum[j]; - - # type2 must be valid, and self-check. - if (type2 == "" || types[type2,"num"] != j) - continue; - - # ignore different route types for the same daemon - # (eg system/kernel/connected) - if (types[type2,"daemon"] == daemon) - continue; - - if ((types[type2,"4"] && types[type,"4"]) \ - || (types[type2,"6"] && types[type,"6"])) { - - if (rstr == "") - rstr = types[type2,"cname"]; - else - rstr = rstr "|" types[type2,"cname"]; - - if ((type2 SUBSEP "lhelp") in types) - hstr2 = types[type2,"lhelp"]; - else if ((type2 SUBSEP "shelp") in types) - hstr2 = types[type2,"shelp"]; - else - hstr2 = types[type2,"cname"]; - - hstr = hstr sprintf(redist_help_str_fmt, hstr2); - } - } - - # dont double-process daemons. - seen_daemons[daemon] = 1; - - printf("/* %s */\n", daemon); - printf(redist_def_fmt, toupper(daemon)); - printf(redist_str_fmt, rstr); - printf(redist_help_def_fmt, toupper(daemon)); - printf("%s", hstr); - printf("\n\n"); - } - - #printf("#define QUAGGA_REDIST_STR_ALL %s\n",all); - -# for (i = 0; i < lcount; i++) { -# if (mlists[i] != "") -# printf (mlistformat "\n", mlists[i]); -# } - printf (footer); -} diff --git a/lib/route_types.pl b/lib/route_types.pl new file mode 100755 index 00000000..e1595afc --- /dev/null +++ b/lib/route_types.pl @@ -0,0 +1,199 @@ +#!/usr/bin/perl +## +## Scan a file of route-type definitions (see eg route_types.txt) and +## generate a corresponding header file with: +## +## - enum of Zserv route-types +## - redistribute strings for the various Quagga daemons +## +## See route_types.txt for the format. +## +## +## Copyright (C) 2009 David Lamparter. +## This file is part of GNU Zebra. +## +## GNU Zebra is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## GNU Zebra is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## 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. +## + +use strict; + +# input processing +# +my @protos; +my %protodetail; + +my %daemons; + +while (<STDIN>) { + # skip comments and empty lines + next if (/^\s*(#|$)/); + + # strip whitespace + chomp; + $_ =~ s/^\s*//; + $_ =~ s/\s*$//; + + # match help strings + if (/^(ZEBRA_ROUTE_[^\s]+)\s*,\s*"(.*)"$/) { + $protodetail{$1}->{'longhelp'} = $2; + next; + } + + $_ =~ s/\s*,\s*/,/g; + + # else: 7-field line + my @f = split(/,/, $_); + unless (@f == 7) { + die "invalid input on route_types line $.\n"; + } + + my $proto = $f[0]; + $f[3] = $1 if ($f[3] =~ /^'(.*)'$/); + $f[6] = $1 if ($f[6] =~ /^"(.*)"$/); + + $protodetail{$proto} = { + "number" => scalar @protos, + "type" => $f[0], + "cname" => $f[1], + "daemon" => $f[2], + "char" => $f[3], + "ipv4" => int($f[4]), + "ipv6" => int($f[5]), + "shorthelp" => $f[6], + }; + push @protos, $proto; + $daemons{$f[2]} = { + "ipv4" => int($f[4]), + "ipv6" => int($f[5]) + } unless ($f[2] eq "NULL"); +} + +# output +printf <<EOF, $ARGV[0]; +/* Auto-generated from route_types.txt by %s. */ +/* Do not edit! */ + +#ifndef _QUAGGA_ROUTE_TYPES_H +#define _QUAGGA_ROUTE_TYPES_H + +/* Zebra route's types. */ +EOF + +push @protos, "ZEBRA_ROUTE_MAX"; +my (@protosv4, @protosv6) = ((), ()); +for (my $c = 0; $c < @protos; $c++) { + my $p = $protos[$c]; + printf "#define %-32s %d\n", $p, $c; + push @protosv4, $p if ($protodetail{$p}->{"ipv4"}); + push @protosv6, $p if ($protodetail{$p}->{"ipv6"}); +} +pop @protos; + +sub codelist { + my (@protos) = @_; + my (@lines) = (); + my $str = " \"Codes: "; + for my $p (@protos) { + my $s = sprintf("%s - %s, ", + $protodetail{$p}->{"char"}, + $protodetail{$p}->{"shorthelp"}); + if (length($str . $s) > 70) { + $str =~ s/ $//; + push @lines, $str . "%s\" \\\n"; + $str = " \" "; + } + $str .= $s; + } + $str =~ s/ $//; + push @lines, $str . "%s\" \\\n"; + push @lines, " \" > - selected route, * - FIB route%s%s\", \\\n"; + my @nl = (); + for (my $c = 0; $c < @lines + 1; $c++) { + push @nl, "VTY_NEWLINE" + } + return join("", @lines) ." ". join(", ", @nl); +} + +print "\n"; +printf "#define SHOW_ROUTE_V4_HEADER \\\n%s\n", codelist(@protosv4); +printf "#define SHOW_ROUTE_V6_HEADER \\\n%s\n", codelist(@protosv6); +print "\n"; + +sub collect { + my ($daemon, $ipv4, $ipv6) = @_; + my (@names, @help) = ((), ()); + for my $p (@protos) { + next if ($protodetail{$p}->{"daemon"} eq $daemon && $daemon ne "zebra"); + next unless (($ipv4 && $protodetail{$p}->{"ipv4"}) + || ($ipv6 && $protodetail{$p}->{"ipv6"})); + push @names, $protodetail{$p}->{"cname"}; + push @help, " \"".$protodetail{$p}->{"longhelp"}."\\n\""; + } + return ("\"(" . join("|", @names) . ")\"", join(" \\\n", @help)); +} + +for my $daemon (sort keys %daemons) { + next unless ($daemons{$daemon}->{"ipv4"} || $daemons{$daemon}->{"ipv6"}); + printf "/* %s */\n", $daemon; + if ($daemons{$daemon}->{"ipv4"} && $daemons{$daemon}->{"ipv6"}) { + my ($names, $help) = collect($daemon, 1, 1); + printf "#define QUAGGA_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; + printf "#define QUAGGA_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; + ($names, $help) = collect($daemon, 1, 0); + printf "#define QUAGGA_IP_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; + printf "#define QUAGGA_IP_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; + ($names, $help) = collect($daemon, 0, 1); + printf "#define QUAGGA_IP6_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; + printf "#define QUAGGA_IP6_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; + } else { + my ($names, $help) = collect($daemon, + $daemons{$daemon}->{"ipv4"}, $daemons{$daemon}->{"ipv6"}); + printf "#define QUAGGA_REDIST_STR_%s \\\n %s\n", uc $daemon, $names; + printf "#define QUAGGA_REDIST_HELP_STR_%s \\\n%s\n", uc $daemon, $help; + } + print "\n"; +} + +print <<EOF; + +#ifdef QUAGGA_DEFINE_DESC_TABLE + +struct zebra_desc_table +{ + unsigned int type; + const char *string; + char chr; +}; + +#define DESC_ENTRY(T,S,C) [(T)] = { (T), (S), (C) } +static const struct zebra_desc_table route_types[] = { +EOF + +for (my $c = 0; $c < @protos; $c++) { + my $p = $protos[$c]; + printf " DESC_ENTRY\t(%s\t \"%s\",\t'%s' ),\n", + $p.",", $protodetail{$p}->{"cname"}, $protodetail{$p}->{"char"}; +} + +print <<EOF; +}; +#undef DESC_ENTRY + +#endif /* QUAGGA_DEFINE_DESC_TABLE */ + +#endif /* _QUAGGA_ROUTE_TYPES_H */ +EOF + diff --git a/lib/route_types.txt b/lib/route_types.txt index e99cacde..fde0bc8d 100644 --- a/lib/route_types.txt +++ b/lib/route_types.txt @@ -42,13 +42,13 @@ ## type cname daemon C 4 6 short help ZEBRA_ROUTE_SYSTEM, system, NULL, 'X', 0, 0, "Reserved" -ZEBRA_ROUTE_KERNEL, kernel, zebra, 'K', 1, 1, NULL -ZEBRA_ROUTE_CONNECT, connected, zebra, 'C', 1, 1, NULL -ZEBRA_ROUTE_STATIC, static, zebra, 'S', 1, 1, NULL +ZEBRA_ROUTE_KERNEL, kernel, zebra, 'K', 1, 1, "kernel route" +ZEBRA_ROUTE_CONNECT, connected, zebra, 'C', 1, 1, "connected" +ZEBRA_ROUTE_STATIC, static, zebra, 'S', 1, 1, "static" ZEBRA_ROUTE_RIP, rip, ripd, 'R', 1, 0, "RIP" ZEBRA_ROUTE_RIPNG, ripng, ripngd, 'R', 0, 1, "RIPng" ZEBRA_ROUTE_OSPF, ospf, ospfd, 'O', 1, 0, "OSPF" -ZEBRA_ROUTE_OSPF6, ospf6, ospf6d, 'O', 0, 1, "OSPF" +ZEBRA_ROUTE_OSPF6, ospf6, ospf6d, 'O', 0, 1, "OSPFv6" ZEBRA_ROUTE_ISIS, isis, isisd, 'I', 1, 1, "IS-IS" ZEBRA_ROUTE_BGP, bgp, bgpd, 'B', 1, 1, "BGP" # HSLS and OLSR both are AFI independent (so: 1, 1), however @@ -57,7 +57,7 @@ ZEBRA_ROUTE_BGP, bgp, bgpd, 'B', 1, 1, "BGP" # to 'switch on' redist support (direct numeric entry remaining # possible). ZEBRA_ROUTE_HSLS, hsls, hslsd, 'H', 0, 0, "HSLS" -ZEBRA_ROUTE_OLSR, olsr, oslrd, 'o', 0, 0, "OLSR" +ZEBRA_ROUTE_OLSR, olsr, olsrd, 'o', 0, 0, "OLSR" ## help strings ZEBRA_ROUTE_SYSTEM, "Reserved route type, for internal use only" @@ -261,7 +261,6 @@ static void smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat, long errindex, u_char val_type, void *arg, size_t arg_len) { - int ret; u_char buf[BUFSIZ]; u_char *ptr, *h1, *h1e, *h2, *h2e; size_t len, length; @@ -317,7 +316,7 @@ smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat, if (debug_smux) zlog_debug ("SMUX getresp send: %td", (ptr - buf)); - ret = send (smux_sock, buf, (ptr - buf), 0); + send (smux_sock, buf, (ptr - buf), 0); } static u_char * @@ -937,7 +936,7 @@ smux_open (int sock) u_char *ptr; size_t len; long version; - u_char progname[] = QUAGGA_PROGNAME "-" QUAGGA_VERSION; + const char progname[] = QUAGGA_PROGNAME "-" QUAGGA_VERSION; if (debug_smux) { @@ -969,6 +968,7 @@ smux_open (int sock) (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), progname, strlen ((void*)progname)); + (const u_char *) progname, strlen (progname)); /* SMUX connection password. */ ptr = asn_build_string (ptr, &len, diff --git a/lib/sockopt.c b/lib/sockopt.c index b1e47c99..178e93fb 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -612,7 +612,7 @@ setsockopt_ipv4_tos(int sock_fd, int tos) /*------------------------------------------------------------------------------ * Process multicast socket options for IPv4 in an OS-dependent manner. - * Supported options are IP_MULTICAST_IF and IP_{ADD,DROP}_MEMBERSHIP. + * Supported options are IP_{ADD,DROP}_MEMBERSHIP. * * Many operating systems have a limit on the number of groups that * can be joined per socket (where each group and local address @@ -632,118 +632,133 @@ setsockopt_ipv4_tos(int sock_fd, int tos) * allow leaves, or implicitly leave all groups joined to down interfaces. */ extern int -setsockopt_multicast_ipv4(int sock_fd, - int optname, - struct in_addr if_addr /* required */, - unsigned int mcast_addr, - unsigned int ifindex /* optional: if non-zero, - may be used instead of - if_addr */ - ) +setsockopt_ipv4_multicast(int sock, + int optname, + unsigned int mcast_addr, + unsigned int ifindex) { +#ifdef HAVE_RFC3678 + struct group_req gr; + struct sockaddr_in *si; + int ret; + memset (&gr, 0, sizeof(gr)); + si = (struct sockaddr_in *)&gr.gr_group; + gr.gr_interface = ifindex; + si->sin_family = AF_INET; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + si->sin_len = sizeof(struct sockaddr_in); +#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ + si->sin_addr.s_addr = mcast_addr; + ret = setsockopt(sock, IPPROTO_IP, (optname == IP_ADD_MEMBERSHIP) ? + MCAST_JOIN_GROUP : MCAST_LEAVE_GROUP, (void *)&gr, sizeof(gr)); + if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE)) + { + setsockopt(sock, IPPROTO_IP, MCAST_LEAVE_GROUP, (void *)&gr, sizeof(gr)); + ret = setsockopt(sock, IPPROTO_IP, MCAST_JOIN_GROUP, (void *)&gr, sizeof(gr)); + } + return ret; -#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX - /* This is better because it uses ifindex directly */ +#elif defined(HAVE_STRUCT_IP_MREQN_IMR_IFINDEX) && !defined(__FreeBSD__) struct ip_mreqn mreqn; int ret; - switch (optname) - { - case IP_MULTICAST_IF: - case IP_ADD_MEMBERSHIP: - case IP_DROP_MEMBERSHIP: - memset (&mreqn, 0, sizeof(mreqn)); - - if (mcast_addr) - mreqn.imr_multiaddr.s_addr = mcast_addr; + assert(optname == IP_ADD_MEMBERSHIP || optname == IP_DROP_MEMBERSHIP); + memset (&mreqn, 0, sizeof(mreqn)); - if (ifindex) - mreqn.imr_ifindex = ifindex; - else - mreqn.imr_address = if_addr; + mreqn.imr_multiaddr.s_addr = mcast_addr; + mreqn.imr_ifindex = ifindex; - ret = setsockopt(sock_fd, IPPROTO_IP, optname, &mreqn, sizeof(mreqn)); - if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE)) - { - /* see above: handle possible problem when interface comes back up */ - char buf[2][INET_ADDRSTRLEN]; - zlog_info("setsockopt_multicast_ipv4 attempting to drop and " - "re-add (fd %d, ifaddr %s, mcast %s, ifindex %u)", - sock_fd, - inet_ntop(AF_INET, &if_addr, buf[0], sizeof(buf[0])), - inet_ntop(AF_INET, &mreqn.imr_multiaddr, - buf[1], sizeof(buf[1])), ifindex); - setsockopt(sock_fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, - &mreqn, sizeof(mreqn)); - ret = setsockopt(sock_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, - &mreqn, sizeof(mreqn)); - } - return ret; - - default: - /* Can out and give an understandable error */ - errno = EINVAL; - return -1; + ret = setsockopt(sock, IPPROTO_IP, optname, + (void *)&mreqn, sizeof(mreqn)); + if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE)) + { + /* see above: handle possible problem when interface comes back up */ + char buf[1][INET_ADDRSTRLEN]; + zlog_info("setsockopt_ipv4_multicast attempting to drop and " + "re-add (fd %d, mcast %s, ifindex %u)", + sock, + inet_ntop(AF_INET, &mreqn.imr_multiaddr, + buf[0], sizeof(buf[0])), ifindex); + setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, + (void *)&mreqn, sizeof(mreqn)); + ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (void *)&mreqn, sizeof(mreqn)); } + return ret; /* Example defines for another OS, boilerplate off other code in this function, AND handle optname as per other sections for consistency !! */ /* #elif defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */ /* Add your favourite OS here! */ -#else /* #if OS_TYPE */ +#elif defined(HAVE_BSD_STRUCT_IP_MREQ_HACK) /* #if OS_TYPE */ /* standard BSD API */ struct in_addr m; struct ip_mreq mreq; int ret; -#ifdef HAVE_BSD_STRUCT_IP_MREQ_HACK - if (ifindex) - m.s_addr = htonl(ifindex); - else -#endif - m = if_addr; + assert(optname == IP_ADD_MEMBERSHIP || optname == IP_DROP_MEMBERSHIP); - switch (optname) - { - case IP_MULTICAST_IF: - return setsockopt (sock_fd, IPPROTO_IP, optname, (void *)&m, sizeof(m)); - break; - - case IP_ADD_MEMBERSHIP: - case IP_DROP_MEMBERSHIP: - memset (&mreq, 0, sizeof(mreq)); - mreq.imr_multiaddr.s_addr = mcast_addr; - mreq.imr_interface = m; - - ret = setsockopt (sock_fd, IPPROTO_IP, optname, (void *)&mreq, sizeof(mreq)); - if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE)) - { - /* see above: handle possible problem when interface comes back up */ - char buf[2][INET_ADDRSTRLEN]; - zlog_info("setsockopt_multicast_ipv4 attempting to drop and " - "re-add (fd %d, ifaddr %s, mcast %s, ifindex %u)", - sock_fd, - inet_ntop(AF_INET, &if_addr, buf[0], sizeof(buf[0])), - inet_ntop(AF_INET, &mreq.imr_multiaddr, - buf[1], sizeof(buf[1])), ifindex); - setsockopt (sock_fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, - &mreq, sizeof(mreq)); - ret = setsockopt (sock_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, - &mreq, sizeof(mreq)); - } - return ret; + m.s_addr = htonl(ifindex); + + memset (&mreq, 0, sizeof(mreq)); + mreq.imr_multiaddr.s_addr = mcast_addr; + mreq.imr_interface = m; - default: - /* Can out and give an understandable error */ - errno = EINVAL; - return -1; + ret = setsockopt (sock, IPPROTO_IP, optname, (void *)&mreq, sizeof(mreq)); + if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE)) + { + /* see above: handle possible problem when interface comes back up */ + char buf[1][INET_ADDRSTRLEN]; + zlog_info("setsockopt_ipv4_multicast attempting to drop and " + "re-add (fd %d, mcast %s, ifindex %u)", + sock, + inet_ntop(AF_INET, &mreq.imr_multiaddr, + buf[0], sizeof(buf[0])), ifindex); + setsockopt (sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, + (void *)&mreq, sizeof(mreq)); + ret = setsockopt (sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (void *)&mreq, sizeof(mreq)); } + return ret; + +#else + #error "Unsupported multicast API" #endif /* #if OS_TYPE */ } +/* + * Set IP_MULTICAST_IF socket option in an OS-dependent manner. + */ +extern int +setsockopt_ipv4_multicast_if(int sock, + unsigned int ifindex) +{ + +#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX + struct ip_mreqn mreqn; + memset (&mreqn, 0, sizeof(mreqn)); + + mreqn.imr_ifindex = ifindex; + return setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&mreqn, sizeof(mreqn)); + + /* Example defines for another OS, boilerplate off other code in this + function */ + /* #elif defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */ + /* Add your favourite OS here! */ +#elif defined(HAVE_BSD_STRUCT_IP_MREQ_HACK) + struct in_addr m; + + m.s_addr = htonl(ifindex); + + return setsockopt (sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&m, sizeof(m)); +#else + #error "Unsupported multicast API" +#endif +} + /*============================================================================== * Set pktinfo and get ifindex etc */ @@ -896,7 +911,7 @@ getsockopt_ifindex (int af, struct msghdr *msgh) #endif default: - zlog_warn ("getsockopt_ifindex: unknown address family %d", af); + zlog_warn ("%s: unknown address family %d", __func__, af); return 0 ; } } @@ -974,6 +989,8 @@ getsockopt_ipv4_ifindex (struct msghdr *msgh) return ifindex; } +#ifdef HAVE_IPV6 + /*------------------------------------------------------------------------------ * AF_INET6: extract ifindex from struct msghdr, if can * @@ -983,7 +1000,6 @@ getsockopt_ipv4_ifindex (struct msghdr *msgh) * 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) { @@ -996,7 +1012,8 @@ getsockopt_ipv6_ifindex (struct msghdr *msgh) else return 0 ; } -#endif + +#endif /* HAVE_IPV6 */ /*------------------------------------------------------------------------------ * Scan msg_control portion of struct msghdr, looking for a cmsg with the given @@ -1020,7 +1037,7 @@ getsockopt_cmsg_data (struct msghdr *msgh, int level, int type) return (void*)CMSG_DATA(cmsg); return NULL; -} +} ; /*------------------------------------------------------------------------------ * swab iph between order system uses for IP_HDRINCL and host order @@ -1232,6 +1249,28 @@ setsockopt_ipv6_multicast_loop (int sock_fd, int val) } ; return ret; } + + + +extern int +setsockopt_ipv6_tclass(int sock_fd, int tclass) +{ + int ret = 0; + +#ifdef IPV6_TCLASS /* RFC3542 */ + ret = setsockopt(sock_fd, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof(tclass)); + if (ret < 0) + { + int err = errno ; + zlog_warn ("Can't set IPV6_TCLASS option for fd %d to %#x: %s", + sock_fd, tclass, errtoa(err, 0).str); + errno = err ; + } ; +#endif + + return ret; +} + #endif /* HAVE_IPV6 */ diff --git a/lib/sockopt.h b/lib/sockopt.h index c706a74f..46a4465f 100644 --- a/lib/sockopt.h +++ b/lib/sockopt.h @@ -38,7 +38,6 @@ extern int getsockopt_so_sendbuf (int sock_fd); 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 * because this macro will only be used #if HAVE_IPV6, and in6_pktinfo @@ -84,16 +83,15 @@ extern int setsockopt_tcp_signature(int sock_fd, union sockunion *su, (((af) == AF_INET) : SOPT_SIZE_CMSG_IFINDEX_IPV4() \ ? SOPT_SIZE_CMSG_PKTINFO_IPV6()) -extern int setsockopt_multicast_ipv4(int sock_fd, int optname, - struct in_addr if_addr - /* required: interface to join on */, - unsigned int mcast_addr, - unsigned int ifindex - /* optional: if non-zero, may be used - instead of if_addr */); extern int setsockopt_ipv4_tos(int sock_fd, int tos); +extern int setsockopt_ipv4_multicast_if(int sock, + unsigned int ifindex); +extern int setsockopt_ipv4_multicast(int sock, int optname, + unsigned int mcast_addr, + unsigned int ifindex); -/* Ask for, and get, ifindex, by whatever method is supported. */ +/* Ask for, and get, ifindex, by whatever method is supported. + */ extern int setsockopt_pktinfo (int, int, int); extern int getsockopt_ifindex (int, struct msghdr *); @@ -112,6 +110,7 @@ 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); +extern int setsockopt_ipv6_tclass (int, int); #endif /* HAVE_IPV6 */ diff --git a/lib/sockunion.c b/lib/sockunion.c index 8604f154..d91d5c6c 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -576,7 +576,7 @@ sockunion_stream_socket (sockunion su) su->sa.sa_family = AF_INET_UNION; return sockunion_socket (su, SOCK_STREAM, 0); -} +} ; /*------------------------------------------------------------------------------ * Initiate a connection @@ -586,7 +586,7 @@ sockunion_stream_socket (sockunion su) * TODO: discover how the ifindex thing is supposed to work !! * * Returns: 0 : OK (so far so good) - * < 0 : failed -- see errno + * != 0 : failed == errno * * Logs a LOG_INFO message if fails. */ @@ -595,7 +595,7 @@ sockunion_connect(int sock_fd, union sockunion* peer_su, unsigned short port, unsigned int ifindex) { union sockunion su ; - int ret, err ; + int err, ret ; int sa_len ; memcpy(&su, peer_su, sizeof(union sockunion)) ; @@ -629,10 +629,9 @@ sockunion_connect(int sock_fd, union sockunion* peer_su, unsigned short port, return 0 ; /* instant success or EINPROGRESS as expected */ zlog_info("cannot connect to %s port %d socket %d: %s", - sutoa(&su).str, port, sock_fd, errtoa(err, 0).str) ; - errno = err ; + sutoa(&su).str, port, sock_fd, errtoa(err, 0).str) ; - return ret ; + return errno = err ; } ; /*------------------------------------------------------------------------------ @@ -658,7 +657,7 @@ sockunion_listen(int sock_fd, int backlog) } ; return ret ; -} ; +} /*------------------------------------------------------------------------------ * Bind socket to address/port. diff --git a/lib/sockunion.h b/lib/sockunion.h index a3f9b70a..66fbe030 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -48,6 +48,7 @@ typedef struct prefix* prefix ; typedef union sockunion* sockunion ; typedef union sockunion sockunion_t ; + union sockunion { struct sockaddr sa; @@ -64,8 +65,9 @@ union sockunion #define AF_INET_UNION AF_INET #endif -/* Sockunion address string length. Accommodate either IPv4 or IPv6. */ -#define SU_ADDRSTRLEN 46 +/* Sockunion address string length. Accommodate either IPv4 or IPv6. + */ +#define SU_ADDRSTRLEN 50 CONFIRM(SU_ADDRSTRLEN >= INET_ADDRSTRLEN) ; #if HAVE_IPV6 diff --git a/lib/stream.c b/lib/stream.c index b2c37049..2c3088da 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -54,6 +54,8 @@ stream_new (size_t size) * endp -- 0 -- empty * size -- X -- see below * + * startp -- 0 -- tidy + * * overrun -- false -- OK so far ! * overflow -- false -- ditto * diff --git a/lib/stream.h b/lib/stream.h index 8da93076..4ceb9f18 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -116,6 +116,8 @@ struct stream size_t endp; /* last valid data position */ size_t size; /* size of data segment */ + size_t startp ; /* not used by stream itself */ + bool overflow ; /* set if attempts to put beyond size */ bool overrun ; /* set if attempts to get beyond endp */ @@ -159,8 +161,10 @@ Inline size_t stream_get_getp(struct stream* s); Inline size_t stream_get_endp(struct stream* s); Inline size_t stream_get_len(struct stream* s) ; Inline size_t stream_get_size(struct stream* s) ; +Inline size_t stream_get_startp(struct stream* s) ; Inline byte* stream_get_data(struct stream* s) ; Inline byte* stream_get_pnt(struct stream* s) ; +Inline byte* stream_get_pnt_to (struct stream *s, size_t pos) ; Inline size_t stream_get_read_left(struct stream* s) ; Inline size_t stream_get_read_left_from(struct stream* s, size_t from) ; @@ -170,13 +174,17 @@ Inline size_t stream_get_write_left_at(struct stream* s, size_t at) ; Inline bool stream_has_write_left(struct stream* s, size_t len) ; Inline bool stream_has_overrun(struct stream* s) ; Inline bool stream_has_overflowed(struct stream* s) ; +Inline void stream_clear_overrun(struct stream* s) ; +Inline void stream_clear_overflow(struct stream* s) ; Inline void stream_set_getp(struct stream *, size_t); Inline void stream_set_endp(struct stream *, size_t); +Inline void stream_set_startp(struct stream* s, size_t) ; +Inline void stream_reset_getp(struct stream* s) ; Inline void stream_forward_getp(struct stream *, size_t); Inline void stream_forward_endp(struct stream *, size_t); -Inline bool stream_push_endp(struct stream* s, size_t len, size_t* old_endp) ; +Inline size_t stream_push_endp(struct stream* s, size_t len) ; Inline bool stream_pop_endp(struct stream* s, size_t old_endp) ; extern void stream_put (struct stream *, const void *, size_t); @@ -265,7 +273,7 @@ stream_is_empty (struct stream *s) Inline void stream_reset (struct stream *s) { - s->getp = s->endp = 0 ; + s->getp = s->endp = s->startp = 0 ; s->overflow = s->overrun = false ; } @@ -323,6 +331,21 @@ stream_get_size(struct stream* s) } ; /*------------------------------------------------------------------------------ + * The current s->startp + * + * s->startp is set to zero when a stream is created or reset. + * + * Otherwise the s->startp is of no interest to the stream code itself, but may + * be used for whatever purpose by users of the stream. + */ +Inline size_t +stream_get_startp(struct stream* s) +{ + qassert_stream(s) ; + return s->startp ; +} ; + +/*------------------------------------------------------------------------------ * The current stream data body * * May be NULL -- if size is zero. @@ -357,6 +380,27 @@ stream_get_pnt (struct stream *s) } /*------------------------------------------------------------------------------ + * Return pointer to byte at given position + * + * If the given position is > s->endp, then returns position of s->endp. + * + * stream_get_read_left_from() will get the number of bytes available at the + * given position. + * + * NB: if the stream size is changed, the address returned here may become out + * of date. + * + * NB: for ordinary processing of the contents of a stream, the various + * get/put functions are *recommended* ! + */ +Inline byte* +stream_get_pnt_to (struct stream *s, size_t pos) +{ + qassert_stream(s) ; + return s->data + ((pos <= s->endp) ? pos : s->endp) ; +} + +/*------------------------------------------------------------------------------ * Count of bytes between s->getp and s->endp. */ Inline size_t @@ -379,7 +423,7 @@ stream_get_read_left_from(struct stream* s, size_t from) } ; /*------------------------------------------------------------------------------ - * See if has at least len bytes between s->getp and s->lenp + * See if has at least len bytes between s->getp and s->endp */ Inline bool stream_has_read_left(struct stream* s, size_t len) @@ -439,6 +483,24 @@ stream_has_overflowed(struct stream* s) } ; /*------------------------------------------------------------------------------ + * Clear the overrun flag + */ +Inline void +stream_clear_overrun(struct stream* s) +{ + s->overrun = false ; +} + +/*------------------------------------------------------------------------------ + * Clear the overflow flag + */ +Inline void +stream_clear_overflow(struct stream* s) +{ + s->overflow = false ; +} + +/*------------------------------------------------------------------------------ * Set s->getp to given value. * * If value > s->endp will force to s->endp and set s->overrun. @@ -482,6 +544,40 @@ stream_set_endp (struct stream *s, size_t pos) } ; /*------------------------------------------------------------------------------ + * Set the s->startp to the given value. + * + * The s->startp is of no interest to the stream code itself, but may + * be used for whatever purpose by users of the stream. + */ +Inline void +stream_set_startp(struct stream* s, size_t pos) +{ + qassert_stream(s) ; + s->startp = pos ; +} ; + +/*------------------------------------------------------------------------------ + * Reset s->getp to the current s->startp + * + * s->startp is set to zero when a stream is created or reset. + * + * Otherwise the s->startp is of no interest to the stream code itself, but may + * be used for whatever purpose by users of the stream. + * + * If s->getp is now > s->endp will force to s->endp and set s->overrun. + */ +Inline void +stream_reset_getp (struct stream *s) +{ + qassert_stream(s) ; + + s->getp = s->startp ; + + if (s->getp > s->endp) + stream_set_overs(s) ; +} ; + +/*------------------------------------------------------------------------------ * Move s->getp forwards by given step. * * If result > s->endp will force to s->endp and set s->overrun. @@ -516,57 +612,54 @@ stream_forward_endp (struct stream *s, size_t step) } ; /*------------------------------------------------------------------------------ - * Push current s->endp and set a new value -- for reading ! + * Return current s->endp and set a new s->end *wrt* current s->getp (push) * * This may be used when reader knows that is about to read some unit of data * which is expected to be len bytes long. * - * Fails if there are fewer than len bytes between s->getp and s->endp. - * - * Returns: true <=> OK -- new s->endp set. - * false <=> failed -- s->endp unchanged and overrun set + * If there are fewer than len bytes between s->getp and s->endp, leaves + * s->endp as it is and sets overrun. * - * If during reading the s->getp would move beyond the current s->endp, will - * return zeros and set overrun in the usual way. + * Caller can check overrun immediately or leave for later -- proceeding to + * read will hit the current s->endp and set overrun again. * - * Caller can ignore the return code and continue, overrun is already set and - * will, presumably, hit overrun again. Popping the saved value will work - * fine. + * In any case, restoring (pop) the saved value will work fine (even if failed). */ -Inline bool -stream_push_endp(struct stream* s, size_t len, size_t* old_endp) +Inline size_t +stream_push_endp(struct stream* s, size_t len) { - size_t new_endp ; + size_t new_endp, old_endp ; qassert_stream(s) ; - *old_endp = s->endp ; - new_endp = s->getp + len ; + old_endp = s->endp ; + new_endp = s->getp + len ; - if (new_endp <= *old_endp) - { - s->endp = new_endp ; - return true ; - } + if (new_endp <= old_endp) + s->endp = new_endp ; else - { - s->overrun = true ; - return false ; - } ; + s->overrun = true ; + + return old_endp ; } ; /*------------------------------------------------------------------------------ * Pop saved value for s->endp -- restore to as before stream_push_endp() * * This deemed to be OK if s->getp == s->endp -- ie the s->getp has reached the - * end of the unit of data was about to process when did stream_push_endp(). + * end of the unit of data was about to process when did stream_push_endp(), + * AND has not overrun. + * + * If not OK will force s->getp to the current s->endp. * - * If not OK will force s->getp and set s->overrun. + * NB: if have not read everything, returns false without setting s->overrun. + * So, provided s->overrun was not set at the time of the push, can + * distinguish underrun from overrun. * * Expects the value being restored to be valid -- but checks for overflow and * overrun just in case ! * - * Returns: OK or not + * Returns: (getp == old endp) && not overrun */ Inline bool stream_pop_endp(struct stream* s, size_t old_endp) @@ -574,22 +667,19 @@ stream_pop_endp(struct stream* s, size_t old_endp) bool ok ; qassert_stream(s) ; - qassert((old_endp <= s->size) && (s->endp <= old_endp)) ; + qassert((s->endp <= old_endp) && (old_endp <= s->size)) ; - ok = s->getp == s->endp ; + ok = (s->getp == s->endp) ; if (!ok) - { - s->getp = s->endp ; - s->overrun = true ; - } ; + s->getp = s->endp ; s->endp = old_endp ; - if ((s->endp > s->size) || (s->getp > s->endp)) + if ((s->endp > s->size) || (s->getp > s->endp)) /* impossible ! */ stream_set_overs(s) ; - return ok ; + return ok && !s->overrun ; } ; #endif /* _ZEBRA_STREAM_H */ diff --git a/lib/thread.c b/lib/thread.c index 6b3b8f37..be490f9f 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -298,7 +298,7 @@ cpu_record_hash_free (void *a) XFREE (MTYPE_THREAD_STATS, hist); } -static inline void +static void vty_out_cpu_thread_history(struct vty* vty, const struct cpu_thread_history *a) { @@ -664,7 +664,7 @@ thread_master_free (struct thread_master *m) } /* Thread list is empty or not. */ -static inline int +static int thread_empty (struct thread_list *list) { return list->head ? 0 : 1; diff --git a/lib/thread.h b/lib/thread.h index 379df3bd..32de40dc 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -1,5 +1,6 @@ /* Thread management routine header. * Copyright (C) 1998 Kunihiro Ishiguro + * Portions Copyright (c) 2008 Everton da Silva Marques <everton.marques@gmail.com> * * This file is part of GNU Zebra. * @@ -145,6 +146,12 @@ enum quagga_clkid { thread = thread_add_timer (master, func, arg, time); \ } while (0) +#define THREAD_TIMER_MSEC_ON(master,thread,func,arg,time) \ + do { \ + if (! thread) \ + thread = thread_add_timer_msec (master, func, arg, time); \ + } while (0) + #define THREAD_OFF(thread) \ do { \ if (thread) \ diff --git a/lib/vector.h b/lib/vector.h index 7dafc52d..f80f85c6 100644 --- a/lib/vector.h +++ b/lib/vector.h @@ -60,7 +60,8 @@ enum #define VECTOR_INIT_EMPTY { .p_items = NULL, .end = 0, .limit = 0 } -/* Under very controlled circumstances, may access the vector body */ +/* Under very controlled circumstances, may access the vector body + */ typedef p_vector_item const* vector_body_t ; /*------------------------------------------------------------------------------ diff --git a/lib/workqueue.c b/lib/workqueue.c index 8a96bce7..5ca21a9c 100644 --- a/lib/workqueue.c +++ b/lib/workqueue.c @@ -92,7 +92,7 @@ work_queue_free (struct work_queue *wq) return; } -static inline int +static int work_queue_schedule (struct work_queue *wq, unsigned int delay) { /* if appropriate, schedule work queue thread */ diff --git a/lib/zclient.c b/lib/zclient.c index 00ee394e..88667d05 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -36,6 +36,8 @@ /* Zebra client events. */ enum event {ZLOOKUP_SCHEDULE, ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT}; +char *zclient_serv_path = NULL; + /* This file local debug flag. */ int zclient_debug = 0; @@ -199,8 +201,10 @@ zclient_reset (struct zclient *zclient) zclient_init (zclient, zclient->redist_default); } +#ifdef HAVE_TCP_ZEBRA + /* Make socket to zebra daemon. Return zebra socket. */ -int +static int zclient_socket(void) { int sock; @@ -231,10 +235,12 @@ zclient_socket(void) return sock; } +#else + /* For sockaddr_un. */ #include <sys/un.h> -int +static int zclient_socket_un (const char *path) { int ret; @@ -264,6 +270,27 @@ zclient_socket_un (const char *path) return sock; } +#endif /* HAVE_TCP_ZEBRA */ + +/** + * Connect to zebra daemon. + * @param zclient a pointer to zclient structure + * @return socket fd just to make sure that connection established + * @see zclient_init + * @see zclient_new + */ +static int +zclient_socket_connect (struct zclient *zc) +{ +#ifdef HAVE_TCP_ZEBRA + zc->sock = zclient_socket (); +#else + zc->sock = zclient_socket_un (zclient_serv_path ? zclient_serv_path + : ZEBRA_SERV_PATH); +#endif + return zc->sock; +} + static int zclient_failed(struct zclient *zclient) { @@ -383,6 +410,25 @@ zebra_message_send (struct zclient *zclient, int command) return zclient_send_message(zclient); } +static int +zebra_hello_send (struct zclient *zclient) +{ + struct stream *s; + + if (zclient->redist_default) + { + s = zclient->obuf; + stream_reset (s); + + zclient_create_header (s, ZEBRA_HELLO); + stream_putc (s, zclient->redist_default); + stream_putw_at (s, 0, stream_get_endp (s)); + return zclient_send_message(zclient); + } + + return 0; +} + /* Make connection to zebra daemon. */ int zclient_start (struct zclient *zclient) @@ -409,12 +455,7 @@ zclient_start (struct zclient *zclient) return 0; /* Make socket. */ -#ifdef HAVE_TCP_ZEBRA - zclient->sock = zclient_socket (); -#else - zclient->sock = zclient_socket_un (ZEBRA_SERV_PATH); -#endif /* HAVE_TCP_ZEBRA */ - if (zclient->sock < 0) + if (zclient_socket_connect(zclient) < 0) { if (zclient_debug) zlog_debug ("zclient connection fail"); @@ -423,6 +464,9 @@ zclient_start (struct zclient *zclient) return -1; } + if (zclient_nexus) + qps_add_file(zclient_nexus->selection, zclient->qf, zclient->sock, zclient); + if (set_nonblocking(zclient->sock) < 0) zlog_warn("%s: set_nonblocking(%d) failed", __func__, zclient->sock); @@ -431,12 +475,11 @@ zclient_start (struct zclient *zclient) if (zclient_debug) zlog_debug ("zclient connect success with socket [%d]", zclient->sock); - if (zclient_nexus) - qps_add_file(zclient_nexus->selection, zclient->qf, zclient->sock, zclient); - /* Create read thread. */ zclient_event (ZCLIENT_READ, zclient); + zebra_hello_send (zclient); + /* We need router-id information. */ zebra_message_send (zclient, ZEBRA_ROUTER_ID_ADD); @@ -496,18 +539,10 @@ zlookup_connect_t (struct thread *t) zlookup = THREAD_ARG (t); zlookup->t_connect = NULL; - if (zlookup->sock != -1) - return 0; - -#ifdef HAVE_TCP_ZEBRA - zlookup->sock = zclient_socket (); -#else - zlookup->sock = zclient_socket_un (ZEBRA_SERV_PATH); -#endif /* HAVE_TCP_ZEBRA */ if (zlookup->sock < 0) - return -1; + zclient_socket_connect(zlookup) ; - return 0; + return (zlookup->sock >= 0) ? 0 : -1 ; } /* Connect to zebra for nexthop lookup. @@ -519,17 +554,10 @@ zlookup_connect_r (qtimer qtr, void* timer_info, qtime_t when) qtimer_unset(qtr); - if (zlookup->sock != -1) - return; - -#ifdef HAVE_TCP_ZEBRA - zlookup->sock = zclient_socket (); -#else - zlookup->sock = zclient_socket_un (ZEBRA_SERV_PATH); -#endif /* HAVE_TCP_ZEBRA */ + if (zlookup->sock < 0) + zclient_socket_connect(zlookup) ; } - /* * "xdr_encode"-like interface that allows daemon (client) to send * a message to zebra server for a route that needs to be @@ -544,7 +572,9 @@ zlookup_connect_r (qtimer qtr, void* timer_info, qtime_t when) * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Length (2) | Command | Route Type | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | ZEBRA Flags | Message Flags | Prefix length | + * | ZEBRA Flags | Message Flags | SAFI | + * +---------------+---------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Prefix length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Destination IPv4 Prefix for route | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -592,6 +622,7 @@ zapi_ipv4_route (u_char cmd, struct zclient *zclient, struct prefix_ipv4 *p, stream_putc (s, api->type); stream_putc (s, api->flags); stream_putc (s, api->message); + stream_putw (s, api->safi); /* Put prefix information. */ psize = PSIZE (p->prefixlen); @@ -653,6 +684,7 @@ zapi_ipv6_route (u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, stream_putc (s, api->type); stream_putc (s, api->flags); stream_putc (s, api->message); + stream_putw (s, api->safi); /* Put prefix information. */ psize = PSIZE (p->prefixlen); @@ -970,7 +1002,6 @@ zclient_read_t (struct thread *thread) static int zclient_read (struct zclient *zclient) { - int ret; size_t already; uint16_t length, command; uint8_t marker, version; @@ -1060,47 +1091,47 @@ zclient_read (struct zclient *zclient) { case ZEBRA_ROUTER_ID_UPDATE: if (zclient->router_id_update) - ret = (*zclient->router_id_update) (command, zclient, length); + (*zclient->router_id_update) (command, zclient, length); break; case ZEBRA_INTERFACE_ADD: if (zclient->interface_add) - ret = (*zclient->interface_add) (command, zclient, length); + (*zclient->interface_add) (command, zclient, length); break; case ZEBRA_INTERFACE_DELETE: if (zclient->interface_delete) - ret = (*zclient->interface_delete) (command, zclient, length); + (*zclient->interface_delete) (command, zclient, length); break; case ZEBRA_INTERFACE_ADDRESS_ADD: if (zclient->interface_address_add) - ret = (*zclient->interface_address_add) (command, zclient, length); + (*zclient->interface_address_add) (command, zclient, length); break; case ZEBRA_INTERFACE_ADDRESS_DELETE: if (zclient->interface_address_delete) - ret = (*zclient->interface_address_delete) (command, zclient, length); + (*zclient->interface_address_delete) (command, zclient, length); break; case ZEBRA_INTERFACE_UP: if (zclient->interface_up) - ret = (*zclient->interface_up) (command, zclient, length); + (*zclient->interface_up) (command, zclient, length); break; case ZEBRA_INTERFACE_DOWN: if (zclient->interface_down) - ret = (*zclient->interface_down) (command, zclient, length); + (*zclient->interface_down) (command, zclient, length); break; case ZEBRA_IPV4_ROUTE_ADD: if (zclient->ipv4_route_add) - ret = (*zclient->ipv4_route_add) (command, zclient, length); + (*zclient->ipv4_route_add) (command, zclient, length); break; case ZEBRA_IPV4_ROUTE_DELETE: if (zclient->ipv4_route_delete) - ret = (*zclient->ipv4_route_delete) (command, zclient, length); + (*zclient->ipv4_route_delete) (command, zclient, length); break; case ZEBRA_IPV6_ROUTE_ADD: if (zclient->ipv6_route_add) - ret = (*zclient->ipv6_route_add) (command, zclient, length); + (*zclient->ipv6_route_add) (command, zclient, length); break; case ZEBRA_IPV6_ROUTE_DELETE: if (zclient->ipv6_route_delete) - ret = (*zclient->ipv6_route_delete) (command, zclient, length); + (*zclient->ipv6_route_delete) (command, zclient, length); break; default: break; @@ -1235,3 +1266,29 @@ zclient_event_t (enum event event, struct zclient *zclient) break; } } + +void +zclient_serv_path_set (char *path) +{ + struct stat sb; + + /* reset */ + zclient_serv_path = NULL; + + /* test if `path' is socket. don't set it otherwise. */ + if (stat(path, &sb) == -1) + { + zlog_warn ("%s: zebra socket `%s' does not exist", __func__, path); + return; + } + + if ((sb.st_mode & S_IFMT) != S_IFSOCK) + { + zlog_warn ("%s: `%s' is not unix socket, sir", __func__, path); + return; + } + + /* it seems that path is unix socket */ + zclient_serv_path = path; +} + diff --git a/lib/zclient.h b/lib/zclient.h index 02d0a0ad..f488c8b0 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -114,6 +114,8 @@ struct zapi_ipv4 u_char message; + safi_t safi; + u_char nexthop_num; struct in_addr **nexthop; @@ -135,11 +137,7 @@ extern void zclient_reset (struct zclient *); extern void zclient_free (struct zclient *); extern void zlookup_schedule(struct zclient *); -/* Get TCP socket connection to zebra daemon at loopback address. */ -extern int zclient_socket (void); - -/* Get unix stream socket connection to zebra daemon at given path. */ -extern int zclient_socket_un (const char *); +extern void zclient_serv_path_set (char *path); /* Send redistribute command to zebra daemon. Do not update zclient state. */ extern int zebra_redistribute_send (int command, struct zclient *, int type); @@ -176,6 +174,8 @@ struct zapi_ipv6 u_char message; + safi_t safi; + u_char nexthop_num; struct in6_addr **nexthop; diff --git a/lib/zebra.h b/lib/zebra.h index 031fe85c..2909bb8c 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -235,10 +235,6 @@ typedef int socklen_t; #define UINT32_MAX (4294967295U) #endif -#ifdef HAVE_LIBUTIL_H -#include <libutil.h> -#endif /* HAVE_LIBUTIL_H */ - #ifdef HAVE_GLIBC_BACKTRACE #include <execinfo.h> #endif /* HAVE_GLIBC_BACKTRACE */ @@ -419,7 +415,8 @@ struct in_pktinfo #define ZEBRA_ROUTER_ID_ADD 20 #define ZEBRA_ROUTER_ID_DELETE 21 #define ZEBRA_ROUTER_ID_UPDATE 22 -#define ZEBRA_MESSAGE_MAX 23 +#define ZEBRA_HELLO 23 +#define ZEBRA_MESSAGE_MAX 24 /* Marker value used in new Zserv, in the byte location corresponding * the command value in the old zserv header. To allow old and new @@ -427,19 +424,8 @@ struct in_pktinfo */ #define ZEBRA_HEADER_MARKER 255 -/* Zebra route's types. */ -#define ZEBRA_ROUTE_SYSTEM 0 -#define ZEBRA_ROUTE_KERNEL 1 -#define ZEBRA_ROUTE_CONNECT 2 -#define ZEBRA_ROUTE_STATIC 3 -#define ZEBRA_ROUTE_RIP 4 -#define ZEBRA_ROUTE_RIPNG 5 -#define ZEBRA_ROUTE_OSPF 6 -#define ZEBRA_ROUTE_OSPF6 7 -#define ZEBRA_ROUTE_ISIS 8 -#define ZEBRA_ROUTE_BGP 9 -#define ZEBRA_ROUTE_HSLS 10 -#define ZEBRA_ROUTE_MAX 11 +/* Zebra route's types are defined in route_types.h */ +#include "lib/route_types.h" /* Note: whenever a new route-type or zserv-command is added the * corresponding {command,route}_types[] table in lib/log.c MUST be @@ -453,6 +439,10 @@ extern char zebra_route_char(unsigned int route_type); * e.g. ZEBRA_INTERFACE_ADD -> "ZEBRA_INTERFACE_ADD" */ /* Map a protocol name to its number. e.g. ZEBRA_ROUTE_BGP->9*/ extern int proto_name2num(const char *s); +/* Map redistribute X argument to protocol number. + * unlike proto_name2num, this accepts shorthands and takes + * an AFI value to restrict input */ +extern int proto_redistnum(int afi, const char *s); extern const char *zserv_command_string (unsigned int command); diff --git a/m4/.cvsignore b/m4/.cvsignore deleted file mode 100644 index 2f02fdbd..00000000 --- a/m4/.cvsignore +++ /dev/null @@ -1,4 +0,0 @@ -Makefile -Makefile.in -.arch-inventory -.arch-ids diff --git a/ospf6d/.cvsignore b/ospf6d/.cvsignore deleted file mode 100644 index 522397a1..00000000 --- a/ospf6d/.cvsignore +++ /dev/null @@ -1,15 +0,0 @@ -Makefile.in -Makefile -*.o -*.patch -ospf6d -ospf6d.conf -tags -TAGS -.deps -.nfs* -*.lo -*.la -*.libs -.arch-inventory -.arch-ids diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index e03ec842..67242b74 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -555,7 +555,8 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa) prefix.family = AF_INET6; prefix.prefixlen = prefix_lsa->prefix.prefix_length; ospf6_prefix_in6_addr (&prefix.u.prefix6, &prefix_lsa->prefix); - prefix2str (&prefix, buf, sizeof (buf)); + if (is_debug) + prefix2str (&prefix, buf, sizeof (buf)); table = oa->ospf6->route_table; type = OSPF6_DEST_TYPE_NETWORK; prefix_options = prefix_lsa->prefix.prefix_options; @@ -574,7 +575,8 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa) router_lsa = (struct ospf6_inter_router_lsa *) OSPF6_LSA_HEADER_END (lsa->header); ospf6_linkstate_prefix (router_lsa->router_id, htonl (0), &prefix); - inet_ntop (AF_INET, &router_lsa->router_id, buf, sizeof (buf)); + if (is_debug) + inet_ntop (AF_INET, &router_lsa->router_id, buf, sizeof (buf)); table = oa->ospf6->brouter_table; type = OSPF6_DEST_TYPE_ROUTER; options[0] = router_lsa->options[0]; diff --git a/ospf6d/ospf6_abr.h b/ospf6d/ospf6_abr.h index 5d00c474..816f5964 100644 --- a/ospf6d/ospf6_abr.h +++ b/ospf6d/ospf6_abr.h @@ -22,6 +22,9 @@ #ifndef OSPF6_ABR_H #define OSPF6_ABR_H +/* for struct ospf6_route */ +#include "ospf6_route.h" + /* Debug option */ extern unsigned char conf_debug_ospf6_abr; #define OSPF6_DEBUG_ABR_ON() \ @@ -32,6 +35,7 @@ extern unsigned char conf_debug_ospf6_abr; (conf_debug_ospf6_abr) /* Inter-Area-Prefix-LSA */ +#define OSPF6_INTER_PREFIX_LSA_MIN_SIZE 4U /* w/o IPv6 prefix */ struct ospf6_inter_prefix_lsa { u_int32_t metric; @@ -39,6 +43,7 @@ struct ospf6_inter_prefix_lsa }; /* Inter-Area-Router-LSA */ +#define OSPF6_INTER_ROUTER_LSA_FIX_SIZE 12U struct ospf6_inter_router_lsa { u_char mbz; diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index f4b327e4..9934e6b9 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -420,6 +420,18 @@ ospf6_area_config_write (struct vty *vty) prefix2str (&range->prefix, buf, sizeof (buf)); vty_out (vty, " area %s range %s%s", oa->name, buf, VNL); } + if (PREFIX_NAME_IN (oa)) + vty_out (vty, " area %s filter-list prefix %s in%s", + oa->name, PREFIX_NAME_IN (oa), VNL); + if (PREFIX_NAME_OUT (oa)) + vty_out (vty, " area %s filter-list prefix %s out%s", + oa->name, PREFIX_NAME_OUT (oa), VNL); + if (IMPORT_NAME (oa)) + vty_out (vty, " area %s import-list %s%s", + oa->name, IMPORT_NAME (oa), VNL); + if (EXPORT_NAME (oa)) + vty_out (vty, " area %s export-list %s%s", + oa->name, EXPORT_NAME (oa), VNL); } } @@ -441,14 +453,14 @@ DEFUN (area_filter_list, argc--; argv++; - plist = prefix_list_lookup (AFI_IP6, argv[1]); - if (strncmp (argv[2], "in", 2) == 0) + plist = prefix_list_lookup (AFI_IP6, argv[0]); + if (strncmp (argv[1], "in", 2) == 0) { PREFIX_LIST_IN (area) = plist; if (PREFIX_NAME_IN (area)) free (PREFIX_NAME_IN (area)); - PREFIX_NAME_IN (area) = strdup (argv[1]); + PREFIX_NAME_IN (area) = strdup (argv[0]); ospf6_abr_reimport (area); } else @@ -457,7 +469,7 @@ DEFUN (area_filter_list, if (PREFIX_NAME_OUT (area)) free (PREFIX_NAME_OUT (area)); - PREFIX_NAME_OUT (area) = strdup (argv[1]); + PREFIX_NAME_OUT (area) = strdup (argv[0]); ospf6_abr_enable_area (area); } @@ -483,11 +495,11 @@ DEFUN (no_area_filter_list, argc--; argv++; - plist = prefix_list_lookup (AFI_IP6, argv[1]); - if (strncmp (argv[2], "in", 2) == 0) + plist = prefix_list_lookup (AFI_IP6, argv[0]); + if (strncmp (argv[1], "in", 2) == 0) { if (PREFIX_NAME_IN (area)) - if (strcmp (PREFIX_NAME_IN (area), argv[1]) != 0) + if (strcmp (PREFIX_NAME_IN (area), argv[0]) != 0) return CMD_SUCCESS; PREFIX_LIST_IN (area) = NULL; @@ -500,7 +512,7 @@ DEFUN (no_area_filter_list, else { if (PREFIX_NAME_OUT (area)) - if (strcmp (PREFIX_NAME_OUT (area), argv[1]) != 0) + if (strcmp (PREFIX_NAME_OUT (area), argv[0]) != 0) return CMD_SUCCESS; PREFIX_LIST_OUT (area) = NULL; diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index b1351bff..679a5112 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -447,6 +447,7 @@ ospf6_asbr_redistribute_add (int type, int ifindex, struct prefix *prefix, memset (&troute, 0, sizeof (troute)); memset (&tinfo, 0, sizeof (tinfo)); troute.route_option = &tinfo; + tinfo.ifindex = ifindex; ret = route_map_apply (ospf6->rmap[type].map, prefix, RMAP_OSPF6, &troute); @@ -616,27 +617,16 @@ ospf6_asbr_redistribute_remove (int type, int ifindex, struct prefix *prefix) DEFUN (ospf6_redistribute, ospf6_redistribute_cmd, - "redistribute (static|kernel|connected|ripng|bgp)", + "redistribute " QUAGGA_REDIST_STR_OSPF6D, "Redistribute\n" - "Static route\n" - "Kernel route\n" - "Connected route\n" - "RIPng route\n" - "BGP route\n" + QUAGGA_REDIST_HELP_STR_OSPF6D ) { - int type = 0; - - if (strncmp (argv[0], "sta", 3) == 0) - type = ZEBRA_ROUTE_STATIC; - else if (strncmp (argv[0], "ker", 3) == 0) - type = ZEBRA_ROUTE_KERNEL; - else if (strncmp (argv[0], "con", 3) == 0) - type = ZEBRA_ROUTE_CONNECT; - else if (strncmp (argv[0], "rip", 3) == 0) - type = ZEBRA_ROUTE_RIPNG; - else if (strncmp (argv[0], "bgp", 3) == 0) - type = ZEBRA_ROUTE_BGP; + int type; + + type = proto_redistnum(AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_OSPF6) + return CMD_WARNING; ospf6_asbr_redistribute_unset (type); ospf6_asbr_routemap_unset (type); @@ -646,29 +636,18 @@ DEFUN (ospf6_redistribute, DEFUN (ospf6_redistribute_routemap, ospf6_redistribute_routemap_cmd, - "redistribute (static|kernel|connected|ripng|bgp) route-map WORD", + "redistribute " QUAGGA_REDIST_STR_OSPF6D " route-map WORD", "Redistribute\n" - "Static routes\n" - "Kernel route\n" - "Connected route\n" - "RIPng route\n" - "BGP route\n" + QUAGGA_REDIST_HELP_STR_OSPF6D "Route map reference\n" "Route map name\n" ) { - int type = 0; - - if (strncmp (argv[0], "sta", 3) == 0) - type = ZEBRA_ROUTE_STATIC; - else if (strncmp (argv[0], "ker", 3) == 0) - type = ZEBRA_ROUTE_KERNEL; - else if (strncmp (argv[0], "con", 3) == 0) - type = ZEBRA_ROUTE_CONNECT; - else if (strncmp (argv[0], "rip", 3) == 0) - type = ZEBRA_ROUTE_RIPNG; - else if (strncmp (argv[0], "bgp", 3) == 0) - type = ZEBRA_ROUTE_BGP; + int type; + + type = proto_redistnum(AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_OSPF6) + return CMD_WARNING; ospf6_asbr_redistribute_unset (type); ospf6_asbr_routemap_set (type, argv[1]); @@ -678,28 +657,17 @@ DEFUN (ospf6_redistribute_routemap, DEFUN (no_ospf6_redistribute, no_ospf6_redistribute_cmd, - "no redistribute (static|kernel|connected|ripng|bgp)", + "no redistribute " QUAGGA_REDIST_STR_OSPF6D, NO_STR "Redistribute\n" - "Static route\n" - "Kernel route\n" - "Connected route\n" - "RIPng route\n" - "BGP route\n" + QUAGGA_REDIST_HELP_STR_OSPF6D ) { - int type = 0; - - if (strncmp (argv[0], "sta", 3) == 0) - type = ZEBRA_ROUTE_STATIC; - else if (strncmp (argv[0], "ker", 3) == 0) - type = ZEBRA_ROUTE_KERNEL; - else if (strncmp (argv[0], "con", 3) == 0) - type = ZEBRA_ROUTE_CONNECT; - else if (strncmp (argv[0], "rip", 3) == 0) - type = ZEBRA_ROUTE_RIPNG; - else if (strncmp (argv[0], "bgp", 3) == 0) - type = ZEBRA_ROUTE_BGP; + int type; + + type = proto_redistnum(AFI_IP6, argv[0]); + if (type < 0 || type == ZEBRA_ROUTE_OSPF6) + return CMD_WARNING; ospf6_asbr_redistribute_unset (type); ospf6_asbr_routemap_unset (type); @@ -813,6 +781,54 @@ ospf6_routemap_rule_match_address_prefixlist_cmd = ospf6_routemap_rule_match_address_prefixlist_free, }; +/* `match interface IFNAME' */ +/* Match function should return 1 if match is success else return + zero. */ +static route_map_result_t +ospf6_routemap_rule_match_interface (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct interface *ifp; + struct ospf6_external_info *ei; + + if (type == RMAP_OSPF6) + { + ei = ((struct ospf6_route *) object)->route_option; + ifp = if_lookup_by_name ((char *)rule); + + if (ifp != NULL + && ei->ifindex == ifp->ifindex) + return RMAP_MATCH; + } + + return RMAP_NOMATCH; +} + +/* Route map `interface' match statement. `arg' should be + interface name. */ +static void * +ospf6_routemap_rule_match_interface_compile (const char *arg) +{ + return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `interface' value. */ +static void +ospf6_routemap_rule_match_interface_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for interface matching. */ +struct route_map_rule_cmd +ospf6_routemap_rule_match_interface_cmd = +{ + "interface", + ospf6_routemap_rule_match_interface, + ospf6_routemap_rule_match_interface_compile, + ospf6_routemap_rule_match_interface_free +}; + static route_map_result_t ospf6_routemap_rule_set_metric_type (void *rule, struct prefix *prefix, route_map_object_t type, void *object) @@ -990,6 +1006,39 @@ DEFUN (ospf6_routemap_no_match_address_prefixlist, return route_map_command_status (vty, ret); } +/* "match interface" */ +DEFUN (ospf6_routemap_match_interface, + ospf6_routemap_match_interface_cmd, + "match interface WORD", + MATCH_STR + "Match first hop interface of route\n" + "Interface name\n") +{ + return route_map_add_match ((struct route_map_index *) vty->index, + "interface", argv[0]); +} + +/* "no match interface WORD" */ +DEFUN (ospf6_routemap_no_match_interface, + ospf6_routemap_no_match_interface_cmd, + "no match interface", + MATCH_STR + NO_STR + "Match first hop interface of route\n") +{ + int ret = route_map_delete_match ((struct route_map_index *) vty->index, + "interface", (argc == 0) ? NULL : argv[0]); + return route_map_command_status (vty, ret); +} + +ALIAS (ospf6_routemap_no_match_interface, + ospf6_routemap_no_match_interface_val_cmd, + "no match interface WORD", + MATCH_STR + NO_STR + "Match first hop interface of route\n" + "Interface name\n") + /* add "set metric-type" */ DEFUN (ospf6_routemap_set_metric_type, ospf6_routemap_set_metric_type_cmd, @@ -1082,6 +1131,8 @@ ospf6_routemap_init (void) route_map_delete_hook (ospf6_asbr_routemap_update); route_map_install_match (&ospf6_routemap_rule_match_address_prefixlist_cmd); + route_map_install_match (&ospf6_routemap_rule_match_interface_cmd); + route_map_install_set (&ospf6_routemap_rule_set_metric_type_cmd); route_map_install_set (&ospf6_routemap_rule_set_metric_cmd); route_map_install_set (&ospf6_routemap_rule_set_forwarding_cmd); @@ -1090,6 +1141,11 @@ ospf6_routemap_init (void) install_element (RMAP_NODE, &ospf6_routemap_match_address_prefixlist_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_match_address_prefixlist_cmd); + /* Match interface */ + install_element (RMAP_NODE, &ospf6_routemap_match_interface_cmd); + install_element (RMAP_NODE, &ospf6_routemap_no_match_interface_cmd); + install_element (RMAP_NODE, &ospf6_routemap_no_match_interface_val_cmd); + /* ASE Metric Type (e.g. Type-1/Type-2) */ install_element (RMAP_NODE, &ospf6_routemap_set_metric_type_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd); diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index d7bad420..8964cbeb 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -22,10 +22,12 @@ #ifndef OSPF6_ASBR_H #define OSPF6_ASBR_H +/* for struct ospf6_prefix */ #include "ospf6_proto.h" +/* for struct ospf6_lsa */ #include "ospf6_lsa.h" +/* for struct ospf6_route */ #include "ospf6_route.h" -#include "ospf6_top.h" /* Debug option */ extern unsigned char conf_debug_ospf6_asbr; @@ -46,9 +48,12 @@ struct ospf6_external_info struct in6_addr forwarding; /* u_int32_t tag; */ + + unsigned int ifindex; }; /* AS-External-LSA */ +#define OSPF6_AS_EXTERNAL_LSA_MIN_SIZE 4U /* w/o IPv6 prefix */ struct ospf6_as_external_lsa { u_int32_t bits_metric; diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 236baf17..71aa6859 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -108,14 +108,14 @@ ospf6_interface_create (struct interface *ifp) oi->neighbor_list = list_new (); oi->neighbor_list->cmp = ospf6_neighbor_cmp; oi->linklocal_addr = (struct in6_addr *) NULL; - oi->instance_id = 0; - oi->transdelay = 1; - oi->priority = 1; - - oi->hello_interval = 10; - oi->dead_interval = 40; - oi->rxmt_interval = 5; - oi->cost = 1; + oi->instance_id = OSPF6_INTERFACE_INSTANCE_ID; + oi->transdelay = OSPF6_INTERFACE_TRANSDELAY; + oi->priority = OSPF6_INTERFACE_PRIORITY; + + oi->hello_interval = OSPF6_INTERFACE_HELLO_INTERVAL; + oi->dead_interval = OSPF6_INTERFACE_DEAD_INTERVAL; + oi->rxmt_interval = OSPF6_INTERFACE_RXMT_INTERVAL; + oi->cost = OSPF6_INTERFACE_COST; oi->state = OSPF6_INTERFACE_DOWN; oi->flag = 0; oi->mtu_ignore = 0; @@ -399,12 +399,12 @@ ospf6_interface_state_change (u_char next_state, struct ospf6_interface *oi) prev_state == OSPF6_INTERFACE_BDR) && (next_state != OSPF6_INTERFACE_DR && next_state != OSPF6_INTERFACE_BDR)) - ospf6_leave_alldrouters (oi->interface->ifindex); + ospf6_sso (oi->interface->ifindex, &alldrouters6, IPV6_LEAVE_GROUP); if ((prev_state != OSPF6_INTERFACE_DR && prev_state != OSPF6_INTERFACE_BDR) && (next_state == OSPF6_INTERFACE_DR || next_state == OSPF6_INTERFACE_BDR)) - ospf6_join_alldrouters (oi->interface->ifindex); + ospf6_sso (oi->interface->ifindex, &alldrouters6, IPV6_JOIN_GROUP); OSPF6_ROUTER_LSA_SCHEDULE (oi->area); if (next_state == OSPF6_INTERFACE_DOWN) @@ -612,7 +612,7 @@ interface_up (struct thread *thread) } /* Join AllSPFRouters */ - ospf6_join_allspfrouters (oi->interface->ifindex); + ospf6_sso (oi->interface->ifindex, &allspfrouters6, IPV6_JOIN_GROUP); /* Update interface route */ ospf6_interface_connected_route_update (oi->interface); @@ -707,7 +707,7 @@ interface_down (struct thread *thread) /* Leave AllSPFRouters */ if (oi->state > OSPF6_INTERFACE_DOWN) - ospf6_leave_allspfrouters (oi->interface->ifindex); + ospf6_sso (oi->interface->ifindex, &allspfrouters6, IPV6_LEAVE_GROUP); ospf6_interface_state_change (OSPF6_INTERFACE_DOWN, oi); @@ -929,7 +929,7 @@ ALIAS (show_ipv6_ospf6_interface_ifname_prefix, "Display connected prefixes to advertise\n" OSPF6_ROUTE_ADDRESS_STR OSPF6_ROUTE_PREFIX_STR - "Dispaly details of the prefixes\n" + "Display details of the prefixes\n" ) ALIAS (show_ipv6_ospf6_interface_ifname_prefix, @@ -943,7 +943,7 @@ ALIAS (show_ipv6_ospf6_interface_ifname_prefix, "Display connected prefixes to advertise\n" OSPF6_ROUTE_PREFIX_STR OSPF6_ROUTE_MATCH_STR - "Dispaly details of the prefixes\n" + "Display details of the prefixes\n" ) DEFUN (show_ipv6_ospf6_interface_prefix, @@ -982,7 +982,7 @@ ALIAS (show_ipv6_ospf6_interface_prefix, "Display connected prefixes to advertise\n" OSPF6_ROUTE_ADDRESS_STR OSPF6_ROUTE_PREFIX_STR - "Dispaly details of the prefixes\n" + "Display details of the prefixes\n" ) ALIAS (show_ipv6_ospf6_interface_prefix, @@ -995,7 +995,7 @@ ALIAS (show_ipv6_ospf6_interface_prefix, "Display connected prefixes to advertise\n" OSPF6_ROUTE_PREFIX_STR OSPF6_ROUTE_MATCH_STR - "Dispaly details of the prefixes\n" + "Display details of the prefixes\n" ) @@ -1522,23 +1522,36 @@ config_write_ospf6_interface (struct vty *vty) if (ifp->desc) vty_out (vty, " description %s%s", ifp->desc, VNL); - if (ifp->mtu6 != oi->ifmtu) vty_out (vty, " ipv6 ospf6 ifmtu %d%s", oi->ifmtu, VNL); - vty_out (vty, " ipv6 ospf6 cost %d%s", - oi->cost, VNL); - vty_out (vty, " ipv6 ospf6 hello-interval %d%s", - oi->hello_interval, VNL); - vty_out (vty, " ipv6 ospf6 dead-interval %d%s", - oi->dead_interval, VNL); - vty_out (vty, " ipv6 ospf6 retransmit-interval %d%s", - oi->rxmt_interval, VNL); - vty_out (vty, " ipv6 ospf6 priority %d%s", - oi->priority, VNL); - vty_out (vty, " ipv6 ospf6 transmit-delay %d%s", - oi->transdelay, VNL); - vty_out (vty, " ipv6 ospf6 instance-id %d%s", - oi->instance_id, VNL); + + if (oi->cost != OSPF6_INTERFACE_COST) + vty_out (vty, " ipv6 ospf6 cost %d%s", + oi->cost, VNL); + + if (oi->hello_interval != OSPF6_INTERFACE_HELLO_INTERVAL) + vty_out (vty, " ipv6 ospf6 hello-interval %d%s", + oi->hello_interval, VNL); + + if (oi->dead_interval != OSPF6_INTERFACE_DEAD_INTERVAL) + vty_out (vty, " ipv6 ospf6 dead-interval %d%s", + oi->dead_interval, VNL); + + if (oi->rxmt_interval != OSPF6_INTERFACE_RXMT_INTERVAL) + vty_out (vty, " ipv6 ospf6 retransmit-interval %d%s", + oi->rxmt_interval, VNL); + + if (oi->priority != OSPF6_INTERFACE_PRIORITY) + vty_out (vty, " ipv6 ospf6 priority %d%s", + oi->priority, VNL); + + if (oi->transdelay != OSPF6_INTERFACE_TRANSDELAY) + vty_out (vty, " ipv6 ospf6 transmit-delay %d%s", + oi->transdelay, VNL); + + if (oi->instance_id != OSPF6_INTERFACE_INSTANCE_ID) + vty_out (vty, " ipv6 ospf6 instance-id %d%s", + oi->instance_id, VNL); if (oi->plist_name) vty_out (vty, " ipv6 ospf6 advertise prefix-list %s%s", diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index cf758c07..2d1ff34d 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -124,6 +124,15 @@ extern const char *ospf6_interface_state_str[]; #define OSPF6_INTERFACE_DISABLE 0x01 #define OSPF6_INTERFACE_PASSIVE 0x02 +/* default values */ +#define OSPF6_INTERFACE_HELLO_INTERVAL 10 +#define OSPF6_INTERFACE_DEAD_INTERVAL 40 +#define OSPF6_INTERFACE_RXMT_INTERVAL 5 +#define OSPF6_INTERFACE_COST 1 +#define OSPF6_INTERFACE_PRIORITY 1 +#define OSPF6_INTERFACE_TRANSDELAY 1 +#define OSPF6_INTERFACE_INSTANCE_ID 0 + /* Function Prototypes */ diff --git a/ospf6d/ospf6_intra.h b/ospf6d/ospf6_intra.h index 31643fd8..3810174e 100644 --- a/ospf6d/ospf6_intra.h +++ b/ospf6d/ospf6_intra.h @@ -69,6 +69,7 @@ extern u_int32_t conf_debug_ospf6_brouter_specific_area_id; conf_debug_ospf6_brouter_specific_area_id == (area_id)) /* Router-LSA */ +#define OSPF6_ROUTER_LSA_MIN_SIZE 4U struct ospf6_router_lsa { u_char bits; @@ -77,6 +78,7 @@ struct ospf6_router_lsa }; /* Link State Description in Router-LSA */ +#define OSPF6_ROUTER_LSDESC_FIX_SIZE 16U struct ospf6_router_lsdesc { u_char type; @@ -105,6 +107,7 @@ struct ospf6_router_lsdesc (((struct ospf6_router_lsdesc *)(x))->neighbor_router_id) /* Network-LSA */ +#define OSPF6_NETWORK_LSA_MIN_SIZE 4U struct ospf6_network_lsa { u_char reserved; @@ -113,6 +116,7 @@ struct ospf6_network_lsa }; /* Link State Description in Router-LSA */ +#define OSPF6_NETWORK_LSDESC_FIX_SIZE 4U struct ospf6_network_lsdesc { u_int32_t router_id; @@ -121,6 +125,7 @@ struct ospf6_network_lsdesc (((struct ospf6_network_lsdesc *)(x))->router_id) /* Link-LSA */ +#define OSPF6_LINK_LSA_MIN_SIZE 24U /* w/o 1st IPv6 prefix */ struct ospf6_link_lsa { u_char priority; @@ -131,6 +136,7 @@ struct ospf6_link_lsa }; /* Intra-Area-Prefix-LSA */ +#define OSPF6_INTRA_PREFIX_LSA_MIN_SIZE 12U /* w/o 1st IPv6 prefix */ struct ospf6_intra_prefix_lsa { u_int16_t prefix_num; diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 9643e04d..d87d500b 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -163,9 +163,19 @@ ospf6_lsa_is_changed (struct ospf6_lsa *lsa1, return 1; if (ntohs (lsa1->header->length) != ntohs (lsa2->header->length)) return 1; + /* Going beyond LSA headers to compare the payload only makes sense, when both LSAs aren't header-only. */ + if (CHECK_FLAG (lsa1->flag, OSPF6_LSA_HEADERONLY) != CHECK_FLAG (lsa2->flag, OSPF6_LSA_HEADERONLY)) + { + zlog_warn ("%s: only one of two (%s, %s) LSAs compared is header-only", __func__, lsa1->name, lsa2->name); + return 1; + } + if (CHECK_FLAG (lsa1->flag, OSPF6_LSA_HEADERONLY)) + return 0; length = OSPF6_LSA_SIZE (lsa1->header) - sizeof (struct ospf6_lsa_header); - assert (length > 0); + /* Once upper layer verifies LSAs received, length underrun should become a warning. */ + if (length <= 0) + return 0; return memcmp (OSPF6_LSA_HEADER_END (lsa1->header), OSPF6_LSA_HEADER_END (lsa2->header), length); diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index c1093cab..7d93f5cb 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -79,6 +79,7 @@ (ntohs (type) & OSPF6_LSTYPE_SCOPE_MASK) /* LSA Header */ +#define OSPF6_LSA_HEADER_SIZE 20U struct ospf6_lsa_header { u_int16_t age; /* LS age */ @@ -244,7 +245,6 @@ extern struct ospf6_lsa_handler *ospf6_get_lsa_handler (u_int16_t type); extern void ospf6_lsa_init (void); extern void ospf6_lsa_terminate (void); -extern void ospf6_lsa_cmd_init (void); extern int config_write_ospf6_debug_lsa (struct vty *vty); extern void install_element_ospf6_debug_lsa (void); diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index cd00fa86..9f610a8f 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -35,10 +35,13 @@ #include "plist.h" #include "privs.h" #include "sigevent.h" +#include "zclient.h" #include "ospf6d.h" -#include "ospf6_asbr.h" +#include "ospf6_top.h" #include "ospf6_message.h" +#include "ospf6_asbr.h" +#include "ospf6_lsa.h" /* Default configuration file name for ospf6d. */ #define OSPF6_DEFAULT_CONFIG "ospf6d.conf" @@ -75,6 +78,7 @@ struct option longopts[] = { "daemon", no_argument, NULL, 'd'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, + { "socket", required_argument, NULL, 'z'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "user", required_argument, NULL, 'u'}, @@ -113,6 +117,7 @@ Daemon which manages OSPF version 3.\n\n\ -d, --daemon Runs in daemon mode\n\ -f, --config_file Set configuration file name\n\ -i, --pid_file Set process identifier file name\n\ +-z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -u, --user User to run as\n\ @@ -127,7 +132,7 @@ Report bugs to zebra@zebra.org\n", progname); exit (status); } -static void +static void __attribute__ ((noreturn)) ospf6_exit (int status) { extern struct ospf6 *ospf6; @@ -176,6 +181,7 @@ static void sigterm (void) { zlog_notice ("Terminating on signal SIGTERM"); + ospf6_clean(); ospf6_exit (0); } @@ -229,8 +235,7 @@ main (int argc, char *argv[], char *envp[]) /* Command line argument treatment. */ while (1) { - opt = getopt_long (argc, argv, "df:i:hp:A:P:u:g:vC", longopts, 0); - + opt = getopt_long (argc, argv, "df:i:z:hp:A:P:u:g:vC", longopts, 0); if (opt == EOF) break; @@ -250,6 +255,9 @@ main (int argc, char *argv[], char *envp[]) case 'i': pid_file = optarg; break; + case 'z': + zclient_serv_path_set (optarg); + break; case 'P': /* Deal with atoi() returning 0 on failure, and ospf6d not listening on ospf6d port... */ @@ -284,6 +292,13 @@ main (int argc, char *argv[], char *envp[]) } } + if (geteuid () != 0) + { + errno = EPERM; + perror (progname); + exit (1); + } + /* thread master */ master = thread_master_create (); diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 9a8345df..62c22489 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -39,12 +39,55 @@ #include "ospf6_neighbor.h" #include "ospf6_interface.h" +/* for structures and macros ospf6_lsa_examin() needs */ +#include "ospf6_abr.h" +#include "ospf6_asbr.h" +#include "ospf6_intra.h" + #include "ospf6_flood.h" #include "ospf6d.h" +#include <netinet/ip6.h> + unsigned char conf_debug_ospf6_message[6] = {0x03, 0, 0, 0, 0, 0}; -const char *ospf6_message_type_str[] = - { "Unknown", "Hello", "DbDesc", "LSReq", "LSUpdate", "LSAck" }; +static const struct message ospf6_message_type_str [] = +{ + { OSPF6_MESSAGE_TYPE_HELLO, "Hello" }, + { OSPF6_MESSAGE_TYPE_DBDESC, "DbDesc" }, + { OSPF6_MESSAGE_TYPE_LSREQ, "LSReq" }, + { OSPF6_MESSAGE_TYPE_LSUPDATE, "LSUpdate" }, + { OSPF6_MESSAGE_TYPE_LSACK, "LSAck" }, +}; +static const size_t ospf6_message_type_str_max = + sizeof (ospf6_message_type_str) / sizeof (ospf6_message_type_str[0]); + +/* Minimum (besides the standard OSPF packet header) lengths for OSPF + packets of particular types, offset is the "type" field. */ +const u_int16_t ospf6_packet_minlen[OSPF6_MESSAGE_TYPE_ALL] = +{ + 0, + OSPF6_HELLO_MIN_SIZE, + OSPF6_DB_DESC_MIN_SIZE, + OSPF6_LS_REQ_MIN_SIZE, + OSPF6_LS_UPD_MIN_SIZE, + OSPF6_LS_ACK_MIN_SIZE +}; + +/* Minimum (besides the standard LSA header) lengths for LSAs of particular + types, offset is the "LSA function code" portion of "LSA type" field. */ +const u_int16_t ospf6_lsa_minlen[OSPF6_LSTYPE_SIZE] = +{ + 0, + /* 0x2001 */ OSPF6_ROUTER_LSA_MIN_SIZE, + /* 0x2002 */ OSPF6_NETWORK_LSA_MIN_SIZE, + /* 0x2003 */ OSPF6_INTER_PREFIX_LSA_MIN_SIZE, + /* 0x2004 */ OSPF6_INTER_ROUTER_LSA_FIX_SIZE, + /* 0x4005 */ OSPF6_AS_EXTERNAL_LSA_MIN_SIZE, + /* 0x2006 */ 0, + /* 0x2007 */ OSPF6_AS_EXTERNAL_LSA_MIN_SIZE, + /* 0x0008 */ OSPF6_LINK_LSA_MIN_SIZE, + /* 0x2009 */ OSPF6_INTRA_PREFIX_LSA_MIN_SIZE +}; /* print functions */ @@ -93,8 +136,7 @@ ospf6_hello_print (struct ospf6_header *oh) zlog_debug (" Neighbor: %s", neighbor); } - if (p != OSPF6_MESSAGE_END (oh)) - zlog_debug ("Trailing garbage exists"); + assert (p == OSPF6_MESSAGE_END (oh)); } void @@ -126,8 +168,7 @@ ospf6_dbdesc_print (struct ospf6_header *oh) p += sizeof (struct ospf6_lsa_header)) ospf6_lsa_header_print_raw ((struct ospf6_lsa_header *) p); - if (p != OSPF6_MESSAGE_END (oh)) - zlog_debug ("Trailing garbage exists"); + assert (p == OSPF6_MESSAGE_END (oh)); } void @@ -150,8 +191,7 @@ ospf6_lsreq_print (struct ospf6_header *oh) ospf6_lstype_name (e->type), id, adv_router); } - if (p != OSPF6_MESSAGE_END (oh)) - zlog_debug ("Trailing garbage exists"); + assert (p == OSPF6_MESSAGE_END (oh)); } void @@ -176,35 +216,9 @@ ospf6_lsupdate_print (struct ospf6_header *oh) p += OSPF6_LSA_SIZE (p)) { ospf6_lsa_header_print_raw ((struct ospf6_lsa_header *) p); - if (OSPF6_LSA_SIZE (p) < sizeof (struct ospf6_lsa_header)) - { - zlog_debug (" Malformed LSA length, quit printing"); - break; - } } - if (p != OSPF6_MESSAGE_END (oh)) - { - char buf[32]; - - int num = 0; - memset (buf, 0, sizeof (buf)); - - zlog_debug (" Trailing garbage exists"); - while (p < OSPF6_MESSAGE_END (oh)) - { - snprintf (buf, sizeof (buf), "%s %2x", buf, *p++); - num++; - if (num == 8) - { - zlog_debug (" %s", buf); - memset (buf, 0, sizeof (buf)); - num = 0; - } - } - if (num) - zlog_debug (" %s", buf); - } + assert (p == OSPF6_MESSAGE_END (oh)); } void @@ -220,56 +234,7 @@ ospf6_lsack_print (struct ospf6_header *oh) p += sizeof (struct ospf6_lsa_header)) ospf6_lsa_header_print_raw ((struct ospf6_lsa_header *) p); - if (p != OSPF6_MESSAGE_END (oh)) - zlog_debug ("Trailing garbage exists"); -} - -/* Receive function */ -#define MSG_OK 0 -#define MSG_NG 1 -static int -ospf6_header_examin (struct in6_addr *src, struct in6_addr *dst, - struct ospf6_interface *oi, struct ospf6_header *oh) -{ - u_char type; - type = OSPF6_MESSAGE_TYPE_CANONICAL (oh->type); - - /* version check */ - if (oh->version != OSPFV3_VERSION) - { - if (IS_OSPF6_DEBUG_MESSAGE (type, RECV)) - zlog_debug ("Message with unknown version"); - return MSG_NG; - } - - /* Area-ID check */ - if (oh->area_id != oi->area->area_id) - { - if (oh->area_id == BACKBONE_AREA_ID) - { - if (IS_OSPF6_DEBUG_MESSAGE (type, RECV)) - zlog_debug ("Message may be via Virtual Link: not supported"); - return MSG_NG; - } - - if (IS_OSPF6_DEBUG_MESSAGE (type, RECV)) - zlog_debug ("Area-ID mismatch"); - return MSG_NG; - } - - /* Instance-ID check */ - if (oh->instance_id != oi->instance_id) - { - if (IS_OSPF6_DEBUG_MESSAGE (type, RECV)) - zlog_debug ("Instance-ID mismatch"); - return MSG_NG; - } - - /* Router-ID check */ - if (oh->router_id == oi->area->ospf6->router_id) - zlog_warn ("Detect duplicate Router-ID"); - - return MSG_OK; + assert (p == OSPF6_MESSAGE_END (oh)); } static void @@ -283,9 +248,6 @@ ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst, int neighborchange = 0; int backupseen = 0; - if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK) - return; - hello = (struct ospf6_hello *) ((caddr_t) oh + sizeof (struct ospf6_header)); @@ -339,11 +301,7 @@ ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst, twoway++; } - if (p != OSPF6_MESSAGE_END (oh)) - { - if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) - zlog_debug ("Trailing garbage ignored"); - } + assert (p == OSPF6_MESSAGE_END (oh)); /* RouterPriority check */ if (on->priority != hello->priority) @@ -578,11 +536,7 @@ ospf6_dbdesc_recv_master (struct ospf6_header *oh, } } - if (p != OSPF6_MESSAGE_END (oh)) - { - if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) - zlog_debug ("Trailing garbage ignored"); - } + assert (p == OSPF6_MESSAGE_END (oh)); /* Increment sequence number */ on->dbdesc_seqnum ++; @@ -792,11 +746,7 @@ ospf6_dbdesc_recv_slave (struct ospf6_header *oh, ospf6_lsa_delete (his); } - if (p != OSPF6_MESSAGE_END (oh)) - { - if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) - zlog_debug ("Trailing garbage ignored"); - } + assert (p == OSPF6_MESSAGE_END (oh)); /* Set sequence number to Master's */ on->dbdesc_seqnum = ntohl (dbdesc->seqnum); @@ -821,9 +771,6 @@ ospf6_dbdesc_recv (struct in6_addr *src, struct in6_addr *dst, struct ospf6_neighbor *on; struct ospf6_dbdesc *dbdesc; - if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK) - return; - on = ospf6_neighbor_lookup (oh->router_id, oi); if (on == NULL) { @@ -873,9 +820,6 @@ ospf6_lsreq_recv (struct in6_addr *src, struct in6_addr *dst, struct ospf6_lsdb *lsdb = NULL; struct ospf6_lsa *lsa; - if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK) - return; - on = ospf6_neighbor_lookup (oh->router_id, oi); if (on == NULL) { @@ -938,11 +882,7 @@ ospf6_lsreq_recv (struct in6_addr *src, struct in6_addr *dst, ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->lsupdate_list); } - if (p != OSPF6_MESSAGE_END (oh)) - { - if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) - zlog_debug ("Trailing garbage ignored"); - } + assert (p == OSPF6_MESSAGE_END (oh)); /* schedule send lsupdate */ THREAD_OFF (on->thread_send_lsupdate); @@ -950,18 +890,441 @@ ospf6_lsreq_recv (struct in6_addr *src, struct in6_addr *dst, thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0); } +/* Verify, that the specified memory area contains exactly N valid IPv6 + prefixes as specified by RFC5340, A.4.1. */ +static unsigned +ospf6_prefixes_examin +( + struct ospf6_prefix *current, /* start of buffer */ + unsigned length, + const u_int32_t req_num_pfxs /* always compared with the actual number of prefixes */ +) +{ + u_char requested_pfx_bytes; + u_int32_t real_num_pfxs = 0; + + while (length) + { + if (length < OSPF6_PREFIX_MIN_SIZE) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: undersized IPv6 prefix header", __func__); + return MSG_NG; + } + /* safe to look deeper */ + if (current->prefix_length > IPV6_MAX_BITLEN) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: invalid PrefixLength (%u bits)", __func__, current->prefix_length); + return MSG_NG; + } + /* covers both fixed- and variable-sized fields */ + requested_pfx_bytes = OSPF6_PREFIX_MIN_SIZE + OSPF6_PREFIX_SPACE (current->prefix_length); + if (requested_pfx_bytes > length) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: undersized IPv6 prefix", __func__); + return MSG_NG; + } + /* next prefix */ + length -= requested_pfx_bytes; + current = (struct ospf6_prefix *) ((caddr_t) current + requested_pfx_bytes); + real_num_pfxs++; + } + if (real_num_pfxs != req_num_pfxs) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: IPv6 prefix number mismatch (%u required, %u real)", + __func__, req_num_pfxs, real_num_pfxs); + return MSG_NG; + } + return MSG_OK; +} + +/* Verify an LSA to have a valid length and dispatch further (where + appropriate) to check if the contents, including nested IPv6 prefixes, + is properly sized/aligned within the LSA. Note that this function gets + LSA type in network byte order, uses in host byte order and passes to + ospf6_lstype_name() in network byte order again. */ +static unsigned +ospf6_lsa_examin (struct ospf6_lsa_header *lsah, const u_int16_t lsalen, const u_char headeronly) +{ + struct ospf6_intra_prefix_lsa *intra_prefix_lsa; + struct ospf6_as_external_lsa *as_external_lsa; + struct ospf6_link_lsa *link_lsa; + unsigned exp_length; + u_int8_t ltindex; + u_int16_t lsatype; + + /* In case an additional minimum length constraint is defined for current + LSA type, make sure that this constraint is met. */ + lsatype = ntohs (lsah->type); + ltindex = lsatype & OSPF6_LSTYPE_FCODE_MASK; + if + ( + ltindex < OSPF6_LSTYPE_SIZE && + ospf6_lsa_minlen[ltindex] && + lsalen < ospf6_lsa_minlen[ltindex] + OSPF6_LSA_HEADER_SIZE + ) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: undersized (%u B) LSA", __func__, lsalen); + return MSG_NG; + } + switch (lsatype) + { + case OSPF6_LSTYPE_ROUTER: + /* RFC5340 A.4.3, LSA header + OSPF6_ROUTER_LSA_MIN_SIZE bytes followed + by N>=0 interface descriptions. */ + if ((lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_ROUTER_LSA_MIN_SIZE) % OSPF6_ROUTER_LSDESC_FIX_SIZE) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: interface description alignment error", __func__); + return MSG_NG; + } + break; + case OSPF6_LSTYPE_NETWORK: + /* RFC5340 A.4.4, LSA header + OSPF6_NETWORK_LSA_MIN_SIZE bytes + followed by N>=0 attached router descriptions. */ + if ((lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_NETWORK_LSA_MIN_SIZE) % OSPF6_NETWORK_LSDESC_FIX_SIZE) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: router description alignment error", __func__); + return MSG_NG; + } + break; + case OSPF6_LSTYPE_INTER_PREFIX: + /* RFC5340 A.4.5, LSA header + OSPF6_INTER_PREFIX_LSA_MIN_SIZE bytes + followed by 3-4 fields of a single IPv6 prefix. */ + if (headeronly) + break; + return ospf6_prefixes_examin + ( + (struct ospf6_prefix *) ((caddr_t) lsah + OSPF6_LSA_HEADER_SIZE + OSPF6_INTER_PREFIX_LSA_MIN_SIZE), + lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_INTER_PREFIX_LSA_MIN_SIZE, + 1 + ); + case OSPF6_LSTYPE_INTER_ROUTER: + /* RFC5340 A.4.6, fixed-size LSA. */ + if (lsalen > OSPF6_LSA_HEADER_SIZE + OSPF6_INTER_ROUTER_LSA_FIX_SIZE) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: oversized (%u B) LSA", __func__, lsalen); + return MSG_NG; + } + break; + case OSPF6_LSTYPE_AS_EXTERNAL: /* RFC5340 A.4.7, same as A.4.8. */ + case OSPF6_LSTYPE_TYPE_7: + /* RFC5340 A.4.8, LSA header + OSPF6_AS_EXTERNAL_LSA_MIN_SIZE bytes + followed by 3-4 fields of IPv6 prefix and 3 conditional LSA fields: + 16 bytes of forwarding address, 4 bytes of external route tag, + 4 bytes of referenced link state ID. */ + if (headeronly) + break; + as_external_lsa = (struct ospf6_as_external_lsa *) ((caddr_t) lsah + OSPF6_LSA_HEADER_SIZE); + exp_length = OSPF6_LSA_HEADER_SIZE + OSPF6_AS_EXTERNAL_LSA_MIN_SIZE; + /* To find out if the last optional field (Referenced Link State ID) is + assumed in this LSA, we need to access fixed fields of the IPv6 + prefix before ospf6_prefix_examin() confirms its sizing. */ + if (exp_length + OSPF6_PREFIX_MIN_SIZE > lsalen) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: undersized (%u B) LSA header", __func__, lsalen); + return MSG_NG; + } + /* forwarding address */ + if (CHECK_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F)) + exp_length += 16; + /* external route tag */ + if (CHECK_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T)) + exp_length += 4; + /* referenced link state ID */ + if (as_external_lsa->prefix.u._prefix_referenced_lstype) + exp_length += 4; + /* All the fixed-size fields (mandatory and optional) must fit. I.e., + this check does not include any IPv6 prefix fields. */ + if (exp_length > lsalen) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: undersized (%u B) LSA header", __func__, lsalen); + return MSG_NG; + } + /* The last call completely covers the remainder (IPv6 prefix). */ + return ospf6_prefixes_examin + ( + (struct ospf6_prefix *) ((caddr_t) as_external_lsa + OSPF6_AS_EXTERNAL_LSA_MIN_SIZE), + lsalen - exp_length, + 1 + ); + case OSPF6_LSTYPE_LINK: + /* RFC5340 A.4.9, LSA header + OSPF6_LINK_LSA_MIN_SIZE bytes followed + by N>=0 IPv6 prefix blocks (with N declared beforehand). */ + if (headeronly) + break; + link_lsa = (struct ospf6_link_lsa *) ((caddr_t) lsah + OSPF6_LSA_HEADER_SIZE); + return ospf6_prefixes_examin + ( + (struct ospf6_prefix *) ((caddr_t) link_lsa + OSPF6_LINK_LSA_MIN_SIZE), + lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_LINK_LSA_MIN_SIZE, + ntohl (link_lsa->prefix_num) /* 32 bits */ + ); + case OSPF6_LSTYPE_INTRA_PREFIX: + /* RFC5340 A.4.10, LSA header + OSPF6_INTRA_PREFIX_LSA_MIN_SIZE bytes + followed by N>=0 IPv6 prefixes (with N declared beforehand). */ + if (headeronly) + break; + intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *) ((caddr_t) lsah + OSPF6_LSA_HEADER_SIZE); + return ospf6_prefixes_examin + ( + (struct ospf6_prefix *) ((caddr_t) intra_prefix_lsa + OSPF6_INTRA_PREFIX_LSA_MIN_SIZE), + lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_INTRA_PREFIX_LSA_MIN_SIZE, + ntohs (intra_prefix_lsa->prefix_num) /* 16 bits */ + ); + } + /* No additional validation is possible for unknown LSA types, which are + themselves valid in OPSFv3, hence the default decision is to accept. */ + return MSG_OK; +} + +/* Verify if the provided input buffer is a valid sequence of LSAs. This + includes verification of LSA blocks length/alignment and dispatching + of deeper-level checks. */ +static unsigned +ospf6_lsaseq_examin +( + struct ospf6_lsa_header *lsah, /* start of buffered data */ + size_t length, + const u_char headeronly, + /* When declared_num_lsas is not 0, compare it to the real number of LSAs + and treat the difference as an error. */ + const u_int32_t declared_num_lsas +) +{ + u_int32_t counted_lsas = 0; + + while (length) + { + u_int16_t lsalen; + if (length < OSPF6_LSA_HEADER_SIZE) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: undersized (%zu B) trailing (#%u) LSA header", + __func__, length, counted_lsas); + return MSG_NG; + } + /* save on ntohs() calls here and in the LSA validator */ + lsalen = OSPF6_LSA_SIZE (lsah); + if (lsalen < OSPF6_LSA_HEADER_SIZE) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: malformed LSA header #%u, declared length is %u B", + __func__, counted_lsas, lsalen); + return MSG_NG; + } + if (headeronly) + { + /* less checks here and in ospf6_lsa_examin() */ + if (MSG_OK != ospf6_lsa_examin (lsah, lsalen, 1)) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: anomaly in header-only %s LSA #%u", __func__, + ospf6_lstype_name (lsah->type), counted_lsas); + return MSG_NG; + } + lsah = (struct ospf6_lsa_header *) ((caddr_t) lsah + OSPF6_LSA_HEADER_SIZE); + length -= OSPF6_LSA_HEADER_SIZE; + } + else + { + /* make sure the input buffer is deep enough before further checks */ + if (lsalen > length) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: anomaly in %s LSA #%u: declared length is %u B, buffered length is %zu B", + __func__, ospf6_lstype_name (lsah->type), counted_lsas, lsalen, length); + return MSG_NG; + } + if (MSG_OK != ospf6_lsa_examin (lsah, lsalen, 0)) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: anomaly in %s LSA #%u", __func__, + ospf6_lstype_name (lsah->type), counted_lsas); + return MSG_NG; + } + lsah = (struct ospf6_lsa_header *) ((caddr_t) lsah + lsalen); + length -= lsalen; + } + counted_lsas++; + } + + if (declared_num_lsas && counted_lsas != declared_num_lsas) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: #LSAs declared (%u) does not match actual (%u)", + __func__, declared_num_lsas, counted_lsas); + return MSG_NG; + } + return MSG_OK; +} + +/* Verify a complete OSPF packet for proper sizing/alignment. */ +static unsigned +ospf6_packet_examin (struct ospf6_header *oh, const unsigned bytesonwire) +{ + struct ospf6_lsupdate *lsupd; + unsigned test; + + /* length, 1st approximation */ + if (bytesonwire < OSPF6_HEADER_SIZE) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: undersized (%u B) packet", __func__, bytesonwire); + return MSG_NG; + } + /* Now it is safe to access header fields. */ + if (bytesonwire != ntohs (oh->length)) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: packet length error (%u real, %u declared)", + __func__, bytesonwire, ntohs (oh->length)); + return MSG_NG; + } + /* version check */ + if (oh->version != OSPFV3_VERSION) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: invalid (%u) protocol version", __func__, oh->version); + return MSG_NG; + } + /* length, 2nd approximation */ + if + ( + oh->type < OSPF6_MESSAGE_TYPE_ALL && + ospf6_packet_minlen[oh->type] && + bytesonwire < OSPF6_HEADER_SIZE + ospf6_packet_minlen[oh->type] + ) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: undersized (%u B) %s packet", __func__, + bytesonwire, LOOKUP (ospf6_message_type_str, oh->type)); + return MSG_NG; + } + /* type-specific deeper validation */ + switch (oh->type) + { + case OSPF6_MESSAGE_TYPE_HELLO: + /* RFC5340 A.3.2, packet header + OSPF6_HELLO_MIN_SIZE bytes followed + by N>=0 router-IDs. */ + if (0 == (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_HELLO_MIN_SIZE) % 4) + return MSG_OK; + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: alignment error in %s packet", + __func__, LOOKUP (ospf6_message_type_str, oh->type)); + return MSG_NG; + case OSPF6_MESSAGE_TYPE_DBDESC: + /* RFC5340 A.3.3, packet header + OSPF6_DB_DESC_MIN_SIZE bytes followed + by N>=0 header-only LSAs. */ + test = ospf6_lsaseq_examin + ( + (struct ospf6_lsa_header *) ((caddr_t) oh + OSPF6_HEADER_SIZE + OSPF6_DB_DESC_MIN_SIZE), + bytesonwire - OSPF6_HEADER_SIZE - OSPF6_DB_DESC_MIN_SIZE, + 1, + 0 + ); + break; + case OSPF6_MESSAGE_TYPE_LSREQ: + /* RFC5340 A.3.4, packet header + N>=0 LS description blocks. */ + if (0 == (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_REQ_MIN_SIZE) % OSPF6_LSREQ_LSDESC_FIX_SIZE) + return MSG_OK; + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: alignment error in %s packet", + __func__, LOOKUP (ospf6_message_type_str, oh->type)); + return MSG_NG; + case OSPF6_MESSAGE_TYPE_LSUPDATE: + /* RFC5340 A.3.5, packet header + OSPF6_LS_UPD_MIN_SIZE bytes followed + by N>=0 full LSAs (with N declared beforehand). */ + lsupd = (struct ospf6_lsupdate *) ((caddr_t) oh + OSPF6_HEADER_SIZE); + test = ospf6_lsaseq_examin + ( + (struct ospf6_lsa_header *) ((caddr_t) lsupd + OSPF6_LS_UPD_MIN_SIZE), + bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_UPD_MIN_SIZE, + 0, + ntohl (lsupd->lsa_number) /* 32 bits */ + ); + break; + case OSPF6_MESSAGE_TYPE_LSACK: + /* RFC5340 A.3.6, packet header + N>=0 header-only LSAs. */ + test = ospf6_lsaseq_examin + ( + (struct ospf6_lsa_header *) ((caddr_t) oh + OSPF6_HEADER_SIZE + OSPF6_LS_ACK_MIN_SIZE), + bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_ACK_MIN_SIZE, + 1, + 0 + ); + break; + default: + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: invalid (%u) message type", __func__, oh->type); + return MSG_NG; + } + if (test != MSG_OK && IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: anomaly in %s packet", __func__, LOOKUP (ospf6_message_type_str, oh->type)); + return test; +} + +/* Verify particular fields of otherwise correct received OSPF packet to + meet the requirements of RFC. */ +static int +ospf6_rxpacket_examin (struct ospf6_interface *oi, struct ospf6_header *oh, const unsigned bytesonwire) +{ + char buf[2][INET_ADDRSTRLEN]; + + if (MSG_OK != ospf6_packet_examin (oh, bytesonwire)) + return MSG_NG; + + /* Area-ID check */ + if (oh->area_id != oi->area->area_id) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + { + if (oh->area_id == BACKBONE_AREA_ID) + zlog_debug ("%s: Message may be via Virtual Link: not supported", __func__); + else + zlog_debug + ( + "%s: Area-ID mismatch (my %s, rcvd %s)", __func__, + inet_ntop (AF_INET, &oi->area->area_id, buf[0], INET_ADDRSTRLEN), + inet_ntop (AF_INET, &oh->area_id, buf[1], INET_ADDRSTRLEN) + ); + } + return MSG_NG; + } + + /* Instance-ID check */ + if (oh->instance_id != oi->instance_id) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_debug ("%s: Instance-ID mismatch (my %u, rcvd %u)", __func__, oi->instance_id, oh->instance_id); + return MSG_NG; + } + + /* Router-ID check */ + if (oh->router_id == oi->area->ospf6->router_id) + { + zlog_warn ("%s: Duplicate Router-ID (%s)", __func__, inet_ntop (AF_INET, &oh->router_id, buf[0], INET_ADDRSTRLEN)); + return MSG_NG; + } + return MSG_OK; +} + static void ospf6_lsupdate_recv (struct in6_addr *src, struct in6_addr *dst, struct ospf6_interface *oi, struct ospf6_header *oh) { struct ospf6_neighbor *on; struct ospf6_lsupdate *lsupdate; - unsigned long num; char *p; - if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK) - return; - on = ospf6_neighbor_lookup (oh->router_id, oi); if (on == NULL) { @@ -982,37 +1345,16 @@ ospf6_lsupdate_recv (struct in6_addr *src, struct in6_addr *dst, lsupdate = (struct ospf6_lsupdate *) ((caddr_t) oh + sizeof (struct ospf6_header)); - num = ntohl (lsupdate->lsa_number); - /* Process LSAs */ for (p = (char *) ((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); p < OSPF6_MESSAGE_END (oh) && p + OSPF6_LSA_SIZE (p) <= OSPF6_MESSAGE_END (oh); p += OSPF6_LSA_SIZE (p)) { - if (num == 0) - break; - if (OSPF6_LSA_SIZE (p) < sizeof (struct ospf6_lsa_header)) - { - if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) - zlog_debug ("Malformed LSA length, quit processing"); - break; - } - ospf6_receive_lsa (on, (struct ospf6_lsa_header *) p); - num--; } - if (num != 0) - { - if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) - zlog_debug ("Malformed LSA number or LSA length"); - } - if (p != OSPF6_MESSAGE_END (oh)) - { - if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) - zlog_debug ("Trailing garbage ignored"); - } + assert (p == OSPF6_MESSAGE_END (oh)); /* RFC2328 Section 10.9: When the neighbor responds to these requests with the proper Link State Update packet(s), the Link state request @@ -1039,8 +1381,6 @@ ospf6_lsack_recv (struct in6_addr *src, struct in6_addr *dst, struct ospf6_lsdb *lsdb = NULL; assert (oh->type == OSPF6_MESSAGE_TYPE_LSACK); - if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK) - return; on = ospf6_neighbor_lookup (oh->router_id, oi); if (on == NULL) @@ -1132,11 +1472,7 @@ ospf6_lsack_recv (struct in6_addr *src, struct in6_addr *dst, ospf6_lsa_delete (his); } - if (p != OSPF6_MESSAGE_END (oh)) - { - if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) - zlog_debug ("Trailing garbage ignored"); - } + assert (p == OSPF6_MESSAGE_END (oh)); } static u_char *recvbuf = NULL; @@ -1225,11 +1561,6 @@ ospf6_receive (struct thread *thread) zlog_err ("Excess message read"); return 0; } - else if (len < sizeof (struct ospf6_header)) - { - zlog_err ("Deficient message read"); - return 0; - } oi = ospf6_interface_lookup_by_ifindex (ifindex); if (oi == NULL || oi->area == NULL) @@ -1237,8 +1568,22 @@ ospf6_receive (struct thread *thread) zlog_debug ("Message received on disabled interface"); return 0; } + if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE)) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_debug ("%s: Ignore message on passive interface %s", + __func__, oi->interface->name); + return 0; + } oh = (struct ospf6_header *) recvbuf; + if (ospf6_rxpacket_examin (oi, oh, len) != MSG_OK) + return 0; + + /* Being here means, that no sizing/alignment issues were detected in + the input packet. This renders the additional checks performed below + and also in the type-specific dispatching functions a dead code, + which can be dismissed in a cleanup-focused review round later. */ /* Log */ if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) @@ -1246,11 +1591,9 @@ ospf6_receive (struct thread *thread) inet_ntop (AF_INET6, &src, srcname, sizeof (srcname)); inet_ntop (AF_INET6, &dst, dstname, sizeof (dstname)); zlog_debug ("%s received on %s", - OSPF6_MESSAGE_TYPE_NAME (oh->type), oi->interface->name); + LOOKUP (ospf6_message_type_str, oh->type), oi->interface->name); zlog_debug (" src: %s", srcname); zlog_debug (" dst: %s", dstname); - if (len != ntohs (oh->length)) - zlog_debug ("Message length does not match actually received: %d", len); switch (oh->type) { @@ -1270,19 +1613,10 @@ ospf6_receive (struct thread *thread) ospf6_lsack_print (oh); break; default: - zlog_debug ("Unknown message"); - break; + assert (0); } } - if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE)) - { - if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) - zlog_debug ("Ignore message on passive interface %s", - oi->interface->name); - return 0; - } - switch (oh->type) { case OSPF6_MESSAGE_TYPE_HELLO: @@ -1306,9 +1640,7 @@ ospf6_receive (struct thread *thread) break; default: - if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) - zlog_debug ("Unknown message"); - break; + assert (0); } return 0; @@ -1347,7 +1679,7 @@ ospf6_send (struct in6_addr *src, struct in6_addr *dst, else memset (srcname, 0, sizeof (srcname)); zlog_debug ("%s send on %s", - OSPF6_MESSAGE_TYPE_NAME (oh->type), oi->interface->name); + LOOKUP (ospf6_message_type_str, oh->type), oi->interface->name); zlog_debug (" src: %s", srcname); zlog_debug (" dst: %s", dstname); @@ -1381,6 +1713,13 @@ ospf6_send (struct in6_addr *src, struct in6_addr *dst, zlog_err ("Could not send entire message"); } +static uint32_t +ospf6_packet_max(struct ospf6_interface *oi) +{ + assert (oi->ifmtu > sizeof (struct ip6_hdr)); + return oi->ifmtu - (sizeof (struct ip6_hdr)); +} + int ospf6_hello_send (struct thread *thread) { @@ -1427,7 +1766,7 @@ ospf6_hello_send (struct thread *thread) if (on->state < OSPF6_NEIGHBOR_INIT) continue; - if (p - sendbuf + sizeof (u_int32_t) > oi->ifmtu) + if (p - sendbuf + sizeof (u_int32_t) > ospf6_packet_max(oi)) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_HELLO, SEND)) zlog_debug ("sending Hello message: exceeds I/F MTU"); @@ -1503,7 +1842,7 @@ ospf6_dbdesc_send (struct thread *thread) /* MTU check */ if (p - sendbuf + sizeof (struct ospf6_lsa_header) > - on->ospf6_if->ifmtu) + ospf6_packet_max(on->ospf6_if)) { ospf6_lsa_unlock (lsa); break; @@ -1537,7 +1876,7 @@ ospf6_dbdesc_send_newone (struct thread *thread) for (lsa = ospf6_lsdb_head (on->summary_list); lsa; lsa = ospf6_lsdb_next (lsa)) { - if (size + sizeof (struct ospf6_lsa_header) > on->ospf6_if->ifmtu) + if (size + sizeof (struct ospf6_lsa_header) > ospf6_packet_max(on->ospf6_if)) { ospf6_lsa_unlock (lsa); break; @@ -1604,7 +1943,7 @@ ospf6_lsreq_send (struct thread *thread) lsa = ospf6_lsdb_next (lsa)) { /* MTU check */ - if (p - sendbuf + sizeof (struct ospf6_lsreq_entry) > on->ospf6_if->ifmtu) + if (p - sendbuf + sizeof (struct ospf6_lsreq_entry) > ospf6_packet_max(on->ospf6_if)) { ospf6_lsa_unlock (lsa); break; @@ -1673,7 +2012,7 @@ ospf6_lsupdate_send_neighbor (struct thread *thread) { /* MTU check */ if ( (p - sendbuf + (unsigned int)OSPF6_LSA_SIZE (lsa->header)) - > on->ospf6_if->ifmtu) + > ospf6_packet_max(on->ospf6_if)) { ospf6_lsa_unlock (lsa); break; @@ -1693,7 +2032,7 @@ ospf6_lsupdate_send_neighbor (struct thread *thread) { /* MTU check */ if ( (p - sendbuf + (unsigned int)OSPF6_LSA_SIZE (lsa->header)) - > on->ospf6_if->ifmtu) + > ospf6_packet_max(on->ospf6_if)) { ospf6_lsa_unlock (lsa); break; @@ -1766,7 +2105,7 @@ ospf6_lsupdate_send_interface (struct thread *thread) { /* MTU check */ if ( (p - sendbuf + ((unsigned int)OSPF6_LSA_SIZE (lsa->header))) - > oi->ifmtu) + > ospf6_packet_max(oi)) { ospf6_lsa_unlock (lsa); break; @@ -1833,7 +2172,7 @@ ospf6_lsack_send_neighbor (struct thread *thread) lsa = ospf6_lsdb_next (lsa)) { /* MTU check */ - if (p - sendbuf + sizeof (struct ospf6_lsa_header) > on->ospf6_if->ifmtu) + if (p - sendbuf + sizeof (struct ospf6_lsa_header) > ospf6_packet_max(on->ospf6_if)) { /* if we run out of packet size/space here, better to try again soon. */ @@ -1893,7 +2232,7 @@ ospf6_lsack_send_interface (struct thread *thread) lsa = ospf6_lsdb_next (lsa)) { /* MTU check */ - if (p - sendbuf + sizeof (struct ospf6_lsa_header) > oi->ifmtu) + if (p - sendbuf + sizeof (struct ospf6_lsa_header) > ospf6_packet_max(oi)) { /* if we run out of packet size/space here, better to try again soon. */ diff --git a/ospf6d/ospf6_message.h b/ospf6d/ospf6_message.h index c72f0af4..b085a967 100644 --- a/ospf6d/ospf6_message.h +++ b/ospf6d/ospf6_message.h @@ -44,14 +44,8 @@ extern unsigned char conf_debug_ospf6_message[]; #define OSPF6_MESSAGE_TYPE_LSACK 0x5 /* Flooding acknowledgment */ #define OSPF6_MESSAGE_TYPE_ALL 0x6 /* For debug option */ -#define OSPF6_MESSAGE_TYPE_CANONICAL(T) \ - ((T) > OSPF6_MESSAGE_TYPE_LSACK ? OSPF6_MESSAGE_TYPE_UNKNOWN : (T)) - -extern const char *ospf6_message_type_str[]; -#define OSPF6_MESSAGE_TYPE_NAME(T) \ - (ospf6_message_type_str[ OSPF6_MESSAGE_TYPE_CANONICAL (T) ]) - /* OSPFv3 packet header */ +#define OSPF6_HEADER_SIZE 16U struct ospf6_header { u_char version; @@ -67,6 +61,7 @@ struct ospf6_header #define OSPF6_MESSAGE_END(H) ((caddr_t) (H) + ntohs ((H)->length)) /* Hello */ +#define OSPF6_HELLO_MIN_SIZE 20U struct ospf6_hello { u_int32_t interface_id; @@ -80,6 +75,7 @@ struct ospf6_hello }; /* Database Description */ +#define OSPF6_DB_DESC_MIN_SIZE 12U struct ospf6_dbdesc { u_char reserved1; @@ -96,7 +92,9 @@ struct ospf6_dbdesc #define OSPF6_DBDESC_IBIT (0x04) /* initial bit */ /* Link State Request */ +#define OSPF6_LS_REQ_MIN_SIZE 0U /* It is just a sequence of entries below */ +#define OSPF6_LSREQ_LSDESC_FIX_SIZE 12U struct ospf6_lsreq_entry { u_int16_t reserved; /* Must Be Zero */ @@ -106,6 +104,7 @@ struct ospf6_lsreq_entry }; /* Link State Update */ +#define OSPF6_LS_UPD_MIN_SIZE 4U struct ospf6_lsupdate { u_int32_t lsa_number; @@ -113,6 +112,7 @@ struct ospf6_lsupdate }; /* Link State Acknowledgement */ +#define OSPF6_LS_ACK_MIN_SIZE 0U /* It is just a sequence of LSA Headers */ /* Function definition */ diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c index d9783385..2b4dab30 100644 --- a/ospf6d/ospf6_network.c +++ b/ospf6d/ospf6_network.c @@ -64,6 +64,14 @@ ospf6_set_pktinfo (void) } void +ospf6_set_transport_class (void) +{ +#ifdef IPTOS_PREC_INTERNETCONTROL + setsockopt_ipv6_tclass (ospf6_sock, IPTOS_PREC_INTERNETCONTROL); +#endif +} + +void ospf6_set_checksum (void) { int offset = 12; @@ -102,6 +110,7 @@ ospf6_serv_sock (void) #endif /*1*/ ospf6_reset_mcastloop (); ospf6_set_pktinfo (); + ospf6_set_transport_class (); ospf6_set_checksum (); /* setup global in6_addr, allspf6 and alldr6 for later use */ @@ -111,86 +120,22 @@ ospf6_serv_sock (void) return 0; } +/* ospf6 set socket option */ void -ospf6_join_allspfrouters (u_int ifindex) +ospf6_sso (u_int ifindex, struct in6_addr *group, int option) { struct ipv6_mreq mreq6; - int retval; + int ret; assert (ifindex); mreq6.ipv6mr_interface = ifindex; - memcpy (&mreq6.ipv6mr_multiaddr, &allspfrouters6, - sizeof (struct in6_addr)); + memcpy (&mreq6.ipv6mr_multiaddr, group, sizeof (struct in6_addr)); - retval = setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, - &mreq6, sizeof (mreq6)); - - if (retval < 0) - zlog_err ("Network: Join AllSPFRouters on ifindex %d failed: %s", - ifindex, safe_strerror (errno)); -#if 0 - else - zlog_debug ("Network: Join AllSPFRouters on ifindex %d", ifindex); -#endif -} - -void -ospf6_leave_allspfrouters (u_int ifindex) -{ - struct ipv6_mreq mreq6; - - assert (ifindex); - mreq6.ipv6mr_interface = ifindex; - memcpy (&mreq6.ipv6mr_multiaddr, &allspfrouters6, - sizeof (struct in6_addr)); - - if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, - &mreq6, sizeof (mreq6)) < 0) - zlog_warn ("Network: Leave AllSPFRouters on ifindex %d Failed: %s", - ifindex, safe_strerror (errno)); -#if 0 - else - zlog_debug ("Network: Leave AllSPFRouters on ifindex %d", ifindex); -#endif -} - -void -ospf6_join_alldrouters (u_int ifindex) -{ - struct ipv6_mreq mreq6; - - assert (ifindex); - mreq6.ipv6mr_interface = ifindex; - memcpy (&mreq6.ipv6mr_multiaddr, &alldrouters6, - sizeof (struct in6_addr)); - - if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, - &mreq6, sizeof (mreq6)) < 0) - zlog_warn ("Network: Join AllDRouters on ifindex %d Failed: %s", - ifindex, safe_strerror (errno)); -#if 0 - else - zlog_debug ("Network: Join AllDRouters on ifindex %d", ifindex); -#endif -} - -void -ospf6_leave_alldrouters (u_int ifindex) -{ - struct ipv6_mreq mreq6; - - assert (ifindex); - mreq6.ipv6mr_interface = ifindex; - memcpy (&mreq6.ipv6mr_multiaddr, &alldrouters6, - sizeof (struct in6_addr)); - - if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, - &mreq6, sizeof (mreq6)) < 0) - zlog_warn ("Network: Leave AllDRouters on ifindex %d Failed", ifindex); -#if 0 - else - zlog_debug ("Network: Leave AllDRouters on ifindex %d", ifindex); -#endif + ret = setsockopt (ospf6_sock, IPPROTO_IPV6, option, + &mreq6, sizeof (mreq6)); + if (ret < 0) + zlog_err ("Network: setsockopt (%d) on ifindex %d failed: %s", + option, ifindex, safe_strerror (errno)); } static int diff --git a/ospf6d/ospf6_network.h b/ospf6d/ospf6_network.h index fd8758e8..0526b3e1 100644 --- a/ospf6d/ospf6_network.h +++ b/ospf6d/ospf6_network.h @@ -35,11 +35,7 @@ extern void ospf6_set_pktinfo (void); extern void ospf6_set_checksum (void); extern int ospf6_serv_sock (void); - -extern void ospf6_join_allspfrouters (u_int); -extern void ospf6_leave_allspfrouters (u_int); -extern void ospf6_join_alldrouters (u_int); -extern void ospf6_leave_alldrouters (u_int); +extern void ospf6_sso (u_int ifindex, struct in6_addr *group, int option); extern int ospf6_sendmsg (struct in6_addr *, struct in6_addr *, unsigned int *, struct iovec *); diff --git a/ospf6d/ospf6_proto.c b/ospf6d/ospf6_proto.c index c792aa45..d011601f 100644 --- a/ospf6d/ospf6_proto.c +++ b/ospf6d/ospf6_proto.c @@ -42,11 +42,10 @@ ospf6_prefix_apply_mask (struct ospf6_prefix *op) return; } - if (index == 16) - return; - - pnt[index] &= mask; - index ++; + /* nonzero mask means no check for this byte because if it contains + * prefix bits it must be there for us to write */ + if (mask) + pnt[index++] &= mask; while (index < OSPF6_PREFIX_SPACE (op->prefix_length)) pnt[index++] = 0; diff --git a/ospf6d/ospf6_proto.h b/ospf6d/ospf6_proto.h index a8c1b1a0..64625004 100644 --- a/ospf6d/ospf6_proto.h +++ b/ospf6d/ospf6_proto.h @@ -73,6 +73,7 @@ #define OSPF6_OPT_V6 (1 << 0) /* IPv6 forwarding Capability */ /* OSPF6 Prefix */ +#define OSPF6_PREFIX_MIN_SIZE 4U /* .length == 0 */ struct ospf6_prefix { u_int8_t prefix_length; diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h index 22ecd3ff..ae792ebf 100644 --- a/ospf6d/ospf6_route.h +++ b/ospf6d/ospf6_route.h @@ -304,6 +304,7 @@ extern void ospf6_brouter_show (struct vty *vty, struct ospf6_route *route); extern int config_write_ospf6_debug_route (struct vty *vty); extern void install_element_ospf6_debug_route (void); extern void ospf6_route_init (void); +extern void ospf6_clean (void); #endif /* OSPF6_ROUTE_H */ diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 25b86007..065d4080 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -282,8 +282,7 @@ ospf6_spf_install (struct ospf6_vertex *v, { struct ospf6_route *route; int i, j; - struct ospf6_vertex *prev; //, *w; -//struct listnode *node, *nnode; + struct ospf6_vertex *prev; if (IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_debug ("SPF install %s hops %d cost %d", @@ -392,6 +391,8 @@ ospf6_spf_calculation (u_int32_t router_id, caddr_t lsdesc; struct ospf6_lsa *lsa; + ospf6_spf_table_finish (result_table); + /* Install the calculating router itself as the root of the SPF tree */ /* construct root vertex */ lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_ROUTER), htonl (0), @@ -403,8 +404,6 @@ ospf6_spf_calculation (u_int32_t router_id, candidate_list = pqueue_create (); candidate_list->cmp = ospf6_vertex_cmp; - ospf6_spf_table_finish (result_table); - root = ospf6_vertex_create (lsa); root->area = oa; root->cost = 0; diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index bc0b477e..03561952 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -601,10 +601,10 @@ ALIAS (show_ipv6_ospf6_route, IP6_STR OSPF6_STR ROUTE_STR - "Dispaly Intra-Area routes\n" - "Dispaly Inter-Area routes\n" - "Dispaly Type-1 External routes\n" - "Dispaly Type-2 External routes\n" + "Display Intra-Area routes\n" + "Display Inter-Area routes\n" + "Display Type-1 External routes\n" + "Display Type-2 External routes\n" ) DEFUN (show_ipv6_ospf6_route_type_detail, @@ -614,10 +614,10 @@ DEFUN (show_ipv6_ospf6_route_type_detail, IP6_STR OSPF6_STR ROUTE_STR - "Dispaly Intra-Area routes\n" - "Dispaly Inter-Area routes\n" - "Dispaly Type-1 External routes\n" - "Dispaly Type-2 External routes\n" + "Display Intra-Area routes\n" + "Display Inter-Area routes\n" + "Display Type-1 External routes\n" + "Display Type-2 External routes\n" "Detailed information\n" ) { diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 881771a7..f09e9d22 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -451,6 +451,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request) api.type = ZEBRA_ROUTE_OSPF6; api.flags = 0; api.message = 0; + api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = nhcount; api.nexthop = nexthops; diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index 0b7a1ff5..978e4017 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -1892,4 +1892,11 @@ ospf6_init (void) thread_add_read (master, ospf6_receive, NULL, ospf6_sock); } - +void +ospf6_clean (void) +{ + if (ospf6->route_table) + ospf6_route_remove_all (ospf6->route_table); + if (ospf6->brouter_table) + ospf6_route_remove_all (ospf6->brouter_table); +} diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h index b6f1b737..2ac6300e 100644 --- a/ospf6d/ospf6d.h +++ b/ospf6d/ospf6d.h @@ -49,6 +49,9 @@ extern struct thread_master *master; #endif /* IPV6_DROP_MEMBERSHIP */ #endif /* ! IPV6_LEAVE_GROUP */ +#define MSG_OK 0 +#define MSG_NG 1 + /* cast macro: XXX - these *must* die, ick ick. */ #define OSPF6_PROCESS(x) ((struct ospf6 *) (x)) #define OSPF6_AREA(x) ((struct ospf6_area *) (x)) diff --git a/ospfclient/.cvsignore b/ospfclient/.cvsignore deleted file mode 100644 index d6de29ab..00000000 --- a/ospfclient/.cvsignore +++ /dev/null @@ -1,13 +0,0 @@ -Makefile -Makefile.in -*.o -ospfclient -tags -TAGS -.deps -.nfs* -*.lo -*.la -*.libs -.arch-inventory -.arch-ids diff --git a/ospfd/.cvsignore b/ospfd/.cvsignore deleted file mode 100644 index 6fce629e..00000000 --- a/ospfd/.cvsignore +++ /dev/null @@ -1,14 +0,0 @@ -Makefile -Makefile.in -*.o -ospfd -ospfd.conf -tags -TAGS -.deps -.nfs* -*.lo -*.la -*.libs -.arch-inventory -.arch-ids diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index 410d59ac..497355c0 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -384,7 +384,7 @@ ospf_abr_nssa_am_elected (struct ospf_area *area) if (best == NULL) best = &lsa->data->id; else - if ( IPV4_ADDR_CMP (&best, &lsa->data->id) < 0) + if (IPV4_ADDR_CMP (&best->s_addr, &lsa->data->id.s_addr) < 0) best = &lsa->data->id; } @@ -395,7 +395,7 @@ ospf_abr_nssa_am_elected (struct ospf_area *area) if (best == NULL) return 1; - if ( IPV4_ADDR_CMP (&best, &area->ospf->router_id) < 0) + if (IPV4_ADDR_CMP (&best->s_addr, &area->ospf->router_id.s_addr) < 0) return 1; else return 0; @@ -615,19 +615,6 @@ set_metric (struct ospf_lsa *lsa, u_int32_t metric) memcpy(header->metric, mp, 3); } -static int -ospf_abr_check_nssa_range (struct prefix_ipv4 *p, u_int32_t cost, - struct ospf_area *area) - __attribute__((unused)) ; -static int -ospf_abr_check_nssa_range (struct prefix_ipv4 *p, u_int32_t cost, - struct ospf_area *area) -{ - /* The Type-7 is tested against the aggregated prefix and forwarded - for lsa installation and flooding */ - return 0; -} - /* ospf_abr_translate_nssa */ static int ospf_abr_translate_nssa (struct ospf_area *area, struct ospf_lsa *lsa) @@ -1583,45 +1570,6 @@ ospf_abr_send_nssa_aggregates (struct ospf *ospf) /* temporarily turned off */ } static void -ospf_abr_announce_nssa_defaults (struct ospf *ospf) __attribute__((unused)) ; - -static void -ospf_abr_announce_nssa_defaults (struct ospf *ospf) /* By ABR-Translator */ -{ - struct listnode *node; - struct ospf_area *area; - - if (! IS_OSPF_ABR (ospf)) - return; - - if (IS_DEBUG_OSPF_NSSA) - zlog_debug ("ospf_abr_announce_stub_defaults(): Start"); - - for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) - { - if (IS_DEBUG_OSPF_NSSA) - zlog_debug ("ospf_abr_announce_nssa_defaults(): looking at area %s", - inet_ntoa (area->area_id)); - - if (area->external_routing != OSPF_AREA_NSSA) - continue; - - if (OSPF_IS_AREA_BACKBONE (area)) - continue; /* Sanity Check */ - - /* if (!TranslatorRole continue V 1.0 look for "always" conf */ - if (area->NSSATranslatorState) - { - if (IS_DEBUG_OSPF_NSSA) - zlog_debug ("ospf_abr_announce_nssa_defaults(): " - "announcing 0.0.0.0/0 to this nssa"); - /* ospf_abr_announce_nssa_asbr_to_as (&p, area->default_cost, area); */ - /*ospf_abr_announce_network_to_area (&p, area->default_cost, area);*/ - } - } -} - -static void ospf_abr_announce_stub_defaults (struct ospf *ospf) { struct listnode *node; diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index c39efee1..a23b4f2b 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -284,6 +284,9 @@ ospf_redistribute_withdraw (struct ospf *ospf, u_char type) continue; ospf_external_lsa_flush (ospf, type, &ei->p, ei->ifindex /*, ei->nexthop */); - ospf_external_info_delete (type, ei->p); + + ospf_external_info_free (ei); + route_unlock_node (rn); + rn->info = NULL; } } diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index 77f2e161..2ebae89a 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -319,7 +319,8 @@ ospf_flood (struct ospf *ospf, struct ospf_neighbor *nbr, procedure cannot overwrite the newly installed LSA until MinLSArrival seconds have elapsed. */ - new = ospf_lsa_install (ospf, nbr->oi, new); + if (! (new = ospf_lsa_install (ospf, nbr->oi, new))) + return -1; /* unknown LSA type or any other error condition */ /* Acknowledge the receipt of the LSA by sending a Link State Acknowledgment packet back out the receiving interface. */ diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 45087de9..7e6c21dd 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -748,7 +748,7 @@ ospf_stub_router_timer (struct thread *t) return 0; } -inline static void +static void ospf_stub_router_check (struct ospf_area *area) { /* area must either be administratively configured to be stub @@ -1639,7 +1639,7 @@ ospf_external_lsa_new (struct ospf *ospf, if (ei == NULL) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) - zlog_debug ("LSA[Type5]: External info is NULL, could not originated"); + zlog_debug ("LSA[Type5]: External info is NULL, can't originate"); return NULL; } @@ -2840,9 +2840,9 @@ ospf_maxage_lsa_remover (struct thread *thread) OSPF_TIMER_ON (ospf->t_maxage, ospf_maxage_lsa_remover, 0); /* Remove LSA from the LSDB */ - if (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF)) + if (IS_LSA_SELF (lsa)) if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) - zlog_debug ("LSA[Type%d:%s]: LSA 0x%lx is self-oririnated: ", + zlog_debug ("LSA[Type%d:%s]: LSA 0x%lx is self-originated: ", lsa->data->type, inet_ntoa (lsa->data->id), (u_long)lsa); if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) @@ -3391,7 +3391,7 @@ ospf_lsa_is_self_originated (struct ospf *ospf, struct ospf_lsa *lsa) /* This LSA is already checked. */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF_CHECKED)) - return CHECK_FLAG (lsa->flags, OSPF_LSA_SELF); + return IS_LSA_SELF (lsa); /* Make sure LSA is self-checked. */ SET_FLAG (lsa->flags, OSPF_LSA_SELF_CHECKED); @@ -3416,11 +3416,11 @@ ospf_lsa_is_self_originated (struct ospf *ospf, struct ospf_lsa *lsa) { /* to make it easier later */ SET_FLAG (lsa->flags, OSPF_LSA_SELF); - return CHECK_FLAG (lsa->flags, OSPF_LSA_SELF); + return IS_LSA_SELF (lsa); } } - return CHECK_FLAG (lsa->flags, OSPF_LSA_SELF); + return IS_LSA_SELF (lsa); } /* Get unique Link State ID. */ @@ -3545,6 +3545,7 @@ ospf_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa) struct external_info *ei; struct ospf_lsa *new = NULL; assert (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF)); + assert (IS_LSA_SELF (lsa)); assert (lsa->lock > 0); switch (lsa->data->type) @@ -3593,7 +3594,7 @@ ospf_refresher_register_lsa (struct ospf *ospf, struct ospf_lsa *lsa) u_int16_t index, current_index; assert (lsa->lock > 0); - assert (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF)); + assert (IS_LSA_SELF (lsa)); if (lsa->refresh_list < 0) { @@ -3636,7 +3637,7 @@ void ospf_refresher_unregister_lsa (struct ospf *ospf, struct ospf_lsa *lsa) { assert (lsa->lock > 0); - assert (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF)); + assert (IS_LSA_SELF (lsa)); if (lsa->refresh_list >= 0) { struct list *refresh_list = ospf->lsa_refresh_queue.qs[lsa->refresh_list]; diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index 72e2f8a5..f364840f 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -49,6 +49,7 @@ #define OSPF_LSA_HEADER_SIZE 20U #define OSPF_ROUTER_LSA_LINK_SIZE 12U +#define OSPF_ROUTER_LSA_TOS_SIZE 4U #define OSPF_MAX_LSA_SIZE 1500U /* AS-external-LSA refresh method. */ @@ -274,6 +275,7 @@ extern struct in_addr ospf_get_ip_from_ifp (struct ospf_interface *); extern struct ospf_lsa *ospf_external_lsa_originate (struct ospf *, struct external_info *); extern int ospf_external_lsa_originate_timer (struct thread *); +extern int ospf_default_originate_timer (struct thread *); extern struct ospf_lsa *ospf_lsa_lookup (struct ospf_area *, u_int32_t, struct in_addr, struct in_addr); extern struct ospf_lsa *ospf_lsa_lookup_by_id (struct ospf_area *, diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 8b9a3458..bad674b6 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -38,6 +38,7 @@ #include "memory.h" #include "privs.h" #include "sigevent.h" +#include "zclient.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -80,6 +81,7 @@ struct option longopts[] = { "daemon", no_argument, NULL, 'd'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, + { "socket", required_argument, NULL, 'z'}, { "dryrun", no_argument, NULL, 'C'}, { "help", no_argument, NULL, 'h'}, { "vty_addr", required_argument, NULL, 'A'}, @@ -116,6 +118,7 @@ Daemon which manages OSPF.\n\n\ -d, --daemon Runs in daemon mode\n\ -f, --config_file Set configuration file name\n\ -i, --pid_file Set process identifier file name\n\ +-z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -u, --user User to run as\n\ @@ -191,30 +194,11 @@ main (int argc, char **argv) /* get program name */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); - /* Invoked by a priviledged user? -- endo. */ - if (geteuid () != 0) - { - errno = EPERM; - perror (progname); - exit (1); - } - - zlog_default = openzlog (progname, ZLOG_OSPF, - LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); - - /* OSPF master init. */ - ospf_master_init (); - -#ifdef SUPPORT_OSPF_API - /* OSPF apiserver is disabled by default. */ - ospf_apiserver_enable = 0; -#endif /* SUPPORT_OSPF_API */ - while (1) { int opt; - opt = getopt_long (argc, argv, "df:i:hA:P:u:g:avC", longopts, 0); + opt = getopt_long (argc, argv, "df:i:z:hA:P:u:g:avC", longopts, 0); if (opt == EOF) break; @@ -235,6 +219,9 @@ main (int argc, char **argv) case 'i': pid_file = optarg; break; + case 'z': + zclient_serv_path_set (optarg); + break; case 'P': /* Deal with atoi() returning 0 on failure, and ospfd not listening on ospfd port... */ @@ -274,6 +261,25 @@ main (int argc, char **argv) } } + /* Invoked by a priviledged user? -- endo. */ + if (geteuid () != 0) + { + errno = EPERM; + perror (progname); + exit (1); + } + + zlog_default = openzlog (progname, ZLOG_OSPF, + LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + + /* OSPF master init. */ + ospf_master_init (); + +#ifdef SUPPORT_OSPF_API + /* OSPF apiserver is disabled by default. */ + ospf_apiserver_enable = 0; +#endif /* SUPPORT_OSPF_API */ + /* Initializations. */ master = om->master; diff --git a/ospfd/ospf_network.c b/ospfd/ospf_network.c index dc06cb61..e11a6a2a 100644 --- a/ospfd/ospf_network.c +++ b/ospfd/ospf_network.c @@ -52,8 +52,8 @@ ospf_if_add_allspfrouters (struct ospf *top, struct prefix *p, { int ret; - ret = setsockopt_multicast_ipv4 (top->fd, IP_ADD_MEMBERSHIP, - p->u.prefix4, htonl (OSPF_ALLSPFROUTERS), + ret = setsockopt_ipv4_multicast (top->fd, IP_ADD_MEMBERSHIP, + htonl (OSPF_ALLSPFROUTERS), ifindex); if (ret < 0) zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %s, " @@ -73,8 +73,8 @@ ospf_if_drop_allspfrouters (struct ospf *top, struct prefix *p, { int ret; - ret = setsockopt_multicast_ipv4 (top->fd, IP_DROP_MEMBERSHIP, - p->u.prefix4, htonl (OSPF_ALLSPFROUTERS), + ret = setsockopt_ipv4_multicast (top->fd, IP_DROP_MEMBERSHIP, + htonl (OSPF_ALLSPFROUTERS), ifindex); if (ret < 0) zlog_warn ("can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %s, " @@ -94,8 +94,8 @@ ospf_if_add_alldrouters (struct ospf *top, struct prefix *p, unsigned int { int ret; - ret = setsockopt_multicast_ipv4 (top->fd, IP_ADD_MEMBERSHIP, - p->u.prefix4, htonl (OSPF_ALLDROUTERS), + ret = setsockopt_ipv4_multicast (top->fd, IP_ADD_MEMBERSHIP, + htonl (OSPF_ALLDROUTERS), ifindex); if (ret < 0) zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %s, " @@ -115,8 +115,8 @@ ospf_if_drop_alldrouters (struct ospf *top, struct prefix *p, unsigned int { int ret; - ret = setsockopt_multicast_ipv4 (top->fd, IP_DROP_MEMBERSHIP, - p->u.prefix4, htonl (OSPF_ALLDROUTERS), + ret = setsockopt_ipv4_multicast (top->fd, IP_DROP_MEMBERSHIP, + htonl (OSPF_ALLDROUTERS), ifindex); if (ret < 0) zlog_warn ("can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %s, " @@ -151,8 +151,7 @@ ospf_if_ipmulticast (struct ospf *top, struct prefix *p, unsigned int ifindex) zlog_warn ("can't setsockopt IP_MULTICAST_TTL(1) for fd %d: %s", top->fd, safe_strerror (errno)); - ret = setsockopt_multicast_ipv4 (top->fd, IP_MULTICAST_IF, - p->u.prefix4, 0, ifindex); + ret = setsockopt_ipv4_multicast_if (top->fd, ifindex); if (ret < 0) zlog_warn("can't setsockopt IP_MULTICAST_IF(fd %d, addr %s, " "ifindex %u): %s", diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 23eae565..d3a60de0 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -266,7 +266,7 @@ ospf_packet_dup (struct ospf_packet *op) } /* XXX inline */ -static inline unsigned int +static unsigned int ospf_packet_authspace (struct ospf_interface *oi) { int auth = 0; @@ -1567,8 +1567,13 @@ ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s, sum = lsah->checksum; if (sum != ospf_lsa_checksum (lsah)) { - zlog_warn ("Link State Update: LSA checksum error %x, %x.", - sum, lsah->checksum); + /* (bug #685) more details in a one-line message make it possible + * to identify problem source on the one hand and to have a better + * chance to compress repeated messages in syslog on the other */ + zlog_warn ("Link State Update: LSA checksum error %x/%x, ID=%s from: nbr %s, router ID %s, adv router %s", + sum, lsah->checksum, inet_ntoa (lsah->id), + inet_ntoa (nbr->src), inet_ntoa (nbr->router_id), + inet_ntoa (lsah->adv_router)); continue; } @@ -2115,7 +2120,7 @@ ospf_recv_packet (int fd, struct interface **ifp, struct stream *ibuf) ip_len = iph->ip_len; -#if !defined(GNU_LINUX) && (OpenBSD < 200311) +#if !defined(GNU_LINUX) && (OpenBSD < 200311) && (__FreeBSD_version < 1000000) /* * Kernel network code touches incoming IP header parameters, * before protocol specific processing. @@ -2207,7 +2212,7 @@ ospf_associate_packet_vl (struct ospf *ospf, struct interface *ifp, return NULL; } -static inline int +static int ospf_check_area_id (struct ospf_interface *oi, struct ospf_header *ospfh) { /* Check match the Area ID of the receiving interface. */ @@ -2320,6 +2325,13 @@ ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi, return -1; } + /* Valid OSPFv2 packet types are 1 through 5 inclusive. */ + if (ospfh->type < 1 || ospfh->type > 5) + { + zlog_warn ("interface %s: invalid packet type %u", IF_NAME (oi), ospfh->type); + return -1; + } + /* Check Area ID. */ if (!ospf_check_area_id (oi, ospfh)) { @@ -2429,15 +2441,29 @@ ospf_read (struct thread *thread) return 0; } - /* Adjust size to message length. */ + /* Advance from IP header to OSPF header (iph->ip_hl has been verified + by ospf_recv_packet() to be correct). */ stream_forward_getp (ibuf, iph->ip_hl * 4); - - /* Get ospf packet header. */ + + /* Make sure the OSPF header is really there. */ + if (stream_get_endp (ibuf) - stream_get_getp (ibuf) < OSPF_HEADER_SIZE) + { + zlog_debug ("ospf_read: ignored OSPF packet with undersized (%u bytes) header", + stream_get_endp (ibuf) - stream_get_getp (ibuf)); + return -1; + } + + /* Now it is safe to access all fields of OSPF packet header. */ ospfh = (struct ospf_header *) STREAM_PNT (ibuf); /* associate packet with ospf interface */ oi = ospf_if_lookup_recv_if (ospf, iph->ip_src, ifp); + /* ospf_verify_header() relies on a valid "oi" and thus can be called only + after the passive/backbone/other checks below are passed. These checks + in turn access the fields of unverified "ospfh" structure for their own + purposes and must remain very accurate in doing this. */ + /* If incoming interface is passive one, ignore it. */ if (oi && OSPF_IF_PASSIVE_STATUS (oi) == OSPF_IF_PASSIVE) { @@ -2528,6 +2554,17 @@ ospf_read (struct thread *thread) return 0; } + /* Verify more OSPF header fields. */ + ret = ospf_verify_header (ibuf, oi, iph, ospfh); + if (ret < 0) + { + if (IS_DEBUG_OSPF_PACKET (0, RECV)) + zlog_debug ("ospf_read[%s]: Header check failed, " + "dropping.", + inet_ntoa (iph->ip_src)); + return ret; + } + /* Show debug receiving packet. */ if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) { @@ -2547,20 +2584,6 @@ ospf_read (struct thread *thread) zlog_debug ("-----------------------------------------------------"); } - /* Some header verification. */ - ret = ospf_verify_header (ibuf, oi, iph, ospfh); - if (ret < 0) - { - if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) - { - zlog_debug ("ospf_read[%s/%s]: Header check failed, " - "dropping.", - ospf_packet_type_str[ospfh->type], - inet_ntoa (iph->ip_src)); - } - return ret; - } - stream_forward_getp (ibuf, OSPF_HEADER_SIZE); /* Adjust size to message length. */ diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c index f1251e99..488ed4de 100644 --- a/ospfd/ospf_route.c +++ b/ospfd/ospf_route.c @@ -145,7 +145,7 @@ ospf_route_match_same (struct route_table *rt, struct prefix_ipv4 *prefix, rn = route_node_lookup (rt, (struct prefix *) prefix); if (! rn || ! rn->info) return 0; - + route_unlock_node (rn); or = rn->info; @@ -159,7 +159,7 @@ ospf_route_match_same (struct route_table *rt, struct prefix_ipv4 *prefix, /* Check each path. */ for (n1 = listhead (or->paths), n2 = listhead (newor->paths); n1 && n2; n1 = listnextnode (n1), n2 = listnextnode (n2)) - { + { op = listgetdata (n1); newop = listgetdata (n2); @@ -179,16 +179,16 @@ ospf_route_match_same (struct route_table *rt, struct prefix_ipv4 *prefix, /* delete routes generated from AS-External routes if there is a inter/intra * area route */ -static void +static void ospf_route_delete_same_ext(struct route_table *external_routes, struct route_table *routes) { struct route_node *rn, *ext_rn; - + if ( (external_routes == NULL) || (routes == NULL) ) return; - + /* Remove deleted routes */ for ( rn = route_top (routes); rn; rn = route_next (rn) ) { @@ -217,13 +217,13 @@ ospf_route_delete_uniq (struct route_table *rt, struct route_table *cmprt) struct ospf_route *or; for (rn = route_top (rt); rn; rn = route_next (rn)) - if ((or = rn->info) != NULL) + if ((or = rn->info) != NULL) if (or->path_type == OSPF_PATH_INTRA_AREA || or->path_type == OSPF_PATH_INTER_AREA) { if (or->type == OSPF_DESTINATION_NETWORK) { - if (! ospf_route_match_same (cmprt, + if (! ospf_route_match_same (cmprt, (struct prefix_ipv4 *) &rn->p, or)) ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or); } @@ -272,65 +272,6 @@ ospf_route_install (struct ospf *ospf, struct route_table *rt) } } -static void -ospf_intra_route_add (struct route_table *rt, struct vertex *v, - struct ospf_area *area) - __attribute__((unused)) ; -static void -ospf_intra_route_add (struct route_table *rt, struct vertex *v, - struct ospf_area *area) -{ - struct route_node *rn; - struct ospf_route *or; - struct prefix_ipv4 p; - struct ospf_path *path; - struct vertex_parent *parent; - struct listnode *node, *nnode; - - p.family = AF_INET; - p.prefix = v->id; - if (v->type == OSPF_VERTEX_ROUTER) - p.prefixlen = IPV4_MAX_BITLEN; - else - { - struct network_lsa *lsa = (struct network_lsa *) v->lsa; - p.prefixlen = ip_masklen (lsa->mask); - } - apply_mask_ipv4 (&p); - - rn = route_node_get (rt, (struct prefix *) &p); - if (rn->info) - { - zlog_warn ("Same routing information exists for %s", inet_ntoa (v->id)); - route_unlock_node (rn); - return; - } - - or = ospf_route_new (); - - if (v->type == OSPF_VERTEX_NETWORK) - { - or->type = OSPF_DESTINATION_NETWORK; - - for (ALL_LIST_ELEMENTS (v->parents, node, nnode, parent)) - { - path = ospf_path_new (); - path->nexthop = parent->nexthop->router; - listnode_add (or->paths, path); - } - } - else - or->type = OSPF_DESTINATION_ROUTER; - - or->id = v->id; - or->u.std.area_id = area->area_id; - or->u.std.external_routing= area->external_routing; - or->path_type = OSPF_PATH_INTRA_AREA; - or->cost = v->distance; - - rn->info = or; -} - /* RFC2328 16.1. (4). For "router". */ void ospf_intra_add_router (struct route_table *rt, struct vertex *v, @@ -349,7 +290,7 @@ ospf_intra_add_router (struct route_table *rt, struct vertex *v, if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_router: LS ID: %s", inet_ntoa (lsa->header.id)); - + if (!OSPF_IS_AREA_BACKBONE(area)) ospf_vl_up_check (area, lsa->header.id, v); @@ -465,7 +406,7 @@ ospf_intra_add_transit (struct route_table *rt, struct vertex *v, if (v->distance > cur_or->cost || IPV4_ADDR_CMP (&cur_or->u.std.origin->id, &lsa->header.id) > 0) return; - + ospf_route_free (rn->info); } @@ -480,7 +421,7 @@ ospf_intra_add_transit (struct route_table *rt, struct vertex *v, or->u.std.origin = (struct lsa_header *) lsa; ospf_route_copy_nexthops_from_vertex (or, v); - + rn->info = or; } @@ -509,7 +450,7 @@ ospf_intra_add_stub (struct route_table *rt, struct router_lsa_link *link, apply_mask_ipv4 (&p); if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("ospf_intra_add_stub(): processing route to %s/%d", + zlog_debug ("ospf_intra_add_stub(): processing route to %s/%d", inet_ntoa (p.prefix), p.prefixlen); /* (1) Calculate the distance D of stub network from the root. D is @@ -519,9 +460,9 @@ ospf_intra_add_stub (struct route_table *rt, struct router_lsa_link *link, cost = v->distance + ntohs (link->m[0].metric); if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("ospf_intra_add_stub(): calculated cost is %d + %d = %d", + zlog_debug ("ospf_intra_add_stub(): calculated cost is %d + %d = %d", v->distance, ntohs(link->m[0].metric), cost); - + /* PtP links with /32 masks adds host routes to remote, directly * connected hosts, see RFC 2328, 12.4.1.1, Option 1. * Such routes can just be ignored for the sake of tidyness. @@ -534,7 +475,7 @@ ospf_intra_add_stub (struct route_table *rt, struct router_lsa_link *link, __func__, inet_ntoa (link->link_id)); return; } - + rn = route_node_get (rt, (struct prefix *) &p); /* Lookup current routing table. */ @@ -690,7 +631,7 @@ ospf_route_table_dump (struct route_table *rt) { if (or->type == OSPF_DESTINATION_NETWORK) { - zlog_debug ("N %s/%d\t%s\t%s\t%d", + zlog_debug ("N %s/%d\t%s\t%s\t%d", inet_ntop (AF_INET, &rn->p.u.prefix4, buf1, BUFSIZ), rn->p.prefixlen, inet_ntop (AF_INET, &or->u.std.area_id, buf2, @@ -701,7 +642,7 @@ ospf_route_table_dump (struct route_table *rt) zlog_debug (" -> %s", inet_ntoa (path->nexthop)); } else - zlog_debug ("R %s\t%s\t%s\t%d", + zlog_debug ("R %s\t%s\t%s\t%d", inet_ntop (AF_INET, &rn->p.u.prefix4, buf1, BUFSIZ), inet_ntop (AF_INET, &or->u.std.area_id, buf2, BUFSIZ), @@ -724,10 +665,6 @@ ospf_asbr_route_cmp (struct ospf *ospf, struct ospf_route *r1, r1_type = r1->path_type; r2_type = r2->path_type; - /* If RFC1583Compat flag is on -- all paths are equal. */ - if (CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE)) - return 0; - /* r1/r2 itself is backbone, and it's Inter-area path. */ if (OSPF_IS_AREA_ID_BACKBONE (r1->u.std.area_id)) r1_type = OSPF_PATH_INTER_AREA; @@ -778,7 +715,7 @@ ospf_route_cmp (struct ospf *ospf, struct ospf_route *r1, return ret; } break; - } + } /* Anyway, compare the costs. */ return (r1->cost - r2->cost); @@ -813,8 +750,8 @@ ospf_route_copy_nexthops_from_vertex (struct ospf_route *to, for (ALL_LIST_ELEMENTS_RO (v->parents, node, vp)) { nexthop = vp->nexthop; - - if (nexthop->oi != NULL) + + if (nexthop->oi != NULL) { if (! ospf_path_exist (to->paths, nexthop->router, nexthop->oi)) { diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 66f1df2c..66e76392 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -356,9 +356,6 @@ ospf_lsa_has_link (struct lsa_header *w, struct lsa_header *v) return -1; } -#define ROUTER_LSA_MIN_SIZE 12 -#define ROUTER_LSA_TOS_SIZE 4 - /* Find the next link after prev_link from v to w. If prev_link is * NULL, return the first link from v to w. Ignore stub and virtual links; * these link types will never be returned. @@ -380,8 +377,8 @@ ospf_get_next_link (struct vertex *v, struct vertex *w, else { p = (u_char *) prev_link; - p += (ROUTER_LSA_MIN_SIZE + - (prev_link->m[0].tos_count * ROUTER_LSA_TOS_SIZE)); + p += (OSPF_ROUTER_LSA_LINK_SIZE + + (prev_link->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); } lim = ((u_char *) v->lsa) + ntohs (v->lsa->length); @@ -390,7 +387,7 @@ ospf_get_next_link (struct vertex *v, struct vertex *w, { l = (struct router_lsa_link *) p; - p += (ROUTER_LSA_MIN_SIZE + (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE)); + p += (OSPF_ROUTER_LSA_LINK_SIZE + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); if (l->m[0].type != lsa_type) continue; @@ -755,8 +752,8 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area, { l = (struct router_lsa_link *) p; - p += (ROUTER_LSA_MIN_SIZE + - (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE)); + p += (OSPF_ROUTER_LSA_LINK_SIZE + + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); /* (a) If this is a link to a stub network, examine the next link in V's LSA. Links to stub networks will be @@ -989,8 +986,8 @@ ospf_spf_process_stubs (struct ospf_area *area, struct vertex *v, { l = (struct router_lsa_link *) p; - p += (ROUTER_LSA_MIN_SIZE + - (l->m[0].tos_count * ROUTER_LSA_TOS_SIZE)); + p += (OSPF_ROUTER_LSA_LINK_SIZE + + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); if (l->m[0].type == LSA_LINK_TYPE_STUB) ospf_intra_add_stub (rt, l, v, area, parent_is_root); @@ -1047,6 +1044,7 @@ ospf_rtrs_free (struct route_table *rtrs) static void ospf_rtrs_print (struct route_table *rtrs) __attribute__((unused)) ; +#if 0 static void ospf_rtrs_print (struct route_table *rtrs) { @@ -1106,6 +1104,7 @@ ospf_rtrs_print (struct route_table *rtrs) zlog_debug ("ospf_rtrs_print() end"); } +#endif /* Calculating the shortest-path tree for an area. */ static void diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 19dfb1c4..e9578076 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -81,8 +81,11 @@ ospf_str2area_id (const char *str, struct in_addr *area_id, int *format) /* match "<0-4294967295>". */ else { + if (*str == '-') + return -1; + errno = 0; ret = strtoul (str, &endptr, 10); - if (*endptr != '\0' || (ret == ULONG_MAX && errno == ERANGE)) + if (*endptr != '\0' || errno || ret > UINT32_MAX) return -1; area_id->s_addr = htonl (ret); @@ -94,29 +97,6 @@ ospf_str2area_id (const char *str, struct in_addr *area_id, int *format) static int -str2distribute_source (const char *str, int *source) -{ - /* Sanity check. */ - if (str == NULL) - return 0; - - if (strncmp (str, "k", 1) == 0) - *source = ZEBRA_ROUTE_KERNEL; - else if (strncmp (str, "c", 1) == 0) - *source = ZEBRA_ROUTE_CONNECT; - else if (strncmp (str, "s", 1) == 0) - *source = ZEBRA_ROUTE_STATIC; - else if (strncmp (str, "r", 1) == 0) - *source = ZEBRA_ROUTE_RIP; - else if (strncmp (str, "b", 1) == 0) - *source = ZEBRA_ROUTE_BGP; - else - return 0; - - return 1; -} - -static int str2metric (const char *str, int *metric) { /* Sanity check. */ @@ -3762,7 +3742,7 @@ show_as_external_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) return 0; } -/* N.B. This function currently seems to be unused. */ +#if 0 static int show_as_external_lsa_stdvty (struct ospf_lsa *lsa) __attribute__((unused)) ; @@ -3789,6 +3769,7 @@ show_as_external_lsa_stdvty (struct ospf_lsa *lsa) return 0; } +#endif /* Show AS-NSSA-LSA detail information. */ static int @@ -5828,7 +5809,8 @@ DEFUN (ospf_redistribute_source_metric_type, int metric = -1; /* Get distribute source. */ - if (!str2distribute_source (argv[0], &source)) + source = proto_redistnum(AFI_IP, argv[0]); + if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; /* Get metric value. */ @@ -5889,7 +5871,8 @@ DEFUN (ospf_redistribute_source_type_metric, int metric = -1; /* Get distribute source. */ - if (!str2distribute_source (argv[0], &source)) + source = proto_redistnum(AFI_IP, argv[0]); + if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; /* Get metric value. */ @@ -5953,7 +5936,8 @@ DEFUN (ospf_redistribute_source_metric_routemap, int metric = -1; /* Get distribute source. */ - if (!str2distribute_source (argv[0], &source)) + source = proto_redistnum(AFI_IP, argv[0]); + if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; /* Get metric value. */ @@ -5986,7 +5970,8 @@ DEFUN (ospf_redistribute_source_type_routemap, int type = -1; /* Get distribute source. */ - if (!str2distribute_source (argv[0], &source)) + source = proto_redistnum(AFI_IP, argv[0]); + if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; /* Get metric value. */ @@ -6014,7 +5999,8 @@ DEFUN (ospf_redistribute_source_routemap, int source; /* Get distribute source. */ - if (!str2distribute_source (argv[0], &source)) + source = proto_redistnum(AFI_IP, argv[0]); + if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; if (argc == 2) @@ -6035,7 +6021,8 @@ DEFUN (no_ospf_redistribute_source, struct ospf *ospf = vty->index; int source; - if (!str2distribute_source (argv[0], &source)) + source = proto_redistnum(AFI_IP, argv[0]); + if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; ospf_routemap_unset (ospf, source); @@ -6054,7 +6041,8 @@ DEFUN (ospf_distribute_list_out, int source; /* Get distribute source. */ - if (!str2distribute_source (argv[1], &source)) + source = proto_redistnum(AFI_IP, argv[0]); + if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; return ospf_distribute_list_out_set (ospf, source, argv[0]); @@ -6072,7 +6060,8 @@ DEFUN (no_ospf_distribute_list_out, struct ospf *ospf = vty->index; int source; - if (!str2distribute_source (argv[1], &source)) + source = proto_redistnum(AFI_IP, argv[0]); + if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; return ospf_distribute_list_out_unset (ospf, source, argv[0]); @@ -7906,9 +7895,9 @@ config_write_ospf_distribute (struct vty *vty, struct ospf *ospf) { /* distribute-list print. */ for (type = 0; type < ZEBRA_ROUTE_MAX; type++) - if (ospf->dlist[type].name) + if (DISTRIBUTE_NAME (ospf, type)) vty_out (vty, " distribute-list %s out %s%s", - ospf->dlist[type].name, + DISTRIBUTE_NAME (ospf, type), zebra_route_string(type), VTY_NEWLINE); /* default-information print. */ diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 0a486199..9562199e 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -359,6 +359,7 @@ ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or) stream_putc (s, ZEBRA_ROUTE_OSPF); stream_putc (s, flags); stream_putc (s, message); + stream_putw (s, SAFI_UNICAST); /* Put prefix information. */ psize = PSIZE (p->prefixlen); @@ -428,6 +429,7 @@ ospf_zebra_delete (struct prefix_ipv4 *p, struct ospf_route *or) api.type = ZEBRA_ROUTE_OSPF; api.flags = 0; api.message = 0; + api.safi = SAFI_UNICAST; api.ifindex_num = 0; api.nexthop_num = 0; @@ -484,6 +486,7 @@ ospf_zebra_add_discard (struct prefix_ipv4 *p) api.type = ZEBRA_ROUTE_OSPF; api.flags = ZEBRA_FLAG_BLACKHOLE; api.message = 0; + api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 0; api.ifindex_num = 0; @@ -506,6 +509,7 @@ ospf_zebra_delete_discard (struct prefix_ipv4 *p) api.type = ZEBRA_ROUTE_OSPF; api.flags = ZEBRA_FLAG_BLACKHOLE; api.message = 0; + api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 0; api.ifindex_num = 0; @@ -671,7 +675,7 @@ ospf_external_lsa_originate_check (struct ospf *ospf, if (is_prefix_default (&ei->p)) if (ospf->default_originate == DEFAULT_ORIGINATE_NONE) { - zlog_info ("LSA[Type5:0.0.0.0]: Not originate AS-exntenal-LSA " + zlog_info ("LSA[Type5:0.0.0.0]: Not originate AS-external-LSA " "for default"); return 0; } diff --git a/ospfd/ospf_zebra.h b/ospfd/ospf_zebra.h index 3efd8958..fbb34442 100644 --- a/ospfd/ospf_zebra.h +++ b/ospfd/ospf_zebra.h @@ -50,8 +50,6 @@ extern void ospf_zebra_delete (struct prefix_ipv4 *, struct ospf_route *); extern void ospf_zebra_add_discard (struct prefix_ipv4 *); extern void ospf_zebra_delete_discard (struct prefix_ipv4 *); -extern int ospf_default_originate_timer (struct thread *); - extern int ospf_redistribute_check (struct ospf *, struct external_info *, int *); extern int ospf_distribute_check_connected (struct ospf *, diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 48453a9b..fe7312df 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -1204,6 +1204,7 @@ ospf_area_nssa_translator_role_set (struct ospf *ospf, struct in_addr area_id, return 1; } +#if 0 /* XXX: unused? Leave for symmetry? */ static int ospf_area_nssa_translator_role_unset (struct ospf *ospf, @@ -1225,6 +1226,7 @@ ospf_area_nssa_translator_role_unset (struct ospf *ospf, return 1; } +#endif int ospf_area_export_list_set (struct ospf *ospf, diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 0e57c452..7a56d163 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -72,10 +72,6 @@ #define OSPF_ALLSPFROUTERS 0xe0000005 /* 224.0.0.5 */ #define OSPF_ALLDROUTERS 0xe0000006 /* 224.0.0.6 */ -/* XXX Where is this used? And why it was used only if compiled with - * NSSA support. */ -#define OSPF_LOOPer 0x7f000000 /* 127.0.0.0 */ - #define OSPF_AREA_BACKBONE 0x00000000 /* 0.0.0.0 */ /* OSPF Authentication Type. */ diff --git a/pkgsrc/.cvsignore b/pkgsrc/.cvsignore deleted file mode 100644 index 818bd175..00000000 --- a/pkgsrc/.cvsignore +++ /dev/null @@ -1,5 +0,0 @@ -Makefile -Makefile.in -*.sh -.arch-inventory -.arch-ids diff --git a/ports/.cvsignore b/ports/.cvsignore deleted file mode 100644 index 73bcf19d..00000000 --- a/ports/.cvsignore +++ /dev/null @@ -1,3 +0,0 @@ -.arch-inventory -.arch-ids - diff --git a/ports/files/.cvsignore b/ports/files/.cvsignore deleted file mode 100644 index 73bcf19d..00000000 --- a/ports/files/.cvsignore +++ /dev/null @@ -1,3 +0,0 @@ -.arch-inventory -.arch-ids - diff --git a/ports/pkg/.cvsignore b/ports/pkg/.cvsignore deleted file mode 100644 index 73bcf19d..00000000 --- a/ports/pkg/.cvsignore +++ /dev/null @@ -1,3 +0,0 @@ -.arch-inventory -.arch-ids - diff --git a/redhat/.cvsignore b/redhat/.cvsignore deleted file mode 100644 index 98ca65a2..00000000 --- a/redhat/.cvsignore +++ /dev/null @@ -1,7 +0,0 @@ -zebra.spec -quagga.spec -Makefile -Makefile.in -.nfs* -.arch-inventory -.arch-ids diff --git a/ripd/.cvsignore b/ripd/.cvsignore deleted file mode 100644 index 41fd8c82..00000000 --- a/ripd/.cvsignore +++ /dev/null @@ -1,14 +0,0 @@ -Makefile -Makefile.in -*.o -ripd -ripd.conf -tags -TAGS -.deps -.nfs* -*.lo -*.la -*.libs -.arch-inventory -.arch-ids diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index c1291a1d..c9086f79 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -78,9 +78,8 @@ ipv4_multicast_join (int sock, { int ret; - ret = setsockopt_multicast_ipv4 (sock, + ret = setsockopt_ipv4_multicast (sock, IP_ADD_MEMBERSHIP, - ifa, group.s_addr, ifindex); @@ -100,9 +99,8 @@ ipv4_multicast_leave (int sock, { int ret; - ret = setsockopt_multicast_ipv4 (sock, + ret = setsockopt_ipv4_multicast (sock, IP_DROP_MEMBERSHIP, - ifa, group.s_addr, ifindex); @@ -138,18 +136,13 @@ rip_interface_new (void) void rip_interface_multicast_set (int sock, struct connected *connected) { - struct in_addr addr; - assert (connected != NULL); - addr = CONNECTED_ID(connected)->u.prefix4; - - if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF, addr, 0, - connected->ifp->ifindex) < 0) + if (setsockopt_ipv4_multicast_if (sock, connected->ifp->ifindex) < 0) { zlog_warn ("Can't setsockopt IP_MULTICAST_IF on fd %d to " - "source address %s for interface %s", - sock, inet_ntoa(addr), + "ifindex %d for interface %s", + sock, connected->ifp->ifindex, connected->ifp->name); } diff --git a/ripd/rip_main.c b/ripd/rip_main.c index 57b5f3af..ccb5fa01 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -32,6 +32,7 @@ #include "log.h" #include "privs.h" #include "sigevent.h" +#include "zclient.h" #include "ripd/ripd.h" @@ -41,6 +42,7 @@ static struct option longopts[] = { "daemon", no_argument, NULL, 'd'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, + { "socket", required_argument, NULL, 'z'}, { "help", no_argument, NULL, 'h'}, { "dryrun", no_argument, NULL, 'C'}, { "vty_addr", required_argument, NULL, 'A'}, @@ -109,6 +111,7 @@ Daemon which manages RIP version 1 and 2.\n\n\ -d, --daemon Runs in daemon mode\n\ -f, --config_file Set configuration file name\n\ -i, --pid_file Set process identifier file name\n\ +-z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -C, --dryrun Check configuration for validity and exit\n\ @@ -206,7 +209,7 @@ main (int argc, char **argv) { int opt; - opt = getopt_long (argc, argv, "df:i:hA:P:u:g:rvC", longopts, 0); + opt = getopt_long (argc, argv, "df:i:z:hA:P:u:g:rvC", longopts, 0); if (opt == EOF) break; @@ -227,6 +230,9 @@ main (int argc, char **argv) case 'i': pid_file = optarg; break; + case 'z': + zclient_serv_path_set (optarg); + break; case 'P': /* Deal with atoi() returning 0 on failure, and ripd not listening on rip port... */ diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index 326ea658..4286256f 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -47,6 +47,7 @@ rip_zebra_ipv4_add (struct prefix_ipv4 *p, struct in_addr *nexthop, api.type = ZEBRA_ROUTE_RIP; api.flags = 0; api.message = 0; + api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; @@ -77,6 +78,7 @@ rip_zebra_ipv4_delete (struct prefix_ipv4 *p, struct in_addr *nexthop, api.type = ZEBRA_ROUTE_RIP; api.flags = 0; api.message = 0; + api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; diff --git a/ripngd/.cvsignore b/ripngd/.cvsignore deleted file mode 100644 index 48f45cef..00000000 --- a/ripngd/.cvsignore +++ /dev/null @@ -1,14 +0,0 @@ -Makefile -Makefile.in -*.o -ripngd -ripngd.conf -tags -TAGS -.deps -.nfs* -*.lo -*.la -*.libs -.arch-inventory -.arch-ids diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c index 85209a15..f4a62440 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -47,6 +47,7 @@ struct option longopts[] = { "daemon", no_argument, NULL, 'd'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, + { "socket", required_argument, NULL, 'z'}, { "dryrun", no_argument, NULL, 'C'}, { "help", no_argument, NULL, 'h'}, { "vty_addr", required_argument, NULL, 'A'}, @@ -112,6 +113,7 @@ Daemon which manages RIPng.\n\n\ -d, --daemon Runs in daemon mode\n\ -f, --config_file Set configuration file name\n\ -i, --pid_file Set process identifier file name\n\ +-z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -r, --retain When program terminates, retain added route by ripngd.\n\ @@ -205,7 +207,7 @@ main (int argc, char **argv) { int opt; - opt = getopt_long (argc, argv, "df:i:hA:P:u:g:vC", longopts, 0); + opt = getopt_long (argc, argv, "df:i:z:hA:P:u:g:vC", longopts, 0); if (opt == EOF) break; @@ -225,7 +227,10 @@ main (int argc, char **argv) break; case 'i': pid_file = optarg; - break; + break; + case 'z': + zclient_serv_path_set (optarg); + break; case 'P': /* Deal with atoi() returning 0 on failure, and ripngd not listening on ripngd port... */ diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index 4c444550..c931a291 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -53,6 +53,7 @@ ripng_zebra_ipv6_add (struct prefix_ipv6 *p, struct in6_addr *nexthop, api.type = ZEBRA_ROUTE_RIPNG; api.flags = 0; api.message = 0; + api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; @@ -77,6 +78,7 @@ ripng_zebra_ipv6_delete (struct prefix_ipv6 *p, struct in6_addr *nexthop, api.type = ZEBRA_ROUTE_RIPNG; api.flags = 0; api.message = 0; + api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 6a7bbc54..03775da7 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -119,6 +119,11 @@ ripng_make_socket (void) ret = setsockopt_ipv6_pktinfo (sock, 1); if (ret < 0) return ret; +#ifdef IPTOS_PREC_INTERNETCONTROL + ret = setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL); + if (ret < 0) + return ret; +#endif ret = setsockopt_ipv6_multicast_hops (sock, 255); if (ret < 0) return ret; @@ -2482,28 +2487,10 @@ DEFUN (ripng_timers, unsigned long update; unsigned long timeout; unsigned long garbage; - char *endptr = NULL; - update = strtoul (argv[0], &endptr, 10); - if (update == ULONG_MAX || *endptr != '\0') - { - vty_out (vty, "update timer value error%s", VTY_NEWLINE); - return CMD_WARNING; - } - - timeout = strtoul (argv[1], &endptr, 10); - if (timeout == ULONG_MAX || *endptr != '\0') - { - vty_out (vty, "timeout timer value error%s", VTY_NEWLINE); - return CMD_WARNING; - } - - garbage = strtoul (argv[2], &endptr, 10); - if (garbage == ULONG_MAX || *endptr != '\0') - { - vty_out (vty, "garbage timer value error%s", VTY_NEWLINE); - return CMD_WARNING; - } + VTY_GET_INTEGER_RANGE("update timer", update, argv[0], 0, 65535); + VTY_GET_INTEGER_RANGE("timeout timer", timeout, argv[1], 0, 65535); + VTY_GET_INTEGER_RANGE("garbage timer", garbage, argv[2], 0, 65535); /* Set each timer value. */ ripng->update_time = update; diff --git a/solaris/.cvsignore b/solaris/.cvsignore deleted file mode 100644 index 810874ca..00000000 --- a/solaris/.cvsignore +++ /dev/null @@ -1,14 +0,0 @@ -Makefile -Makefile.in -?.manifest -*.xml -pkginfo.*.full -pkginfo.tmpl -prototype.daemons -prototype.dev -prototype.doc -prototype.libs -prototype.smf -quagga.init -*.pkg -*.pkg.gz diff --git a/solaris/Makefile.am b/solaris/Makefile.am index ecaf9b9b..dcee240c 100644 --- a/solaris/Makefile.am +++ b/solaris/Makefile.am @@ -1,5 +1,4 @@ # Solaris packages automake file -# $Id$ # XXX This file uses GNU make extensions. diff --git a/solaris/quagga.init.in b/solaris/quagga.init.in index 8457e990..00426241 100755 --- a/solaris/quagga.init.in +++ b/solaris/quagga.init.in @@ -20,8 +20,6 @@ # Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # -# $Id$ -# # Starts/stops the given daemon SMFINCLUDE=/lib/svc/share/smf_include.sh diff --git a/tests/.cvsignore b/tests/.cvsignore deleted file mode 100644 index 4c3e50dc..00000000 --- a/tests/.cvsignore +++ /dev/null @@ -1,22 +0,0 @@ -Makefile -Makefile.in -*.o -tags -TAGS -.deps -.nfs* -*.lo -*.la -*.libs -testsig -.arch-inventory -.arch-ids -testbuffer -testmemory -testsig -aspathtest -heavy -heavythread -heavywq -testprivs -teststream diff --git a/tests/Makefile.am b/tests/Makefile.am index f55edbb6..e12a9d96 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -7,7 +7,7 @@ AM_LDFLAGS = $(PILDFLAGS) noinst_PROGRAMS = testsig testbuffer testmemory heavy heavywq heavythread \ aspathtest testprivs teststream testbgpcap ecommtest \ testbgpmpattr testchecksum testvector testsymtab \ - testlistutil testqpath testavl testqfs + testlistutil testqpath testavl testqfs testprefix testsig_SOURCES = test-sig.c testbuffer_SOURCES = test-buffer.c @@ -28,6 +28,7 @@ testlistutil_SOURCES = test-list_util.c testqpath_SOURCES = test-qpath.c testavl_SOURCES = test-avl.c testqfs_SOURCES = test-qfs.c +testprefix_SOURCES = test-prefix.c testsig_LDADD = ../lib/libzebra.la @LIBCAP@ testbuffer_LDADD = ../lib/libzebra.la @LIBCAP@ @@ -48,3 +49,4 @@ testlistutil_LDADD = ../lib/libzebra.la @LIBCAP@ testqpath_LDADD = ../lib/libzebra.la @LIBCAP@ testavl_LDADD = ../lib/libzebra.la @LIBCAP@ testqfs_LDADD = ../lib/libzebra.la @LIBCAP@ +testprefix_LDADD = ../lib/libzebra.la @LIBCAP@ diff --git a/tests/aspath_test.c b/tests/aspath_test.c index 6384945d..96cc5464 100644 --- a/tests/aspath_test.c +++ b/tests/aspath_test.c @@ -7,6 +7,7 @@ #include "privs.h" #include "bgpd/bgpd.h" +#include "bgpd/bgp_peer.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_attr.h" @@ -1200,8 +1201,9 @@ handle_attr_test (struct aspath_tests *t) int ret; int initfail = failed; struct aspath *asp; - size_t datalen; + size_t datalen, endp; char host[] = { "none" } ; + bool mp_eor ; asp = make_aspath (t->segment->asdata, t->segment->len, 0); @@ -1217,7 +1219,9 @@ handle_attr_test (struct aspath_tests *t) stream_put (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); + endp = stream_push_endp(peer.ibuf, t->len + datalen) ; + + ret = bgp_attr_parse (&peer, &attr, NULL, NULL, &mp_eor); if (ret != t->result) { diff --git a/tests/bgp_capability_test.c b/tests/bgp_capability_test.c index a53374e4..a72e841a 100644 --- a/tests/bgp_capability_test.c +++ b/tests/bgp_capability_test.c @@ -10,6 +10,7 @@ #include "memory.h" #include "bgpd/bgpd.h" +#include "bgpd/bgp_peer.h" #include "bgpd/bgp_open.h" #include "bgpd/bgp_debug.h" @@ -99,10 +100,10 @@ static struct test_segment mp_segments[] = }, /* 6 */ { "MP3", - "MP IP6/VPNv4", + "MP IP6/MPLS-labeled VPN", { CAPABILITY_CODE_MP, 0x4, 0x0, 0x2, 0x0, 0x80 }, - 6, SHOULD_PARSE, 0, /* parses, but invalid afi,safi */ - 1, AFI_IP6, BGP_SAFI_VPNV4, INVALID_AFI, + 6, SHOULD_PARSE, 0, + 1, AFI_IP6, SAFI_MPLS_LABELED_VPN, VALID_AFI, }, /* 7 */ { "MP5", @@ -113,21 +114,14 @@ static struct test_segment mp_segments[] = }, /* 8 */ { "MP6", - "MP IP4/VPNv4", + "MP IP4/MPLS-laveled VPN", { CAPABILITY_CODE_MP, 0x4, 0x0, 0x1, 0x0, 0x80 }, 6, SHOULD_PARSE, 0, - 1, AFI_IP, BGP_SAFI_VPNV4, VALID_AFI, - }, - /* 9 */ - { "MP7", - "MP IP4/VPNv6", - { CAPABILITY_CODE_MP, 0x4, 0x0, 0x1, 0x0, 0x81 }, - 6, SHOULD_PARSE, 0, /* parses, but invalid afi,safi tuple */ - 1, AFI_IP, BGP_SAFI_VPNV6, INVALID_AFI, + 1, AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, }, /* 10 */ { "MP8", - "MP unknown AFI", + "MP unknown AFI/SAFI", { CAPABILITY_CODE_MP, 0x4, 0x0, 0xa, 0x0, 0x81 }, 6, SHOULD_PARSE, 0, 1, 0xa, 0x81, INVALID_AFI, /* parses, but unknown */ diff --git a/tests/bgp_mp_attr_test.c b/tests/bgp_mp_attr_test.c index 5520279c..2219ea47 100644 --- a/tests/bgp_mp_attr_test.c +++ b/tests/bgp_mp_attr_test.c @@ -9,6 +9,7 @@ #include "memory.h" #include "bgpd/bgpd.h" +#include "bgpd/bgp_peer.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_open.h" #include "bgpd/bgp_debug.h" @@ -288,10 +289,10 @@ static struct test_segment { SHOULD_ERR, AFI_IP, SAFI_UNICAST, VALID_AFI, }, - { "IPv4-vpnv4", - "IPv4/VPNv4 MP Reach, RD, Nexthop, 3 NLRIs", + { "IPv4-MLVPN", + "IPv4/MPLS-labeled VPN MP Reach, RD, Nexthop, 3 NLRIs", { - /* AFI / SAFI */ 0x0, AFI_IP, BGP_SAFI_VPNV4, + /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, /* nexthop bytes */ 12, /* RD */ 0, 0, 1, 2, 0, 0xff, 3, 4, @@ -411,10 +412,10 @@ static struct test_segment mp_unreach_segments [] = SHOULD_ERR, AFI_IP, SAFI_UNICAST, VALID_AFI, }, - { "IPv4-unreach-vpnv4", - "IPv4/VPNv4 MP Unreach, RD, 3 NLRIs", + { "IPv4-unreach-MLVPN", + "IPv4/MPLS-labeled VPN MP Unreach, RD, 3 NLRIs", { - /* AFI / SAFI */ 0x0, AFI_IP, BGP_SAFI_VPNV4, + /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, /* nexthop bytes */ 12, /* RD */ 0, 0, 1, 2, 0, 0xff, 3, 4, @@ -436,24 +437,38 @@ static struct test_segment mp_unreach_segments [] = static void parse_test (struct peer *peer, struct test_segment *t, int type) { + byte flag ; int ret; int oldfailed = failed; struct attr attr; struct bgp_nlri nlri; + bool mp_eor ; #define RANDOM_FUZZ 35 stream_reset (peer->ibuf); stream_put (peer->ibuf, NULL, RANDOM_FUZZ); stream_set_getp (peer->ibuf, RANDOM_FUZZ); + flag = BGP_ATTR_FLAG_OPTIONAL | ((t->len < 256) ? 0 : BGP_ATTR_FLAG_EXTLEN) ; + + stream_putc(peer->ibuf, flag) ; + stream_putc(peer->ibuf, type) ; + if (flag & BGP_ATTR_FLAG_EXTLEN) + stream_putw(peer->ibuf, t->len) ; + else + stream_putc(peer->ibuf, t->len) ; + + stream_set_startp(peer->ibuf, stream_get_getp(peer->ibuf)) ; stream_put (peer->ibuf, t->data, t->len); printf ("%s: %s\n", t->name, t->desc); + mp_eor = false ; + if (type == BGP_ATTR_MP_REACH_NLRI) - ret = bgp_mp_reach_parse (peer, t->len, &attr, &nlri); + ret = bgp_mp_reach_parse (peer, t->len, &attr, flag, &nlri); else - ret = bgp_mp_unreach_parse (peer, t->len, &nlri); + ret = bgp_mp_unreach_parse (peer, t->len, flag, &nlri, &mp_eor); if (!ret) { diff --git a/tests/heavy-wq.c b/tests/heavy-wq.c index ee3753ae..8d6785a0 100644 --- a/tests/heavy-wq.c +++ b/tests/heavy-wq.c @@ -1,6 +1,4 @@ /* - * $Id$ - * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it diff --git a/tests/test-prefix.c b/tests/test-prefix.c new file mode 100644 index 00000000..63a4ce07 --- /dev/null +++ b/tests/test-prefix.c @@ -0,0 +1,1413 @@ +#include <zebra.h> +#include "misc.h" +#include "qlib_init.h" +#include "command.h" + +#include "prefix.h" + +/*------------------------------------------------------------------------------ + * Infrastructure + */ +typedef struct +{ + uint errs ; + uint errs_total ; + + uint good ; + uint total ; +} counts_t ; + +typedef counts_t* counts ; + +typedef void (*test_func_t)(counts ct) ; + +typedef struct +{ + test_func_t func ; + + uint good ; + uint total ; +} test_t ; + + +static uint get_pbit(byte* v, uint bn) __attribute__((unused)) ; +static void set_pbit(byte* v, uint bn) ; +static void clear_pbit(byte* v, uint bn) ; +static void flip_pbit(byte* v, uint bn) ; + +/*------------------------------------------------------------------------------ + * The actual testing + */ +static void test_masklen2ip(counts ct) ; +static void test_masklen2ip6(counts ct) ; +static void test_ip_masklen(counts ct) ; +static void test_ip6_masklen(counts ct) ; +static void test_prefix_raw_ipv4(counts ct) ; +static void test_prefix_raw_ipv6(counts ct) ; +static void test_prefix_match(counts ct) ; +static void test_prefix_same(counts ct) ; +static void test_prefix_cmp(counts ct) ; +static void test_prefix_common_bits(counts ct) ; +static void test_spfxtoa_str2prefix(counts ct) ; + +static const test_t tests[] = +{ + { .func = test_masklen2ip, .good = 33, .total = 256 }, + { .func = test_masklen2ip6, .good = 129, .total = 256 }, + { .func = test_ip_masklen, .good = 33, .total = 256 }, + { .func = test_ip6_masklen, .good = 129, .total = 512 }, + { .func = test_prefix_raw_ipv4, .good = 33, .total = 256 }, + { .func = test_prefix_raw_ipv6, .good = 129, .total = 256 }, + { .func = test_prefix_match, .good = 723905, .total = 1098177 }, + { .func = test_prefix_same, .good = 512, .total = 36864 }, + { .func = test_prefix_cmp, .good = 8385, .total = 133128 }, + { .func = test_prefix_common_bits, .good = 83592, .total = 650160 }, + { .func = test_spfxtoa_str2prefix, .good = 512, .total = 512 }, + + { .func = NULL } +} ; + +static byte mask_n[256][32] ; + +int +main (int argc, char **argv) +{ + const test_t* test ; + counts_t ct[1] ; + + uint i ; + + qlib_init_first_stage(0); /* Absolutely first */ + host_init(argv[0]) ; + + for (i = 0 ; i <= 256 ; ++i) + { + uint b ; + + for (b = 0 ; b < i ; b++) + set_pbit(mask_n[i], b) ; + + for (b = i ; b < 256 ; b++) + clear_pbit(mask_n[i], b) ; + } ; + +#if 0 + for (i = 0 ; i <= 256 ; ++i) + { + uint b ; + + fprintf(stderr, "%4u:", i) ; + for (b = 0 ; b < 32 ; ++b) + fprintf(stderr, " %02x", mask_n[i][b]) ; + fprintf(stderr, "\n") ; + } ; +#endif + + test = tests ; + ct->errs_total = 0 ; + + while (test->func != NULL) + { + ct->errs = 0 ; + ct->good = 0 ; + ct->total = 0 ; + + test->func(ct) ; + + if (ct->errs == 0) + { + fprintf(stderr, " -- OK %u/%u", ct->good, ct->total) ; + + if ((ct->good == test->good) && (ct->total == test->total)) + fprintf(stderr, " -- as expected\n") ; + else + { + fprintf(stderr, " *** but expected %u/%u\n", test->good, + test->total) ; + ++ct->errs ; + } ; + } + else + { + fprintf(stderr, "\n === %u errors (%u/%u)\n", ct->errs, ct->good, + ct->total) ; + } ; + + ct->errs_total += ct->errs ; + + ++test ; + } ; + + if (ct->errs_total == 0) + fprintf(stderr, "All tests completed -- OK\n") ; + else + fprintf(stderr, "*** All tests completed, with a total of %u errors\n", + ct->errs_total) ; + + if (ct->errs_total == 0) + return 0; + else + return 1 ; +} ; + +/*------------------------------------------------------------------------------ + * masklen2ip() -- converts a mask length to a mask. + */ +static void +test_masklen2ip(counts ct) +{ + uint plen ; + + fprintf(stderr, "Test masklen2ip()") ; + for (plen = 0 ; plen <= 255 ; ++plen) + { + struct in_addr get ; + struct in_addr expect ; + + masklen2ip (plen, &get) ; + + /* For plen 0..32 we expect to get a mask 0x00000000..0xFFFFFFFF + * + * For all other plen we get the maximum mask 0xFFFFFFFF. + * + * We count 0..32 as "good" -- so final mark should be 33/256. + */ + memcpy(&expect, mask_n[plen], 4) ; + + ++ct->total ; + + if (expect.s_addr == get.s_addr) + { + if (plen <= 32) + ++ct->good ; + } + else + { + ++ct->errs ; + fprintf(stderr, "\n *** for plen=%u expect 0x%08x got 0x%08x", + plen, ntohl(expect.s_addr), ntohl(get.s_addr)) ; + } ; + } ; +} ; + +/*------------------------------------------------------------------------------ + * masklen2ip6() -- converts a mask length to a mask. + */ +static void +test_masklen2ip6(counts ct) +{ + uint plen ; + + fprintf(stderr, "Test masklen2ip6()") ; + for (plen = 0 ; plen <= 255 ; ++plen) + { + union ip6_test + { + struct + { + char dummy_0[7] ; + struct in6_addr ip6 ; + char dummy_1[5] ; + } a ; + char t[1] ; + } ; + + union ip6_test get, expect ; + + memset(&get, 0xA5, sizeof(union ip6_test)) ; + memset(&expect, 0xA5, sizeof(union ip6_test)) ; + + masklen2ip6 (plen, &get.a.ip6) ; + + /* For plen 0..128 we expect to get a mask 0x00...00..0xFF...FF + * + * For all other plen we get the maximum mask 0xFF...FF. + * + * We count 0..128 as "good" -- so final mark should be 129/256. + */ + memcpy(&expect.a.ip6, mask_n[plen], 16) ; + + ++ct->total ; + + if (memcmp(&get, &expect, sizeof(union ip6_test)) == 0) + { + if (plen <= 128) + ++ct->good ; + } + else + { + uint i ; + ++ct->errs ; + fprintf(stderr, "\n *** for plen=%u", plen) ; + fprintf(stderr, "\n exp:") ; + for (i = 0 ; i < 16 ; ++i) + fprintf(stderr, " %02x", expect.a.ip6.s6_addr[i]) ; + fprintf(stderr, "\n got:") ; + for (i = 0 ; i < 16 ; ++i) + fprintf(stderr, " %02x", get.a.ip6.s6_addr[i]) ; + } ; + } ; +} ; + +/*------------------------------------------------------------------------------ + * ip_masklen() & ip_mask_check() -- converts mask to prefix/checks mask + */ +static void +test_ip_masklen(counts ct) +{ + uint plen ; + + fprintf(stderr, "Test ip_masklen() & ip_mask_check()") ; + for (plen = 0 ; plen <= 255 ; ++plen) + { + uint get, expect ; + bool get_ok, expect_ok ; + struct in_addr mask ; + + /* ip_masklen() will give a result for any mask. + * + * We use plen > 32 to construct masks of lengths 0..30, and perturb + * one bit after the first '0'. + * + * Expect final score of 33/256. + */ + if (plen <= 32) + { + masklen2ip (plen, &mask) ; + expect = plen ; + expect_ok = true ; /* good mask */ + } + else + { + uint px ; + + expect = plen % 31 ; /* 0..30 */ + expect_ok = false ; + + masklen2ip (expect, &mask) ; + + px = expect + 1 ; /* bit after first '0' */ + set_pbit((byte*)&mask, px + (rand() % (32 - px))) ; + } ; + + get = ip_masklen(mask) ; + get_ok = ip_mask_check(mask) ; + + ++ct->total ; + + if ((get == expect) && (get_ok == expect_ok)) + { + if (expect_ok) + ++ct->good ; + } + else + { + ++ct->errs ; + fprintf(stderr, "\n *** for mask=0x%08x expect %u got %u, " + "expect_ok %u got_ok %u", + ntohl(mask.s_addr), expect, get, expect_ok, get_ok) ; + } ; + } ; +} ; + +/*------------------------------------------------------------------------------ + * ip6_masklen() & ip6_mask_check() -- converts mask to prefix/checks mask + */ +static void +test_ip6_masklen(counts ct) +{ + uint plen ; + + fprintf(stderr, "Test ip6_masklen() & ip6_mask_check()") ; + for (plen = 0 ; plen <= 511 ; ++plen) + { + uint get, expect ; + int get_ok, expect_ok ; + struct in6_addr mask ; + + /* ip_masklen() will give a result for any mask. + * + * We use plen > 128 to construct masks of lengths 0..126, and perturb + * one bit after the first '0'. + * + * Expect final score of 129/512. + */ + if (plen <= 128) + { + masklen2ip6 (plen, &mask) ; + expect = plen ; + expect_ok = plen ; + } + else + { + uint px ; + + expect = plen % 127 ; /* 0..126 */ + expect_ok = -1 ; + + masklen2ip6 (expect, &mask) ; + px = expect + 1 ; /* bit after first '0' */ + set_pbit(mask.s6_addr, px + (rand() % (128 - px))) ; + } ; + + get = ip6_masklen(mask) ; + get_ok = ip6_mask_check(mask) ; + + ++ct->total ; + if ((expect == get) && (expect_ok == get_ok)) + { + if (expect_ok >= 0) + ++ct->good ; + } + else + { + uint i ; + ++ct->errs ; + fprintf(stderr, "\n *** for mask=0x%02x", mask.s6_addr[0]) ; + for (i = 1 ; i < 16 ; ++i) + fprintf(stderr, " %02x", mask.s6_addr[i]) ; + fprintf(stderr, " expect %u got %u, expect_ok %d got_ok %d", + expect, get, expect_ok, get_ok) ; + } ; + } ; +} ; + +/*------------------------------------------------------------------------------ + * prefix_to_raw() & prefix_from_raw() -- converts prefix to/from raw form + */ +static void +test_prefix_raw_ipv4(counts ct) +{ + uint plen ; + + fprintf(stderr, "Test prefix_to/from_raw() IPv4") ; + for (plen = 0 ; plen <= 255 ; ++plen) + { + struct prefix p1[1] ; + prefix_raw_t raw_in ; + prefix_raw_t raw_out ; + prefix_raw_t raw_exp ; + const byte* pm ; + uint i ; + bool ok ; + + pm = mask_n[plen] ; + + /* We generate raw_in which are full to the brim (256) bits of rubbish, + * and *ensure* that all bits beyond the plen are set '1' ! + * + * Only plen 0..32 are kosher, so expect final score of 33/256. + * + * The raw_out is only significant for the prefix_len part, but we fill + * that with the opposite of the raw-in, to make sure it is not set + * by accident. + * + * The raw_exp is the bits of raw_in which are valid. + */ + raw_in->prefix_len = plen ; + raw_out->prefix_len = ~plen ; + raw_exp->prefix_len = (plen <= 32) ? plen : 32 ; + + for (i = 0 ; i < (256/8) ; ++i) + { + if (i < 16) + { + raw_in->prefix[i] = (rand() & 0xFF) | ~ pm[i] ; + raw_exp->prefix[i] = raw_in->prefix[i] & pm[i] ; + } + else + { + raw_in->prefix[i] = 0xFF ; + raw_exp->prefix[i] = 0 ; + } + + raw_out->prefix[i] = ~raw_in->prefix[i] ; + } ; + + prefix_from_raw(p1, raw_in, AF_INET) ; + + ++ct->total ; + if ((p1->family == AF_INET) && (p1->prefixlen == raw_exp->prefix_len) + && (memcmp(p1->u.b, raw_exp->prefix, 4) == 0)) + { + ok = true ; + } + else + { + uint i ; + + ++ct->errs ; + ok = false ; + + fprintf(stderr, "\n *** raw=%3u:", raw_in->prefix_len) ; + for (i = 0 ; i < 4 ; ++i) + fprintf(stderr, " %02x", raw_in->prefix[i]) ; + + if (p1->family != AF_INET) + fprintf(stderr, "\n expect AF=%u got %u", AF_INET, p1->family) ; + + fprintf(stderr, "\n got=%3u:", p1->prefixlen) ; + for (i = 0 ; i < 4 ; ++i) + fprintf(stderr, " %02x", p1->u.b[i]) ; + } ; + + prefix_to_raw(raw_out, p1) ; + + if ((raw_exp->prefix_len == raw_out->prefix_len) + && ( (raw_exp->prefix_len == 0) + || (memcmp(raw_exp->prefix, raw_exp->prefix, + (raw_exp->prefix_len + 7u) / 8) == 0) )) + { + if (ok && (plen <= 32)) + ++ct->good ; + } + else + { + uint i ; + ++ct->errs ; + fprintf(stderr, "\n *** raw=%3u:", raw_in->prefix_len) ; + for (i = 0 ; i < 4 ; ++i) + fprintf(stderr, " %02x", raw_in->prefix[i]) ; + + fprintf(stderr, "\n got=%3u:", raw_out->prefix_len) ; + for (i = 0 ; i < (raw_out->prefix_len + 7u) / 8 ; ++i) + fprintf(stderr, " %02x", raw_out->prefix[i]) ; + + fprintf(stderr, "\n exp=%3u:", raw_exp->prefix_len) ; + for (i = 0 ; i < (raw_exp->prefix_len + 7u) / 8 ; ++i) + fprintf(stderr, " %02x", raw_exp->prefix[i]) ; + } ; + } ; +} ; + +/*------------------------------------------------------------------------------ + * prefix_to_raw() & prefix_from_raw() -- converts prefix to/from raw form + */ +static void +test_prefix_raw_ipv6(counts ct) +{ + uint plen ; + + fprintf(stderr, "Test prefix_to/from_raw() IPv6") ; + for (plen = 0 ; plen <= 255 ; ++plen) + { + struct prefix p1[1] ; + prefix_raw_t raw_in ; + prefix_raw_t raw_out ; + prefix_raw_t raw_exp ; + const byte* pm ; + uint i ; + bool ok ; + + pm = mask_n[plen] ; + + /* We generate raw_in which are full to the brim (256) bits of rubbish, + * and *ensure* that all bits beyond the plen are set '1' ! + * + * Only plen 0..128 are kosher, so expect final score of 129/256. + * + * The raw_out is only significant for the prefix_len part, but we fill + * that with the opposite of the raw-in, to make sure it is not set + * by accident. + * + * The raw_exp is the bits of raw_in which are valid. + */ + raw_in->prefix_len = plen ; + raw_out->prefix_len = ~plen ; + raw_exp->prefix_len = (plen <= 128) ? plen : 128 ; + + for (i = 0 ; i < (256/8) ; ++i) + { + if (i < 16) + { + raw_in->prefix[i] = (rand() & 0xFF) | ~ pm[i] ; + raw_exp->prefix[i] = raw_in->prefix[i] & pm[i] ; + } + else + { + raw_in->prefix[i] = 0xFF ; + raw_exp->prefix[i] = 0 ; + } + + raw_out->prefix[i] = ~raw_in->prefix[i] ; + } ; + + prefix_from_raw(p1, raw_in, AF_INET6) ; + + ++ct->total ; + if ((p1->family == AF_INET6) && (p1->prefixlen == raw_exp->prefix_len) + && (memcmp(p1->u.b, raw_exp->prefix, 16) == 0)) + { + ok = true ; + } + else + { + uint i ; + + ++ct->errs ; + ok = false ; + + fprintf(stderr, "\n *** raw=%3u:", raw_in->prefix_len) ; + for (i = 0 ; i < 4 ; ++i) + fprintf(stderr, " %02x", raw_in->prefix[i]) ; + + if (p1->family != AF_INET6) + fprintf(stderr, "\n expect AF=%u got %u", AF_INET6, p1->family) ; + + fprintf(stderr, "\n got=%3u:", p1->prefixlen) ; + for (i = 0 ; i < 4 ; ++i) + fprintf(stderr, " %02x", p1->u.b[i]) ; + } ; + + prefix_to_raw(raw_out, p1) ; + + if ((raw_exp->prefix_len == raw_out->prefix_len) + && ( (raw_exp->prefix_len == 0) + || (memcmp(raw_exp->prefix, raw_exp->prefix, + (raw_exp->prefix_len + 7u) / 8) == 0) )) + { + if (ok && (plen <= 128)) + ++ct->good ; + } + else + { + uint i ; + ++ct->errs ; + fprintf(stderr, "\n *** raw=%3u:", raw_in->prefix_len) ; + for (i = 0 ; i < 4 ; ++i) + fprintf(stderr, " %02x", raw_in->prefix[i]) ; + + fprintf(stderr, "\n got=%3u:", raw_out->prefix_len) ; + for (i = 0 ; i < (raw_out->prefix_len + 7u) / 8 ; ++i) + fprintf(stderr, " %02x", raw_out->prefix[i]) ; + + fprintf(stderr, "\n exp=%3u:", raw_exp->prefix_len) ; + for (i = 0 ; i < (raw_exp->prefix_len + 7u) / 8 ; ++i) + fprintf(stderr, " %02x", raw_exp->prefix[i]) ; + } ; + } ; +} ; + +/*------------------------------------------------------------------------------ + * prefix_match() tests whether prefix p1 includes (or is equal to) p2. + * + * NB: takes no notice of the prefixes' families. + */ +static void +test_prefix_match(counts ct) +{ + uint plen ; + + fprintf(stderr, "Test prefix_match()") ; + for (plen = 0 ; plen <= 128 ; ++plen) + { + struct prefix p1[1] ; + struct prefix p2[1] ; + uint i ; + uint p2_len ; + + /* For prefix lengths 0..129 full p1 and p2 with rubbish, and the set + * the two prefix addresses to be equal. + */ + for (i = 0 ; i < sizeof(struct prefix) ; ++i) + { + ((byte*)p1)[i] = rand() & 0xFF ; + ((byte*)p2)[i] = rand() & 0xFF ; + } ; + + for (i = 0 ; i < 16 ; ++i) + p1->u.b[i] = p2->u.b[i] ; + + /* We run a test for p1 taking plen (0..128), and p2 taking prefix + * lengths plen-1..128 (or 0..128) -- 8513 cases. + * + * For each case we perturb zero out of 128 bits, and then one of the + * 128 bits for all possible bits -- 129 tests. + * + * Total of 8513 * 129 = 1,098,177 tests. + * + * For plen == 0 everything matches: so 129 cases * 129 tests + * == 1 everything but 1 128 cases * 129 - 1 + * == 2 everything but 2 127 cases * 129 - 2 + * == 3 3 126 cases * 129 - 3 + * .... + * == 127 127 2 cases * 129 - 127 + * == 128 128 1 cases * 129 - 128 + * + * So expect sum(n*n) dir n = 1..129 == 723,905 tests to be good ! + * + * Score should be 723905/1098177 + */ + p1->prefixlen = plen ; + + for (p2_len = (plen == 0) ? 0 : plen -1 ; p2_len <= 128 ; ++p2_len) + { + uint px ; + + p2->prefixlen = p2_len ; + + for (px = 0 ; px <= 128 ; ++px) + { + int get, expect ; + + if (px < 128) + flip_pbit(p1->u.b, px) ; /* perturb bit just beyond + * prefix of length px. */ + get = prefix_match(p1, p2) ; + + expect = (p2_len >= plen) && (px >= plen) ? 1 : 0 ; + + ++ct->total ; + if (get == expect) + { + if (expect == 1) + ++ct->good ; + } + else + { + uint i ; + ++ct->errs ; + fprintf(stderr, "\n *** expected %d but got %d (px = %u)", + expect, get, px) ; + fprintf(stderr, "\n p1=%3u:", p1->prefixlen) ; + for (i = 0 ; i < 16 ; ++i) + fprintf(stderr, " %02x", p1->u.b[i]) ; + + fprintf(stderr, "\n p2=%3u:", p2->prefixlen) ; + for (i = 0 ; i < 16 ; ++i) + fprintf(stderr, " %02x", p2->u.b[i]) ; + } ; + + if (px < 128) + flip_pbit(p2->u.b, px) ; /* keep p1 & p2 equal */ + } ; + } ; + } ; +} ; + +/*------------------------------------------------------------------------------ + * Test prefix_same() + * + * Family, Prefix Length and *entire* Prefix must be the same. + * + * And Family must be known. But does not check Prefix Length is valid ! + */ +static void +test_prefix_same(counts ct) +{ + uint plen ; + + fprintf(stderr, "Test prefix_same()") ; + for (plen = 0 ; plen <= 255 ; ++plen) + { + struct prefix p1[1] ; + struct prefix p2[1] ; + uint i ; + uint fi ; + sa_family_t fam[] = { AF_UNSPEC, AF_INET, AF_INET6, 31415 } ; + + for (i = 0 ; i < sizeof(struct prefix) ; ++i) + { + ((byte*)p1)[i] = rand() & 0xFF ; + ((byte*)p2)[i] = rand() & 0xFF ; + } ; + + /* We set p1 to the above 4 families. + * prefix length to all possible 0..255. + * prefix to a random value + * + * We set p2 family, 3 cases: the same as p1 + * slightly different (AF_INET <=> AF_INET6) + * random, but different + * + * p2 prefix length, 4 cases: the same as p1 + * one more (mod 256) + * one less (mod 256) + * random, but different + * + * p2 address, 3 cases: the same as p1 -- for the family length + * one bit different within family length + * random, but different + * + * Score should be: 512/36864 + */ + for (fi = 0 ; fi < (sizeof(fam)/sizeof(fam[0])) ; ++fi) + { + sa_family_t fam1 ; + bool fam_known ; + uint fam_len ; + uint ft, plt, pt ; + + fam1 = fam[fi] ; + + switch (fam1) + { + case AF_INET: + fam_len = 32 ; + fam_known = true ; + break ; + + case AF_INET6: + fam_len = 128 ; + fam_known = true ; + break ; + + default: + fam_len = 128 ; + fam_known = false ; + break ; + } ; + + for (ft = 0 ; ft < 3 ; ++ft) + { + sa_family_t fam2 ; + + switch (ft) + { + case 0: + fam2 = fam1 ; + break ; + + case 1: + switch (fam1) + { + case AF_INET: + fam2 = AF_INET6 ; + break ; + + case AF_INET6: + fam2 = AF_INET ; + break ; + + default: + fam2 = fam1 + 1 ; + break ; + } ; + break ; + + case 2: + fam1 = rand() % 31415 ; + do + fam2 = rand() % 31415 ; + while (fam2 == fam1) ; + break ; + } ; + + for (plt = 0 ; plt < 4 ; ++plt) + { + uint plen2 ; + + switch (plt) + { + case 0: + plen2 = plen ; + break ; + + case 1: + if (plen < 255) + plen2 = plen + 1 ; + else + plen2 = 0 ; + break ; + + case 2: + if (plen > 0) + plen2 = plen - 1 ; + else + plen2 = 255 ; + break ; + + case 3: + do + plen2 = rand() % 256 ; + while (plen2 == plen) ; + } ; + + p1->family = fam1 ; + p2->family = fam2 ; + p1->prefixlen = plen ; + p2->prefixlen = plen2 ; + + for (pt = 0 ; pt < 3 ; ++pt) + { + int expect, get ; + + i = 0 ; + + if (pt < 2) + { + for (i = 0 ; i < (fam_len / 8) ; ++i) + p1->u.b[i] = p2->u.b[i] ; + + } ; + + if (pt == 1) + p2->u.b[rand() % i] ^= (1 << (rand() % 8)) ; + + for (; i < 16 ; ++i) + { + byte d ; + do + d = rand() % 256 ; + while (d == 0) ; + + p1->u.b[i] = p2->u.b[i] ^ d ; + } ; + + expect = fam_known && (ft == 0) && (plt == 0) + && (pt == 0) ? 1 : 0 ; + get = prefix_same(p1, p2) ; + + ++ct->total ; + if (get == expect) + { + if (expect == 1) + ++ct->good ; + } + else + { + uint i ; + ++ct->errs ; + fprintf(stderr, "\n *** expected %d but got %d""" + " (plen=%u, ft=%u, plt=%u, pt=%u)", + expect, get, plen, ft, plt, pt) ; + fprintf(stderr, "\n p1=%3u %3u:", + p1->family, p1->prefixlen) ; + for (i = 0 ; i < 16 ; ++i) + fprintf(stderr, " %02x", p1->u.b[i]) ; + + fprintf(stderr, "\n p2=%3u %3u:", + p2->family, p2->prefixlen) ; + for (i = 0 ; i < 16 ; ++i) + fprintf(stderr, " %02x", p2->u.b[i]) ; + } ; + } ; + } ; + } ; + } ; + } ; +} ; + +/*------------------------------------------------------------------------------ + * Test prefix_cmp() + * + * Family, Prefix Length and Prefix under mask must be the same. + * + * Does not care what the Family is and does not check that Prefix Length is + * feasible (either for the Family or for the size of the struct prefix !) + */ +static void +test_prefix_cmp(counts ct) +{ + uint plen ; + + fprintf(stderr, "Test prefix_cmp()") ; + for (plen = 0 ; plen <= 128 ; ++plen) + { + struct prefix p1[1] ; + struct prefix p2[1] ; + uint i ; + uint ft, plt, pt ; + + for (i = 0 ; i < sizeof(struct prefix) ; ++i) + { + ((byte*)p1)[i] = rand() & 0xFF ; + ((byte*)p2)[i] = rand() & 0xFF ; + } ; + + /* For each prefix length 0..128 + * + * we try 2 family cases: same + * randomly different + * 4 prefix length cases: same + * one greater (modulo 129) + * one less (modulo 129) + * randomly different + * + * Sets both prefix addresses equal, then perturbs 1 out of 129 bits. + * + * So 129 * 2 * 4 * 129 = 133128 tests + * + * Of which for prefix length 0, all 129 perturbed bits pass + * 1, 129 - 1 perturbed bits pass... + * ..... + * so: score 8385/133128 + */ + for (ft = 0 ; ft < 2 ; ++ft) + { + sa_family_t fam1, fam2 ; + + switch (ft) + { + case 0: + fam2 = fam1 = rand() % 65536 ; + break ; + + case 1: + fam1 = rand() % 65536 ; + do + fam2 = fam1 ^ rand() % 65536 ; + while (fam2 == fam1) ; + break ; + } ; + + for (plt = 0 ; plt < 4 ; ++plt) + { + uint plen2 ; + + switch (plt) + { + case 0: + plen2 = plen ; + break ; + + case 1: + if (plen < 128) + plen2 = plen + 1 ; + else + plen2 = 0 ; + break ; + + case 2: + if (plen > 1) + plen2 = plen - 1 ; + else + plen2 = 128 ; + break ; + + case 3: + do + plen2 = rand() % 129 ; + while (plen2 == plen) ; + } ; + + p1->family = fam1 ; + p2->family = fam2 ; + p1->prefixlen = plen ; + p2->prefixlen = plen2 ; + + for (i = 0 ; i < (128 / 8) ; ++i) + p1->u.b[i] = p2->u.b[i] = rand() % 256 ; + + for (pt = 0 ; pt <= 128 ; ++pt) + { + int expect, get ; + + if (pt < 128) + flip_pbit(p1->u.b, pt) ; /* perturb bit just beyond + * prefix of length px. */ + + expect = (ft == 0) && (plt == 0) && (pt >= plen) ? 0 : 1 ; + get = prefix_cmp(p1, p2) ; + + ++ct->total ; + if (get == expect) + { + if (expect == 0) + ++ct->good ; + } + else + { + uint i ; + ++ct->errs ; + fprintf(stderr, "\n *** expected %d but got %d""" + " (plen=%u, ft=%u, plt=%u, pt=%u)", + expect, get, plen, ft, plt, pt) ; + fprintf(stderr, "\n p1=%3u %3u:", + p1->family, p1->prefixlen) ; + for (i = 0 ; i < 16 ; ++i) + fprintf(stderr, " %02x", p1->u.b[i]) ; + + fprintf(stderr, "\n p2=%3u %3u:", + p2->family, p2->prefixlen) ; + for (i = 0 ; i < 16 ; ++i) + fprintf(stderr, " %02x", p2->u.b[i]) ; + } ; + + if (pt < 128) + flip_pbit(p2->u.b, pt) ; /* keep p1 & p2 equal */ + } ; + } ; + } ; + } ; +} ; + +/*------------------------------------------------------------------------------ + * Test prefix_common_bits() + * + * Counts leading equal bits on the prefix address, ignoring the prefix + * length... counting only within the known address family length. + * + * Does not use or check the Prefix Length. + */ +static void +test_prefix_common_bits(counts ct) +{ + uint plen ; + + fprintf(stderr, "Test prefix_common_bits()") ; + for (plen = 0 ; plen <= 128 ; ++plen) + { + struct prefix p1[1] ; + struct prefix p2[1] ; + uint i ; + uint fi ; + sa_family_t fam[] = { AF_UNSPEC, AF_INET, AF_INET6, 31415 } ; + + for (i = 0 ; i < sizeof(struct prefix) ; ++i) + { + ((byte*)p1)[i] = rand() & 0xFF ; + ((byte*)p2)[i] = rand() & 0xFF ; + } ; + + /* We set p1 to the above 4 families. + * prefix length to all possible 0..128. + * prefix to a random value + * + * We set p2 family, 3 cases: the same as p1 + * slightly different (AF_INET <=> AF_INET6) + * random, but different + * + * p2 prefix length, 4 cases: the same as p1 + * one more (mod 256) + * one less (mod 256) + * random, but different + * + * p2 address, family length + 1 cases + * set all bits beyond family length to some random + * value. + * + * Then no bits different, and then 1 bit different + * for all possible family length bits + * + * Score should be: 83592/650160 + */ + for (fi = 0 ; fi < (sizeof(fam)/sizeof(fam[0])) ; ++fi) + { + sa_family_t fam1 ; + bool fam_known ; + uint fam_len ; + uint ft, plt, pt ; + + fam1 = fam[fi] ; + + switch (fam1) + { + case AF_INET: + fam_len = 32 ; + fam_known = true ; + break ; + + case AF_INET6: + fam_len = 128 ; + fam_known = true ; + break ; + + default: + fam_len = 128 ; + fam_known = false ; + break ; + } ; + + for (ft = 0 ; ft < 3 ; ++ft) + { + sa_family_t fam2 ; + + switch (ft) + { + case 0: + fam2 = fam1 ; + break ; + + case 1: + switch (fam1) + { + case AF_INET: + fam2 = AF_INET6 ; + break ; + + case AF_INET6: + fam2 = AF_INET ; + break ; + + default: + fam2 = fam1 + 1 ; + break ; + } ; + break ; + + case 2: + fam1 = rand() % 31415 ; + do + fam2 = rand() % 31415 ; + while (fam2 == fam1) ; + break ; + } ; + + for (plt = 0 ; plt < 4 ; ++plt) + { + uint plen2 ; + + switch (plt) + { + case 0: + plen2 = plen ; + break ; + + case 1: + if (plen < 255) + plen2 = plen + 1 ; + else + plen2 = 0 ; + break ; + + case 2: + if (plen > 0) + plen2 = plen - 1 ; + else + plen2 = 255 ; + break ; + + case 3: + do + plen2 = rand() % 256 ; + while (plen2 == plen) ; + } ; + + p1->family = fam1 ; + p2->family = fam2 ; + p1->prefixlen = plen ; + p2->prefixlen = plen2 ; + + for (i = 0 ; i < 16 ; ++i) + p1->u.b[i] = rand() & 0xFF ; + + for (i = 0 ; i < (fam_len / 8) ; ++i) + p2->u.b[i] = p1->u.b[i] ; + + for (; i < 16 ; ++i) + { + byte d ; + do + d = rand() % 256 ; + while (d == 0) ; + + p2->u.b[i] = p1->u.b[i] ^ d ; + } ; + + for (pt = 0 ; pt <= fam_len ; ++pt) + { + int expect, get ; + + if (pt < 128) + flip_pbit(p2->u.b, pt) ; /* perturb bit just beyond + * prefix of length px. */ + + expect = fam_known && (ft == 0) ? (int)pt : -1 ; + get = prefix_common_bits(p1, p2) ; + + ++ct->total ; + if (get == expect) + { + if (expect != -1) + ++ct->good ; + } + else + { + uint i ; + ++ct->errs ; + fprintf(stderr, "\n *** expected %d but got %d""" + " (plen=%u, ft=%u, plt=%u, pt=%u)", + expect, get, plen, ft, plt, pt) ; + fprintf(stderr, "\n p1=%3u %3u:", + p1->family, p1->prefixlen) ; + for (i = 0 ; i < 16 ; ++i) + fprintf(stderr, " %02x", p1->u.b[i]) ; + + fprintf(stderr, "\n p2=%3u %3u:", + p2->family, p2->prefixlen) ; + for (i = 0 ; i < 16 ; ++i) + fprintf(stderr, " %02x", p2->u.b[i]) ; + } ; + + if (pt < 128) + flip_pbit(p1->u.b, pt) ; /* keep p1 & p2 equal */ + } ; + } ; + } ; + } ; + } ; +} ; + +/*------------------------------------------------------------------------------ + * Some tests of spfxtoa() str2prefix () + * + * All 512 tests pass "good" + */ +static void +test_spfxtoa_str2prefix(counts ct) +{ + struct prefix p1[1] ; + uint plen ; + const char* unknown ; + char buffer[100] ; + + fprintf(stderr, "Test spfxtoa & str2prefix") ; + + memset(p1, 0xA5, sizeof(struct prefix)) ; + + snprintf(buffer, sizeof(buffer), "'%s'", spfxtoa(p1).str) ; + + unknown = "'?unknown address family=42405?'" ; + if (strcmp(buffer, unknown)) + { + ++ct->errs ; + fprintf(stderr, "\n *** for unknown AF=0xA5 expect: %s", unknown) ; + fprintf(stderr, "\n got: %s", buffer) ; + } ; + + for (plen = 0 ; plen <= 255 ; ++plen) + { + uint i ; + prefix_raw_t raw_in ; + prefix_raw_t raw_out ; + const byte* pm ; + + pm = mask_n[plen] ; + + memset(&raw_in, 0xA5, sizeof(prefix_raw_t)) ; + memset(&raw_out, 0x5A, sizeof(prefix_raw_t)) ; + + raw_in->prefix_len = plen ; + + for (i = 0 ; i < 16 ; ++i) + raw_in->prefix[i] = rand() & pm[i] ; + + /* AF_INET + */ + raw_in->prefix_len = (plen <= 32) ? plen : 32 ; + + prefix_from_raw(p1, raw_in, AF_INET) ; + snprintf(buffer, sizeof(buffer), "%s", spfxtoa(p1).str) ; + str2prefix(buffer, p1) ; + prefix_to_raw(raw_out, p1) ; + + ++ct->total ; + if ((raw_in->prefix_len == raw_out->prefix_len) + && ( (raw_in->prefix_len == 0) + || (memcmp(raw_in->prefix, raw_out->prefix, + (raw_out->prefix_len + 7u) / 8) == 0) )) + { + ++ct->good ; + } + else + { + uint i ; + ++ct->errs ; + fprintf(stderr, "\n *** for AF_INET raw=0x%02x", raw_in->prefix_len) ; + for (i = 0 ; i < (raw_in->prefix_len + 7u) / 8 ; ++i) + fprintf(stderr, " %02x", raw_in->prefix[i]) ; + + fprintf(stderr, "\n got=0x%02x", + raw_out->prefix_len) ; + for (i = 0 ; i < (raw_out->prefix_len + 7u) / 8 ; ++i) + fprintf(stderr, " %02x", raw_out->prefix[i]) ; + } ; + + /* AF_INET6 + */ + raw_in->prefix_len = (plen <= 128) ? plen : 128 ; + + prefix_from_raw(p1, raw_in, AF_INET6) ; + snprintf(buffer, sizeof(buffer), "%s", spfxtoa(p1).str) ; + str2prefix(buffer, p1) ; + prefix_to_raw(raw_out, p1) ; + + ++ct->total ; + if ((raw_in->prefix_len == raw_out->prefix_len) + || ( (raw_in->prefix_len == 0) + || (memcmp(raw_in->prefix, raw_out->prefix, + (raw_out->prefix_len + 7u) / 8) ==0) )) + { + ++ct->good ; + } + else + { + uint i ; + ++ct->errs ; + fprintf(stderr, "\n *** for AF_INET6 raw=0x%02x", raw_in->prefix_len); + for (i = 0 ; i < (raw_in->prefix_len + 7u) / 8 ; ++i) + fprintf(stderr, " %02x", raw_in->prefix[i]) ; + + fprintf(stderr, "\n got=0x%02x", + raw_out->prefix_len) ; + for (i = 0 ; i < (raw_out->prefix_len + 7u) / 8 ; ++i) + fprintf(stderr, " %02x", raw_out->prefix[i]) ; + } ; + } ; +} ; + +/*============================================================================== + * Utilities + */ + +/*------------------------------------------------------------------------------ + * Return state of given prefix bit -- bits are numbered as per prefix length. + * + * Bit 0 is the ms bit -- the first bit *after* a prefix of length 0. + */ +static uint +get_pbit(byte* v, uint bn) +{ + byte b ; + + b = 0x80 >> (bn % 8) ; + + return (v[bn / 8] & b) ? 1 : 0 ; +} ; + +/*------------------------------------------------------------------------------ + * Set given prefix bit -- bits are numbered as per prefix length. + * + * Bit 0 is the ms bit -- the first bit *after* a prefix of length 0. + */ +static void +set_pbit(byte* v, uint bn) +{ + byte b ; + + b = 0x80 >> (bn % 8) ; + + v[bn / 8] |= b ; +} ; + +/*------------------------------------------------------------------------------ + * Clear given prefix bit -- bits are numbered as per prefix length. + * + * Bit 0 is the ms bit -- the first bit *after* a prefix of length 0. + */ +static void +clear_pbit(byte* v, uint bn) +{ + byte b ; + + b = 0x80 >> (bn % 8) ; + + v[bn / 8] &= ~b ; +} ; + +/*------------------------------------------------------------------------------ + * Flip given prefix bit -- bits are numbered as per prefix length. + * + * Bit 0 is the ms bit -- the first bit *after* a prefix of length 0. + */ +static void +flip_pbit(byte* v, uint bn) +{ + byte b ; + + b = 0x80 >> (bn % 8) ; + + v[bn / 8] ^= b ; +} ; + diff --git a/tools/.cvsignore b/tools/.cvsignore deleted file mode 100644 index 73bcf19d..00000000 --- a/tools/.cvsignore +++ /dev/null @@ -1,3 +0,0 @@ -.arch-inventory -.arch-ids - diff --git a/vtysh/.cvsignore b/vtysh/.cvsignore deleted file mode 100644 index ed3f1f39..00000000 --- a/vtysh/.cvsignore +++ /dev/null @@ -1,13 +0,0 @@ -Makefile -Makefile.in -*.o -vtysh -tags -TAGS -.deps -vtysh_cmd.c -.nfs* -extract.pl -.libs -.arch-inventory -.arch-ids diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index 66d00f66..efda88b9 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -25,13 +25,13 @@ vtysh_cmd_FILES = \ $(top_srcdir)/bgpd/*.c \ $(top_srcdir)/zebra/*.c -# <<<<To be added back in when command tables are fixed up. +# <+<+<+<+To be added back in when command tables are fixed up. # $(top_srcdir)/isisd/*.c \... # $(top_srcdir)/ospfd/*.c \... # $(top_srcdir)/ospf6d/*.c \... # $(top_srcdir)/ripd/*.c \... # $(top_srcdir)/ripngd/*.c \... -# >>>> +# +>+>+>+> vtysh_cmd.c: $(vtysh_cmd_FILES) ./$(EXTRA_DIST) $(vtysh_cmd_FILES) > vtysh_cmd.c diff --git a/watchquagga/.cvsignore b/watchquagga/.cvsignore deleted file mode 100644 index c661510b..00000000 --- a/watchquagga/.cvsignore +++ /dev/null @@ -1,13 +0,0 @@ -Makefile -Makefile.in -*.o -watchquagga -tags -TAGS -.deps -.nfs* -*.lo -*.la -*.libs -.arch-inventory -.arch-ids diff --git a/watchquagga/watchquagga.c b/watchquagga/watchquagga.c index 5492f92e..e3f7b391 100644 --- a/watchquagga/watchquagga.c +++ b/watchquagga/watchquagga.c @@ -1,6 +1,4 @@ /* - $Id$ - Monitor status of quagga daemons and restart if necessary. Copyright (C) 2004 Andrew J. Schorr diff --git a/zebra/.cvsignore b/zebra/.cvsignore deleted file mode 100644 index 59c5889e..00000000 --- a/zebra/.cvsignore +++ /dev/null @@ -1,13 +0,0 @@ -Makefile -Makefile.in -*.o -zebra -zebra.conf -client -tags -TAGS -.deps -.nfs* -.libs -.arch-inventory -.arch-ids diff --git a/zebra/connected.c b/zebra/connected.c index 95399fa1..f699b147 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -189,7 +189,7 @@ connected_up_ipv4 (struct interface *ifp, struct connected *ifc) return; rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex, - RT_TABLE_MAIN, ifp->metric, 0); + RT_TABLE_MAIN, ifp->metric, 0, SAFI_UNICAST); rib_update (); } @@ -295,7 +295,7 @@ connected_down_ipv4 (struct interface *ifp, struct connected *ifc) return; /* Same logic as for connected_up_ipv4(): push the changes into the head. */ - rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0); + rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, SAFI_UNICAST); rib_update (); } @@ -343,7 +343,7 @@ connected_up_ipv6 (struct interface *ifp, struct connected *ifc) #endif rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, RT_TABLE_MAIN, - ifp->metric, 0); + ifp->metric, 0, SAFI_UNICAST); rib_update (); } @@ -417,7 +417,7 @@ connected_down_ipv6 (struct interface *ifp, struct connected *ifc) if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix)) return; - rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0); + rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, SAFI_UNICAST); rib_update (); } diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index 14d40481..9c858830 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.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. */ /* This is compiled and linked if found to be required at "configure" time. */ @@ -51,7 +51,7 @@ interface_list_ioctl (void) /* Normally SIOCGIFCONF works with AF_INET socket. */ sock = socket (AF_INET, SOCK_DGRAM, 0); - if (sock < 0) + if (sock < 0) { zlog_warn ("Can't make AF_INET socket stream: %s", safe_strerror (errno)); return -1; @@ -73,14 +73,14 @@ interface_list_ioctl (void) lastlen = 0; /* Loop until SIOCGIFCONF success. */ - for (;;) + for (;;) { ifconf.ifc_len = sizeof (struct ifreq) * ifnum; ifconf.ifc_buf = XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len); ret = ioctl(sock, SIOCGIFCONF, &ifconf); - if (ret < 0) + if (ret < 0) { zlog_warn ("SIOCGIFCONF: %s", safe_strerror(errno)); goto end; @@ -164,7 +164,7 @@ if_get_index (struct interface *ifp) #endif #else -/* Linux 2.2.X does not provide individual interface index +/* Linux 2.2.X does not provide individual interface index for aliases and we know it. For others issue a warning. */ #if !defined(HAVE_BROKEN_ALIASES) #warning "Using if_fake_index. You may want to add appropriate" @@ -220,9 +220,9 @@ if_getaddrs (void) struct ifaddrs *ifap; struct ifaddrs *ifapfree; struct interface *ifp; - int prefixlen; + u_char prefixlen; - ret = getifaddrs (&ifap); + ret = getifaddrs (&ifap); if (ret != 0) { zlog_err ("getifaddrs(): %s", safe_strerror (errno)); @@ -237,7 +237,7 @@ if_getaddrs (void) __func__, (ifap->ifa_name ? ifap->ifa_name : "(null)")); continue; } - + ifp = if_lookup_by_name (ifap->ifa_name); if (ifp == NULL) { @@ -315,15 +315,15 @@ if_getaddrs (void) } #if defined(KAME) - if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) + if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { addr->sin6_scope_id = ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]); addr->sin6_addr.s6_addr[2] = addr->sin6_addr.s6_addr[3] = 0; - } -#endif + } +#endif - connected_add_ipv6 (ifp, flags, &addr->sin6_addr, prefixlen, + connected_add_ipv6 (ifp, flags, &addr->sin6_addr, prefixlen, dest_pnt, NULL); } #endif /* HAVE_IPV6 */ @@ -331,7 +331,7 @@ if_getaddrs (void) freeifaddrs (ifapfree); - return 0; + return 0; } #else /* HAVE_GETIFADDRS */ /* Interface address lookup by ioctl. This function only looks up @@ -354,7 +354,7 @@ if_get_addr (struct interface *ifp) /* Interface's address. */ ret = if_ioctl (SIOCGIFADDR, (caddr_t) &ifreq); - if (ret < 0) + if (ret < 0) { if (errno != EADDRNOTAVAIL) { @@ -367,9 +367,9 @@ if_get_addr (struct interface *ifp) /* Interface's network mask. */ ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq); - if (ret < 0) + if (ret < 0) { - if (errno != EADDRNOTAVAIL) + if (errno != EADDRNOTAVAIL) { zlog_warn ("SIOCGIFNETMASK fail: %s", safe_strerror (errno)); return ret; @@ -387,9 +387,9 @@ if_get_addr (struct interface *ifp) dest_pnt = NULL; ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq); - if (ret < 0) + if (ret < 0) { - if (errno != EADDRNOTAVAIL) + if (errno != EADDRNOTAVAIL) zlog_warn ("SIOCGIFDSTADDR fail: %s", safe_strerror (errno)); } else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_dstaddr.sin_addr)) @@ -401,9 +401,9 @@ if_get_addr (struct interface *ifp) if (!dest_pnt) { ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq); - if (ret < 0) + if (ret < 0) { - if (errno != EADDRNOTAVAIL) + if (errno != EADDRNOTAVAIL) zlog_warn ("SIOCGIFBRDADDR fail: %s", safe_strerror (errno)); } else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_broadaddr.sin_addr)) @@ -427,7 +427,7 @@ interface_info_ioctl () { struct listnode *node, *nnode; struct interface *ifp; - + for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) { if_get_index (ifp); diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 4a4a2862..bb1a92c8 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -23,6 +23,8 @@ #include <zebra.h> #include "if_method.h" +#include "zebra/zserv.h" + extern int interface_lookup_netlink (void); /* Interface information read by netlink. */ diff --git a/zebra/interface.c b/zebra/interface.c index 979cc087..3b866314 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -76,9 +76,9 @@ if_zebra_new_hook (struct interface *ifp) rtadv->AdvReachableTime = 0; rtadv->AdvRetransTimer = 0; rtadv->AdvCurHopLimit = 0; - rtadv->AdvDefaultLifetime = RTADV_ADV_DEFAULT_LIFETIME; + rtadv->AdvDefaultLifetime = -1; /* derive from MaxRtrAdvInterval */ rtadv->HomeAgentPreference = 0; - rtadv->HomeAgentLifetime = RTADV_ADV_DEFAULT_LIFETIME; + rtadv->HomeAgentLifetime = -1; /* derive from AdvDefaultLifetime */ rtadv->AdvIntervalOption = 0; rtadv->DefaultPreference = RTADV_PREF_MEDIUM; @@ -216,7 +216,7 @@ if_subnet_delete (struct interface *ifp, struct connected *ifc) * interface will affect only the primary interface/address on Solaris. ************************End Solaris flags hacks *********************** */ -static inline void +static void if_flags_mangle (struct interface *ifp, uint64_t *newflags) { #ifdef SUNOS_5 @@ -630,8 +630,12 @@ nd_dump_vty (struct vty *vty, struct interface *ifp) vty_out (vty, " ND router advertisements are sent every " "%d seconds%s", interval / 1000, VTY_NEWLINE); - vty_out (vty, " ND router advertisements live for %d seconds%s", - rtadv->AdvDefaultLifetime, VTY_NEWLINE); + if (rtadv->AdvDefaultLifetime != -1) + vty_out (vty, " ND router advertisements live for %d seconds%s", + rtadv->AdvDefaultLifetime, VTY_NEWLINE); + else + vty_out (vty, " ND router advertisements lifetime tracks ra-interval%s", + VTY_NEWLINE); vty_out (vty, " ND router advertisement default router preference is " "%s%s", rtadv_pref_strs[rtadv->DefaultPreference], VTY_NEWLINE); @@ -642,9 +646,19 @@ nd_dump_vty (struct vty *vty, struct interface *ifp) vty_out (vty, " Hosts use stateless autoconfig for addresses.%s", VTY_NEWLINE); if (rtadv->AdvHomeAgentFlag) + { vty_out (vty, " ND router advertisements with " "Home Agent flag bit set.%s", VTY_NEWLINE); + if (rtadv->HomeAgentLifetime != -1) + vty_out (vty, " Home Agent lifetime is %u seconds%s", + rtadv->HomeAgentLifetime, VTY_NEWLINE); + else + vty_out (vty, " Home Agent lifetime tracks ra-lifetime%s", + VTY_NEWLINE); + vty_out (vty, " Home Agent preference is %u%s", + rtadv->HomeAgentPreference, VTY_NEWLINE); + } if (rtadv->AdvIntervalOption) vty_out (vty, " ND router advertisements with Adv. Interval option.%s", VTY_NEWLINE); diff --git a/zebra/interface.h b/zebra/interface.h index 147521c6..5efb5510 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -46,7 +46,7 @@ #endif #ifdef RTADV -/* Router advertisement parameter. From RFC2461, RFC3775 and RFC4191. */ +/* Router advertisement parameter. From RFC4861, RFC6275 and RFC4191. */ struct rtadvconf { /* A flag indicating whether or not the router sends periodic Router @@ -56,8 +56,8 @@ struct rtadvconf /* The maximum time allowed between sending unsolicited multicast Router Advertisements from the interface, in milliseconds. - MUST be no less than 70 ms (RFC3775, section 7.4) and no greater - than 1800000 ms (See RFC2461). + MUST be no less than 70 ms [RFC6275 7.5] and no greater + than 1800000 ms [RFC4861 6.2.1]. Default: 600000 milliseconds */ int MaxRtrAdvInterval; @@ -65,11 +65,11 @@ struct rtadvconf /* The minimum time allowed between sending unsolicited multicast Router Advertisements from the interface, in milliseconds. - MUST be no less than 30 ms (See RFC3775, section 7.4). + MUST be no less than 30 ms [RFC6275 7.5]. MUST be no greater than .75 * MaxRtrAdvInterval. Default: 0.33 * MaxRtrAdvInterval */ - int MinRtrAdvInterval; + int MinRtrAdvInterval; /* This field is currently unused. */ #define RTADV_MIN_RTR_ADV_INTERVAL (0.33 * RTADV_MAX_RTR_ADV_INTERVAL) /* Unsolicited Router Advertisements' interval timer. */ @@ -131,8 +131,7 @@ struct rtadvconf Default: 3 * MaxRtrAdvInterval */ int AdvDefaultLifetime; -#define RTADV_ADV_DEFAULT_LIFETIME (3 * RTADV_MAX_RTR_ADV_INTERVAL) - +#define RTADV_MAX_RTRLIFETIME 9000 /* 2.5 hours */ /* A list of prefixes to be placed in Prefix Information options in Router Advertisement messages sent from the interface. @@ -144,7 +143,7 @@ struct rtadvconf struct list *AdvPrefixList; /* The TRUE/FALSE value to be placed in the "Home agent" - flag field in the Router Advertisement. See [RFC3775 7.1]. + flag field in the Router Advertisement. See [RFC6275 7.1]. Default: FALSE */ int AdvHomeAgentFlag; @@ -167,7 +166,7 @@ struct rtadvconf #define RTADV_MAX_HALIFETIME 65520 /* 18.2 hours */ /* The TRUE/FALSE value to insert or not an Advertisement Interval - option. See [RFC 3775 7.3] + option. See [RFC 6275 7.3] Default: FALSE */ int AdvIntervalOption; diff --git a/zebra/ipforward_proc.c b/zebra/ipforward_proc.c index 84eee005..3586bf8f 100644 --- a/zebra/ipforward_proc.c +++ b/zebra/ipforward_proc.c @@ -46,7 +46,6 @@ ipforward (void) { FILE *fp; int ipforwarding = 0; - char *pnt; char buf[10]; fp = fopen (proc_net_snmp, "r"); @@ -60,8 +59,8 @@ ipforward (void) /* Get ip_statistics.IpForwarding : 1 => ip forwarding enabled 2 => ip forwarding off. */ - pnt = fgets (buf, 6, fp); - sscanf (buf, "Ip: %d", &ipforwarding); + if (fgets (buf, 6, fp)) + sscanf (buf, "Ip: %d", &ipforwarding); fclose(fp); @@ -141,8 +140,8 @@ ipforward_ipv6 (void) if (fp == NULL) return -1; - fgets (buf, 2, fp); - sscanf (buf, "%d", &ipforwarding); + if (fgets (buf, 2, fp)) + sscanf (buf, "%d", &ipforwarding); fclose (fp); return ipforwarding; diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c index 80a1a4e2..85067059 100644 --- a/zebra/irdp_interface.c +++ b/zebra/irdp_interface.c @@ -99,14 +99,11 @@ if_group (struct interface *ifp, u_int32_t group, int add_leave) { - struct zebra_if *zi; struct ip_mreq m; struct prefix *p; int ret; char b1[INET_ADDRSTRLEN]; - zi = ifp->info; - memset (&m, 0, sizeof (m)); m.imr_multiaddr.s_addr = htonl (group); p = irdp_get_prefix(ifp); diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index feeaf5d0..bfccd85c 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -16,7 +16,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> @@ -70,7 +70,7 @@ extern struct zebra_t zebrad; ROUNDUP(sizeof(struct sockaddr_in6)) : \ (((struct sockaddr *)(X))->sa_family == AF_LINK ? \ ROUNDUP(sizeof(struct sockaddr_dl)) : sizeof(struct sockaddr)))) -#else /* HAVE_IPV6 */ +#else /* HAVE_IPV6 */ #define SAROUNDUP(X) \ (((struct sockaddr *)(X))->sa_family == AF_INET ? \ ROUNDUP(sizeof(struct sockaddr_in)):\ @@ -233,7 +233,7 @@ af_check (int family) #endif /* HAVE_IPV6 */ return 0; } - + /* Dump routing table flag for debug purpose. */ static void rtm_flag_dump (int flag) @@ -259,21 +259,21 @@ static int ifan_read (struct if_announcemsghdr *ifan) { struct interface *ifp; - + ifp = if_lookup_by_index (ifan->ifan_index); - + if (ifp) - assert ( (ifp->ifindex == ifan->ifan_index) + assert ( (ifp->ifindex == ifan->ifan_index) || (ifp->ifindex == IFINDEX_INTERNAL) ); - if ( (ifp == NULL) + if ( (ifp == NULL) || ((ifp->ifindex == IFINDEX_INTERNAL) && (ifan->ifan_what == IFAN_ARRIVAL)) ) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: creating interface for ifindex %d, name %s", __func__, ifan->ifan_index, ifan->ifan_name); - + /* Create Interface */ ifp = if_get_by_name_len(ifan->ifan_name, strnlen(ifan->ifan_name, @@ -290,7 +290,7 @@ ifan_read (struct if_announcemsghdr *ifan) if_get_metric (ifp); if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("%s: interface %s index %d", + zlog_debug ("%s: interface %s index %d", __func__, ifan->ifan_name, ifan->ifan_index); return 0; @@ -319,13 +319,14 @@ int ifm_read (struct if_msghdr *ifm) { struct interface *ifp = NULL; + struct sockaddr_dl *sdl; char ifname[IFNAMSIZ]; short ifnlen = 0; caddr_t *cp; - + /* terminate ifname at head (for strnlen) and tail (for safety) */ ifname[IFNAMSIZ - 1] = '\0'; - + /* paranoia: sanity check structure */ if (ifm->ifm_msglen < sizeof(struct if_msghdr)) { @@ -341,7 +342,7 @@ ifm_read (struct if_msghdr *ifm) cp = (void *)(ifm + 1); #ifdef SUNOS_5 - /* + /* * XXX This behavior should be narrowed to only the kernel versions * for which the structures returned do not match the headers. * @@ -356,15 +357,16 @@ ifm_read (struct if_msghdr *ifm) RTA_ADDR_GET (NULL, RTA_GATEWAY, ifm->ifm_addrs, cp); RTA_ATTR_GET (NULL, RTA_NETMASK, ifm->ifm_addrs, cp); RTA_ADDR_GET (NULL, RTA_GENMASK, ifm->ifm_addrs, cp); + sdl = (struct sockaddr_dl *)cp; RTA_NAME_GET (ifname, RTA_IFP, ifm->ifm_addrs, cp, ifnlen); RTA_ADDR_GET (NULL, RTA_IFA, ifm->ifm_addrs, cp); RTA_ADDR_GET (NULL, RTA_AUTHOR, ifm->ifm_addrs, cp); RTA_ADDR_GET (NULL, RTA_BRD, ifm->ifm_addrs, cp); - + if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: sdl ifname %s", __func__, (ifnlen ? ifname : "(nil)")); - - /* + + /* * Look up on ifindex first, because ifindices are the primary handle for * interfaces across the user/kernel boundary, for most systems. (Some * messages, such as up/down status changes on NetBSD, do not include a @@ -385,8 +387,8 @@ ifm_read (struct if_msghdr *ifm) ifp = NULL; } } - - /* + + /* * If we dont have an ifp, try looking up by name. Particularly as some * systems (Solaris) have a 1:many mapping of ifindex:ifname - the ifname * is therefore our unique handle to that interface. @@ -423,25 +425,25 @@ ifm_read (struct if_msghdr *ifm) if (!CHECK_FLAG (ifm->ifm_flags, IFF_UP)) return 0; #endif /* !RTM_IFANNOUNCE */ - + if (ifp == NULL) { - /* Interface that zebra was not previously aware of, so create. */ + /* Interface that zebra was not previously aware of, so create. */ ifp = if_create (ifname, ifnlen); if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("%s: creating ifp for ifindex %d", + zlog_debug ("%s: creating ifp for ifindex %d", __func__, ifm->ifm_index); } if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: updated/created ifp, ifname %s, ifindex %d", __func__, ifp->name, ifp->ifindex); - /* + /* * Fill in newly created interface structure, or larval * structure with ifindex IFINDEX_INTERNAL. */ ifp->ifindex = ifm->ifm_index; - + #ifdef HAVE_BSD_LINK_DETECT /* translate BSD kernel msg for link-state */ bsd_linkdetect_translate(ifm); #endif /* HAVE_BSD_LINK_DETECT */ @@ -454,6 +456,16 @@ ifm_read (struct if_msghdr *ifm) #endif /* __bsdi__ */ if_get_metric (ifp); + /* + * XXX sockaddr_dl contents can be larger than the structure + * definition, so the user of the stored structure must be + * careful not to read off the end. + * + * a nonzero ifnlen from RTA_NAME_GET() means sdl is valid + */ + if (ifnlen) + memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl)); + if_add_update (ifp); } else @@ -468,18 +480,18 @@ ifm_read (struct if_msghdr *ifm) if (ifp->ifindex != ifm->ifm_index) { zlog_warn ("%s: index mismatch, ifname %s, ifp index %d, " - "ifm index %d", + "ifm index %d", __func__, ifp->name, ifp->ifindex, ifm->ifm_index); return -1; } - + #ifdef HAVE_BSD_LINK_DETECT /* translate BSD kernel msg for link-state */ bsd_linkdetect_translate(ifm); #endif /* HAVE_BSD_LINK_DETECT */ /* update flags and handle operative->inoperative transition, if any */ if_flags_update (ifp, ifm->ifm_flags); - + #ifndef RTM_IFANNOUNCE if (!if_is_up (ifp)) { @@ -511,12 +523,12 @@ ifm_read (struct if_msghdr *ifm) #endif /* HAVE_NET_RT_IFLIST */ if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("%s: interface %s index %d", + zlog_debug ("%s: interface %s index %d", __func__, ifp->name, ifp->ifindex); return 0; } - + /* Address read from struct ifa_msghdr. */ static void ifam_read_mesg (struct ifa_msghdr *ifm, @@ -579,9 +591,9 @@ ifam_read_mesg (struct ifa_msghdr *ifm, { char buf[4][INET6_ADDRSTRLEN]; zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x, " - "ifam_flags 0x%x, addr %s/%d broad %s dst %s " + "ifam_flags 0x%x, addr %s/%u broad %s dst %s " "gateway %s", - __func__, ifm->ifam_index, + __func__, ifm->ifam_index, (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs, ifm->ifam_flags, inet_ntop(AF_INET6,&addr->sin6.sin6_addr, @@ -598,7 +610,7 @@ ifam_read_mesg (struct ifa_msghdr *ifm, #endif /* HAVE_IPV6 */ default: zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x", - __func__, ifm->ifam_index, + __func__, ifm->ifam_index, (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs); break; } @@ -606,7 +618,7 @@ ifam_read_mesg (struct ifa_msghdr *ifm, /* Assert read up end point matches to end point */ if (pnt != end) - zlog_warn ("ifam_read() does't read all socket data"); + zlog_warn ("ifam_read() doesn't read all socket data"); } /* Interface's address information get. */ @@ -619,22 +631,22 @@ ifam_read (struct ifa_msghdr *ifam) short ifnlen = 0; char isalias = 0; int flags = 0; - + ifname[0] = ifname[INTERFACE_NAMSIZ - 1] = '\0'; - + /* Allocate and read address information. */ ifam_read_mesg (ifam, &addr, &mask, &brd, ifname, &ifnlen); - + if ((ifp = if_lookup_by_index(ifam->ifam_index)) == NULL) { - zlog_warn ("%s: no interface for ifname %s, index %d", + zlog_warn ("%s: no interface for ifname %s, index %d", __func__, ifname, ifam->ifam_index); return -1; } - + if (ifnlen && strncmp (ifp->name, ifname, INTERFACE_NAMSIZ)) isalias = 1; - + /* N.B. The info in ifa_msghdr does not tell us whether the RTA_BRD field contains a broadcast address or a peer address, so we are forced to rely upon the interface type. */ @@ -655,12 +667,12 @@ ifam_read (struct ifa_msghdr *ifam) { case AF_INET: if (ifam->ifam_type == RTM_NEWADDR) - connected_add_ipv4 (ifp, flags, &addr.sin.sin_addr, + connected_add_ipv4 (ifp, flags, &addr.sin.sin_addr, ip_masklen (mask.sin.sin_addr), &brd.sin.sin_addr, (isalias ? ifname : NULL)); else - connected_delete_ipv4 (ifp, flags, &addr.sin.sin_addr, + connected_delete_ipv4 (ifp, flags, &addr.sin.sin_addr, ip_masklen (mask.sin.sin_addr), &brd.sin.sin_addr); break; @@ -672,13 +684,13 @@ ifam_read (struct ifa_msghdr *ifam) SET_IN6_LINKLOCAL_IFINDEX (addr.sin6.sin6_addr, 0); if (ifam->ifam_type == RTM_NEWADDR) - connected_add_ipv6 (ifp, flags, &addr.sin6.sin6_addr, + connected_add_ipv6 (ifp, flags, &addr.sin6.sin6_addr, ip6_masklen (mask.sin6.sin6_addr), &brd.sin6.sin6_addr, (isalias ? ifname : NULL)); else connected_delete_ipv6 (ifp, - &addr.sin6.sin6_addr, + &addr.sin6.sin6_addr, ip6_masklen (mask.sin6.sin6_addr), &brd.sin6.sin6_addr); break; @@ -687,14 +699,14 @@ ifam_read (struct ifa_msghdr *ifam) /* Unsupported family silently ignore... */ break; } - + /* Check interface flag for implicit up of the interface. */ if_refresh (ifp); #ifdef SUNOS_5 - /* In addition to lacking IFANNOUNCE, on SUNOS IFF_UP is strange. + /* In addition to lacking IFANNOUNCE, on SUNOS IFF_UP is strange. * See comments for SUNOS_5 in interface.c::if_flags_mangle. - * + * * Here we take care of case where the real IFF_UP was previously * unset (as kept in struct zebra_if.primary_state) and the mangled * IFF_UP (ie IFF_UP set || listcount(connected) has now transitioned @@ -707,10 +719,10 @@ ifam_read (struct ifa_msghdr *ifam) if (!if_is_up (ifp)) if_delete_update (ifp); #endif /* SUNOS_5 */ - + return 0; } - + /* Interface function for reading kernel routing table information. */ static int rtm_read_mesg (struct rt_msghdr *rtm, @@ -727,11 +739,11 @@ rtm_read_mesg (struct rt_msghdr *rtm, end = ((caddr_t)rtm) + rtm->rtm_msglen; /* rt_msghdr version check. */ - if (rtm->rtm_version != RTM_VERSION) + if (rtm->rtm_version != RTM_VERSION) zlog (NULL, LOG_WARNING, "Routing message version different %d should be %d." "This may cause problem\n", rtm->rtm_version, RTM_VERSION); - + /* Be sure structure is cleared */ memset (dest, 0, sizeof (union sockunion)); memset (gate, 0, sizeof (union sockunion)); @@ -753,8 +765,8 @@ rtm_read_mesg (struct rt_msghdr *rtm, mask->sa.sa_family = dest->sa.sa_family; /* Assert read up to the end of pointer. */ - if (pnt != end) - zlog (NULL, LOG_WARNING, "rtm_read() does't read all socket data."); + if (pnt != end) + zlog (NULL, LOG_WARNING, "rtm_read() doesn't read all socket data."); return rtm->rtm_flags; } @@ -818,7 +830,7 @@ rtm_read (struct rt_msghdr *rtm) p.prefixlen = IPV4_MAX_PREFIXLEN; else p.prefixlen = ip_masklen (mask.sin.sin_addr); - + /* Catch self originated messages and match them against our current RIB. * At the same time, ignore unconfirmed messages, they should be tracked * by rtm_write() and kernel_rtm_ipv4(). @@ -829,7 +841,7 @@ rtm_read (struct rt_msghdr *rtm) int ret; if (! IS_ZEBRA_DEBUG_RIB) return; - ret = rib_lookup_ipv4_route (&p, &gate); + ret = rib_lookup_ipv4_route (&p, &gate); inet_ntop (AF_INET, &p.prefix, buf, INET_ADDRSTRLEN); switch (rtm->rtm_type) { @@ -894,16 +906,16 @@ rtm_read (struct rt_msghdr *rtm) */ if (rtm->rtm_type == RTM_CHANGE) rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, - NULL, 0, 0); - - if (rtm->rtm_type == RTM_GET + NULL, 0, 0, SAFI_UNICAST); + + if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) - rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, - &p, &gate.sin.sin_addr, NULL, 0, 0, 0, 0); + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, + &p, &gate.sin.sin_addr, NULL, 0, 0, 0, 0, SAFI_UNICAST); else - rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, - &p, &gate.sin.sin_addr, 0, 0); + rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, + &p, &gate.sin.sin_addr, 0, 0, SAFI_UNICAST); } #ifdef HAVE_IPV6 if (dest.sa.sa_family == AF_INET6) @@ -936,16 +948,16 @@ rtm_read (struct rt_msghdr *rtm) */ if (rtm->rtm_type == RTM_CHANGE) rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, - NULL, 0, 0); - - if (rtm->rtm_type == RTM_GET + NULL, 0, 0, SAFI_UNICAST); + + if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, - &p, &gate.sin6.sin6_addr, ifindex, 0, 0, 0); + &p, &gate.sin6.sin6_addr, ifindex, 0, 0, 0, SAFI_UNICAST); else rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, - &p, &gate.sin6.sin6_addr, ifindex, 0); + &p, &gate.sin6.sin6_addr, ifindex, 0, SAFI_UNICAST); } #endif /* HAVE_IPV6 */ } @@ -971,12 +983,12 @@ rtm_write (int message, static int msg_seq = 0; /* Struct of rt_msghdr and buffer for storing socket's data. */ - struct + struct { struct rt_msghdr rtm; char buf[512]; } msg; - + if (routing_sock < 0) return ZEBRA_ERR_EPERM; @@ -1030,7 +1042,7 @@ rtm_write (int message, if (mask) msg.rtm.rtm_addrs |= RTA_NETMASK; - else if (message == RTM_ADD) + else if (message == RTM_ADD) msg.rtm.rtm_flags |= RTF_HOST; /* Tagging route with flags */ @@ -1051,7 +1063,7 @@ rtm_write (int message, memcpy (pnt, (caddr_t)(X), len); \ pnt += len; \ } -#else +#else #define SOCKADDRSET(X,R) \ if (msg.rtm.rtm_addrs & (R)) \ { \ @@ -1072,22 +1084,22 @@ rtm_write (int message, ret = write (routing_sock, &msg, msg.rtm.rtm_msglen); - if (ret != msg.rtm.rtm_msglen) + if (ret != msg.rtm.rtm_msglen) { - if (errno == EEXIST) + if (errno == EEXIST) return ZEBRA_ERR_RTEXIST; if (errno == ENETUNREACH) return ZEBRA_ERR_RTUNREACH; if (errno == ESRCH) return ZEBRA_ERR_RTNOEXIST; - + zlog_warn ("%s: write : %s (%d)", __func__, safe_strerror (errno), errno); return ZEBRA_ERR_KERNEL; } return ZEBRA_ERR_NOERROR; } - + #include "thread.h" #include "zebra/zserv.h" @@ -1127,10 +1139,10 @@ kernel_read (struct thread *thread) * since the buffer needs to be big enough for a message and the * sockaddrs together. */ - union + union { /* Routing information. */ - struct + struct { struct rt_msghdr rtm; struct sockaddr_storage addr[RTAX_MAX]; @@ -1227,7 +1239,7 @@ routing_socket (void) routing_sock = socket (AF_ROUTE, SOCK_RAW, 0); - if (routing_sock < 0) + if (routing_sock < 0) { if ( zserv_privs.change (ZPRIVS_LOWER) ) zlog_err ("routing_socket: Can't lower privileges"); @@ -1235,13 +1247,13 @@ routing_socket (void) return; } - /* XXX: Socket should be NONBLOCK, however as we currently + /* XXX: Socket should be NONBLOCK, however as we currently * discard failed writes, this will lead to inconsistencies. * For now, socket must be blocking. */ - /*if (fcntl (routing_sock, F_SETFL, O_NONBLOCK) < 0) + /*if (fcntl (routing_sock, F_SETFL, O_NONBLOCK) < 0) zlog_warn ("Can't set O_NONBLOCK to routing socket");*/ - + if ( zserv_privs.change (ZPRIVS_LOWER) ) zlog_err ("routing_socket: Can't lower privileges"); diff --git a/zebra/main.c b/zebra/main.c index e2c3c3b4..727dcc3f 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -71,6 +71,7 @@ struct option longopts[] = { "keep_kernel", no_argument, NULL, 'k'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, + { "socket", required_argument, NULL, 'z'}, { "help", no_argument, NULL, 'h'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, @@ -128,6 +129,7 @@ usage (const char *progname, int status) "-d, --daemon Runs in daemon mode\n"\ "-f, --config_file Set configuration file name\n"\ "-i, --pid_file Set process identifier file name\n"\ + "-z, --socket Set path of zebra socket\n"\ "-k, --keep_kernel Don't delete old routes which installed by "\ "zebra.\n"\ "-C, --dryrun Check configuration for validity and exit\n"\ @@ -212,6 +214,7 @@ main (int argc, char **argv) int daemon_mode = 0; char *config_file = NULL; struct thread thread; + char *zserv_path = NULL; /* First things first -- and qlib_init_first_stage() is absolutely first. */ @@ -226,9 +229,9 @@ main (int argc, char **argv) int opt; #ifdef HAVE_NETLINK - opt = getopt_long (argc, argv, "bdkf:i:hA:P:ru:g:vs:C", longopts, 0); + opt = getopt_long (argc, argv, "bdkf:i:z:hA:P:ru:g:vs:C", longopts, 0); #else - opt = getopt_long (argc, argv, "bdkf:i:hA:P:ru:g:vC", longopts, 0); + opt = getopt_long (argc, argv, "bdkf:i:z:hA:P:ru:g:vC", longopts, 0); #endif /* HAVE_NETLINK */ if (opt == EOF) @@ -258,6 +261,9 @@ main (int argc, char **argv) case 'i': pid_file = optarg; break; + case 'z': + zserv_path = optarg; + break; case 'P': /* Deal with atoi() returning 0 on failure, and zebra not listening on zebra port... */ @@ -396,7 +402,7 @@ main (int argc, char **argv) pid = getpid (); /* This must be done only after locking pidfile (bug #403). */ - zebra_zserv_socket_init (); + zebra_zserv_socket_init (zserv_path); /* Make vty server socket. */ vty_start(vty_addr, vty_port, ZEBRA_VTYSH_PATH); diff --git a/zebra/redistribute.c b/zebra/redistribute.c index a8107aeb..4276f1d0 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -245,26 +245,15 @@ zebra_redistribute_add (int command, struct zserv *client, int length) type = stream_getc (client->ibuf); - switch (type) + if (type == 0 || type >= ZEBRA_ROUTE_MAX) + return; + + if (! client->redist[type]) { - case ZEBRA_ROUTE_KERNEL: - case ZEBRA_ROUTE_CONNECT: - case ZEBRA_ROUTE_STATIC: - case ZEBRA_ROUTE_RIP: - case ZEBRA_ROUTE_RIPNG: - case ZEBRA_ROUTE_OSPF: - case ZEBRA_ROUTE_OSPF6: - case ZEBRA_ROUTE_BGP: - if (! client->redist[type]) - { - client->redist[type] = 1; - zebra_redistribute (client, type); - } - break; - default: - break; + client->redist[type] = 1; + zebra_redistribute (client, type); } -} +} void zebra_redistribute_delete (int command, struct zserv *client, int length) @@ -273,22 +262,11 @@ zebra_redistribute_delete (int command, struct zserv *client, int length) type = stream_getc (client->ibuf); - switch (type) - { - case ZEBRA_ROUTE_KERNEL: - case ZEBRA_ROUTE_CONNECT: - case ZEBRA_ROUTE_STATIC: - case ZEBRA_ROUTE_RIP: - case ZEBRA_ROUTE_RIPNG: - case ZEBRA_ROUTE_OSPF: - case ZEBRA_ROUTE_OSPF6: - case ZEBRA_ROUTE_BGP: - client->redist[type] = 0; - break; - default: - break; - } -} + if (type == 0 || type >= ZEBRA_ROUTE_MAX) + return; + + client->redist[type] = 0; +} void zebra_redistribute_default_add (int command, struct zserv *client, int length) diff --git a/zebra/rib.h b/zebra/rib.h index 887ed3c2..2872fc03 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -249,13 +249,13 @@ extern struct route_table *vrf_static_table (afi_t afi, safi_t safi, u_int32_t i extern int rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct in_addr *gate, struct in_addr *src, unsigned int ifindex, u_int32_t vrf_id, - u_int32_t, u_char); + u_int32_t, u_char, safi_t); -extern int rib_add_ipv4_multipath (struct prefix_ipv4 *, struct rib *); +extern int rib_add_ipv4_multipath (struct prefix_ipv4 *, struct rib *, safi_t); extern int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct in_addr *gate, unsigned int ifindex, - u_int32_t); + u_int32_t, safi_t safi); extern struct rib *rib_match_ipv4 (struct in_addr); @@ -266,6 +266,7 @@ extern void rib_weed_tables (void); extern void rib_sweep_route (void); extern void rib_close (void); extern void rib_init (void); +extern unsigned long rib_score_proto (u_char proto); extern int static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, @@ -279,11 +280,11 @@ static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, extern int rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id, - u_int32_t metric, u_char distance); + u_int32_t metric, u_char distance, safi_t safi); extern int rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, - struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id); + struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id, safi_t safi); extern struct rib *rib_lookup_ipv6 (struct in6_addr *); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 19ecca2c..cad04b72 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -724,7 +724,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) memcpy (&p.prefix, dest, 4); p.prefixlen = rtm->rtm_dst_len; - rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0); + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0, SAFI_UNICAST); } #ifdef HAVE_IPV6 if (rtm->rtm_family == AF_INET6) @@ -735,7 +735,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) p.prefixlen = rtm->rtm_dst_len; rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, - metric, 0); + metric, 0, SAFI_UNICAST); } #endif /* HAVE_IPV6 */ @@ -769,6 +769,8 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) int index; int table; + int metric; + void *dest; void *gate; void *src; @@ -826,6 +828,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) } index = 0; + metric = 0; dest = NULL; gate = NULL; src = NULL; @@ -844,6 +847,9 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) if (tb[RTA_PREFSRC]) src = RTA_DATA (tb[RTA_PREFSRC]); + if (h->nlmsg_type == RTM_NEWROUTE && tb[RTA_PRIORITY]) + metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]); + if (rtm->rtm_family == AF_INET) { struct prefix_ipv4 p; @@ -862,9 +868,9 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) } if (h->nlmsg_type == RTM_NEWROUTE) - rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0); + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, metric, 0, SAFI_UNICAST); else - rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table); + rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST); } #ifdef HAVE_IPV6 @@ -890,9 +896,9 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) } if (h->nlmsg_type == RTM_NEWROUTE) - rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0); + rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, metric, 0, SAFI_UNICAST); else - rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table); + rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST); } #endif /* HAVE_IPV6 */ @@ -1823,11 +1829,7 @@ kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc) static int kernel_read (struct thread *thread) { - int ret; - int sock; - - sock = THREAD_FD (thread); - ret = netlink_parse_info (netlink_information_fetch, &netlink); + netlink_parse_info (netlink_information_fetch, &netlink); thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock); return 0; diff --git a/zebra/rtadv.c b/zebra/rtadv.c index fff1bc27..70adba2b 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -163,6 +163,7 @@ rtadv_send_packet (int sock, struct interface *ifp) struct rtadv_prefix *rprefix; u_char all_nodes_addr[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; struct listnode *node; + u_int16_t pkt_RouterLifetime; /* * Allocate control message bufffer. This is dynamic because @@ -190,7 +191,7 @@ rtadv_send_packet (int sock, struct interface *ifp) addr.sin6_len = sizeof (struct sockaddr_in6); #endif /* SIN6_LEN */ addr.sin6_port = htons (IPPROTO_ICMPV6); - memcpy (&addr.sin6_addr, all_nodes_addr, sizeof (struct in6_addr)); + IPV6_ADDR_COPY (&addr.sin6_addr, all_nodes_addr); /* Fetch interface information. */ zif = ifp->info; @@ -215,13 +216,32 @@ rtadv_send_packet (int sock, struct interface *ifp) rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER; if (zif->rtadv.AdvHomeAgentFlag) rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_HOME_AGENT; - rtadv->nd_ra_router_lifetime = htons (zif->rtadv.AdvDefaultLifetime); + /* Note that according to Neighbor Discovery (RFC 4861 [18]), + * AdvDefaultLifetime is by default based on the value of + * MaxRtrAdvInterval. AdvDefaultLifetime is used in the Router Lifetime + * field of Router Advertisements. Given that this field is expressed + * in seconds, a small MaxRtrAdvInterval value can result in a zero + * value for this field. To prevent this, routers SHOULD keep + * AdvDefaultLifetime in at least one second, even if the use of + * MaxRtrAdvInterval would result in a smaller value. -- RFC6275, 7.5 */ + pkt_RouterLifetime = zif->rtadv.AdvDefaultLifetime != -1 ? + zif->rtadv.AdvDefaultLifetime : + MAX (1, 0.003 * zif->rtadv.MaxRtrAdvInterval); + rtadv->nd_ra_router_lifetime = htons (pkt_RouterLifetime); rtadv->nd_ra_reachable = htonl (zif->rtadv.AdvReachableTime); rtadv->nd_ra_retransmit = htonl (0); len = sizeof (struct nd_router_advert); - if (zif->rtadv.AdvHomeAgentFlag) + /* If both the Home Agent Preference and Home Agent Lifetime are set to + * their default values specified above, this option SHOULD NOT be + * included in the Router Advertisement messages sent by this home + * agent. -- RFC6275, 7.4 */ + if + ( + zif->rtadv.AdvHomeAgentFlag && + (zif->rtadv.HomeAgentPreference || zif->rtadv.HomeAgentLifetime != -1) + ) { struct nd_opt_homeagent_info *ndopt_hai = (struct nd_opt_homeagent_info *)(buf + len); @@ -229,7 +249,17 @@ rtadv_send_packet (int sock, struct interface *ifp) ndopt_hai->nd_opt_hai_len = 1; ndopt_hai->nd_opt_hai_reserved = 0; ndopt_hai->nd_opt_hai_preference = htons(zif->rtadv.HomeAgentPreference); - ndopt_hai->nd_opt_hai_lifetime = htons(zif->rtadv.HomeAgentLifetime); + /* 16-bit unsigned integer. The lifetime associated with the home + * agent in units of seconds. The default value is the same as the + * Router Lifetime, as specified in the main body of the Router + * Advertisement. The maximum value corresponds to 18.2 hours. A + * value of 0 MUST NOT be used. -- RFC6275, 7.5 */ + ndopt_hai->nd_opt_hai_lifetime = htons + ( + zif->rtadv.HomeAgentLifetime != -1 ? + zif->rtadv.HomeAgentLifetime : + MAX (1, pkt_RouterLifetime) /* 0 is OK for RL, but not for HAL*/ + ); len += sizeof(struct nd_opt_homeagent_info); } @@ -267,8 +297,7 @@ rtadv_send_packet (int sock, struct interface *ifp) pinfo->nd_opt_pi_preferred_time = htonl (rprefix->AdvPreferredLifetime); pinfo->nd_opt_pi_reserved2 = 0; - memcpy (&pinfo->nd_opt_pi_prefix, &rprefix->prefix.u.prefix6, - sizeof (struct in6_addr)); + IPV6_ADDR_COPY (&pinfo->nd_opt_pi_prefix, &rprefix->prefix.prefix); #ifdef DEBUG { @@ -319,6 +348,17 @@ rtadv_send_packet (int sock, struct interface *ifp) } #endif /* HAVE_STRUCT_SOCKADDR_DL */ + /* MTU */ + if (zif->rtadv.AdvLinkMTU) + { + struct nd_opt_mtu * opt = (struct nd_opt_mtu *) (buf + len); + opt->nd_opt_mtu_type = ND_OPT_MTU; + opt->nd_opt_mtu_len = 1; + opt->nd_opt_mtu_reserved = 0; + opt->nd_opt_mtu_mtu = htonl (zif->rtadv.AdvLinkMTU); + len += sizeof (struct nd_opt_mtu); + } + msg.msg_name = (void *) &addr; msg.msg_namelen = sizeof (struct sockaddr_in6); msg.msg_iov = &iov; @@ -368,7 +408,7 @@ rtadv_timer (struct thread *thread) for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) { - if (if_is_loopback (ifp)) + if (if_is_loopback (ifp) || ! if_is_operative (ifp)) continue; zif = ifp->info; @@ -378,6 +418,8 @@ rtadv_timer (struct thread *thread) zif->rtadv.AdvIntervalTimer -= period; if (zif->rtadv.AdvIntervalTimer <= 0) { + /* FIXME: using MaxRtrAdvInterval each time isn't what section + 6.2.4 of RFC4861 tells to do. */ zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval; rtadv_send_packet (rtadv->sock, ifp); } @@ -552,19 +594,19 @@ rtadv_prefix_free (struct rtadv_prefix *rtadv_prefix) } static struct rtadv_prefix * -rtadv_prefix_lookup (struct list *rplist, struct prefix *p) +rtadv_prefix_lookup (struct list *rplist, struct prefix_ipv6 *p) { struct listnode *node; struct rtadv_prefix *rprefix; for (ALL_LIST_ELEMENTS_RO (rplist, node, rprefix)) - if (prefix_same (&rprefix->prefix, p)) + if (prefix_same ((struct prefix *) &rprefix->prefix, (struct prefix *) p)) return rprefix; return NULL; } static struct rtadv_prefix * -rtadv_prefix_get (struct list *rplist, struct prefix *p) +rtadv_prefix_get (struct list *rplist, struct prefix_ipv6 *p) { struct rtadv_prefix *rprefix; @@ -573,7 +615,7 @@ rtadv_prefix_get (struct list *rplist, struct prefix *p) return rprefix; rprefix = rtadv_prefix_new (); - memcpy (&rprefix->prefix, p, sizeof (struct prefix)); + memcpy (&rprefix->prefix, p, sizeof (struct prefix_ipv6)); listnode_add (rplist, rprefix); return rprefix; @@ -681,26 +723,22 @@ DEFUN (no_ipv6_nd_suppress_ra, DEFUN (ipv6_nd_ra_interval_msec, ipv6_nd_ra_interval_msec_cmd, - "ipv6 nd ra-interval msec MILLISECONDS", + "ipv6 nd ra-interval msec <70-1800000>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n" "Router Advertisement interval in milliseconds\n") { - int interval; - struct interface *ifp; - struct zebra_if *zif; - - ifp = (struct interface *) vty->index; - zif = ifp->info; + unsigned interval; + struct interface *ifp = (struct interface *) vty->index; + struct zebra_if *zif = ifp->info; - interval = atoi (argv[0]); - - if (interval <= 0) - { - vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE); - return CMD_WARNING; - } + VTY_GET_INTEGER_RANGE ("router advertisement interval", interval, argv[0], 70, 1800000); + if ((zif->rtadv.AdvDefaultLifetime != -1 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime * 1000)) + { + vty_out (vty, "This ra-interval would conflict with configured ra-lifetime!%s", VTY_NEWLINE); + return CMD_WARNING; + } if (zif->rtadv.MaxRtrAdvInterval % 1000) rtadv->adv_msec_if_count--; @@ -717,26 +755,22 @@ DEFUN (ipv6_nd_ra_interval_msec, DEFUN (ipv6_nd_ra_interval, ipv6_nd_ra_interval_cmd, - "ipv6 nd ra-interval SECONDS", + "ipv6 nd ra-interval <1-1800>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n" "Router Advertisement interval in seconds\n") { - int interval; - struct interface *ifp; - struct zebra_if *zif; - - ifp = (struct interface *) vty->index; - zif = ifp->info; + unsigned interval; + struct interface *ifp = (struct interface *) vty->index; + struct zebra_if *zif = ifp->info; - interval = atoi (argv[0]); - - if (interval <= 0) - { - vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE); - return CMD_WARNING; - } + VTY_GET_INTEGER_RANGE ("router advertisement interval", interval, argv[0], 1, 1800); + if ((zif->rtadv.AdvDefaultLifetime != -1 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime)) + { + vty_out (vty, "This ra-interval would conflict with configured ra-lifetime!%s", VTY_NEWLINE); + return CMD_WARNING; + } if (zif->rtadv.MaxRtrAdvInterval % 1000) rtadv->adv_msec_if_count--; @@ -775,13 +809,30 @@ DEFUN (no_ipv6_nd_ra_interval, return CMD_SUCCESS; } +ALIAS (no_ipv6_nd_ra_interval, + no_ipv6_nd_ra_interval_val_cmd, + "no ipv6 nd ra-interval <1-1800>", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Router Advertisement interval\n") + +ALIAS (no_ipv6_nd_ra_interval, + no_ipv6_nd_ra_interval_msec_val_cmd, + "no ipv6 nd ra-interval msec <1-1800000>", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Router Advertisement interval\n" + "Router Advertisement interval in milliseconds\n") + DEFUN (ipv6_nd_ra_lifetime, ipv6_nd_ra_lifetime_cmd, - "ipv6 nd ra-lifetime SECONDS", + "ipv6 nd ra-lifetime <0-9000>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router lifetime\n" - "Router lifetime in seconds\n") + "Router lifetime in seconds (0 stands for a non-default gw)\n") { int lifetime; struct interface *ifp; @@ -790,11 +841,15 @@ DEFUN (ipv6_nd_ra_lifetime, ifp = (struct interface *) vty->index; zif = ifp->info; - lifetime = atoi (argv[0]); + VTY_GET_INTEGER_RANGE ("router lifetime", lifetime, argv[0], 0, 9000); - if (lifetime < 0 || lifetime > 0xffff) + /* The value to be placed in the Router Lifetime field + * of Router Advertisements sent from the interface, + * in seconds. MUST be either zero or between + * MaxRtrAdvInterval and 9000 seconds. -- RFC4861, 6.2.1 */ + if ((lifetime != 0 && lifetime * 1000 < zif->rtadv.MaxRtrAdvInterval)) { - vty_out (vty, "Invalid Router Lifetime%s", VTY_NEWLINE); + vty_out (vty, "This ra-lifetime would conflict with configured ra-interval%s", VTY_NEWLINE); return CMD_WARNING; } @@ -817,36 +872,31 @@ DEFUN (no_ipv6_nd_ra_lifetime, ifp = (struct interface *) vty->index; zif = ifp->info; - zif->rtadv.AdvDefaultLifetime = RTADV_ADV_DEFAULT_LIFETIME; + zif->rtadv.AdvDefaultLifetime = -1; return CMD_SUCCESS; } +ALIAS (no_ipv6_nd_ra_lifetime, + no_ipv6_nd_ra_lifetime_val_cmd, + "no ipv6 nd ra-lifetime <0-9000>", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Router lifetime\n" + "Router lifetime in seconds (0 stands for a non-default gw)\n") + DEFUN (ipv6_nd_reachable_time, ipv6_nd_reachable_time_cmd, - "ipv6 nd reachable-time MILLISECONDS", + "ipv6 nd reachable-time <1-3600000>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Reachable time\n" "Reachable time in milliseconds\n") { - u_int32_t rtime; - struct interface *ifp; - struct zebra_if *zif; - - ifp = (struct interface *) vty->index; - zif = ifp->info; - - rtime = (u_int32_t) atol (argv[0]); - - if (rtime > RTADV_MAX_REACHABLE_TIME) - { - vty_out (vty, "Invalid Reachable time%s", VTY_NEWLINE); - return CMD_WARNING; - } - - zif->rtadv.AdvReachableTime = rtime; - + struct interface *ifp = (struct interface *) vty->index; + struct zebra_if *zif = ifp->info; + VTY_GET_INTEGER_RANGE ("reachable time", zif->rtadv.AdvReachableTime, argv[0], 1, RTADV_MAX_REACHABLE_TIME); return CMD_SUCCESS; } @@ -869,31 +919,26 @@ DEFUN (no_ipv6_nd_reachable_time, return CMD_SUCCESS; } +ALIAS (no_ipv6_nd_reachable_time, + no_ipv6_nd_reachable_time_val_cmd, + "no ipv6 nd reachable-time <1-3600000>", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Reachable time\n" + "Reachable time in milliseconds\n") + DEFUN (ipv6_nd_homeagent_preference, ipv6_nd_homeagent_preference_cmd, - "ipv6 nd home-agent-preference PREFERENCE", + "ipv6 nd home-agent-preference <0-65535>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent preference\n" - "Home Agent preference value 0..65535\n") + "preference value (default is 0, least preferred)\n") { - u_int32_t hapref; - struct interface *ifp; - struct zebra_if *zif; - - ifp = (struct interface *) vty->index; - zif = ifp->info; - - hapref = (u_int32_t) atol (argv[0]); - - if (hapref > 65535) - { - vty_out (vty, "Invalid Home Agent preference%s", VTY_NEWLINE); - return CMD_WARNING; - } - - zif->rtadv.HomeAgentPreference = hapref; - + struct interface *ifp = (struct interface *) vty->index; + struct zebra_if *zif = ifp->info; + VTY_GET_INTEGER_RANGE ("home agent preference", zif->rtadv.HomeAgentPreference, argv[0], 0, 65535); return CMD_SUCCESS; } @@ -916,31 +961,26 @@ DEFUN (no_ipv6_nd_homeagent_preference, return CMD_SUCCESS; } +ALIAS (no_ipv6_nd_homeagent_preference, + no_ipv6_nd_homeagent_preference_val_cmd, + "no ipv6 nd home-agent-preference <0-65535>", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Home Agent preference\n" + "preference value (default is 0, least preferred)\n") + DEFUN (ipv6_nd_homeagent_lifetime, ipv6_nd_homeagent_lifetime_cmd, - "ipv6 nd home-agent-lifetime SECONDS", + "ipv6 nd home-agent-lifetime <0-65520>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent lifetime\n" - "Home Agent lifetime in seconds\n") + "Home Agent lifetime in seconds (0 to track ra-lifetime)\n") { - u_int32_t ha_ltime; - struct interface *ifp; - struct zebra_if *zif; - - ifp = (struct interface *) vty->index; - zif = ifp->info; - - ha_ltime = (u_int32_t) atol (argv[0]); - - if (ha_ltime > RTADV_MAX_HALIFETIME) - { - vty_out (vty, "Invalid Home Agent Lifetime time%s", VTY_NEWLINE); - return CMD_WARNING; - } - - zif->rtadv.HomeAgentLifetime = ha_ltime; - + struct interface *ifp = (struct interface *) vty->index; + struct zebra_if *zif = ifp->info; + VTY_GET_INTEGER_RANGE ("home agent lifetime", zif->rtadv.HomeAgentLifetime, argv[0], 0, RTADV_MAX_HALIFETIME); return CMD_SUCCESS; } @@ -958,11 +998,20 @@ DEFUN (no_ipv6_nd_homeagent_lifetime, ifp = (struct interface *) vty->index; zif = ifp->info; - zif->rtadv.HomeAgentLifetime = 0; + zif->rtadv.HomeAgentLifetime = -1; return CMD_SUCCESS; } +ALIAS (no_ipv6_nd_homeagent_lifetime, + no_ipv6_nd_homeagent_lifetime_val_cmd, + "no ipv6 nd home-agent-lifetime <0-65520>", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Home Agent lifetime\n" + "Home Agent lifetime in seconds (0 to track ra-lifetime)\n") + DEFUN (ipv6_nd_managed_config_flag, ipv6_nd_managed_config_flag_cmd, "ipv6 nd managed-config-flag", @@ -1137,12 +1186,13 @@ DEFUN (ipv6_nd_prefix, ifp = (struct interface *) vty->index; zebra_if = ifp->info; - ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix); + ret = str2prefix_ipv6 (argv[0], &rp.prefix); if (!ret) { vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE); return CMD_WARNING; } + apply_mask_ipv6 (&rp.prefix); /* RFC4861 4.6.2 */ rp.AdvOnLinkFlag = 1; rp.AdvAutonomousFlag = 1; rp.AdvRouterAddressFlag = 0; @@ -1364,12 +1414,13 @@ DEFUN (no_ipv6_nd_prefix, ifp = (struct interface *) vty->index; zebra_if = ifp->info; - ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp.prefix); + ret = str2prefix_ipv6 (argv[0], &rp.prefix); if (!ret) { vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE); return CMD_WARNING; } + apply_mask_ipv6 (&rp.prefix); /* RFC4861 4.6.2 */ ret = rtadv_prefix_reset (zebra_if, &rp); if (!ret) @@ -1430,6 +1481,54 @@ DEFUN (no_ipv6_nd_router_preference, return CMD_SUCCESS; } +ALIAS (no_ipv6_nd_router_preference, + no_ipv6_nd_router_preference_val_cmd, + "no ipv6 nd router-preference (high|medium|low", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Default router preference\n" + "High default router preference\n" + "Low default router preference\n" + "Medium default router preference (default)\n") + +DEFUN (ipv6_nd_mtu, + ipv6_nd_mtu_cmd, + "ipv6 nd mtu <1-65535>", + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Advertised MTU\n" + "MTU in bytes\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct zebra_if *zif = ifp->info; + VTY_GET_INTEGER_RANGE ("MTU", zif->rtadv.AdvLinkMTU, argv[0], 1, 65535); + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_nd_mtu, + no_ipv6_nd_mtu_cmd, + "no ipv6 nd mtu", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Advertised MTU\n") +{ + struct interface *ifp = (struct interface *) vty->index; + struct zebra_if *zif = ifp->info; + zif->rtadv.AdvLinkMTU = 0; + return CMD_SUCCESS; +} + +ALIAS (no_ipv6_nd_mtu, + no_ipv6_nd_mtu_val_cmd, + "no ipv6 nd mtu <1-65535>", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Advertised MTU\n" + "MTU in bytes\n") + /* Write configuration about router advertisement. */ void rtadv_config_write (struct vty *vty, struct interface *ifp) @@ -1463,10 +1562,24 @@ rtadv_config_write (struct vty *vty, struct interface *ifp) vty_out (vty, " ipv6 nd ra-interval %d%s", interval / 1000, VTY_NEWLINE); - if (zif->rtadv.AdvDefaultLifetime != RTADV_ADV_DEFAULT_LIFETIME) + if (zif->rtadv.AdvIntervalOption) + vty_out (vty, " ipv6 nd adv-interval-option%s", VTY_NEWLINE); + + if (zif->rtadv.AdvDefaultLifetime != -1) vty_out (vty, " ipv6 nd ra-lifetime %d%s", zif->rtadv.AdvDefaultLifetime, VTY_NEWLINE); + if (zif->rtadv.HomeAgentPreference) + vty_out (vty, " ipv6 nd home-agent-preference %u%s", + zif->rtadv.HomeAgentPreference, VTY_NEWLINE); + + if (zif->rtadv.HomeAgentLifetime != -1) + vty_out (vty, " ipv6 nd home-agent-lifetime %u%s", + zif->rtadv.HomeAgentLifetime, VTY_NEWLINE); + + if (zif->rtadv.AdvHomeAgentFlag) + vty_out (vty, " ipv6 nd home-agent-config-flag%s", VTY_NEWLINE); + if (zif->rtadv.AdvReachableTime) vty_out (vty, " ipv6 nd reachable-time %d%s", zif->rtadv.AdvReachableTime, VTY_NEWLINE); @@ -1482,10 +1595,13 @@ rtadv_config_write (struct vty *vty, struct interface *ifp) rtadv_pref_strs[zif->rtadv.DefaultPreference], VTY_NEWLINE); + if (zif->rtadv.AdvLinkMTU) + vty_out (vty, " ipv6 nd mtu %d%s", zif->rtadv.AdvLinkMTU, VTY_NEWLINE); + for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix)) { vty_out (vty, " ipv6 nd prefix %s/%d", - inet_ntop (AF_INET6, &rprefix->prefix.u.prefix6, + inet_ntop (AF_INET6, &rprefix->prefix.prefix, (char *) buf, INET6_ADDRSTRLEN), rprefix->prefix.prefixlen); if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME) || @@ -1565,10 +1681,14 @@ CMD_INSTALL_TABLE(static, zebra_rtadv_cmd_table, ZEBRA) = { INTERFACE_NODE, &ipv6_nd_ra_interval_cmd }, { INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd }, { INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd }, + { INTERFACE_NODE, &no_ipv6_nd_ra_interval_val_cmd }, + { INTERFACE_NODE, &no_ipv6_nd_ra_interval_msec_val_cmd }, { INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd }, { INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd }, + { INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_val_cmd }, { INTERFACE_NODE, &ipv6_nd_reachable_time_cmd }, { INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd }, + { INTERFACE_NODE, &no_ipv6_nd_reachable_time_val_cmd }, { INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd }, { INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd }, { INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd }, @@ -1577,8 +1697,10 @@ CMD_INSTALL_TABLE(static, zebra_rtadv_cmd_table, ZEBRA) = { INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd }, { INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd }, { INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd }, + { INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_val_cmd }, { INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd }, { INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd }, + { INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_val_cmd }, { INTERFACE_NODE, &ipv6_nd_adv_interval_config_option_cmd }, { INTERFACE_NODE, &no_ipv6_nd_adv_interval_config_option_cmd }, { INTERFACE_NODE, &ipv6_nd_prefix_cmd }, @@ -1598,6 +1720,10 @@ CMD_INSTALL_TABLE(static, zebra_rtadv_cmd_table, ZEBRA) = { INTERFACE_NODE, &no_ipv6_nd_prefix_cmd }, { INTERFACE_NODE, &ipv6_nd_router_preference_cmd }, { INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd }, + { INTERFACE_NODE, &no_ipv6_nd_router_preference_val_cmd }, + { INTERFACE_NODE, &ipv6_nd_mtu_cmd }, + { INTERFACE_NODE, &no_ipv6_nd_mtu_cmd }, + { INTERFACE_NODE, &no_ipv6_nd_mtu_val_cmd }, CMD_INSTALL_END } ; diff --git a/zebra/rtadv.h b/zebra/rtadv.h index 0e600a4e..cbe6cce1 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -30,7 +30,7 @@ struct rtadv_prefix { /* Prefix to be advertised. */ - struct prefix prefix; + struct prefix_ipv6 prefix; /* The value to be placed in the Valid Lifetime in the Prefix */ u_int32_t AdvValidLifetime; @@ -47,7 +47,7 @@ struct rtadv_prefix /* The value to be placed in the Autonomous Flag. */ int AdvAutonomousFlag; - /* The value to be placed in the Router Address Flag (RFC3775 7.2). */ + /* The value to be placed in the Router Address Flag [RFC6275 7.2]. */ int AdvRouterAddressFlag; #ifndef ND_OPT_PI_FLAG_RADDR #define ND_OPT_PI_FLAG_RADDR 0x20 @@ -59,7 +59,7 @@ extern void rtadv_config_write (struct vty *, struct interface *); extern void rtadv_cmd_init (void); extern void rtadv_init (void); -/* draft-ietf-mip6-mipext-advapi-03 */ +/* RFC4584 Extension to Sockets API for Mobile IPv6 */ #ifndef ND_OPT_ADV_INTERVAL #define ND_OPT_ADV_INTERVAL 7 /* Adv Interval Option */ diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index 7a68ec8b..e1a501fc 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -91,7 +91,7 @@ handle_route_entry (mib2_ipRouteEntry_t *routeEntry) gateway.s_addr = routeEntry->ipRouteNextHop; rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &prefix, - &gateway, NULL, 0, 0, 0, 0); + &gateway, NULL, 0, 0, 0, 0, SAFI_UNICAST); } void diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c index 7013b480..fb316cdf 100644 --- a/zebra/rtread_netlink.c +++ b/zebra/rtread_netlink.c @@ -22,6 +22,9 @@ #ifndef VTYSH_EXTRACT_PL #include <zebra.h> +#include "zebra/zserv.h" + +extern void netlink_route_read (void); #include "zebra/rtread.h" diff --git a/zebra/rtread_proc.c b/zebra/rtread_proc.c index 6b9de199..685acc61 100644 --- a/zebra/rtread_proc.c +++ b/zebra/rtread_proc.c @@ -97,7 +97,7 @@ proc_route_read (void) p.prefixlen = ip_masklen (tmpmask); sscanf (gate, "%lX", (unsigned long *)&gateway); - rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, NULL, 0, 0, 0, 0); + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, NULL, 0, 0, 0, 0, SAFI_UNICAST); } fclose (fp); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 0677cafd..e687bb93 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -67,6 +67,7 @@ static const struct {ZEBRA_ROUTE_OSPF6, 110}, {ZEBRA_ROUTE_ISIS, 115}, {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */} + /* no entry/default: 150 */ }; /* Vector for routing table. */ @@ -89,6 +90,11 @@ vrf_alloc (const char *name) vrf->table[AFI_IP6][SAFI_UNICAST] = route_table_init (); vrf->stable[AFI_IP][SAFI_UNICAST] = route_table_init (); vrf->stable[AFI_IP6][SAFI_UNICAST] = route_table_init (); + vrf->table[AFI_IP][SAFI_MULTICAST] = route_table_init (); + vrf->table[AFI_IP6][SAFI_MULTICAST] = route_table_init (); + vrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init (); + vrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init (); + return vrf; } @@ -1493,7 +1499,7 @@ int rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct in_addr *gate, struct in_addr *src, unsigned int ifindex, u_int32_t vrf_id, - u_int32_t metric, u_char distance) + u_int32_t metric, u_char distance, safi_t safi) { struct rib *rib; struct rib *same = NULL; @@ -1502,7 +1508,7 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct nexthop *nexthop; /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = vrf_table (AFI_IP, safi, 0); if (! table) return 0; @@ -1512,7 +1518,10 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, /* Set default distance by route type. */ if (distance == 0) { - distance = route_info[type].distance; + if ((unsigned)type >= sizeof(route_info) / sizeof(route_info[0])) + distance = 150; + else + distance = route_info[type].distance; /* iBGP distance is 200. */ if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP)) @@ -1748,7 +1757,7 @@ void rib_lookup_and_pushup (struct prefix_ipv4 * p) } int -rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib) +rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) { struct route_table *table; struct route_node *rn; @@ -1756,9 +1765,10 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib) struct nexthop *nexthop; /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = vrf_table (AFI_IP, safi, 0); if (! table) return 0; + /* Make it sure prefixlen is applied to the prefix. */ apply_mask_ipv4 (p); @@ -1821,7 +1831,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib) /* XXX factor with rib_delete_ipv6 */ int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, - struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id) + struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id, safi_t safi) { struct route_table *table; struct route_node *rn; @@ -1833,7 +1843,7 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, char buf2[INET_ADDRSTRLEN]; /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = vrf_table (AFI_IP, safi, 0); if (! table) return 0; @@ -1880,8 +1890,10 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, if (rib->type != type) continue; if (rib->type == ZEBRA_ROUTE_CONNECT && (nexthop = rib->nexthop) && - nexthop->type == NEXTHOP_TYPE_IFINDEX && nexthop->ifindex == ifindex) + nexthop->type == NEXTHOP_TYPE_IFINDEX) { + if (nexthop->ifindex != ifindex) + continue; if (rib->refcnt) { rib->refcnt--; @@ -2282,7 +2294,7 @@ rib_bogus_ipv6 (int type, struct prefix_ipv6 *p, int rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id, - u_int32_t metric, u_char distance) + u_int32_t metric, u_char distance, safi_t safi) { struct rib *rib; struct rib *same = NULL; @@ -2291,7 +2303,7 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct nexthop *nexthop; /* Lookup table. */ - table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + table = vrf_table (AFI_IP6, safi, 0); if (! table) return 0; @@ -2376,7 +2388,7 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, /* XXX factor with rib_delete_ipv6 */ int rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, - struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id) + struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id, safi_t safi) { struct route_table *table; struct route_node *rn; @@ -2391,7 +2403,7 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, apply_mask_ipv6 (p); /* Lookup table. */ - table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + table = vrf_table (AFI_IP6, safi, 0); if (! table) return 0; @@ -2428,8 +2440,10 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, if (rib->type != type) continue; if (rib->type == ZEBRA_ROUTE_CONNECT && (nexthop = rib->nexthop) && - nexthop->type == NEXTHOP_TYPE_IFINDEX && nexthop->ifindex == ifindex) + nexthop->type == NEXTHOP_TYPE_IFINDEX) { + if (nexthop->ifindex != ifindex) + continue; if (rib->refcnt) { rib->refcnt--; @@ -2879,6 +2893,40 @@ rib_sweep_route (void) rib_sweep_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); } +/* Remove specific by protocol routes from 'table'. */ +static unsigned long +rib_score_proto_table (u_char proto, struct route_table *table) +{ + struct route_node *rn; + struct rib *rib; + struct rib *next; + unsigned long n = 0; + + if (table) + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = next) + { + next = rib->next; + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + continue; + if (rib->type == proto) + { + rib_delnode (rn, rib); + n++; + } + } + + return n; +} + +/* Remove specific by protocol routes. */ +unsigned long +rib_score_proto (u_char proto) +{ + return rib_score_proto_table (proto, vrf_table (AFI_IP, SAFI_UNICAST, 0)) + +rib_score_proto_table (proto, vrf_table (AFI_IP6, SAFI_UNICAST, 0)); +} + /* Close RIB and clean up kernel routes. */ static void rib_close_table (struct route_table *table) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 43192506..ca72c7cb 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -806,10 +806,6 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) } } -#define SHOW_ROUTE_V4_HEADER "Codes: K - kernel route, C - connected, " \ - "S - static, R - RIP, O - OSPF,%s I - ISIS, B - BGP, " \ - "> - selected route, * - FIB route%s%s" - DEFUN (show_ip_route, show_ip_route_cmd, "show ip route", @@ -832,8 +828,7 @@ DEFUN (show_ip_route, { if (first) { - vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, VTY_NEWLINE, - VTY_NEWLINE); + vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); @@ -875,8 +870,7 @@ DEFUN (show_ip_route_prefix_longer, { if (first) { - vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, - VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); @@ -914,8 +908,7 @@ DEFUN (show_ip_route_supernets, { if (first) { - vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, - VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); @@ -926,17 +919,11 @@ DEFUN (show_ip_route_supernets, DEFUN (show_ip_route_protocol, show_ip_route_protocol_cmd, - "show ip route (bgp|connected|isis|kernel|ospf|rip|static)", + "show ip route " QUAGGA_IP_REDIST_STR_ZEBRA, SHOW_STR IP_STR "IP routing table\n" - "Border Gateway Protocol (BGP)\n" - "Connected\n" - "ISO IS-IS (ISIS)\n" - "Kernel\n" - "Open Shortest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n") + QUAGGA_IP_REDIST_HELP_STR_ZEBRA) { int type; struct route_table *table; @@ -944,21 +931,8 @@ DEFUN (show_ip_route_protocol, struct rib *rib; int first = 1; - if (strncmp (argv[0], "b", 1) == 0) - type = ZEBRA_ROUTE_BGP; - else if (strncmp (argv[0], "c", 1) == 0) - type = ZEBRA_ROUTE_CONNECT; - else if (strncmp (argv[0], "k", 1) ==0) - type = ZEBRA_ROUTE_KERNEL; - else if (strncmp (argv[0], "o", 1) == 0) - type = ZEBRA_ROUTE_OSPF; - else if (strncmp (argv[0], "i", 1) == 0) - type = ZEBRA_ROUTE_ISIS; - else if (strncmp (argv[0], "r", 1) == 0) - type = ZEBRA_ROUTE_RIP; - else if (strncmp (argv[0], "s", 1) == 0) - type = ZEBRA_ROUTE_STATIC; - else + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0) { vty_out (vty, "Unknown route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -975,8 +949,7 @@ DEFUN (show_ip_route_protocol, { if (first) { - vty_out (vty, SHOW_ROUTE_V4_HEADER, - VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); @@ -1770,8 +1743,6 @@ vty_show_ipv6_route (struct vty *vty, struct route_node *rn, } } -#define SHOW_ROUTE_V6_HEADER "Codes: K - kernel route, C - connected, S - static, R - RIPng, O - OSPFv3,%s I - ISIS, B - BGP, * - FIB route.%s%s" - DEFUN (show_ipv6_route, show_ipv6_route_cmd, "show ipv6 route", @@ -1794,7 +1765,7 @@ DEFUN (show_ipv6_route, { if (first) { - vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } vty_show_ipv6_route (vty, rn, rib); @@ -1836,7 +1807,7 @@ DEFUN (show_ipv6_route_prefix_longer, { if (first) { - vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } vty_show_ipv6_route (vty, rn, rib); @@ -1846,17 +1817,11 @@ DEFUN (show_ipv6_route_prefix_longer, DEFUN (show_ipv6_route_protocol, show_ipv6_route_protocol_cmd, - "show ipv6 route (bgp|connected|isis|kernel|ospf6|ripng|static)", + "show ipv6 route " QUAGGA_IP6_REDIST_STR_ZEBRA, SHOW_STR IP_STR "IP routing table\n" - "Border Gateway Protocol (BGP)\n" - "Connected\n" - "ISO IS-IS (ISIS)\n" - "Kernel\n" - "Open Shortest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n") + QUAGGA_IP6_REDIST_HELP_STR_ZEBRA) { int type; struct route_table *table; @@ -1864,21 +1829,8 @@ DEFUN (show_ipv6_route_protocol, struct rib *rib; int first = 1; - if (strncmp (argv[0], "b", 1) == 0) - type = ZEBRA_ROUTE_BGP; - else if (strncmp (argv[0], "c", 1) == 0) - type = ZEBRA_ROUTE_CONNECT; - else if (strncmp (argv[0], "k", 1) ==0) - type = ZEBRA_ROUTE_KERNEL; - else if (strncmp (argv[0], "o", 1) == 0) - type = ZEBRA_ROUTE_OSPF6; - else if (strncmp (argv[0], "i", 1) == 0) - type = ZEBRA_ROUTE_ISIS; - else if (strncmp (argv[0], "r", 1) == 0) - type = ZEBRA_ROUTE_RIPNG; - else if (strncmp (argv[0], "s", 1) == 0) - type = ZEBRA_ROUTE_STATIC; - else + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0) { vty_out (vty, "Unknown route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -1895,7 +1847,7 @@ DEFUN (show_ipv6_route_protocol, { if (first) { - vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } vty_show_ipv6_route (vty, rn, rib); @@ -1999,6 +1951,80 @@ DEFUN (show_ipv6_route_summary, return CMD_SUCCESS; } +/* + * Show IP mroute command to dump the BGP Multicast + * routing table + */ +DEFUN (show_ip_mroute, + show_ip_mroute_cmd, + "show ip mroute", + SHOW_STR + IP_STR + "IP Multicast routing table\n") +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + int first = 1; + + table = vrf_table (AFI_IP, SAFI_MULTICAST, 0); + if (! table) + return CMD_SUCCESS; + + /* Show all IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + +/* + * Show IPv6 mroute command.Used to dump + * the Multicast routing table. + */ + +DEFUN (show_ipv6_mroute, + show_ipv6_mroute_cmd, + "show ipv6 mroute", + SHOW_STR + IP_STR + "IPv6 Multicast routing table\n") +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + int first = 1; + + table = vrf_table (AFI_IP6, SAFI_MULTICAST, 0); + if (! table) + return CMD_SUCCESS; + + /* Show all IPv6 route. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V6_HEADER); + first = 0; + } + vty_show_ipv6_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + + + + + + /* Write IPv6 static route configuration. */ static int static_config_ipv6 (struct vty *vty) @@ -2141,6 +2167,8 @@ CMD_INSTALL_TABLE(static, zebra_vty_cmd_table, ZEBRA) = { ENABLE_NODE, &show_ip_route_protocol_cmd }, { ENABLE_NODE, &show_ip_route_supernets_cmd }, { ENABLE_NODE, &show_ip_route_summary_cmd }, + { VIEW_NODE, &show_ip_mroute_cmd }, + { ENABLE_NODE, &show_ip_mroute_cmd }, #ifdef HAVE_IPV6 { CONFIG_NODE, &ipv6_route_cmd }, @@ -2171,6 +2199,8 @@ CMD_INSTALL_TABLE(static, zebra_vty_cmd_table, ZEBRA) = { ENABLE_NODE, &show_ipv6_route_prefix_cmd }, { ENABLE_NODE, &show_ipv6_route_prefix_longer_cmd }, { ENABLE_NODE, &show_ipv6_route_summary_cmd }, + { VIEW_NODE, &show_ipv6_mroute_cmd }, + { ENABLE_NODE, &show_ipv6_mroute_cmd }, #endif /* HAVE_IPV6 */ CMD_INSTALL_END diff --git a/zebra/zserv.c b/zebra/zserv.c index bafae329..4dd14a4f 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -64,6 +64,15 @@ zserv_delayed_close(struct thread *thread) return 0; } +/* When client connects, it sends hello message + * with promise to send zebra routes of specific type. + * Zebra stores a socket fd of the client into + * this array. And use it to clean up routes that + * client didn't remove for some reasons after closing + * connection. + */ +static int route_type_oaths[ZEBRA_ROUTE_MAX]; + static int zserv_flush_data(struct thread *thread) { @@ -742,6 +751,8 @@ zread_ipv4_add (struct zserv *client, u_short length) struct stream *s; unsigned int ifindex; u_char ifname_len; + safi_t safi; + /* Get input stream. */ s = client->ibuf; @@ -753,6 +764,8 @@ zread_ipv4_add (struct zserv *client, u_short length) rib->type = stream_getc (s); rib->flags = stream_getc (s); message = stream_getc (s); + message = stream_getc (s); + safi = stream_getw (s); rib->uptime = time (NULL); /* IPv4 prefix. */ @@ -804,7 +817,7 @@ zread_ipv4_add (struct zserv *client, u_short length) /* Table */ rib->table=zebrad.rtm_table_default; - rib_add_ipv4_multipath (&p, rib); + rib_add_ipv4_multipath (&p, rib, safi); return 0; } @@ -830,6 +843,7 @@ zread_ipv4_delete (struct zserv *client, u_short length) api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); + api.safi = stream_getw (s); /* IPv4 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv4)); @@ -878,7 +892,7 @@ zread_ipv4_delete (struct zserv *client, u_short length) api.metric = 0; rib_delete_ipv4 (api.type, api.flags, &p, &nexthop, ifindex, - client->rtm_table); + client->rtm_table, api.safi); return 0; } @@ -925,6 +939,7 @@ zread_ipv6_add (struct zserv *client, u_short length) api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); + api.safi = stream_getw (s); /* IPv4 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); @@ -966,10 +981,10 @@ zread_ipv6_add (struct zserv *client, u_short length) if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex, zebrad.rtm_table_default, api.metric, - api.distance); + api.distance, api.safi); else rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, zebrad.rtm_table_default, api.metric, - api.distance); + api.distance, api.safi); return 0; } @@ -992,6 +1007,7 @@ zread_ipv6_delete (struct zserv *client, u_short length) api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); + api.safi = stream_getw (s); /* IPv4 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); @@ -1031,9 +1047,9 @@ zread_ipv6_delete (struct zserv *client, u_short length) api.metric = 0; if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) - rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, client->rtm_table); + rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, client->rtm_table, api.safi); else - rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, client->rtm_table); + rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, client->rtm_table, api.safi); return 0; } @@ -1072,6 +1088,49 @@ zread_router_id_delete (struct zserv *client, u_short length) return 0; } +/* Tie up route-type and client->sock */ +static void +zread_hello (struct zserv *client) +{ + /* type of protocol (lib/zebra.h) */ + u_char proto; + proto = stream_getc (client->ibuf); + + /* accept only dynamic routing protocols */ + if ((proto < ZEBRA_ROUTE_MAX) + && (proto > ZEBRA_ROUTE_STATIC)) + { + zlog_notice ("client %d says hello and bids fair to announce only %s routes", + client->sock, zebra_route_string(proto)); + + /* if route-type was binded by other client */ + if (route_type_oaths[proto]) + zlog_warn ("sender of %s routes changed %c->%c", + zebra_route_string(proto), route_type_oaths[proto], + client->sock); + + route_type_oaths[proto] = client->sock; + } +} + +/* If client sent routes of specific type, zebra removes it + * and returns number of deleted routes. + */ +static void +zebra_score_rib (int client_sock) +{ + int i; + + for (i = ZEBRA_ROUTE_RIP; i < ZEBRA_ROUTE_MAX; i++) + if (client_sock == route_type_oaths[i]) + { + zlog_notice ("client %d disconnected. %lu %s routes removed from the rib", + client_sock, rib_score_proto (i), zebra_route_string (i)); + route_type_oaths[i] = 0; + break; + } +} + /* Close zebra client. */ static void zebra_client_close (struct zserv *client) @@ -1080,6 +1139,7 @@ zebra_client_close (struct zserv *client) if (client->sock) { close (client->sock); + zebra_score_rib (client->sock); client->sock = -1; } @@ -1284,6 +1344,9 @@ zebra_client_read (struct thread *thread) case ZEBRA_IPV4_IMPORT_LOOKUP: zread_ipv4_import_lookup (client, length); break; + case ZEBRA_HELLO: + zread_hello (client); + break; default: zlog_info ("Zebra received unknown command %d", command); break; @@ -1353,6 +1416,7 @@ zebra_serv () return; } + memset (&route_type_oaths, 0, sizeof (route_type_oaths)); memset (&addr, 0, sizeof (struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_port = htons (ZEBRA_PORT); @@ -1423,6 +1487,8 @@ zebra_serv_un (const char *path) return; } + memset (&route_type_oaths, 0, sizeof (route_type_oaths)); + /* Make server socket. */ memset (&serv, 0, sizeof (struct sockaddr_un)); serv.sun_family = AF_UNIX; @@ -1736,11 +1802,11 @@ zebra_init (void) /* Make zebra server socket, wiping any existing one (see bug #403). */ void -zebra_zserv_socket_init (void) +zebra_zserv_socket_init (char *path) { #ifdef HAVE_TCP_ZEBRA zebra_serv (); #else - zebra_serv_un (ZEBRA_SERV_PATH); + zebra_serv_un (path ? path : ZEBRA_SERV_PATH); #endif /* HAVE_TCP_ZEBRA */ } diff --git a/zebra/zserv.h b/zebra/zserv.h index c8a9df0c..a569efac 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -91,7 +91,7 @@ extern void zebra_cmd_init (void); extern void zebra_init (void); extern void zebra_if_cmd_init (void); extern void zebra_if_init (void); -extern void zebra_zserv_socket_init (void); +extern void zebra_zserv_socket_init (char *path); extern void hostinfo_get (void); extern void rib_init (void); extern void kernel_init (void); |