diff options
268 files changed, 14062 insertions, 10993 deletions
diff --git a/Makefile.am b/Makefile.am index 0092ba8c10..7cfe4a97e3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,23 +1,95 @@ ## Process this file with automake to produce Makefile.in. -SUBDIRS = lib qpb fpm @ZEBRA@ @LIBRFP@ @RFPTEST@ \ +AUTOMAKE_OPTIONS = subdir-objects 1.12 +include common.am + +AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir) -I$(top_builddir)/lib +AM_CFLAGS = $(WERROR) +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +LIBCAP = @LIBCAP@ + +EXTRA_DIST = +BUILT_SOURCES = +CLEANFILES = + +examplesdir = $(exampledir) + +bin_PROGRAMS = +sbin_PROGRAMS = +noinst_PROGRAMS = +noinst_HEADERS = +noinst_LIBRARIES = +lib_LTLIBRARIES = +module_LTLIBRARIES = +pkginclude_HEADERS = +dist_examples_DATA = + +include lib/subdir.am +include zebra/subdir.am +include qpb/subdir.am +include fpm/subdir.am + +SUBDIRS = . @LIBRFP@ @RFPTEST@ \ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @LDPD@ \ @ISISD@ @PIMD@ @NHRPD@ @EIGRPD@ @BABELD@ \ - @WATCHFRR@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \ - redhat @SOLARIS@ tests tools snapcraft + @WATCHFRR@ @VTYSH@ @OSPFCLIENT@ @DOC@ \ + @SOLARIS@ tests tools -DIST_SUBDIRS = lib qpb fpm zebra bgpd ripd ripngd ospfd ospf6d ldpd \ - isisd watchfrr vtysh ospfclient doc m4 pkgsrc redhat tests \ +DIST_SUBDIRS = . bgpd ripd ripngd ospfd ospf6d ldpd \ + isisd watchfrr vtysh ospfclient doc tests \ solaris pimd nhrpd eigrpd bgpd/rfp-example/librfp \ - bgpd/rfp-example/rfptest tools snapcraft babeld python \ + bgpd/rfp-example/rfptest tools babeld \ # end -EXTRA_DIST = aclocal.m4 SERVICES REPORTING-BUGS \ +if PKGSRC +rcdir=@pkgsrcrcdir@ +rc_SCRIPTS = \ + pkgsrc/bgpd.sh \ + pkgsrc/ospf6d.sh \ + pkgsrc/ospfd.sh \ + pkgsrc/ripd.sh \ + pkgsrc/ripngd.sh \ + pkgsrc/zebra.sh \ + # end +endif + +EXTRA_DIST += \ + REPORTING-BUGS \ + SERVICES \ + aclocal.m4 \ update-autotools \ - vtysh/Makefile.in vtysh/Makefile.am \ - tools/rrcheck.pl tools/rrlookup.pl tools/zc.pl \ - tools/zebra.el tools/multiple-bgpd.sh + m4/README.txt \ + \ + python/clidef.py \ + python/clippy/__init__.py \ + \ + redhat/frr.init \ + redhat/frr.service \ + redhat/daemons \ + redhat/frr.logrotate \ + redhat/frr.pam \ + redhat/frr.spec \ + redhat/README.rpm_build.md \ + \ + snapcraft/snapcraft.yaml \ + snapcraft/README.snap_build.md \ + snapcraft/README.usage.md \ + snapcraft/extra_version_info.txt \ + snapcraft/scripts \ + snapcraft/defaults \ + snapcraft/helpers \ + snapcraft/snap \ + \ + tools/multiple-bgpd.sh \ + tools/rrcheck.pl \ + tools/rrlookup.pl \ + tools/zc.pl \ + tools/zebra.el \ + \ + vtysh/Makefile.am \ + vtysh/Makefile.in \ + # end ACLOCAL_AMFLAGS = -I m4 -noinst_HEADERS = defaults.h +noinst_HEADERS += defaults.h diff --git a/babeld/babeld.conf.sample b/babeld/babeld.conf.sample index a4924ec7b7..a77453a734 100644 --- a/babeld/babeld.conf.sample +++ b/babeld/babeld.conf.sample @@ -9,8 +9,8 @@ debug babel common router babel ! network wlan0 ! network eth0 -! redistribute kernel -! no redistribute static +! redistribute ipv4 kernel +! no redistribute ipv6 static ! The defaults are fine for a wireless interface diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index ef32b9cf92..dd18797637 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -566,12 +566,6 @@ unsigned int attrhash_key_make(void *p) MIX(attr->nexthop.s_addr); MIX(attr->med); MIX(attr->local_pref); - - key += attr->origin; - key += attr->nexthop.s_addr; - key += attr->med; - key += attr->local_pref; - MIX(attr->aggregator_as); MIX(attr->aggregator_addr.s_addr); MIX(attr->weight); @@ -1677,7 +1671,8 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, { iana_afi_t pkt_afi; afi_t afi; - safi_t pkt_safi, safi; + iana_safi_t pkt_safi; + safi_t safi; bgp_size_t nlri_len; size_t start; struct stream *s; @@ -1826,7 +1821,8 @@ int bgp_mp_unreach_parse(struct bgp_attr_parser_args *args, struct stream *s; iana_afi_t pkt_afi; afi_t afi; - safi_t pkt_safi, safi; + iana_safi_t pkt_safi; + safi_t safi; u_int16_t withdraw_len; struct peer *const peer = args->peer; struct attr *const attr = args->attr; @@ -2593,7 +2589,7 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi, { size_t sizep; iana_afi_t pkt_afi; - safi_t pkt_safi; + iana_safi_t pkt_safi; afi_t nh_afi; /* Set extended bit always to encode the attribute length as 2 bytes */ @@ -3280,7 +3276,7 @@ size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi) { unsigned long attrlen_pnt; iana_afi_t pkt_afi; - safi_t pkt_safi; + iana_safi_t pkt_safi; /* Set extended bit always to encode the attribute length as 2 bytes */ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_EXTLEN); diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index cd6b87b299..2f0b566ccf 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -42,7 +42,7 @@ void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac) memset(&routermac_ecom, 0, sizeof(struct ecommunity_val)); routermac_ecom.val[0] = ECOMMUNITY_ENCODE_EVPN; routermac_ecom.val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC; - memcpy(&routermac_ecom.val[2], routermac->octet, ETHER_ADDR_LEN); + memcpy(&routermac_ecom.val[2], routermac->octet, ETH_ALEN); if (!attr->ecommunity) attr->ecommunity = ecommunity_new(); ecommunity_add_val(attr->ecommunity, &routermac_ecom); diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c index bd3ae27c05..36ffb0e9c5 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -543,8 +543,6 @@ static const char *bgp_get_reuse_time(unsigned int penalty, char *buf, reuse_time = 0; /* Making formatted timer strings. */ -#define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND 60*60*24*7 if (reuse_time == 0) { if (use_json) json_object_int_add(json, "reuseTimerMsecs", 0); diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index f0081e6d02..fe311832a2 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -351,7 +351,7 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, s, add ? ZEBRA_REMOTE_MACIP_ADD : ZEBRA_REMOTE_MACIP_DEL, bgp->vrf_id); stream_putl(s, vpn->vni); - stream_put(s, &p->prefix.mac.octet, ETHER_ADDR_LEN); /* Mac Addr */ + stream_put(s, &p->prefix.mac.octet, ETH_ALEN); /* Mac Addr */ /* IP address length and IP address, if any. */ if (IS_EVPN_PREFIX_IPADDR_NONE(p)) stream_putl(s, 0); @@ -1812,9 +1812,9 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, macaddr_len = *pfx++; /* Get the MAC Addr */ - if (macaddr_len == (ETHER_ADDR_LEN * 8)) { - memcpy(&p.prefix.mac.octet, pfx, ETHER_ADDR_LEN); - pfx += ETHER_ADDR_LEN; + if (macaddr_len == (ETH_ALEN * 8)) { + memcpy(&p.prefix.mac.octet, pfx, ETH_ALEN); + pfx += ETH_ALEN; } else { zlog_err( "%u:%s - Rx EVPN Type-2 NLRI with unsupported MAC address length %d", @@ -2186,7 +2186,7 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len) } else if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { if (IS_EVPN_PREFIX_IPADDR_NONE(p)) snprintf(buf, len, "[%d]:[0]:[0]:[%d]:[%s]", - p->prefix.route_type, 8 * ETHER_ADDR_LEN, + p->prefix.route_type, 8 * ETH_ALEN, prefix_mac2str(&p->prefix.mac, buf1, sizeof(buf1))); else { @@ -2195,7 +2195,7 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len) family = IS_EVPN_PREFIX_IPADDR_V4(p) ? AF_INET : AF_INET6; snprintf(buf, len, "[%d]:[0]:[0]:[%d]:[%s]:[%d]:[%s]", - p->prefix.route_type, 8 * ETHER_ADDR_LEN, + p->prefix.route_type, 8 * ETH_ALEN, prefix_mac2str(&p->prefix.mac, buf1, sizeof(buf1)), family == AF_INET ? IPV4_MAX_BITLEN @@ -2237,7 +2237,7 @@ void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p, stream_put(s, prd->val, 8); /* RD */ stream_put(s, 0, 10); /* ESI */ stream_putl(s, 0); /* Ethernet Tag ID */ - stream_putc(s, 8 * ETHER_ADDR_LEN); /* Mac Addr Len - bits */ + stream_putc(s, 8 * ETH_ALEN); /* Mac Addr Len - bits */ stream_put(s, evp->prefix.mac.octet, 6); /* Mac Addr */ stream_putc(s, 8 * ipa_len); /* IP address Length */ if (ipa_len) diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 816a7df98c..095dfa1b15 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -174,7 +174,7 @@ static inline void build_evpn_type2_prefix(struct prefix_evpn *p, p->family = AF_ETHERNET; p->prefixlen = EVPN_TYPE_2_ROUTE_PREFIXLEN; p->prefix.route_type = BGP_EVPN_MAC_IP_ROUTE; - memcpy(&p->prefix.mac.octet, mac->octet, ETHER_ADDR_LEN); + memcpy(&p->prefix.mac.octet, mac->octet, ETH_ALEN); p->prefix.ip.ipa_type = IPADDR_NONE; if (ip) memcpy(&p->prefix.ip, ip, sizeof(*ip)); diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index cf1cb18689..b609abac69 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -488,7 +488,7 @@ static int bgp_graceful_restart_timer_expire(struct thread *thread) /* NSF delete stale route */ for (afi = AFI_IP; afi < AFI_MAX; afi++) - for (safi = SAFI_UNICAST; safi < SAFI_RESERVED_4; safi++) + for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) if (peer->nsf[afi][safi]) bgp_clear_stale_route(peer, afi, safi); @@ -521,7 +521,7 @@ static int bgp_graceful_stale_timer_expire(struct thread *thread) /* NSF delete stale route */ for (afi = AFI_IP; afi < AFI_MAX; afi++) - for (safi = SAFI_UNICAST; safi < SAFI_RESERVED_4; safi++) + for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) if (peer->nsf[afi][safi]) bgp_clear_stale_route(peer, afi, safi); @@ -1022,7 +1022,7 @@ int bgp_stop(struct peer *peer) for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; - safi < SAFI_RESERVED_4; safi++) + safi <= SAFI_MPLS_VPN; safi++) peer->nsf[afi][safi] = 0; } @@ -1425,7 +1425,7 @@ static int bgp_establish(struct peer *peer) /* graceful restart */ UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT); for (afi = AFI_IP; afi < AFI_MAX; afi++) - for (safi = SAFI_UNICAST; safi < SAFI_RESERVED_4; safi++) { + for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) { if (peer->afc_nego[afi][safi] && CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV) && CHECK_FLAG(peer->af_cap[afi][safi], diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index b18a4b7c46..3ee865e3ba 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -271,7 +271,7 @@ static int bgp_capability_mp(struct peer *peer, struct capability_header *hdr) } static void bgp_capability_orf_not_support(struct peer *peer, iana_afi_t afi, - safi_t safi, u_char type, + iana_safi_t safi, u_char type, u_char mode) { if (bgp_debug_neighbor_events(peer)) @@ -298,7 +298,8 @@ static int bgp_capability_orf_entry(struct peer *peer, u_char num; iana_afi_t pkt_afi; afi_t afi; - safi_t pkt_safi, safi; + iana_safi_t pkt_safi; + safi_t safi; u_char type; u_char mode; u_int16_t sm_cap = 0; /* capability send-mode receive */ @@ -466,7 +467,7 @@ static int bgp_capability_restart(struct peer *peer, afi_t afi; safi_t safi; iana_afi_t pkt_afi = stream_getw(s); - safi_t pkt_safi = stream_getc(s); + iana_safi_t pkt_safi = stream_getc(s); u_char flag = stream_getc(s); /* Convert AFI, SAFI to internal values, check. */ @@ -543,7 +544,7 @@ static int bgp_capability_addpath(struct peer *peer, afi_t afi; safi_t safi; iana_afi_t pkt_afi = stream_getw(s); - safi_t pkt_safi = stream_getc(s); + iana_safi_t pkt_safi = stream_getc(s); u_char send_receive = stream_getc(s); if (bgp_debug_neighbor_events(peer)) @@ -600,7 +601,8 @@ static int bgp_capability_enhe(struct peer *peer, struct capability_header *hdr) while (stream_get_getp(s) + 6 <= end) { iana_afi_t pkt_afi = stream_getw(s); afi_t afi; - safi_t safi, pkt_safi = stream_getw(s); + iana_safi_t pkt_safi = stream_getw(s); + safi_t safi; iana_afi_t pkt_nh_afi = stream_getw(s); afi_t nh_afi; @@ -1199,7 +1201,7 @@ static void bgp_open_capability_orf(struct stream *s, struct peer *peer, unsigned long numberp; int number_of_orfs = 0; iana_afi_t pkt_afi; - safi_t pkt_safi; + iana_safi_t pkt_safi; /* Convert AFI, SAFI to values for packet. */ bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi); @@ -1264,7 +1266,8 @@ void bgp_open_capability(struct stream *s, struct peer *peer) unsigned long cp, capp, rcapp; iana_afi_t pkt_afi; afi_t afi; - safi_t safi, pkt_safi; + safi_t safi; + iana_safi_t pkt_safi; as_t local_as; u_int32_t restart_time; u_char afi_safi_count = 0; diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h index cbd32116b4..83b79a589a 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -29,9 +29,9 @@ struct capability_header { /* Generic MP capability data */ struct capability_mp_data { - iana_afi_t afi; + uint16_t afi; /* iana_afi_t */ u_char reserved; - safi_t safi; + uint8_t safi; /* iana_safi_t */ }; struct capability_as4 { diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index e92f2d6977..003fbaff63 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -142,7 +142,7 @@ static struct stream *bgp_update_packet_eor(struct peer *peer, afi_t afi, { struct stream *s; iana_afi_t pkt_afi; - safi_t pkt_safi; + iana_safi_t pkt_safi; if (DISABLE_BGP_ANNOUNCE) return NULL; @@ -671,7 +671,7 @@ void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi, struct bgp_filter *filter; int orf_refresh = 0; iana_afi_t pkt_afi; - safi_t pkt_safi; + iana_safi_t pkt_safi; if (DISABLE_BGP_ANNOUNCE) return; @@ -761,7 +761,7 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, { struct stream *s; iana_afi_t pkt_afi; - safi_t pkt_safi; + iana_safi_t pkt_safi; /* Convert AFI, SAFI to values for packet. */ bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi); @@ -1338,8 +1338,9 @@ int bgp_nlri_parse(struct peer *peer, struct attr *attr, packet); case SAFI_EVPN: return bgp_nlri_parse_evpn(peer, attr, packet, mp_withdraw); + default: + return -1; } - return -1; } /* Parse BGP Update packet and make attribute object. */ @@ -1697,7 +1698,8 @@ static void bgp_route_refresh_receive(struct peer *peer, bgp_size_t size) { iana_afi_t pkt_afi; afi_t afi; - safi_t pkt_safi, safi; + iana_safi_t pkt_safi; + safi_t safi; struct stream *s; struct peer_af *paf; struct update_group *updgrp; @@ -1965,7 +1967,8 @@ static int bgp_capability_msg_parse(struct peer *peer, u_char *pnt, u_char action; iana_afi_t pkt_afi; afi_t afi; - safi_t pkt_safi, safi; + iana_safi_t pkt_safi; + safi_t safi; end = pnt + length; diff --git a/bgpd/bgp_rd.c b/bgpd/bgp_rd.c index fd01693942..a15828bd36 100644 --- a/bgpd/bgp_rd.c +++ b/bgpd/bgp_rd.c @@ -98,7 +98,7 @@ void decode_rd_vnc_eth(u_char *pnt, struct rd_vnc_eth *rd_vnc_eth) { rd_vnc_eth->type = RD_TYPE_VNC_ETH; rd_vnc_eth->local_nve_id = pnt[1]; - memcpy(rd_vnc_eth->macaddr.octet, pnt + 2, ETHER_ADDR_LEN); + memcpy(rd_vnc_eth->macaddr.octet, pnt + 2, ETH_ALEN); } #endif diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index b554aeb32b..e4e421510f 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2078,7 +2078,7 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data) vnc_import_bgp_add_route(bgp, p, old_select); vnc_import_bgp_exterior_add_route(bgp, p, old_select); #endif - if (bgp_fibupd_safi(safi) && !bgp->name + if (bgp_fibupd_safi(safi) && !bgp_option_check(BGP_OPT_NO_FIB) && new_select->type == ZEBRA_ROUTE_BGP && new_select->sub_type == BGP_ROUTE_NORMAL) @@ -2288,7 +2288,7 @@ int bgp_maximum_prefix_overflow(struct peer *peer, afi_t afi, safi_t safi, int always) { iana_afi_t pkt_afi; - safi_t pkt_safi; + iana_safi_t pkt_safi; if (!CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) return 0; @@ -4775,7 +4775,7 @@ int bgp_static_set_safi(afi_t afi, safi_t safi, struct vty *vty, } if (routermac) { bgp_static->router_mac = - XCALLOC(MTYPE_ATTR, ETHER_ADDR_LEN + 1); + XCALLOC(MTYPE_ATTR, ETH_ALEN + 1); prefix_str2mac(routermac, bgp_static->router_mac); } diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 1a23a36e91..692db32fa4 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -845,7 +845,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) send_attr_str); if (!stream_empty(snlri)) { iana_afi_t pkt_afi; - safi_t pkt_safi; + iana_safi_t pkt_safi; pkt_afi = afi_int2iana(afi); pkt_safi = safi_int2iana(safi); @@ -989,7 +989,7 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp) /* If first time, format the MP_UNREACH header */ if (first_time) { iana_afi_t pkt_afi; - safi_t pkt_safi; + iana_safi_t pkt_safi; pkt_afi = afi_int2iana(afi); pkt_safi = safi_int2iana(safi); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 65a1473f75..0220a7e55d 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -78,6 +78,10 @@ static enum node_type bgp_node_type(afi_t afi, safi_t safi) case SAFI_MPLS_VPN: return BGP_VPNV4_NODE; break; + default: + /* not expected */ + return BGP_IPV4_NODE; + break; } break; case AFI_IP6: @@ -94,6 +98,10 @@ static enum node_type bgp_node_type(afi_t afi, safi_t safi) case SAFI_MPLS_VPN: return BGP_VPNV6_NODE; break; + default: + /* not expected */ + return BGP_IPV4_NODE; + break; } break; case AFI_L2VPN: @@ -7079,12 +7087,6 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, json); } safi++; - if (safi == SAFI_RESERVED_4 - || safi - == SAFI_RESERVED_5) /* handle special - cases to match - zebra.h */ - safi++; if (!safi_wildcard) safi = SAFI_MAX; } diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 4870e54aec..5071be909e 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -2125,7 +2125,7 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient, memset(&ip, 0, sizeof(ip)); s = zclient->ibuf; vni = stream_getl(s); - stream_get(&mac.octet, s, ETHER_ADDR_LEN); + stream_get(&mac.octet, s, ETH_ALEN); ipa_len = stream_getl(s); if (ipa_len != 0 && ipa_len != IPV4_MAX_BYTELEN && ipa_len != IPV6_MAX_BYTELEN) { diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index a0e2d6749a..d30def0f07 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -611,8 +611,8 @@ int bgp_listen_limit_unset(struct bgp *bgp) return 0; } -int bgp_map_afi_safi_iana2int(iana_afi_t pkt_afi, safi_t pkt_safi, afi_t *afi, - safi_t *safi) +int bgp_map_afi_safi_iana2int(iana_afi_t pkt_afi, iana_safi_t pkt_safi, + afi_t *afi, safi_t *safi) { /* Map from IANA values to internal values, return error if * values are unrecognized. @@ -626,7 +626,7 @@ int bgp_map_afi_safi_iana2int(iana_afi_t pkt_afi, safi_t pkt_safi, afi_t *afi, } int bgp_map_afi_safi_int2iana(afi_t afi, safi_t safi, iana_afi_t *pkt_afi, - safi_t *pkt_safi) + iana_safi_t *pkt_safi) { /* Map from internal values to IANA values, return error if * internal values are bad (unexpected). @@ -746,7 +746,7 @@ static unsigned int peer_hash_key_make(void *p) return sockunion_hash(&peer->su); } -static int peer_hash_cmp(const void *p1, const void *p2) +static int peer_hash_same(const void *p1, const void *p2) { const struct peer *peer1 = p1; const struct peer *peer2 = p2; @@ -1842,7 +1842,7 @@ static void peer_nsf_stop(struct peer *peer) UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE); for (afi = AFI_IP; afi < AFI_MAX; afi++) - for (safi = SAFI_UNICAST; safi < SAFI_RESERVED_4; safi++) + for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) peer->nsf[afi][safi] = 0; if (peer->t_gr_restart) { @@ -2757,7 +2757,8 @@ static struct bgp *bgp_create(as_t *as, const char *name, XSTRDUP(MTYPE_BGP_PEER_HOST, "Static announcement"); bgp->peer = list_new(); bgp->peer->cmp = (int (*)(void *, void *))peer_cmp; - bgp->peerhash = hash_create(peer_hash_key_make, peer_hash_cmp, NULL); + bgp->peerhash = hash_create(peer_hash_key_make, peer_hash_same, NULL); + bgp->peerhash->max_size = BGP_PEER_MAX_HASH_SIZE; bgp->group = list_new(); bgp->group->cmp = (int (*)(void *, void *))peer_group_cmp; @@ -6109,11 +6110,6 @@ char *peer_uptime(time_t uptime2, char *buf, size_t len, u_char use_json, uptime1 -= uptime2; tm = gmtime(&uptime1); -/* Making formatted timer strings. */ -#define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND ONE_DAY_SECOND*7 -#define ONE_YEAR_SECOND ONE_DAY_SECOND*365 - if (uptime1 < ONE_DAY_SECOND) snprintf(buf, len, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 67b8289c70..208a4e4b4e 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -36,6 +36,7 @@ #include "bitfield.h" #define BGP_MAX_HOSTNAME 64 /* Linux max, is larger than most other sys */ +#define BGP_PEER_MAX_HASH_SIZE 16384 /* Default interval for IPv6 RAs when triggered by BGP unnumbered neighbor. */ #define BGP_UNNUM_DEFAULT_RA_INTERVAL 10 @@ -922,10 +923,10 @@ DECLARE_QOBJ_TYPE(peer) stream. */ struct bgp_nlri { /* AFI. */ - afi_t afi; + uint16_t afi; /* iana_afi_t */ /* SAFI. */ - safi_t safi; + uint8_t safi; /* iana_safi_t */ /* Pointer to NLRI byte stream. */ u_char *nlri; @@ -1381,10 +1382,10 @@ extern void bgp_route_map_terminate(void); extern int peer_cmp(struct peer *p1, struct peer *p2); -extern int bgp_map_afi_safi_iana2int(iana_afi_t pkt_afi, safi_t pkt_safi, +extern int bgp_map_afi_safi_iana2int(iana_afi_t pkt_afi, iana_safi_t pkt_safi, afi_t *afi, safi_t *safi); extern int bgp_map_afi_safi_int2iana(afi_t afi, safi_t safi, - iana_afi_t *pkt_afi, safi_t *pkt_safi); + iana_afi_t *pkt_afi, iana_safi_t *pkt_safi); extern struct peer_af *peer_af_create(struct peer *, afi_t, safi_t); extern struct peer_af *peer_af_find(struct peer *, afi_t, safi_t); diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index ab71eda126..477716cafb 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -1568,7 +1568,7 @@ rfapi_query_inner(void *handle, struct rfapi_ip_addr *target, if (l2o) { if (!memcmp(l2o->macaddr.octet, rfapi_ethaddr0.octet, - ETHER_ADDR_LEN)) { + ETH_ALEN)) { eth_is_0 = 1; } /* per t/c Paul/Lou 151022 */ @@ -3416,7 +3416,7 @@ DEFUN (debug_rfapi_query_vn_un_l2o, /* construct option chain */ memset(valbuf, 0, sizeof(valbuf)); - memcpy(valbuf, &l2o_buf.macaddr.octet, ETHER_ADDR_LEN); + memcpy(valbuf, &l2o_buf.macaddr.octet, ETH_ALEN); valbuf[11] = (l2o_buf.logical_net_id >> 16) & 0xff; valbuf[12] = (l2o_buf.logical_net_id >> 8) & 0xff; valbuf[13] = l2o_buf.logical_net_id & 0xff; diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 0bbbe12cce..7e0ed9150b 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -308,7 +308,7 @@ int rfapiGetL2o(struct attr *attr, struct rfapi_l2address_option *l2o) if (pEncap->value[1] == 14) { memcpy(l2o->macaddr.octet, pEncap->value + 2, - ETHER_ADDR_LEN); + ETH_ALEN); l2o->label = ((pEncap->value[10] >> 4) @@ -1327,7 +1327,7 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix, vo->type = RFAPI_VN_OPTION_TYPE_L2ADDR; memcpy(&vo->v.l2addr.macaddr, &rn->p.u.prefix_eth.octet, - ETHER_ADDR_LEN); + ETH_ALEN); /* only low 3 bytes of this are significant */ if (bi->attr) { (void)rfapiEcommunityGetLNI( @@ -3872,6 +3872,10 @@ rfapiBgpInfoFilteredImportFunction(safi_t safi) case SAFI_ENCAP: return rfapiBgpInfoFilteredImportEncap; + + default: + /* not expected */ + return NULL; } zlog_err("%s: bad safi %d", __func__, safi); return NULL; diff --git a/bgpd/rfapi/rfapi_monitor.c b/bgpd/rfapi/rfapi_monitor.c index 9c0d9da6ff..6a7595443a 100644 --- a/bgpd/rfapi/rfapi_monitor.c +++ b/bgpd/rfapi/rfapi_monitor.c @@ -805,7 +805,7 @@ void rfapiMonitorTimersRestart(struct rfapi_descriptor *rfd, struct prefix *p) (void **)&mon_eth, &cursor)) { if (!memcmp(mon_eth->macaddr.octet, - p->u.prefix_eth.octet, ETHER_ADDR_LEN)) { + p->u.prefix_eth.octet, ETH_ALEN)) { rfapiMonitorEthTimerRestart(mon_eth); } @@ -1117,7 +1117,7 @@ static int mon_eth_cmp(void *a, void *b) /* * compare ethernet addresses */ - for (i = 0; i < ETHER_ADDR_LEN; ++i) { + for (i = 0; i < ETH_ALEN; ++i) { if (m1->macaddr.octet[i] != m2->macaddr.octet[i]) return (m1->macaddr.octet[i] - m2->macaddr.octet[i]); } diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c index 791eb4c916..748c0c476b 100644 --- a/bgpd/rfapi/rfapi_rib.c +++ b/bgpd/rfapi/rfapi_rib.c @@ -687,7 +687,7 @@ static void rfapiRibBi2Ri(struct bgp_info *bi, struct rfapi_info *ri, /* copy from RD already stored in bi, so we don't need it_node */ memcpy(&vo->v.l2addr.macaddr, bi->extra->vnc.import.rd.val + 2, - ETHER_ADDR_LEN); + ETH_ALEN); if (bi->attr) { (void)rfapiEcommunityGetLNI( diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 98c3decbd8..e7314d2983 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -3092,7 +3092,7 @@ static int rfapiDeleteLocalPrefixesByRFD(struct rfapi_local_reg_delete_arg *cda, if (memcmp(cda->l2o.o.macaddr.octet, adb->u.s.prefix_eth.u .prefix_eth.octet, - ETHER_ADDR_LEN)) { + ETH_ALEN)) { #if DEBUG_L2_EXTRA vnc_zlog_debug_verbose( "%s: adb=%p, macaddr doesn't match, skipping", @@ -3211,7 +3211,7 @@ static int rfapiDeleteLocalPrefixesByRFD(struct rfapi_local_reg_delete_arg *cda, adb->u.s.prefix_eth.u .prefix_eth .octet, - ETHER_ADDR_LEN)) { + ETH_ALEN)) { continue; } @@ -8,12 +8,21 @@ am__v_CLIPPY_ = $(am__v_CLIPPY_$(AM_DEFAULT_VERBOSITY)) am__v_CLIPPY_0 = @echo " CLIPPY " $@; am__v_CLIPPY_1 = -SUFFIXES = _clippy.c +CLIPPY_DEPS = $(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py + +SUFFIXES = _clippy.c .proto .pb-c.c .pb-c.h .pb.h .c_clippy.c: - $(AM_V_at)$(MAKE) -C $(top_builddir)/$(CLIPPYDIR) clippy - $(AM_V_CLIPPY)$(top_builddir)/$(CLIPPYDIR)/clippy $(top_srcdir)/python/clidef.py $< > $@.tmp + @{ test -x $(top_builddir)/$(HOSTTOOLS)lib/clippy || $(MAKE) -C $(top_builddir)/$(HOSTTOOLS) lib/clippy; } + $(AM_V_CLIPPY)$(top_builddir)/$(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py $< > $@.tmp @{ test -f $@ && diff $@.tmp $@ >/dev/null 2>/dev/null; } && rm $@.tmp || mv $@.tmp $@ +## automake's "ylwrap" is a great piece of GNU software... not. +.l.c: + $(AM_V_LEX)$(am__skiplex) $(LEXCOMPILE) $< +.y.c: + $(AM_V_YACC)$(am__skipyacc) $(YACCCOMPILE) $< + + if HAVE_PROTOBUF # Uncomment to use an non-system version of libprotobuf-c. @@ -27,16 +36,19 @@ Q_PROTOBUF_C_CLIENT_LDOPTS=-lprotobuf-c Q_PROTOC=protoc Q_PROTOC_C=protoc-c -Q_PROTOBUF_CFILES = $(filter %.pb-c.c,$(SOURCES)) - -Q_PROTOBUF_SRCS = $(Q_PROTOBUF_CFILES) $(Q_PROTOBUF_HFILES) - # Rules -%.pb.h: %.proto - $(Q_PROTOC) $(PROTOBUF_INCLUDES) --cpp_out=$(top_srcdir) $(top_srcdir)/$(PROTOBUF_PACKAGE)/$^ +.proto.pb.h: + $(Q_PROTOC) -I$(top_srcdir) --cpp_out=$(top_srcdir) $(top_srcdir)/$^ + +AM_V_PROTOC_C = $(am__v_PROTOC_C_$(V)) +am__v_PROTOC_C_ = $(am__v_PROTOC_C_$(AM_DEFAULT_VERBOSITY)) +am__v_PROTOC_C_0 = @echo " PROTOC_C" $@; +am__v_PROTOC_C_1 = -%.pb-c.c %.pb-c.h: %.proto - $(Q_PROTOC_C) $(PROTOBUF_INCLUDES) --c_out=$(top_srcdir) $(top_srcdir)/$(PROTOBUF_PACKAGE)/$^ +.proto.pb-c.c: + $(AM_V_PROTOC_C)$(Q_PROTOC_C) -I$(top_srcdir) --c_out=$(top_srcdir) $(top_srcdir)/$^ +.pb-c.c.pb-c.h: + @/bin/true # # Information about how to link to various libraries. @@ -46,7 +58,3 @@ Q_FRR_PB_CLIENT_LDOPTS = $(top_srcdir)/qpb/libfrr_pb.la $(Q_PROTOBUF_C_CLIENT_LD Q_FPM_PB_CLIENT_LDOPTS = $(top_srcdir)/fpm/libfrrfpm_pb.la $(Q_FRR_PB_CLIENT_LDOPTS) endif # HAVE_PROTOBUF - -Q_CLEANFILES = $(Q_PROTOBUF_SRCS) - -Q_BUILT_SRCS = $(Q_PROTOBUF_SRCS) diff --git a/configure.ac b/configure.ac index cbda2fc84f..6b5cd19a5f 100755 --- a/configure.ac +++ b/configure.ac @@ -46,12 +46,12 @@ AS_IF([test "$host" != "$build"], [ AC_MSG_NOTICE([...]) build_clippy="false" - CLIPPYDIR="hosttools/lib" + HOSTTOOLS="hosttools/" ], [ build_clippy="true" - CLIPPYDIR="lib" + HOSTTOOLS="" ]) -AC_SUBST(CLIPPYDIR) +AC_SUBST(HOSTTOOLS) AM_CONDITIONAL([BUILD_CLIPPY], [$build_clippy]) # Disable portability warnings -- our automake code (in particular @@ -75,14 +75,13 @@ AC_SUBST(exampledir) dnl default is to match previous behavior pkgsrcrcdir="" -pkgsrcdir="" AC_ARG_ENABLE([pkgsrcrcdir], AS_HELP_STRING([--enable-pkgsrcrcdir], [specify directory for rc.d scripts]), - pkgsrcrcdir="$enableval"; pkgsrcdir="pkgsrc",) + pkgsrcrcdir="$enableval",) dnl XXX add --pkgsrcrcdir to autoconf standard directory list somehow -AC_SUBST(pkgsrcdir) AC_SUBST(pkgsrcrcdir) +AM_CONDITIONAL([PKGSRC], [test "x$pkgsrcrcdir" != "x"]) AC_ARG_WITH([moduledir], [AS_HELP_STRING([--with-moduledir=DIR], [module directory (${libdir}/frr/modules)])], [ moduledir="$withval" @@ -379,7 +378,7 @@ AC_ARG_ENABLE([oldvpn_commands], AS_HELP_STRING([--enable-oldvpn-commands], [Keep old vpn commands])) AC_CHECK_HEADERS(json-c/json.h) -AC_CHECK_LIB(json-c, json_object_get, LIBS="$LIBS -ljson-c") +AC_CHECK_LIB(json-c, json_object_get, LIBS="$LIBS -ljson-c", [], [-lm]) if test $ac_cv_lib_json_c_json_object_get = no; then AC_CHECK_LIB(json, json_object_get, LIBS="$LIBS -ljson") if test $ac_cv_lib_json_json_object_get = no; then @@ -415,26 +414,6 @@ if test "${enable_rr_semantics}" != "no" ; then AC_DEFINE(HAVE_V6_RR_SEMANTICS,, Compile in v6 Route Replacement Semantics) fi -dnl ---------- -dnl MPLS check -dnl ---------- -AC_MSG_CHECKING(whether this OS has MPLS stack) -case "$host" in - *-linux*) - MPLS_METHOD="zebra_mpls_netlink.o" - AC_MSG_RESULT(Linux MPLS) - ;; - *-openbsd*) - MPLS_METHOD="zebra_mpls_openbsd.o" - AC_MSG_RESULT(OpenBSD MPLS) - ;; - *) - MPLS_METHOD="zebra_mpls_null.o" - AC_MSG_RESULT(Unsupported kernel) - ;; -esac -AC_SUBST(MPLS_METHOD) - if test "${enable_datacenter}" = "yes" ; then AC_DEFINE(HAVE_DATACENTER,,Compile extensions for a DataCenter) DFLT_NAME="datacenter" @@ -850,50 +829,62 @@ FRR_INCLUDES dnl V6 headers are checked below, after we check for v6 -dnl Some systems (Solaris 2.x) require libnsl (Network Services Library) -case "$host" in - [*-sunos5.[6-7]*] | [*-solaris2.[6-7]*]) - opsys=sol2-6 - AC_DEFINE(SUNOS_56, 1, SunOS 5.6 to 5.7) - AC_DEFINE(SUNOS_5, 1, SunOS 5) - AC_CHECK_LIB(xnet, main) - CURSES=-lcurses - SOLARIS="solaris" - ;; - [*-sunos5.[8-9]] \ - | [*-sunos5.1[0-9]] \ - | [*-sunos5.1[0-9].[0-9]] \ - | [*-solaris2.[8-9]] \ - | [*-solaris2.1[0-9]] \ - | [*-solaris2.1[0-9].[0-9]]) - opsys=sol8 - AC_DEFINE(SUNOS_59, 1, [SunOS 5.8 up]) - AC_DEFINE(SUNOS_5, 1, [SunOS 5]) - AC_CHECK_LIB(socket, main) - AC_CHECK_LIB(nsl, main) - AC_CHECK_LIB(umem, main) - AC_CHECK_FUNCS([printstack], - [AC_DEFINE([HAVE_PRINTSTACK],1,[Solaris printstack]) - AC_DEFINE([HAVE_STACK_TRACE],1,[Stack symbols decode functionality]) - ]) - CURSES=-lcurses - SOLARIS="solaris" - ;; - *-sunos5* | *-solaris2*) - AC_DEFINE(SUNOS_5,,SunOS 5, Unknown SunOS) - AC_CHECK_LIB(socket, main) - AC_CHECK_LIB(nsl, main) - CURSES=-lcurses - SOLARIS="solaris" - ;; - *-linux*) - opsys=gnu-linux - AC_DEFINE(GNU_LINUX,,GNU Linux) - ;; - *-openbsd*) - opsys=openbsd - AC_DEFINE(OPEN_BSD,,OpenBSD) - ;; +AC_MSG_CHECKING([which operating system interface to use]) +case "$host_os" in + sunos* | solaris2*) + AC_MSG_RESULT([Solaris]) + + AC_DEFINE(SUNOS_5, 1, [SunOS 5]) + AC_DEFINE(SOLARIS_IPV6, 1, Solaris IPv6) + + AC_CHECK_LIB(socket, main) + AC_CHECK_LIB(nsl, main) + AC_CHECK_LIB(umem, main) + AC_CHECK_FUNCS([printstack], [ + AC_DEFINE([HAVE_PRINTSTACK],1,[Solaris printstack]) + AC_DEFINE([HAVE_STACK_TRACE],1,[Stack symbols decode functionality]) + ]) + CURSES=-lcurses + SOLARIS="solaris" + ;; + linux*) + AC_MSG_RESULT([Linux]) + + AC_DEFINE(GNU_LINUX,,GNU Linux) + AC_DEFINE(HAVE_NETLINK,,netlink) + AC_DEFINE(LINUX_IPV6,1,Linux IPv6 stack) + + dnl Linux has a compilation problem with mixing + dnl netinet/in.h and linux/in6.h they are not + dnl compatible. There has been discussion on + dnl how to fix it but no real progress on implementation + dnl when they fix it, remove this + AC_DEFINE(IPV6_MINHOPCOUNT, 73, Linux ipv6 Min Hop Count) + + AC_CHECK_DECLS([IFLA_INFO_SLAVE_KIND], [], [], [#include <linux/if_link.h>]) + ;; + openbsd*) + AC_MSG_RESULT([OpenBSD]) + + AC_DEFINE(OPEN_BSD,,OpenBSD) + AC_DEFINE(KAME,1,KAME IPv6) + + if test "x${enable_pimd}" != "xno"; then + case "$host_os" in + openbsd6.0) + ;; + openbsd[6-9]*) + AC_MSG_FAILURE([pimd cannot be enabled as PIM support has been removed from OpenBSD 6.1]) + ;; + esac + fi + ;; + *) + AC_MSG_RESULT([BSD]) + + AC_DEFINE(HAVE_NET_RT_IFLIST,,NET_RT_IFLIST) + AC_DEFINE(KAME,1,KAME IPv6) + ;; esac AC_SYS_LARGEFILE @@ -1049,26 +1040,6 @@ AC_CHECK_HEADER([asm-generic/unistd.h], AC_CHECK_FUNCS(setns)] ) -dnl ------------------------------------ -dnl Determine routing get and set method -dnl ------------------------------------ -AC_MSG_CHECKING(zebra between kernel interface method) -if test x"$opsys" = x"gnu-linux"; then - AC_MSG_RESULT(netlink) - RT_METHOD=rt_netlink.o - KERNEL_METHOD=kernel_netlink.o - AC_DEFINE(HAVE_NETLINK,,netlink) - netlink=yes - AC_CHECK_DECLS([IFLA_INFO_SLAVE_KIND], [], [], [#include <linux/if_link.h>]) -else - AC_MSG_RESULT(Route socket) - KERNEL_METHOD="kernel_socket.o" - RT_METHOD="rt_socket.o" -fi -AC_SUBST(RT_METHOD) -AC_SUBST(KERNEL_METHOD) -AM_CONDITIONAL([HAVE_NETLINK], [test "x$netlink" = "xyes"]) - dnl -------------------------- dnl Determine IS-IS I/O method dnl -------------------------- @@ -1078,27 +1049,32 @@ AC_DEFINE(ISIS_METHOD_BPF, 3, [ constant value for isis method bpf ]) AC_CHECK_HEADER(net/bpf.h) AC_CHECK_HEADER(sys/dlpi.h) AC_MSG_CHECKING(zebra IS-IS I/O method) -if test x"$opsys" = x"gnu-linux"; then - AC_MSG_RESULT(pfpacket) - ISIS_METHOD_MACRO="ISIS_METHOD_PFPACKET" -elif test x"$opsys" = x"sol2-6" -o x"$opsys" = x"sol8"; then - AC_MSG_RESULT(DLPI) - ISIS_METHOD_MACRO="ISIS_METHOD_DLPI" -else - if test $ac_cv_header_net_bpf_h = no; then - if test $ac_cv_header_sys_dlpi_h = no; then - AC_MSG_RESULT(none) - AC_MSG_WARN([*** IS-IS support will not be built ***]) - ISISD="" + +case "$host_os" in + linux*) + AC_MSG_RESULT(pfpacket) + ISIS_METHOD_MACRO="ISIS_METHOD_PFPACKET" + ;; + solaris* | sunos*) + AC_MSG_RESULT(DLPI) + ISIS_METHOD_MACRO="ISIS_METHOD_DLPI" + ;; + *) + if test $ac_cv_header_net_bpf_h = no; then + if test $ac_cv_header_sys_dlpi_h = no; then + AC_MSG_RESULT(none) + AC_MSG_WARN([*** IS-IS support will not be built ***]) + ISISD="" + else + AC_MSG_RESULT(DLPI) + fi + ISIS_METHOD_MACRO="ISIS_METHOD_DLPI" else - AC_MSG_RESULT(DLPI) + AC_MSG_RESULT(BPF) + ISIS_METHOD_MACRO="ISIS_METHOD_BPF" fi - ISIS_METHOD_MACRO="ISIS_METHOD_DLPI" - else - AC_MSG_RESULT(BPF) - ISIS_METHOD_MACRO="ISIS_METHOD_BPF" - fi -fi + ;; +esac AC_DEFINE_UNQUOTED(ISIS_METHOD, $ISIS_METHOD_MACRO, [ selected method for isis, == one of the constants ]) dnl ------------------------------------ @@ -1128,59 +1104,6 @@ main() }]])],[AC_MSG_RESULT(yes - using workaround) AC_DEFINE(HAVE_BROKEN_CMSG_FIRSTHDR,,Broken CMSG_FIRSTHDR)], [AC_MSG_RESULT(no)],[AC_MSG_RESULT(no)]) -dnl ------------------------------ -dnl check kernel route read method -dnl ------------------------------ -AC_CACHE_CHECK([route read method], [frr_cv_rtread_method], -[if test "x$netlink" = xyes; then - frr_cv_rtread_method="netlink" -else -for frr_cv_rtread_method in /dev/ip /dev/null; -do - test x`ls $frr_cv_rtread_method 2>/dev/null` = x"$frr_cv_rtread_method" && break -done -case $frr_cv_rtread_method in - "/dev/ip") - case "$host" in - *-freebsd*) frr_cv_rtread_method="sysctl";; - *) frr_cv_rtread_method="getmsg";; - esac;; - *) - frr_cv_rtread_method="sysctl";; -esac -fi]) -RTREAD_METHOD=rtread_${frr_cv_rtread_method}.o -AC_SUBST(RTREAD_METHOD) - -dnl ----------------------------- -dnl check interface lookup method -dnl ----------------------------- -IOCTL_METHOD=ioctl.o -AC_MSG_CHECKING(interface looking up method) -if test "$netlink" = yes; then - AC_MSG_RESULT(netlink) - IF_METHOD=if_netlink.o -elif test "$opsys" = "sol2-6";then - AC_MSG_RESULT(Solaris GIF) - IF_METHOD=if_ioctl.o -elif test "$opsys" = "sol8";then - AC_MSG_RESULT(Solaris GLIF) - IF_METHOD=if_ioctl_solaris.o - IOCTL_METHOD=ioctl_solaris.o -elif test "$opsys" = "openbsd";then - AC_MSG_RESULT(openbsd) - IF_METHOD=if_ioctl.o -elif grep NET_RT_IFLIST /usr/include/sys/socket.h >/dev/null 2>&1; then - AC_MSG_RESULT(sysctl) - IF_METHOD=if_sysctl.o - AC_DEFINE(HAVE_NET_RT_IFLIST,,NET_RT_IFLIST) -else - AC_MSG_RESULT(ioctl) - IF_METHOD=if_ioctl.o -fi -AC_SUBST(IF_METHOD) -AC_SUBST(IOCTL_METHOD) - dnl --------------------------------------------------------------- dnl figure out how to specify an interface in multicast sockets API dnl --------------------------------------------------------------- @@ -1276,71 +1199,11 @@ if test $ac_cv_have_decl_TCP_MD5SIG = no; then AC_CHECK_DECLS([TCP_MD5SIG], [], [], MD5_INCLUDES)]) fi -dnl ----------------------------- -dnl check ipforward detect method -dnl ----------------------------- -AC_CACHE_CHECK([ipforward method], [frr_cv_ipforward_method], -[if test x$cross_compiling = xyes; then - if test x"$opsys" = x"gnu-linux"; then - frr_cv_ipforward_method=/proc/net/snmp - else - frr_cv_ipforward_method=/dev/ip - fi -else - for frr_cv_ipforward_method in /proc/net/snmp /dev/ip /dev/null; - do - test x`ls $frr_cv_ipforward_method 2>/dev/null` = x"$frr_cv_ipforward_method" && break - done -fi -case $frr_cv_ipforward_method in - "/proc/net/snmp") frr_cv_ipforward_method="proc";; - "/dev/ip") - case "$host" in - *-freebsd*) frr_cv_ipforward_method="sysctl";; - *) frr_cv_ipforward_method="solaris";; - esac;; - *) frr_cv_ipforward_method="sysctl";; -esac]) -IPFORWARD=ipforward_${frr_cv_ipforward_method}.o -AC_SUBST(IPFORWARD) - dnl ---------------------------------------------------------------------------- dnl figure out if domainname is available in the utsname struct (GNU extension). dnl ---------------------------------------------------------------------------- AC_CHECK_MEMBERS([struct utsname.domainname], [], [], [#include <sys/utsname.h>]) -dnl ---------- -dnl IPv6 check -dnl ---------- -AC_MSG_CHECKING(whether does this OS have IPv6 stack) -dnl --------- -dnl KAME IPv6 -dnl --------- - if grep WIDE /usr/include/netinet6/in6.h >/dev/null 2>&1; then - AC_DEFINE(KAME,1,KAME IPv6) - AC_MSG_RESULT(KAME) -dnl ------------------------------------ -dnl Solaris 9, 10 and potentially higher -dnl ------------------------------------ - elif test x"$opsys" = x"sol8"; then - AC_DEFINE(SOLARIS_IPV6, 1, Solaris IPv6) - AC_MSG_RESULT(Solaris IPv6) -dnl ---------- -dnl Linux IPv6 -dnl ---------- - elif test x"$opsys" = x"gnu-linux"; then - AC_DEFINE(LINUX_IPV6,1,Linux IPv6 stack) - dnl Linux has a compilation problem with mixing - dnl netinet/in.h and linux/in6.h they are not - dnl compatible. There has been discussion on - dnl how to fix it but no real progress on implementation - dnl when they fix it, remove this - AC_DEFINE(IPV6_MINHOPCOUNT, 73, Linux ipv6 Min Hop Count) - AC_MSG_RESULT(Linux IPv6) - else - AC_MSG_ERROR([Failed to detect IPv6 stack]) - fi - dnl ------------------ dnl IPv6 header checks dnl ------------------ @@ -1375,12 +1238,7 @@ fi dnl -------------------- dnl Daemon disable check dnl -------------------- -if test "${enable_zebra}" = "no";then - ZEBRA="" -else - ZEBRA="zebra" -fi -AM_CONDITIONAL(ZEBRA, test "x$ZEBRA" = "xzebra") +AM_CONDITIONAL(ZEBRA, test "${enable_zebra}" != "no") if test "${enable_bgpd}" = "no";then BGPD="" @@ -1412,15 +1270,18 @@ fi AM_CONDITIONAL(LDPD, test "x$LDPD" = "xldpd") NHRPD="" -if test "$opsys" = "gnu-linux"; then - if test "${enable_nhrpd}" != "no"; then - NHRPD="nhrpd" - fi -else - if test "${enable_nhrpd}" = "yes"; then - AC_MSG_ERROR([nhrpd requires kernel APIs that are only present on Linux.]) - fi -fi +case "$host_os" in + linux*) + if test "${enable_nhrpd}" != "no"; then + NHRPD="nhrpd" + fi + ;; + *) + if test "${enable_nhrpd}" = "yes"; then + AC_MSG_ERROR([nhrpd requires kernel APIs that are only present on Linux.]) + fi + ;; +esac AM_CONDITIONAL(NHRPD, test "x$NHRPD" = "xnhrpd") if test "${enable_eigrpd}" = "no";then @@ -1506,7 +1367,6 @@ fi AM_CONDITIONAL([ENABLE_BGP_VNC], [test x${enable_bgp_vnc} != xno]) AC_SUBST(DOC) -AC_SUBST(ZEBRA) AC_SUBST(RFPTEST) AC_SUBST(LIBRFP) AC_SUBST(RFPINC) @@ -1527,7 +1387,8 @@ AC_SUBST(VTYSH) AC_SUBST(CURSES) AC_SUBST(OSPFCLIENT) AC_SUBST(OSPFAPI) -AC_CHECK_LIB(crypt, crypt) +AC_CHECK_LIB(crypt, crypt, [], + [AC_CHECK_LIB(crypto, DES_crypt)]) AC_CHECK_LIB(resolv, res_init) dnl --------------------------- @@ -1969,22 +1830,17 @@ AC_CACHE_VAL(ac_cv_htonl_works, ) AC_MSG_RESULT($ac_cv_htonl_works) -AC_CONFIG_FILES([Makefile lib/Makefile qpb/Makefile zebra/Makefile ripd/Makefile +AC_CONFIG_FILES([Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile watchfrr/Makefile ospf6d/Makefile ldpd/Makefile isisd/Makefile vtysh/Makefile - doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile + doc/Makefile ospfclient/Makefile tests/Makefile bgpd/rfp-example/rfptest/Makefile bgpd/rfp-example/librfp/Makefile babeld/Makefile pimd/Makefile eigrpd/Makefile nhrpd/Makefile - redhat/Makefile tools/Makefile - pkgsrc/Makefile - python/Makefile - fpm/Makefile redhat/frr.spec - snapcraft/Makefile snapcraft/snapcraft.yaml lib/version.h tests/lib/cli/test_cli.refout diff --git a/doc/babeld.texi b/doc/babeld.texi index 2dfb5f8c0a..341f692869 100644 --- a/doc/babeld.texi +++ b/doc/babeld.texi @@ -179,8 +179,8 @@ The default is 4@dmn{s}. @node Babel redistribution, Show Babel information, Babel configuration, Babel @section Babel redistribution -@deffn {Babel command} {redistribute @var{kind}} -@deffnx {Babel command} {no redistribute @var{kind}} +@deffn {Babel command} {redistribute @var{<ipv4|ipv6>} @var{kind}} +@deffnx {Babel command} {no redistribute @var{<ipv4|ipv6>} @var{kind}} Specify which kind of routes should be redistributed into Babel. @end deffn diff --git a/eigrpd/eigrp_dump.c b/eigrpd/eigrp_dump.c index ba24abe5b3..15a8a71cf3 100644 --- a/eigrpd/eigrp_dump.c +++ b/eigrpd/eigrp_dump.c @@ -395,11 +395,11 @@ DEFUN (debug_eigrp_transmit, flag = EIGRP_DEBUG_SEND; else if (argv_find(argv, argc, "recv", &idx)) flag = EIGRP_DEBUG_RECV; - else if (argv_find(argv, argc, "all", &idx) == 0) + else if (argv_find(argv, argc, "all", &idx)) flag = EIGRP_DEBUG_SEND_RECV; /* detail option */ - if (argv_find(argv, argc, "detail", &idx) == 0) + if (argv_find(argv, argc, "detail", &idx)) flag = EIGRP_DEBUG_PACKET_DETAIL; if (vty->node == CONFIG_NODE) @@ -426,15 +426,15 @@ DEFUN (no_debug_eigrp_transmit, int idx = 3; /* send or recv. */ - if (argv_find(argv, argc, "send", &idx) == 0) + if (argv_find(argv, argc, "send", &idx)) flag = EIGRP_DEBUG_SEND; - else if (argv_find(argv, argc, "recv", &idx) == 0) + else if (argv_find(argv, argc, "recv", &idx)) flag = EIGRP_DEBUG_RECV; - else if (argv_find(argv, argc, "all", &idx) == 0) + else if (argv_find(argv, argc, "all", &idx)) flag = EIGRP_DEBUG_SEND_RECV; /* detail option */ - if (argv_find(argv, argc, "detail", &idx) == 0) + if (argv_find(argv, argc, "detail", &idx)) flag = EIGRP_DEBUG_PACKET_DETAIL; if (vty->node == CONFIG_NODE) @@ -474,27 +474,27 @@ DEFUN (debug_eigrp_packets, int idx = 0; /* Check packet type. */ - if (argv_find(argv, argc, "hello", &idx) == 0) + if (argv_find(argv, argc, "hello", &idx)) type = EIGRP_DEBUG_HELLO; - if (argv_find(argv, argc, "update", &idx) == 0) + if (argv_find(argv, argc, "update", &idx)) type = EIGRP_DEBUG_UPDATE; - if (argv_find(argv, argc, "query", &idx) == 0) + if (argv_find(argv, argc, "query", &idx)) type = EIGRP_DEBUG_QUERY; - if (argv_find(argv, argc, "ack", &idx) == 0) + if (argv_find(argv, argc, "ack", &idx)) type = EIGRP_DEBUG_ACK; - if (argv_find(argv, argc, "probe", &idx) == 0) + if (argv_find(argv, argc, "probe", &idx)) type = EIGRP_DEBUG_PROBE; - if (argv_find(argv, argc, "stub", &idx) == 0) + if (argv_find(argv, argc, "stub", &idx)) type = EIGRP_DEBUG_STUB; - if (argv_find(argv, argc, "reply", &idx) == 0) + if (argv_find(argv, argc, "reply", &idx)) type = EIGRP_DEBUG_REPLY; - if (argv_find(argv, argc, "request", &idx) == 0) + if (argv_find(argv, argc, "request", &idx)) type = EIGRP_DEBUG_REQUEST; - if (argv_find(argv, argc, "siaquery", &idx) == 0) + if (argv_find(argv, argc, "siaquery", &idx)) type = EIGRP_DEBUG_SIAQUERY; - if (argv_find(argv, argc, "siareply", &idx) == 0) + if (argv_find(argv, argc, "siareply", &idx)) type = EIGRP_DEBUG_SIAREPLY; - if (argv_find(argv, argc, "all", &idx) == 0) + if (argv_find(argv, argc, "all", &idx)) type = EIGRP_DEBUG_PACKETS_ALL; @@ -502,13 +502,13 @@ DEFUN (debug_eigrp_packets, flag = EIGRP_DEBUG_SEND_RECV; /* send or recv. */ - if (argv_find(argv, argc, "s", &idx) == 0) + if (argv_find(argv, argc, "s", &idx)) flag = EIGRP_DEBUG_SEND; - else if (argv_find(argv, argc, "r", &idx) == 0) + else if (argv_find(argv, argc, "r", &idx)) flag = EIGRP_DEBUG_RECV; /* detail. */ - if (argv_find(argv, argc, "detail", &idx) == 0) + if (argv_find(argv, argc, "detail", &idx)) flag |= EIGRP_DEBUG_PACKET_DETAIL; for (i = 0; i < 11; i++) @@ -552,38 +552,38 @@ DEFUN (no_debug_eigrp_packets, int idx = 0; /* Check packet type. */ - if (argv_find(argv, argc, "hello", &idx) == 0) + if (argv_find(argv, argc, "hello", &idx)) type = EIGRP_DEBUG_HELLO; - if (argv_find(argv, argc, "update", &idx) == 0) + if (argv_find(argv, argc, "update", &idx)) type = EIGRP_DEBUG_UPDATE; - if (argv_find(argv, argc, "query", &idx) == 0) + if (argv_find(argv, argc, "query", &idx)) type = EIGRP_DEBUG_QUERY; - if (argv_find(argv, argc, "ack", &idx) == 0) + if (argv_find(argv, argc, "ack", &idx)) type = EIGRP_DEBUG_ACK; - if (argv_find(argv, argc, "probe", &idx) == 0) + if (argv_find(argv, argc, "probe", &idx)) type = EIGRP_DEBUG_PROBE; - if (argv_find(argv, argc, "stub", &idx) == 0) + if (argv_find(argv, argc, "stub", &idx)) type = EIGRP_DEBUG_STUB; - if (argv_find(argv, argc, "reply", &idx) == 0) + if (argv_find(argv, argc, "reply", &idx)) type = EIGRP_DEBUG_REPLY; - if (argv_find(argv, argc, "request", &idx) == 0) + if (argv_find(argv, argc, "request", &idx)) type = EIGRP_DEBUG_REQUEST; - if (argv_find(argv, argc, "siaquery", &idx) == 0) + if (argv_find(argv, argc, "siaquery", &idx)) type = EIGRP_DEBUG_SIAQUERY; - if (argv_find(argv, argc, "siareply", &idx) == 0) + if (argv_find(argv, argc, "siareply", &idx)) type = EIGRP_DEBUG_SIAREPLY; /* Default, both send and recv. */ flag = EIGRP_DEBUG_SEND_RECV; /* send or recv. */ - if (argv_find(argv, argc, "send", &idx) == 0) + if (argv_find(argv, argc, "send", &idx)) flag = EIGRP_DEBUG_SEND; - else if (argv_find(argv, argc, "reply", &idx) == 0) + else if (argv_find(argv, argc, "reply", &idx)) flag = EIGRP_DEBUG_RECV; /* detail. */ - if (argv_find(argv, argc, "detail", &idx) == 0) + if (argv_find(argv, argc, "detail", &idx)) flag |= EIGRP_DEBUG_PACKET_DETAIL; for (i = 0; i < 11; i++) diff --git a/eigrpd/eigrp_packet.c b/eigrpd/eigrp_packet.c index f20ec0ad12..3befd8a118 100644 --- a/eigrpd/eigrp_packet.c +++ b/eigrpd/eigrp_packet.c @@ -161,6 +161,7 @@ int eigrp_check_md5_digest(struct stream *s, { MD5_CTX ctx; unsigned char digest[EIGRP_AUTH_TYPE_MD5_LEN]; + unsigned char orig[EIGRP_AUTH_TYPE_MD5_LEN]; struct key *key = NULL; struct keychain *keychain; u_char *ibuf; @@ -181,7 +182,9 @@ int eigrp_check_md5_digest(struct stream *s, auth_TLV = (struct TLV_MD5_Authentication_Type *)(s->data + EIGRP_HEADER_LEN); - memset(auth_TLV->digest, 0, sizeof(auth_TLV->digest)); + memcpy(orig, auth_TLV->digest, EIGRP_AUTH_TYPE_MD5_LEN); + memset(digest, 0, EIGRP_AUTH_TYPE_MD5_LEN); + memset(auth_TLV->digest, 0, EIGRP_AUTH_TYPE_MD5_LEN); ibuf = s->data; backup_end = s->endp; @@ -219,16 +222,15 @@ int eigrp_check_md5_digest(struct stream *s, MD5Final(digest, &ctx); /* compare the two */ - if (memcmp(authTLV->digest, digest, EIGRP_AUTH_TYPE_MD5_LEN) == 0) { - zlog_debug("VSETKO OK"); - } else { + if (memcmp(orig, digest, EIGRP_AUTH_TYPE_MD5_LEN) != 0) { zlog_warn("interface %s: eigrp_check_md5 checksum mismatch", IF_NAME(nbr->ei)); return 0; } /* save neighbor's crypt_seqnum */ - nbr->crypt_seqnum = authTLV->key_sequence; + if (nbr) + nbr->crypt_seqnum = authTLV->key_sequence; return 1; } @@ -884,6 +886,7 @@ void eigrp_packet_header_init(int type, struct eigrp_interface *ei, { struct eigrp_header *eigrph; + stream_reset(s); eigrph = (struct eigrp_header *)STREAM_DATA(s); eigrph->version = (u_char)EIGRP_HEADER_VERSION; diff --git a/eigrpd/eigrp_update.c b/eigrpd/eigrp_update.c index 3c2ce6ce42..e0169c514b 100644 --- a/eigrpd/eigrp_update.c +++ b/eigrpd/eigrp_update.c @@ -504,10 +504,36 @@ void eigrp_update_send_init(struct eigrp_neighbor *nbr) } } +static void eigrp_update_place_on_nbr_queue(struct eigrp_neighbor *nbr, + struct eigrp_packet *ep, + u_int32_t seq_no, + int length) +{ + if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && + (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) { + eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG); + } + + /* EIGRP Checksum */ + eigrp_packet_checksum(nbr->ei, ep->s, length); + + ep->length = length; + ep->dst.s_addr = nbr->src.s_addr; + + /*This ack number we await from neighbor*/ + ep->sequence_number = seq_no; + + if (IS_DEBUG_EIGRP_PACKET(0, RECV)) + zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]", + ep->length, ep->sequence_number, inet_ntoa(ep->dst)); + + /*Put packet to retransmission queue*/ + eigrp_fifo_push_head(nbr->retrans_queue, ep); +} + void eigrp_update_send_EOT(struct eigrp_neighbor *nbr) { struct eigrp_packet *ep; - // struct eigrp_packet *ep_multicast; u_int16_t length = EIGRP_HEADER_LEN; struct eigrp_neighbor_entry *te; struct eigrp_prefix_entry *pe; @@ -518,38 +544,53 @@ void eigrp_update_send_EOT(struct eigrp_neighbor *nbr) struct prefix_list *plist_i; struct eigrp *e; struct prefix_ipv4 *dest_addr; + u_int32_t seq_no = nbr->ei->eigrp->sequence_number; ep = eigrp_packet_new(nbr->ei->ifp->mtu); /* Prepare EIGRP EOT UPDATE header */ - eigrp_packet_header_init( - EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_EOT_FLAG, - nbr->ei->eigrp->sequence_number, nbr->recv_sequence_number); + eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_EOT_FLAG, + seq_no, + nbr->recv_sequence_number); // encode Authentication TLV, if needed - if ((IF_DEF_PARAMS(nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) - && (IF_DEF_PARAMS(nbr->ei->ifp)->auth_keychain != NULL)) { - length += eigrp_add_authTLV_MD5_to_stream(ep->s, nbr->ei); + if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && + (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) { + length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei); } - for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node, nnode, - pe)) { + for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node, nnode, pe)) { for (ALL_LIST_ELEMENTS(pe->entries, node2, nnode2, te)) { if ((te->ei == nbr->ei) && (te->prefix->nt == EIGRP_TOPOLOGY_TYPE_REMOTE)) continue; + if ((length + 0x001D) > (u_int16_t)nbr->ei->ifp->mtu) { + eigrp_update_place_on_nbr_queue (nbr, ep, seq_no, length); + eigrp_send_packet_reliably(nbr); + seq_no++; + + length = EIGRP_HEADER_LEN; + ep = eigrp_packet_new(nbr->ei->ifp->mtu); + eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_EOT_FLAG, + seq_no, nbr->recv_sequence_number); + + if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && + (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) + { + length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei); + } + } /* Get destination address from prefix */ dest_addr = pe->destination_ipv4; /* * Filtering */ - // TODO: Work in progress + //TODO: Work in progress /* get list from eigrp process */ e = eigrp_lookup(); - /* Get access-lists and prefix-lists from process and - * interface */ + /* Get access-lists and prefix-lists from process and interface */ alist = e->list[EIGRP_FILTER_OUT]; plist = e->prefix[EIGRP_FILTER_OUT]; alist_i = nbr->ei->list[EIGRP_FILTER_OUT]; @@ -557,65 +598,24 @@ void eigrp_update_send_EOT(struct eigrp_neighbor *nbr) /* Check if any list fits */ if ((alist - && access_list_apply(alist, - (struct prefix *)dest_addr) - == FILTER_DENY) - || (plist - && prefix_list_apply(plist, - (struct prefix *)dest_addr) - == PREFIX_DENY) - || (alist_i - && access_list_apply(alist_i, - (struct prefix *)dest_addr) - == FILTER_DENY) - || (plist_i - && prefix_list_apply(plist_i, - (struct prefix *)dest_addr) - == PREFIX_DENY)) { - zlog_info("PROC OUT EOT: Skipping"); - // pe->reported_metric.delay = EIGRP_MAX_METRIC; - zlog_info("PROC OUT EOT Prefix: %s", - inet_ntoa(dest_addr->prefix)); + && access_list_apply (alist, + (struct prefix *) dest_addr) == FILTER_DENY)|| + (plist && prefix_list_apply (plist, + (struct prefix *) dest_addr) == PREFIX_DENY)|| + (alist_i && access_list_apply (alist_i, + (struct prefix *) dest_addr) == FILTER_DENY)|| + (plist_i && prefix_list_apply (plist_i, + (struct prefix *) dest_addr) == PREFIX_DENY)) { + //pe->reported_metric.delay = EIGRP_MAX_METRIC; continue; } else { - zlog_info( - "PROC OUT EOT: NENastavujem metriku "); - length += eigrp_add_internalTLV_to_stream(ep->s, - pe); + length += eigrp_add_internalTLV_to_stream(ep->s, pe); } - /* - * End of filtering - */ - - /* NULL the pointer */ - dest_addr = NULL; } } - if ((IF_DEF_PARAMS(nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) - && (IF_DEF_PARAMS(nbr->ei->ifp)->auth_keychain != NULL)) { - eigrp_make_md5_digest(nbr->ei, ep->s, EIGRP_AUTH_UPDATE_FLAG); - } - - /* EIGRP Checksum */ - eigrp_packet_checksum(nbr->ei, ep->s, length); - - ep->length = length; - ep->dst.s_addr = nbr->src.s_addr; - - /*This ack number we await from neighbor*/ - ep->sequence_number = nbr->ei->eigrp->sequence_number; - - if (IS_DEBUG_EIGRP_PACKET(0, RECV)) - zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]", - ep->length, ep->sequence_number, inet_ntoa(ep->dst)); - - /*Put packet to retransmission queue*/ - eigrp_fifo_push_head(nbr->retrans_queue, ep); - - if (nbr->retrans_queue->count == 1) { - eigrp_send_packet_reliably(nbr); - } + eigrp_update_place_on_nbr_queue (nbr, ep, seq_no, length); + eigrp_send_packet_reliably(nbr); } void eigrp_update_send(struct eigrp_interface *ei) diff --git a/fpm/.gitignore b/fpm/.gitignore index b133c52a42..17e90443e9 100644 --- a/fpm/.gitignore +++ b/fpm/.gitignore @@ -1,4 +1,4 @@ -Makefile +!Makefile Makefile.in *.o tags diff --git a/fpm/Makefile b/fpm/Makefile new file mode 100644 index 0000000000..1d280d176e --- /dev/null +++ b/fpm/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. fpm/libfrrfpm_pb.la +%: ALWAYS + @$(MAKE) -s -C .. fpm/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/fpm/Makefile.am b/fpm/Makefile.am deleted file mode 100644 index 1f46ac6db2..0000000000 --- a/fpm/Makefile.am +++ /dev/null @@ -1,29 +0,0 @@ -include ../common.am - -AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib $(Q_PROTOBUF_C_CLIENT_INCLUDES) - -PROTOBUF_INCLUDES=-I$(top_srcdir) -PROTOBUF_PACKAGE = fpm - -lib_LTLIBRARIES = libfrrfpm_pb.la -libfrrfpm_pb_la_LDFLAGS = -version-info 0:0:0 - -if HAVE_PROTOBUF -protobuf_srcs = - -protobuf_srcs_nodist = \ - fpm.pb-c.c -endif - -libfrrfpm_pb_la_SOURCES = \ - fpm.h \ - fpm_pb.h \ - fpm_pb.c \ - $(protobuf_srcs) - -nodist_libfrrfpm_pb_la_SOURCES = $(protobuf_srcs_nodist) - -CLEANFILES = $(Q_CLEANFILES) - -BUILT_SOURCES = $(Q_PROTOBUF_SRCS) -EXTRA_DIST = fpm.proto diff --git a/fpm/fpm.proto b/fpm/fpm.proto index 318e80a92e..4597c7f8eb 100644 --- a/fpm/fpm.proto +++ b/fpm/fpm.proto @@ -20,6 +20,8 @@ // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // +syntax = "proto2"; + // // Protobuf definitions pertaining to the Forwarding Plane Manager component. // diff --git a/fpm/subdir.am b/fpm/subdir.am new file mode 100644 index 0000000000..f81a84222c --- /dev/null +++ b/fpm/subdir.am @@ -0,0 +1,23 @@ +if FPM +lib_LTLIBRARIES += fpm/libfrrfpm_pb.la +endif + +fpm_libfrrfpm_pb_la_LDFLAGS = -version-info 0:0:0 +fpm_libfrrfpm_pb_la_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir) -I$(top_builddir)/lib \ + $(Q_PROTOBUF_C_CLIENT_INCLUDES) +fpm_libfrrfpm_pb_la_SOURCES = \ + fpm/fpm.h \ + fpm/fpm_pb.h \ + fpm/fpm_pb.c \ + # end + +if HAVE_PROTOBUF +nodist_fpm_libfrrfpm_pb_la_SOURCES = fpm/fpm.pb-c.c +BUILT_SOURCES += fpm/fpm.pb-c.c +CLEANFILES += \ + fpm/fpm.pb-c.c \ + fpm/fpm.pb-c.h \ + # end +endif + +EXTRA_DIST += fpm/fpm.proto diff --git a/isisd/Makefile.am b/isisd/Makefile.am index 2973820eed..dc3d3683a1 100644 --- a/isisd/Makefile.am +++ b/isisd/Makefile.am @@ -8,24 +8,26 @@ LIBS = @LIBS@ AM_CFLAGS = $(WERROR) noinst_LIBRARIES = libisis.a -sbin_PROGRAMS = isisd +sbin_PROGRAMS = isisd libisis_a_SOURCES = \ isis_memory.c \ isis_adjacency.c isis_lsp.c dict.c isis_circuit.c isis_pdu.c \ - isis_tlv.c isisd.c isis_misc.c isis_zebra.c isis_dr.c \ + isisd.c isis_misc.c isis_zebra.c isis_dr.c \ isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \ isis_spf.c isis_redist.c isis_route.c isis_routemap.c isis_te.c \ - isis_vty.c isis_mt.c + isis_vty.c isis_mt.c \ + isis_tlvs.c noinst_HEADERS = \ isis_memory.h \ - isisd.h isis_pdu.h isis_tlv.h isis_adjacency.h isis_constants.h \ + isisd.h isis_pdu.h isis_adjacency.h isis_constants.h \ isis_lsp.h dict.h isis_circuit.h isis_misc.h isis_network.h \ isis_zebra.h isis_dr.h isis_flags.h isis_dynhn.h isis_common.h \ iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_redist.h \ - isis_route.h isis_routemap.h isis_te.h isis_mt.h + isis_route.h isis_routemap.h isis_te.h isis_mt.h \ + isis_tlvs.h isisd_SOURCES = \ isis_main.c $(libisis_a_SOURCES) \ diff --git a/isisd/dict.c b/isisd/dict.c index f09a8152a8..2ea86d1b68 100644 --- a/isisd/dict.c +++ b/isisd/dict.c @@ -174,6 +174,7 @@ static int verify_bintree(dict_t *dict) * subtree is not red-black. */ +#ifdef EXTREME_DICT_DEBUG static unsigned int verify_redblack(dnode_t *nil, dnode_t *root) { unsigned height_left, height_right; @@ -198,6 +199,7 @@ static unsigned int verify_redblack(dnode_t *nil, dnode_t *root) } return 1; } +#endif /* * Compute the actual count of nodes by traversing the tree and @@ -205,6 +207,7 @@ static unsigned int verify_redblack(dnode_t *nil, dnode_t *root) * detect a mismatch. */ +#ifdef EXTREME_DICT_DEBUG static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root) { if (root == nil) @@ -213,6 +216,7 @@ static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root) return 1 + verify_node_count(nil, root->left) + verify_node_count(nil, root->right); } +#endif /* * Verify that the tree contains the given node. This is done by @@ -369,6 +373,7 @@ static void dict_clear(dict_t *dict) int dict_verify(dict_t *dict) { +#ifdef EXTREME_DICT_DEBUG dnode_t *nil = dict_nil(dict), *root = dict_root(dict); /* check that the sentinel node and root node are black */ @@ -389,6 +394,7 @@ int dict_verify(dict_t *dict) return 0; if (verify_node_count(nil, root) != dict_count(dict)) return 0; +#endif return 1; } diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index d8cb32375b..0afa65d726 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -43,7 +43,6 @@ #include "isisd/isis_dr.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_pdu.h" -#include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_spf.h" #include "isisd/isis_events.h" @@ -69,11 +68,6 @@ struct isis_adjacency *isis_new_adj(const u_char *id, const u_char *snpa, adj = adj_alloc(id); /* P2P kludge */ - if (adj == NULL) { - zlog_err("Out of memory!"); - return NULL; - } - if (snpa) { memcpy(adj->snpa, snpa, ETH_ALEN); } else { @@ -137,12 +131,12 @@ void isis_delete_adj(void *arg) /* remove from SPF trees */ spftree_area_adj_del(adj->circuit->area, adj); - if (adj->area_addrs) - list_delete(adj->area_addrs); - if (adj->ipv4_addrs) - list_delete(adj->ipv4_addrs); - if (adj->ipv6_addrs) - list_delete(adj->ipv6_addrs); + if (adj->area_addresses) + XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses); + if (adj->ipv4_addresses) + XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses); + if (adj->ipv6_addresses) + XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv6_addresses); adj_mt_finish(adj); @@ -192,7 +186,7 @@ void isis_adj_state_change(struct isis_adjacency *adj, dyn = dynhn_find_by_id(adj->sysid); if (dyn) - adj_name = (const char *)dyn->name.name; + adj_name = dyn->hostname; else adj_name = sysid_print(adj->sysid); @@ -301,33 +295,29 @@ void isis_adj_state_change(struct isis_adjacency *adj, void isis_adj_print(struct isis_adjacency *adj) { struct isis_dynhn *dyn; - struct listnode *node; - struct in_addr *ipv4_addr; - struct in6_addr *ipv6_addr; - u_char ip6[INET6_ADDRSTRLEN]; if (!adj) return; dyn = dynhn_find_by_id(adj->sysid); if (dyn) - zlog_debug("%s", dyn->name.name); + zlog_debug("%s", dyn->hostname); zlog_debug("SystemId %20s SNPA %s, level %d\nHolding Time %d", sysid_print(adj->sysid), snpa_print(adj->snpa), adj->level, adj->hold_time); - if (adj->ipv4_addrs && listcount(adj->ipv4_addrs) > 0) { + if (adj->ipv4_address_count) { zlog_debug("IPv4 Address(es):"); - - for (ALL_LIST_ELEMENTS_RO(adj->ipv4_addrs, node, ipv4_addr)) - zlog_debug("%s", inet_ntoa(*ipv4_addr)); + for (unsigned int i = 0; i < adj->ipv4_address_count; i++) + zlog_debug("%s", inet_ntoa(adj->ipv4_addresses[i])); } - if (adj->ipv6_addrs && listcount(adj->ipv6_addrs) > 0) { + if (adj->ipv6_address_count) { zlog_debug("IPv6 Address(es):"); - for (ALL_LIST_ELEMENTS_RO(adj->ipv6_addrs, node, ipv6_addr)) { - inet_ntop(AF_INET6, ipv6_addr, (char *)ip6, - INET6_ADDRSTRLEN); - zlog_debug("%s", ip6); + for (unsigned int i = 0; i < adj->ipv6_address_count; i++) { + char buf[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &adj->ipv6_addresses[i], buf, + sizeof(buf)); + zlog_debug("%s", buf); } } zlog_debug("Speaks: %s", nlpid2string(&adj->nlpids)); @@ -358,17 +348,13 @@ int isis_adj_expire(struct thread *thread) void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty, char detail) { - struct in6_addr *ipv6_addr; - u_char ip6[INET6_ADDRSTRLEN]; - struct in_addr *ip_addr; time_t now; struct isis_dynhn *dyn; int level; - struct listnode *node; dyn = dynhn_find_by_id(adj->sysid); if (dyn) - vty_out(vty, " %-20s", dyn->name.name); + vty_out(vty, " %-20s", dyn->hostname); else vty_out(vty, " %-20s", sysid_print(adj->sysid)); @@ -429,8 +415,7 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty, && (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) { dyn = dynhn_find_by_id(adj->lanid); if (dyn) - vty_out(vty, ", LAN id: %s.%02x", - dyn->name.name, + vty_out(vty, ", LAN id: %s.%02x", dyn->hostname, adj->lanid[ISIS_SYS_ID_LEN]); else vty_out(vty, ", LAN id: %s.%02x", @@ -452,28 +437,32 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty, } vty_out(vty, "\n"); - if (adj->area_addrs && listcount(adj->area_addrs) > 0) { - struct area_addr *area_addr; + if (adj->area_address_count) { vty_out(vty, " Area Address(es):\n"); - for (ALL_LIST_ELEMENTS_RO(adj->area_addrs, node, - area_addr)) + for (unsigned int i = 0; i < adj->area_address_count; + i++) { vty_out(vty, " %s\n", - isonet_print(area_addr->area_addr, - area_addr->addr_len)); + isonet_print(adj->area_addresses[i] + .area_addr, + adj->area_addresses[i] + .addr_len)); + } } - if (adj->ipv4_addrs && listcount(adj->ipv4_addrs) > 0) { + if (adj->ipv4_address_count) { vty_out(vty, " IPv4 Address(es):\n"); - for (ALL_LIST_ELEMENTS_RO(adj->ipv4_addrs, node, - ip_addr)) - vty_out(vty, " %s\n", inet_ntoa(*ip_addr)); + for (unsigned int i = 0; i < adj->ipv4_address_count; + i++) + vty_out(vty, " %s\n", + inet_ntoa(adj->ipv4_addresses[i])); } - if (adj->ipv6_addrs && listcount(adj->ipv6_addrs) > 0) { + if (adj->ipv6_address_count) { vty_out(vty, " IPv6 Address(es):\n"); - for (ALL_LIST_ELEMENTS_RO(adj->ipv6_addrs, node, - ipv6_addr)) { - inet_ntop(AF_INET6, ipv6_addr, (char *)ip6, - INET6_ADDRSTRLEN); - vty_out(vty, " %s\n", ip6); + for (unsigned int i = 0; i < adj->ipv6_address_count; + i++) { + char buf[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &adj->ipv6_addresses[i], + buf, sizeof(buf)); + vty_out(vty, " %s\n", buf); } } vty_out(vty, "\n"); diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index 9f4af1b45d..98bb9838fa 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -73,13 +73,16 @@ struct isis_adjacency { int dischanges[ISIS_LEVELS]; /* how many DIS changes ? */ /* an array of N levels for M records */ struct isis_dis_record dis_record[DIS_RECORDS * ISIS_LEVELS]; - enum isis_adj_state adj_state; /* adjacencyState */ - enum isis_adj_usage adj_usage; /* adjacencyUsage */ - struct list *area_addrs; /* areaAdressesOfNeighbour */ - struct nlpids nlpids; /* protocols spoken ... */ - struct list *ipv4_addrs; + enum isis_adj_state adj_state; /* adjacencyState */ + enum isis_adj_usage adj_usage; /* adjacencyUsage */ + struct area_addr *area_addresses; /* areaAdressesOfNeighbour */ + unsigned int area_address_count; + struct nlpids nlpids; /* protocols spoken ... */ + struct in_addr *ipv4_addresses; + unsigned int ipv4_address_count; struct in_addr router_address; - struct list *ipv6_addrs; + struct in6_addr *ipv6_addresses; + unsigned int ipv6_address_count; struct in6_addr router_address6; u_char prio[ISIS_LEVELS]; /* priorityOfNeighbour for DIS */ int circuit_t; /* from hello PDU hdr */ diff --git a/isisd/isis_bpf.c b/isisd/isis_bpf.c index 69c2f941f0..98f612f827 100644 --- a/isisd/isis_bpf.c +++ b/isisd/isis_bpf.c @@ -250,8 +250,8 @@ int isis_recv_pdu_bcast(struct isis_circuit *circuit, u_char *ssnpa) bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN); stream_set_getp(circuit->rcv_stream, 0); - memcpy(ssnpa, readbuff + bpf_hdr->bh_hdrlen + ETHER_ADDR_LEN, - ETHER_ADDR_LEN); + memcpy(ssnpa, readbuff + bpf_hdr->bh_hdrlen + ETH_ALEN, + ETH_ALEN); if (ioctl(circuit->fd, BIOCFLUSH, &one) < 0) zlog_warn("Flushing failed: %s", safe_strerror(errno)); @@ -281,10 +281,10 @@ int isis_send_pdu_bcast(struct isis_circuit *circuit, int level) */ eth = (struct ether_header *)sock_buff; if (level == 1) - memcpy(eth->ether_dhost, ALL_L1_ISS, ETHER_ADDR_LEN); + memcpy(eth->ether_dhost, ALL_L1_ISS, ETH_ALEN); else - memcpy(eth->ether_dhost, ALL_L2_ISS, ETHER_ADDR_LEN); - memcpy(eth->ether_shost, circuit->u.bc.snpa, ETHER_ADDR_LEN); + memcpy(eth->ether_dhost, ALL_L2_ISS, ETH_ALEN); + memcpy(eth->ether_shost, circuit->u.bc.snpa, ETH_ALEN); size_t frame_size = stream_get_endp(circuit->snd_stream) + LLC_LEN; eth->ether_type = htons(isis_ethertype(frame_size)); diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 72810532b0..9622dcdbc4 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -26,10 +26,6 @@ #include <netinet/if_ether.h> #endif -#ifndef ETHER_ADDR_LEN -#define ETHER_ADDR_LEN ETHERADDRL -#endif - #include "log.h" #include "memory.h" #include "vrf.h" @@ -48,7 +44,6 @@ #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" -#include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_pdu.h" #include "isisd/isis_network.h" diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index 5e523cd68b..ad53be4683 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -26,6 +26,7 @@ #include "vty.h" #include "if.h" #include "qobj.h" +#include "prefix.h" #include "isis_constants.h" #include "isis_common.h" diff --git a/isisd/isis_common.h b/isisd/isis_common.h index ba6c5f876d..b157bb1836 100644 --- a/isisd/isis_common.h +++ b/isisd/isis_common.h @@ -47,16 +47,6 @@ struct isis_passwd { }; /* - * (Dynamic) Hostname - * one struct for cache list - * one struct for LSP TLV - */ -struct hostname { - u_char namelen; - u_char name[255]; -}; - -/* * Supported Protocol IDs */ struct nlpids { diff --git a/isisd/isis_constants.h b/isisd/isis_constants.h index 4b5ff888ba..f3a5a24dde 100644 --- a/isisd/isis_constants.h +++ b/isisd/isis_constants.h @@ -167,10 +167,6 @@ ((if_is_broadcast((C)->interface)) ? (C->interface->mtu - LLC_LEN) \ : (C->interface->mtu)) -#ifndef ETH_ALEN -#define ETH_ALEN 6 -#endif - #define MAX_LLC_LEN 0x5ff #define ETHERTYPE_EXT_LLC 0x8870 diff --git a/isisd/isis_csm.c b/isisd/isis_csm.c index b0ccdee769..10870d5c50 100644 --- a/isisd/isis_csm.c +++ b/isisd/isis_csm.c @@ -37,7 +37,6 @@ #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" -#include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_pdu.h" #include "isisd/isis_network.h" diff --git a/isisd/isis_dr.c b/isisd/isis_dr.c index 3f532ecf84..2db8271915 100644 --- a/isisd/isis_dr.c +++ b/isisd/isis_dr.c @@ -42,7 +42,6 @@ #include "isisd/isis_adjacency.h" #include "isisd/isis_constants.h" #include "isisd/isis_pdu.h" -#include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_dr.h" #include "isisd/isis_events.h" diff --git a/isisd/isis_dynhn.c b/isisd/isis_dynhn.c index 9249ad6290..6fa7988304 100644 --- a/isisd/isis_dynhn.c +++ b/isisd/isis_dynhn.c @@ -94,38 +94,26 @@ struct isis_dynhn *dynhn_find_by_name(const char *hostname) struct isis_dynhn *dyn = NULL; for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn)) - if (strncmp((char *)dyn->name.name, hostname, 255) == 0) + if (strncmp(dyn->hostname, hostname, 255) == 0) return dyn; return NULL; } -void isis_dynhn_insert(const u_char *id, struct hostname *hostname, int level) +void isis_dynhn_insert(const u_char *id, const char *hostname, int level) { struct isis_dynhn *dyn; dyn = dynhn_find_by_id(id); - if (dyn) { - memcpy(&dyn->name, hostname, hostname->namelen + 1); - memcpy(dyn->id, id, ISIS_SYS_ID_LEN); - dyn->refresh = time(NULL); - return; - } - dyn = XCALLOC(MTYPE_ISIS_DYNHN, sizeof(struct isis_dynhn)); if (!dyn) { - zlog_warn("isis_dynhn_insert(): out of memory!"); - return; + dyn = XCALLOC(MTYPE_ISIS_DYNHN, sizeof(struct isis_dynhn)); + memcpy(dyn->id, id, ISIS_SYS_ID_LEN); + dyn->level = level; + listnode_add(dyn_cache, dyn); } - /* we also copy the length */ - memcpy(&dyn->name, hostname, hostname->namelen + 1); - memcpy(dyn->id, id, ISIS_SYS_ID_LEN); + snprintf(dyn->hostname, sizeof(dyn->hostname), "%s", hostname); dyn->refresh = time(NULL); - dyn->level = level; - - listnode_add(dyn_cache, dyn); - - return; } void isis_dynhn_remove(const u_char *id) @@ -137,7 +125,6 @@ void isis_dynhn_remove(const u_char *id) return; listnode_delete(dyn_cache, dyn); XFREE(MTYPE_ISIS_DYNHN, dyn); - return; } /* @@ -155,7 +142,7 @@ void dynhn_print_all(struct vty *vty) for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn)) { vty_out(vty, "%-7d", dyn->level); vty_out(vty, "%-15s%-15s\n", sysid_print(dyn->id), - dyn->name.name); + dyn->hostname); } vty_out(vty, " * %s %s\n", sysid_print(isis->sysid), diff --git a/isisd/isis_dynhn.h b/isisd/isis_dynhn.h index f3ca94d40f..635d79f3f3 100644 --- a/isisd/isis_dynhn.h +++ b/isisd/isis_dynhn.h @@ -25,13 +25,13 @@ struct isis_dynhn { u_char id[ISIS_SYS_ID_LEN]; - struct hostname name; + char hostname[256]; time_t refresh; int level; }; void dyn_cache_init(void); -void isis_dynhn_insert(const u_char *id, struct hostname *hostname, int level); +void isis_dynhn_insert(const u_char *id, const char *hostname, int level); void isis_dynhn_remove(const u_char *id); struct isis_dynhn *dynhn_find_by_id(const u_char *id); struct isis_dynhn *dynhn_find_by_name(const char *hostname); diff --git a/isisd/isis_events.c b/isisd/isis_events.c index 9af256ba38..1cc90d031c 100644 --- a/isisd/isis_events.c +++ b/isisd/isis_events.c @@ -37,7 +37,6 @@ #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" -#include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_pdu.h" #include "isisd/isis_network.h" diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 40c6141ab8..51fe41a706 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -44,7 +44,6 @@ #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isisd.h" -#include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_pdu.h" #include "isisd/isis_dynhn.h" @@ -54,6 +53,7 @@ #include "isisd/isis_spf.h" #include "isisd/isis_te.h" #include "isisd/isis_mt.h" +#include "isisd/isis_tlvs.h" /* staticly assigned vars for printing purposes */ char lsp_bits_string[200]; /* FIXME: enough ? */ @@ -105,19 +105,8 @@ static void lsp_clear_data(struct isis_lsp *lsp) if (!lsp) return; - if (lsp->tlv_data.hostname) - isis_dynhn_remove(lsp->lsp_header->lsp_id); - - if (lsp->own_lsp) { - if (lsp->tlv_data.nlpids) - XFREE(MTYPE_ISIS_TLV, lsp->tlv_data.nlpids); - if (lsp->tlv_data.hostname) - XFREE(MTYPE_ISIS_TLV, lsp->tlv_data.hostname); - if (lsp->tlv_data.router_id) - XFREE(MTYPE_ISIS_TLV, lsp->tlv_data.router_id); - } - - free_tlvs(&lsp->tlv_data); + isis_free_tlvs(lsp->tlvs); + lsp->tlvs = NULL; } static void lsp_destroy(struct isis_lsp *lsp) @@ -146,7 +135,7 @@ static void lsp_destroy(struct isis_lsp *lsp) lsp_clear_data(lsp); - if (LSP_FRAGMENT(lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags) { + if (LSP_FRAGMENT(lsp->hdr.lsp_id) == 0 && lsp->lspu.frags) { list_delete(lsp->lspu.frags); lsp->lspu.frags = NULL; } @@ -187,7 +176,7 @@ static void lsp_remove_frags(struct list *frags, dict_t *lspdb) struct isis_lsp *lsp; for (ALL_LIST_ELEMENTS(frags, lnode, lnnode, lsp)) { - dnode = dict_lookup(lspdb, lsp->lsp_header->lsp_id); + dnode = dict_lookup(lspdb, lsp->hdr.lsp_id); lsp_destroy(lsp); dnode_destroy(dict_delete(lspdb, dnode)); } @@ -209,7 +198,7 @@ void lsp_search_and_destroy(u_char *id, dict_t *lspdb) /* * If this is a zero lsp, remove all the frags now */ - if (LSP_FRAGMENT(lsp->lsp_header->lsp_id) == 0) { + if (LSP_FRAGMENT(lsp->hdr.lsp_id) == 0) { if (lsp->lspu.frags) lsp_remove_frags(lsp->lspu.frags, lspdb); } else { @@ -231,29 +220,25 @@ void lsp_search_and_destroy(u_char *id, dict_t *lspdb) * Compares a LSP to given values * Params are given in net order */ -int lsp_compare(char *areatag, struct isis_lsp *lsp, u_int32_t seq_num, - u_int16_t checksum, u_int16_t rem_lifetime) +int lsp_compare(char *areatag, struct isis_lsp *lsp, uint32_t seqno, + uint16_t checksum, uint16_t rem_lifetime) { - /* no point in double ntohl on seqnum */ - if (lsp->lsp_header->seq_num == seq_num - && lsp->lsp_header->checksum == checksum && - /*comparing with 0, no need to do ntohl */ - ((lsp->lsp_header->rem_lifetime == 0 && rem_lifetime == 0) - || (lsp->lsp_header->rem_lifetime != 0 && rem_lifetime != 0))) { + if (lsp->hdr.seqno == seqno && lsp->hdr.checksum == checksum + && ((lsp->hdr.rem_lifetime == 0 && rem_lifetime == 0) + || (lsp->hdr.rem_lifetime != 0 && rem_lifetime != 0))) { if (isis->debugs & DEBUG_SNP_PACKETS) { zlog_debug( - "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x," - " lifetime %us", - areatag, - rawlspid_print(lsp->lsp_header->lsp_id), - ntohl(lsp->lsp_header->seq_num), - ntohs(lsp->lsp_header->checksum), - ntohs(lsp->lsp_header->rem_lifetime)); + "ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32 + ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 + "s", + areatag, rawlspid_print(lsp->hdr.lsp_id), + lsp->hdr.seqno, lsp->hdr.checksum, + lsp->hdr.rem_lifetime); zlog_debug( - "ISIS-Snp (%s): is equal to ours seq 0x%08x," - " cksum 0x%04x, lifetime %us", - areatag, ntohl(seq_num), ntohs(checksum), - ntohs(rem_lifetime)); + "ISIS-Snp (%s): is equal to ours seq 0x%08" PRIx32 + ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 + "s", + areatag, seqno, checksum, rem_lifetime); } return LSP_EQUAL; } @@ -270,171 +255,136 @@ int lsp_compare(char *areatag, struct isis_lsp *lsp, u_int32_t seq_num, * as given * in 7.3.16.2. */ - if (ntohl(seq_num) > ntohl(lsp->lsp_header->seq_num) - || (ntohl(seq_num) == ntohl(lsp->lsp_header->seq_num) - && ((lsp->lsp_header->rem_lifetime != 0 && rem_lifetime == 0) - || lsp->lsp_header->checksum != checksum))) { + if (seqno > lsp->hdr.seqno + || (seqno == lsp->hdr.seqno + && ((lsp->hdr.rem_lifetime != 0 && rem_lifetime == 0) + || lsp->hdr.checksum != checksum))) { if (isis->debugs & DEBUG_SNP_PACKETS) { zlog_debug( - "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x," - " lifetime %us", - areatag, - rawlspid_print(lsp->lsp_header->lsp_id), - ntohl(seq_num), ntohs(checksum), - ntohs(rem_lifetime)); + "ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32 + ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 + "s", + areatag, rawlspid_print(lsp->hdr.lsp_id), seqno, + checksum, rem_lifetime); zlog_debug( - "ISIS-Snp (%s): is newer than ours seq 0x%08x, " - "cksum 0x%04x, lifetime %us", - areatag, ntohl(lsp->lsp_header->seq_num), - ntohs(lsp->lsp_header->checksum), - ntohs(lsp->lsp_header->rem_lifetime)); + "ISIS-Snp (%s): is newer than ours seq 0x%08" PRIx32 + ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 + "s", + areatag, lsp->hdr.seqno, lsp->hdr.checksum, + lsp->hdr.rem_lifetime); } return LSP_NEWER; } if (isis->debugs & DEBUG_SNP_PACKETS) { + zlog_debug("ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32 + ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 "s", + areatag, rawlspid_print(lsp->hdr.lsp_id), seqno, + checksum, rem_lifetime); zlog_debug( - "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us", - areatag, rawlspid_print(lsp->lsp_header->lsp_id), - ntohl(seq_num), ntohs(checksum), ntohs(rem_lifetime)); - zlog_debug( - "ISIS-Snp (%s): is older than ours seq 0x%08x," - " cksum 0x%04x, lifetime %us", - areatag, ntohl(lsp->lsp_header->seq_num), - ntohs(lsp->lsp_header->checksum), - ntohs(lsp->lsp_header->rem_lifetime)); + "ISIS-Snp (%s): is older than ours seq 0x%08" PRIx32 + ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 "s", + areatag, lsp->hdr.seqno, lsp->hdr.checksum, + lsp->hdr.rem_lifetime); } return LSP_OLDER; } -static void lsp_auth_add(struct isis_lsp *lsp) +static void put_lsp_hdr(struct isis_lsp *lsp, size_t *len_pointer) { - struct isis_passwd *passwd; - unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; - - /* - * Add the authentication info if its present - */ - (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) - : (passwd = &lsp->area->domain_passwd); - switch (passwd->type) { - /* Cleartext */ - case ISIS_PASSWD_TYPE_CLEARTXT: - memcpy(&lsp->tlv_data.auth_info, passwd, - sizeof(struct isis_passwd)); - tlv_add_authinfo(passwd->type, passwd->len, passwd->passwd, - lsp->pdu); - break; - - /* HMAC MD5 */ - case ISIS_PASSWD_TYPE_HMAC_MD5: - /* Remember where TLV is written so we can later - * overwrite the MD5 hash */ - lsp->auth_tlv_offset = stream_get_endp(lsp->pdu); - memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); - lsp->tlv_data.auth_info.type = ISIS_PASSWD_TYPE_HMAC_MD5; - lsp->tlv_data.auth_info.len = ISIS_AUTH_MD5_SIZE; - memcpy(&lsp->tlv_data.auth_info.passwd, hmac_md5_hash, - ISIS_AUTH_MD5_SIZE); - tlv_add_authinfo(passwd->type, ISIS_AUTH_MD5_SIZE, - hmac_md5_hash, lsp->pdu); - break; - - default: - break; - } + uint8_t pdu_type = + (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE : L2_LINK_STATE; + struct isis_lsp_hdr *hdr = &lsp->hdr; + struct stream *stream = lsp->pdu; + + fill_fixed_hdr(pdu_type, stream); + + if (len_pointer) + *len_pointer = stream_get_endp(stream); + stream_putw(stream, hdr->pdu_len); + stream_putw(stream, hdr->rem_lifetime); + stream_put(stream, hdr->lsp_id, sizeof(hdr->lsp_id)); + stream_putl(stream, hdr->seqno); + stream_putw(stream, hdr->checksum); + stream_putc(stream, hdr->lsp_bits); } -static void lsp_auth_update(struct isis_lsp *lsp) +static void lsp_add_auth(struct isis_lsp *lsp) { struct isis_passwd *passwd; - unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; - uint16_t checksum, rem_lifetime; + passwd = (lsp->level == IS_LEVEL_1) ? &lsp->area->area_passwd + : &lsp->area->domain_passwd; + isis_tlvs_add_auth(lsp->tlvs, passwd); +} - /* For HMAC MD5 we need to recompute the md5 hash and store it */ - (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) - : (passwd = &lsp->area->domain_passwd); - if (passwd->type != ISIS_PASSWD_TYPE_HMAC_MD5) - return; +static void lsp_pack_pdu(struct isis_lsp *lsp) +{ + if (!lsp->tlvs) + lsp->tlvs = isis_alloc_tlvs(); - /* - * In transient conditions (when net is configured where authentication - * config and lsp regenerate schedule is not yet run), there could be - * an own_lsp with auth_tlv_offset set to 0. In such a case, simply - * return, when lsp_regenerate is run, lsp will have auth tlv. - */ - if (lsp->auth_tlv_offset == 0) - return; + lsp_add_auth(lsp); - /* - * RFC 5304 set auth value, checksum and remaining lifetime to zero - * before computation and reset to old values after computation. - */ - checksum = lsp->lsp_header->checksum; - rem_lifetime = lsp->lsp_header->rem_lifetime; - lsp->lsp_header->checksum = 0; - lsp->lsp_header->rem_lifetime = 0; - /* Set the authentication value as well to zero */ - memset(STREAM_DATA(lsp->pdu) + lsp->auth_tlv_offset + 3, 0, - ISIS_AUTH_MD5_SIZE); - /* Compute autentication value */ - hmac_md5(STREAM_DATA(lsp->pdu), stream_get_endp(lsp->pdu), - (unsigned char *)&passwd->passwd, passwd->len, - (unsigned char *)&hmac_md5_hash); - /* Copy the hash into the stream */ - memcpy(STREAM_DATA(lsp->pdu) + lsp->auth_tlv_offset + 3, hmac_md5_hash, - ISIS_AUTH_MD5_SIZE); - memcpy(&lsp->tlv_data.auth_info.passwd, hmac_md5_hash, - ISIS_AUTH_MD5_SIZE); - /* Copy back the checksum and remaining lifetime */ - lsp->lsp_header->checksum = checksum; - lsp->lsp_header->rem_lifetime = rem_lifetime; + size_t len_pointer; + stream_reset(lsp->pdu); + put_lsp_hdr(lsp, &len_pointer); + isis_pack_tlvs(lsp->tlvs, lsp->pdu, len_pointer, false, true); + + lsp->hdr.pdu_len = stream_get_endp(lsp->pdu); + lsp->hdr.checksum = + ntohs(fletcher_checksum(STREAM_DATA(lsp->pdu) + 12, + stream_get_endp(lsp->pdu) - 12, 12)); } -void lsp_inc_seqnum(struct isis_lsp *lsp, u_int32_t seq_num) +void lsp_inc_seqno(struct isis_lsp *lsp, uint32_t seqno) { - u_int32_t newseq; + uint32_t newseq; - if (seq_num == 0 || ntohl(lsp->lsp_header->seq_num) > seq_num) - newseq = ntohl(lsp->lsp_header->seq_num) + 1; + if (seqno == 0 || lsp->hdr.seqno > seqno) + newseq = lsp->hdr.seqno + 1; else - newseq = seq_num + 1; - - lsp->lsp_header->seq_num = htonl(newseq); - - /* Recompute authentication and checksum information */ - lsp_auth_update(lsp); - /* ISO 10589 - 7.3.11 Generation of the checksum - * The checksum shall be computed over all fields in the LSP which - * appear - * after the Remaining Lifetime field. This field (and those appearing - * before it) are excluded so that the LSP may be aged by systems - * without - * requiring recomputation. - */ - fletcher_checksum(STREAM_DATA(lsp->pdu) + 12, - ntohs(lsp->lsp_header->pdu_len) - 12, 12); + newseq = seqno + 1; + + lsp->hdr.seqno = newseq; + lsp_pack_pdu(lsp); isis_spf_schedule(lsp->area, lsp->level); +} - return; +static void lsp_purge(struct isis_lsp *lsp, int level) +{ + /* reset stream */ + lsp_clear_data(lsp); + stream_reset(lsp->pdu); + + /* update header */ + lsp->hdr.checksum = 0; + lsp->hdr.rem_lifetime = 0; + lsp->level = level; + lsp->age_out = lsp->area->max_lsp_lifetime[level - 1]; + + lsp_pack_pdu(lsp); + lsp_set_all_srmflags(lsp); } /* - * Genetates checksum for LSP and its frags + * Generates checksum for LSP and its frags */ -static void lsp_seqnum_update(struct isis_lsp *lsp0) +static void lsp_seqno_update(struct isis_lsp *lsp0) { struct isis_lsp *lsp; struct listnode *node; - lsp_inc_seqnum(lsp0, 0); + lsp_inc_seqno(lsp0, 0); if (!lsp0->lspu.frags) return; - for (ALL_LIST_ELEMENTS_RO(lsp0->lspu.frags, node, lsp)) - lsp_inc_seqnum(lsp, 0); + for (ALL_LIST_ELEMENTS_RO(lsp0->lspu.frags, node, lsp)) { + if (lsp->tlvs) + lsp_inc_seqno(lsp, 0); + else + lsp_purge(lsp, lsp0->level); + } return; } @@ -453,12 +403,10 @@ static u_int8_t lsp_bits_generate(int level, int overload_bit, int attached_bit) return lsp_bits; } -static void lsp_update_data(struct isis_lsp *lsp, struct stream *stream, +static void lsp_update_data(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr, + struct isis_tlvs *tlvs, struct stream *stream, struct isis_area *area, int level) { - uint32_t expected = 0, found; - int retval; - /* free the old lsp data */ lsp_clear_data(lsp); @@ -467,50 +415,17 @@ static void lsp_update_data(struct isis_lsp *lsp, struct stream *stream, stream_free(lsp->pdu); lsp->pdu = stream_dup(stream); - /* setting pointers to the correct place */ - lsp->isis_header = (struct isis_fixed_hdr *)(STREAM_DATA(lsp->pdu)); - lsp->lsp_header = (struct isis_link_state_hdr *)(STREAM_DATA(lsp->pdu) - + ISIS_FIXED_HDR_LEN); + memcpy(&lsp->hdr, hdr, sizeof(lsp->hdr)); lsp->area = area; lsp->level = level; lsp->age_out = ZERO_AGE_LIFETIME; lsp->installed = time(NULL); - /* - * Get LSP data i.e. TLVs - */ - expected |= TLVFLAG_AUTH_INFO; - expected |= TLVFLAG_AREA_ADDRS; - expected |= TLVFLAG_IS_NEIGHS; - expected |= TLVFLAG_NLPID; - if (area->dynhostname) - expected |= TLVFLAG_DYN_HOSTNAME; - if (area->newmetric) { - expected |= TLVFLAG_TE_IS_NEIGHS; - expected |= TLVFLAG_TE_IPV4_REACHABILITY; - expected |= TLVFLAG_TE_ROUTER_ID; - } - expected |= TLVFLAG_MT_ROUTER_INFORMATION; - expected |= TLVFLAG_IPV4_ADDR; - expected |= TLVFLAG_IPV4_INT_REACHABILITY; - expected |= TLVFLAG_IPV4_EXT_REACHABILITY; - expected |= TLVFLAG_IPV6_ADDR; - expected |= TLVFLAG_IPV6_REACHABILITY; - - retval = parse_tlvs(area->area_tag, - STREAM_DATA(lsp->pdu) + ISIS_FIXED_HDR_LEN - + ISIS_LSP_HDR_LEN, - ntohs(lsp->lsp_header->pdu_len) - ISIS_FIXED_HDR_LEN - - ISIS_LSP_HDR_LEN, - &expected, &found, &lsp->tlv_data, NULL); - if (retval != ISIS_OK) { - zlog_warn("Could not parse LSP"); - return; - } - if ((found & TLVFLAG_DYN_HOSTNAME) && (area->dynhostname)) { - isis_dynhn_insert(lsp->lsp_header->lsp_id, - lsp->tlv_data.hostname, - (lsp->lsp_header->lsp_bits & LSPBIT_IST) + lsp->tlvs = tlvs; + + if (area->dynhostname && lsp->tlvs->hostname) { + isis_dynhn_insert(lsp->hdr.lsp_id, lsp->tlvs->hostname, + (lsp->hdr.lsp_bits & LSPBIT_IST) == IS_LEVEL_1_AND_2 ? IS_LEVEL_2 : IS_LEVEL_1); @@ -519,44 +434,55 @@ static void lsp_update_data(struct isis_lsp *lsp, struct stream *stream, return; } -void lsp_update(struct isis_lsp *lsp, struct stream *stream, - struct isis_area *area, int level) +void lsp_update(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr, + struct isis_tlvs *tlvs, struct stream *stream, + struct isis_area *area, int level, bool confusion) { dnode_t *dnode = NULL; /* Remove old LSP from database. This is required since the * lsp_update_data will free the lsp->pdu (which has the key, lsp_id) - * and will update it with the new data in the stream. */ - dnode = dict_lookup(area->lspdb[level - 1], lsp->lsp_header->lsp_id); + * and will update it with the new data in the stream. + * XXX: This doesn't hold true anymore since the header is now a copy. + * keeping the LSP in the dict if it is already present should be possible */ + dnode = dict_lookup(area->lspdb[level - 1], lsp->hdr.lsp_id); if (dnode) dnode_destroy(dict_delete(area->lspdb[level - 1], dnode)); if (lsp->own_lsp) { zlog_err( "ISIS-Upd (%s): BUG updating LSP %s still marked as own LSP", - area->area_tag, - rawlspid_print(lsp->lsp_header->lsp_id)); + area->area_tag, rawlspid_print(lsp->hdr.lsp_id)); lsp_clear_data(lsp); lsp->own_lsp = 0; } - /* rebuild the lsp data */ - lsp_update_data(lsp, stream, area, level); + if (confusion) { + lsp_clear_data(lsp); + if (lsp->pdu != NULL) + stream_free(lsp->pdu); + lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu); + lsp->age_out = ZERO_AGE_LIFETIME; + lsp->hdr.rem_lifetime = 0; + lsp_pack_pdu(lsp); + } else { + lsp_update_data(lsp, hdr, tlvs, stream, area, level); + } /* insert the lsp back into the database */ lsp_insert(lsp, area->lspdb[level - 1]); } /* creation of LSP directly from what we received */ -struct isis_lsp *lsp_new_from_stream_ptr(struct stream *stream, - u_int16_t pdu_len, - struct isis_lsp *lsp0, - struct isis_area *area, int level) +struct isis_lsp *lsp_new_from_recv(struct isis_lsp_hdr *hdr, + struct isis_tlvs *tlvs, + struct stream *stream, struct isis_lsp *lsp0, + struct isis_area *area, int level) { struct isis_lsp *lsp; lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp)); - lsp_update_data(lsp, stream, area, level); + lsp_update_data(lsp, hdr, tlvs, stream, area, level); if (lsp0 == NULL) { /* @@ -576,8 +502,8 @@ struct isis_lsp *lsp_new_from_stream_ptr(struct stream *stream, } struct isis_lsp *lsp_new(struct isis_area *area, u_char *lsp_id, - u_int16_t rem_lifetime, u_int32_t seq_num, - u_int8_t lsp_bits, u_int16_t checksum, int level) + uint16_t rem_lifetime, uint32_t seqno, + uint8_t lsp_bits, uint16_t checksum, int level) { struct isis_lsp *lsp; @@ -587,44 +513,32 @@ struct isis_lsp *lsp_new(struct isis_area *area, u_char *lsp_id, lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu); if (LSP_FRAGMENT(lsp_id) == 0) lsp->lspu.frags = list_new(); - lsp->isis_header = (struct isis_fixed_hdr *)(STREAM_DATA(lsp->pdu)); - lsp->lsp_header = (struct isis_link_state_hdr *)(STREAM_DATA(lsp->pdu) - + ISIS_FIXED_HDR_LEN); - /* at first we fill the FIXED HEADER */ - (level == IS_LEVEL_1) ? fill_fixed_hdr(lsp->isis_header, L1_LINK_STATE) - : fill_fixed_hdr(lsp->isis_header, L2_LINK_STATE); - - /* now for the LSP HEADER */ /* Minimal LSP PDU size */ - lsp->lsp_header->pdu_len = htons(ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); - memcpy(lsp->lsp_header->lsp_id, lsp_id, ISIS_SYS_ID_LEN + 2); - lsp->lsp_header->checksum = checksum; /* Provided in network order */ - lsp->lsp_header->seq_num = htonl(seq_num); - lsp->lsp_header->rem_lifetime = htons(rem_lifetime); - lsp->lsp_header->lsp_bits = lsp_bits; + lsp->hdr.pdu_len = ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN; + memcpy(lsp->hdr.lsp_id, lsp_id, sizeof(lsp->hdr.lsp_id)); + lsp->hdr.checksum = checksum; + lsp->hdr.seqno = seqno; + lsp->hdr.rem_lifetime = rem_lifetime; + lsp->hdr.lsp_bits = lsp_bits; lsp->level = level; lsp->age_out = ZERO_AGE_LIFETIME; - - stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); + put_lsp_hdr(lsp, NULL); if (isis->debugs & DEBUG_EVENTS) zlog_debug("New LSP with ID %s-%02x-%02x len %d seqnum %08x", - sysid_print(lsp_id), - LSP_PSEUDO_ID(lsp->lsp_header->lsp_id), - LSP_FRAGMENT(lsp->lsp_header->lsp_id), - ntohl(lsp->lsp_header->pdu_len), - ntohl(lsp->lsp_header->seq_num)); + sysid_print(lsp_id), LSP_PSEUDO_ID(lsp->hdr.lsp_id), + LSP_FRAGMENT(lsp->hdr.lsp_id), lsp->hdr.pdu_len, + lsp->hdr.seqno); return lsp; } void lsp_insert(struct isis_lsp *lsp, dict_t *lspdb) { - dict_alloc_insert(lspdb, lsp->lsp_header->lsp_id, lsp); - if (lsp->lsp_header->seq_num != 0) { + dict_alloc_insert(lspdb, lsp->hdr.lsp_id, lsp); + if (lsp->hdr.seqno) isis_spf_schedule(lsp->area, lsp->level); - } } /* @@ -643,14 +557,13 @@ void lsp_build_list_nonzero_ht(u_char *start_id, u_char *stop_id, curr = first; - if (((struct isis_lsp *)(curr->dict_data))->lsp_header->rem_lifetime) + if (((struct isis_lsp *)(curr->dict_data))->hdr.rem_lifetime) listnode_add(list, first->dict_data); while (curr) { curr = dict_next(lspdb, curr); if (curr - && ((struct isis_lsp *)(curr->dict_data)) - ->lsp_header->rem_lifetime) + && ((struct isis_lsp *)(curr->dict_data))->hdr.rem_lifetime) listnode_add(list, curr->dict_data); if (curr == last) break; @@ -659,77 +572,19 @@ void lsp_build_list_nonzero_ht(u_char *start_id, u_char *stop_id, return; } -/* - * Build a list of num_lsps LSPs bounded by start_id and stop_id. - */ -void lsp_build_list(u_char *start_id, u_char *stop_id, u_char num_lsps, - struct list *list, dict_t *lspdb) -{ - u_char count; - dnode_t *first, *last, *curr; - - first = dict_lower_bound(lspdb, start_id); - if (!first) - return; - - last = dict_upper_bound(lspdb, stop_id); - - curr = first; - - listnode_add(list, first->dict_data); - count = 1; - - while (curr) { - curr = dict_next(lspdb, curr); - if (curr) { - listnode_add(list, curr->dict_data); - count++; - } - if (count == num_lsps || curr == last) - break; - } - - return; -} - -/* - * Build a list of LSPs with SSN flag set for the given circuit - */ -void lsp_build_list_ssn(struct isis_circuit *circuit, u_char num_lsps, - struct list *list, dict_t *lspdb) -{ - dnode_t *dnode, *next; - struct isis_lsp *lsp; - u_char count = 0; - - dnode = dict_first(lspdb); - while (dnode != NULL) { - next = dict_next(lspdb, dnode); - lsp = dnode_get(dnode); - if (ISIS_CHECK_FLAG(lsp->SSNflags, circuit)) { - listnode_add(list, lsp); - ++count; - } - if (count == num_lsps) - break; - dnode = next; - } - - return; -} - static void lsp_set_time(struct isis_lsp *lsp) { assert(lsp); - if (lsp->lsp_header->rem_lifetime == 0) { + if (lsp->hdr.rem_lifetime == 0) { if (lsp->age_out > 0) lsp->age_out--; return; } - lsp->lsp_header->rem_lifetime = - htons(ntohs(lsp->lsp_header->rem_lifetime) - 1); + lsp->hdr.rem_lifetime--; + if (lsp->pdu && stream_get_endp(lsp->pdu) >= 12) + stream_putw_at(lsp->pdu, 10, lsp->hdr.rem_lifetime); } static void lspid_print(u_char *lsp_id, u_char *trg, char dynhost, char frag) @@ -743,7 +598,7 @@ static void lspid_print(u_char *lsp_id, u_char *trg, char dynhost, char frag) dyn = NULL; if (dyn) - sprintf((char *)id, "%.14s", dyn->name.name); + sprintf((char *)id, "%.14s", dyn->hostname); else if (!memcmp(isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost) sprintf((char *)id, "%.14s", unix_hostname()); else @@ -756,21 +611,21 @@ static void lspid_print(u_char *lsp_id, u_char *trg, char dynhost, char frag) } /* Convert the lsp attribute bits to attribute string */ -const char *lsp_bits2string(u_char *lsp_bits) +static const char *lsp_bits2string(uint8_t lsp_bits) { char *pos = lsp_bits_string; - if (!*lsp_bits) + if (!lsp_bits) return " none"; /* we only focus on the default metric */ pos += sprintf(pos, "%d/", - ISIS_MASK_LSP_ATT_DEFAULT_BIT(*lsp_bits) ? 1 : 0); + ISIS_MASK_LSP_ATT_DEFAULT_BIT(lsp_bits) ? 1 : 0); pos += sprintf(pos, "%d/", - ISIS_MASK_LSP_PARTITION_BIT(*lsp_bits) ? 1 : 0); + ISIS_MASK_LSP_PARTITION_BIT(lsp_bits) ? 1 : 0); - pos += sprintf(pos, "%d", ISIS_MASK_LSP_OL_BIT(*lsp_bits) ? 1 : 0); + pos += sprintf(pos, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits) ? 1 : 0); *(pos) = '\0'; @@ -783,276 +638,26 @@ void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost) u_char LSPid[255]; char age_out[8]; - lspid_print(lsp->lsp_header->lsp_id, LSPid, dynhost, 1); + lspid_print(lsp->hdr.lsp_id, LSPid, dynhost, 1); vty_out(vty, "%-21s%c ", LSPid, lsp->own_lsp ? '*' : ' '); - vty_out(vty, "%5u ", ntohs(lsp->lsp_header->pdu_len)); - vty_out(vty, "0x%08x ", ntohl(lsp->lsp_header->seq_num)); - vty_out(vty, "0x%04x ", ntohs(lsp->lsp_header->checksum)); - if (ntohs(lsp->lsp_header->rem_lifetime) == 0) { - snprintf(age_out, 8, "(%u)", lsp->age_out); + vty_out(vty, "%5" PRIu16 " ", lsp->hdr.pdu_len); + vty_out(vty, "0x%08" PRIx32 " ", lsp->hdr.seqno); + vty_out(vty, "0x%04" PRIx16 " ", lsp->hdr.checksum); + if (lsp->hdr.rem_lifetime == 0) { + snprintf(age_out, 8, "(%d)", lsp->age_out); age_out[7] = '\0'; vty_out(vty, "%7s ", age_out); } else - vty_out(vty, " %5u ", ntohs(lsp->lsp_header->rem_lifetime)); - vty_out(vty, "%s\n", lsp_bits2string(&lsp->lsp_header->lsp_bits)); -} - -static void lsp_print_mt_reach(struct list *list, struct vty *vty, char dynhost, - uint16_t mtid) -{ - struct listnode *node; - struct te_is_neigh *neigh; - - for (ALL_LIST_ELEMENTS_RO(list, node, neigh)) { - u_char lspid[255]; - - lspid_print(neigh->neigh_id, lspid, dynhost, 0); - if (mtid == ISIS_MT_IPV4_UNICAST) { - vty_out(vty, - " Metric : %-8u IS-Extended : %s\n", - GET_TE_METRIC(neigh), lspid); - } else { - vty_out(vty, - " Metric : %-8u MT-Reach : %s %s\n", - GET_TE_METRIC(neigh), lspid, - isis_mtid2str(mtid)); - } - if (IS_MPLS_TE(isisMplsTE)) - mpls_te_print_detail(vty, neigh); - } -} - -static void lsp_print_mt_ipv6_reach(struct list *list, struct vty *vty, - uint16_t mtid) -{ - struct listnode *node; - struct ipv6_reachability *ipv6_reach; - struct in6_addr in6; - u_char buff[BUFSIZ]; - - for (ALL_LIST_ELEMENTS_RO(list, node, ipv6_reach)) { - memset(&in6, 0, sizeof(in6)); - memcpy(in6.s6_addr, ipv6_reach->prefix, - PSIZE(ipv6_reach->prefix_len)); - inet_ntop(AF_INET6, &in6, (char *)buff, BUFSIZ); - if (mtid == ISIS_MT_IPV4_UNICAST) { - if ((ipv6_reach->control_info & CTRL_INFO_DISTRIBUTION) - == DISTRIBUTION_INTERNAL) - vty_out(vty, " Metric : %-8" PRIu32 - " IPv6-Internal : %s/%d\n", - ntohl(ipv6_reach->metric), buff, - ipv6_reach->prefix_len); - else - vty_out(vty, " Metric : %-8" PRIu32 - " IPv6-External : %s/%d\n", - ntohl(ipv6_reach->metric), buff, - ipv6_reach->prefix_len); - } else { - if ((ipv6_reach->control_info & CTRL_INFO_DISTRIBUTION) - == DISTRIBUTION_INTERNAL) - vty_out(vty, " Metric : %-8" PRIu32 - " IPv6-MT-Int : %s/%d %s\n", - ntohl(ipv6_reach->metric), buff, - ipv6_reach->prefix_len, - isis_mtid2str(mtid)); - else - vty_out(vty, " Metric : %-8" PRIu32 - " IPv6-MT-Ext : %s/%d %s\n", - ntohl(ipv6_reach->metric), buff, - ipv6_reach->prefix_len, - isis_mtid2str(mtid)); - } - } -} - -static void lsp_print_mt_ipv4_reach(struct list *list, struct vty *vty, - uint16_t mtid) -{ - struct listnode *node; - struct te_ipv4_reachability *te_ipv4_reach; - - for (ALL_LIST_ELEMENTS_RO(list, node, te_ipv4_reach)) { - if (mtid == ISIS_MT_IPV4_UNICAST) { - /* FIXME: There should be better way to output this - * stuff. */ - vty_out(vty, " Metric : %-8" PRIu32 - " IPv4-Extended : %s/%d\n", - ntohl(te_ipv4_reach->te_metric), - inet_ntoa(newprefix2inaddr( - &te_ipv4_reach->prefix_start, - te_ipv4_reach->control)), - te_ipv4_reach->control & 0x3F); - } else { - /* FIXME: There should be better way to output this - * stuff. */ - vty_out(vty, " Metric : %-8" PRIu32 - " IPv4-MT : %s/%d %s\n", - ntohl(te_ipv4_reach->te_metric), - inet_ntoa(newprefix2inaddr( - &te_ipv4_reach->prefix_start, - te_ipv4_reach->control)), - te_ipv4_reach->control & 0x3F, - isis_mtid2str(mtid)); - } - } + vty_out(vty, " %5" PRIu16 " ", lsp->hdr.rem_lifetime); + vty_out(vty, "%s\n", lsp_bits2string(lsp->hdr.lsp_bits)); } void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost) { - struct area_addr *area_addr; - int i; - struct listnode *lnode; - struct is_neigh *is_neigh; - struct ipv4_reachability *ipv4_reach; - struct in_addr *ipv4_addr; - struct mt_router_info *mt_router_info; - struct tlv_mt_ipv6_reachs *mt_ipv6_reachs; - struct tlv_mt_neighbors *mt_is_neigh; - struct tlv_mt_ipv4_reachs *mt_ipv4_reachs; - u_char LSPid[255]; - u_char hostname[255]; - u_char ipv4_reach_prefix[20]; - u_char ipv4_reach_mask[20]; - u_char ipv4_address[20]; - - lspid_print(lsp->lsp_header->lsp_id, LSPid, dynhost, 1); lsp_print(lsp, vty, dynhost); - - /* for all area address */ - if (lsp->tlv_data.area_addrs) - for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.area_addrs, lnode, - area_addr)) { - vty_out(vty, " Area Address: %s\n", - isonet_print(area_addr->area_addr, - area_addr->addr_len)); - } - - /* for the nlpid tlv */ - if (lsp->tlv_data.nlpids) { - for (i = 0; i < lsp->tlv_data.nlpids->count; i++) { - switch (lsp->tlv_data.nlpids->nlpids[i]) { - case NLPID_IP: - case NLPID_IPV6: - vty_out(vty, " NLPID : 0x%X\n", - lsp->tlv_data.nlpids->nlpids[i]); - break; - default: - vty_out(vty, " NLPID : %s\n", "unknown"); - break; - } - } - } - - for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_router_info, lnode, - mt_router_info)) { - vty_out(vty, " MT : %s%s\n", - isis_mtid2str(mt_router_info->mtid), - mt_router_info->overload ? " (overload)" : ""); - } - - /* for the hostname tlv */ - if (lsp->tlv_data.hostname) { - bzero(hostname, sizeof(hostname)); - memcpy(hostname, lsp->tlv_data.hostname->name, - lsp->tlv_data.hostname->namelen); - vty_out(vty, " Hostname : %s\n", hostname); - } - - /* authentication tlv */ - if (lsp->tlv_data.auth_info.type != ISIS_PASSWD_TYPE_UNUSED) { - if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_HMAC_MD5) - vty_out(vty, " Auth type : md5\n"); - else if (lsp->tlv_data.auth_info.type - == ISIS_PASSWD_TYPE_CLEARTXT) - vty_out(vty, " Auth type : clear text\n"); - } - - /* TE router id */ - if (lsp->tlv_data.router_id) { - memcpy(ipv4_address, inet_ntoa(lsp->tlv_data.router_id->id), - sizeof(ipv4_address)); - vty_out(vty, " Router ID : %s\n", ipv4_address); - } - - if (lsp->tlv_data.ipv4_addrs) - for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.ipv4_addrs, lnode, - ipv4_addr)) { - memcpy(ipv4_address, inet_ntoa(*ipv4_addr), - sizeof(ipv4_address)); - vty_out(vty, " IPv4 Address: %s\n", ipv4_address); - } - - /* for the IS neighbor tlv */ - if (lsp->tlv_data.is_neighs) - for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.is_neighs, lnode, - is_neigh)) { - lspid_print(is_neigh->neigh_id, LSPid, dynhost, 0); - vty_out(vty, " Metric : %-8" PRIu8 - " IS : %s\n", - is_neigh->metrics.metric_default, LSPid); - } - - /* for the internal reachable tlv */ - if (lsp->tlv_data.ipv4_int_reachs) - for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.ipv4_int_reachs, lnode, - ipv4_reach)) { - memcpy(ipv4_reach_prefix, inet_ntoa(ipv4_reach->prefix), - sizeof(ipv4_reach_prefix)); - memcpy(ipv4_reach_mask, inet_ntoa(ipv4_reach->mask), - sizeof(ipv4_reach_mask)); - vty_out(vty, " Metric : %-8" PRIu8 - " IPv4-Internal : %s %s\n", - ipv4_reach->metrics.metric_default, - ipv4_reach_prefix, ipv4_reach_mask); - } - - /* for the external reachable tlv */ - if (lsp->tlv_data.ipv4_ext_reachs) - for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.ipv4_ext_reachs, lnode, - ipv4_reach)) { - memcpy(ipv4_reach_prefix, inet_ntoa(ipv4_reach->prefix), - sizeof(ipv4_reach_prefix)); - memcpy(ipv4_reach_mask, inet_ntoa(ipv4_reach->mask), - sizeof(ipv4_reach_mask)); - vty_out(vty, " Metric : %-8" PRIu8 - " IPv4-External : %s %s\n", - ipv4_reach->metrics.metric_default, - ipv4_reach_prefix, ipv4_reach_mask); - } - - /* IPv6 tlv */ - lsp_print_mt_ipv6_reach(lsp->tlv_data.ipv6_reachs, vty, - ISIS_MT_IPV4_UNICAST); - - /* MT IPv6 reachability tlv */ - for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_ipv6_reachs, lnode, - mt_ipv6_reachs)) - lsp_print_mt_ipv6_reach(mt_ipv6_reachs->list, vty, - mt_ipv6_reachs->mtid); - - /* TE IS neighbor tlv */ - lsp_print_mt_reach(lsp->tlv_data.te_is_neighs, vty, dynhost, - ISIS_MT_IPV4_UNICAST); - - /* MT IS neighbor tlv */ - for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_is_neighs, lnode, - mt_is_neigh)) - lsp_print_mt_reach(mt_is_neigh->list, vty, dynhost, - mt_is_neigh->mtid); - - /* TE IPv4 tlv */ - lsp_print_mt_ipv4_reach(lsp->tlv_data.te_ipv4_reachs, vty, - ISIS_MT_IPV4_UNICAST); - - /* MT IPv4 reachability tlv */ - for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_ipv4_reachs, lnode, - mt_ipv4_reachs)) - lsp_print_mt_ipv4_reach(mt_ipv4_reachs->list, vty, - mt_ipv4_reachs->mtid); - + if (lsp->tlvs) + vty_multiline(vty, " ", "%s", isis_format_tlvs(lsp->tlvs)); vty_out(vty, "\n"); - - return; } /* print all the lsps info in the local lspdb */ @@ -1083,85 +688,6 @@ int lsp_print_all(struct vty *vty, dict_t *lspdb, char detail, char dynhost) return lsp_count; } -static void _lsp_tlv_fit(struct isis_lsp *lsp, struct list **from, - struct list **to, int frag_thold, - unsigned int tlv_build_func(struct list *, - struct stream *, - void *arg), - void *arg) -{ - while (*from && listcount(*from)) { - unsigned int count; - - count = tlv_build_func(*from, lsp->pdu, arg); - - if (listcount(*to) != 0 || count != listcount(*from)) { - struct listnode *node, *nnode; - void *elem; - - for (ALL_LIST_ELEMENTS(*from, node, nnode, elem)) { - if (!count) - break; - listnode_add(*to, elem); - list_delete_node(*from, node); - --count; - } - } else { - list_free(*to); - *to = *from; - *from = NULL; - } - } -} - -#define FRAG_THOLD(S, T) ((STREAM_SIZE(S) * T) / 100) - -/* stream*, area->lsp_frag_threshold, increment */ -#define FRAG_NEEDED(S, T, I) \ - (STREAM_SIZE(S) - STREAM_REMAIN(S) + (I) > FRAG_THOLD(S, T)) - -/* FIXME: It shouldn't be necessary to pass tlvsize here, TLVs can have - * variable length (TE TLVs, sub TLVs). */ -static void lsp_tlv_fit(struct isis_lsp *lsp, struct list **from, - struct list **to, int tlvsize, int frag_thold, - int tlv_build_func(struct list *, struct stream *)) -{ - int count, i; - - /* can we fit all ? */ - if (!FRAG_NEEDED(lsp->pdu, frag_thold, - listcount(*from) * tlvsize + 2)) { - tlv_build_func(*from, lsp->pdu); - if (listcount(*to) != 0) { - struct listnode *node, *nextnode; - void *elem; - - for (ALL_LIST_ELEMENTS(*from, node, nextnode, elem)) { - listnode_add(*to, elem); - list_delete_node(*from, node); - } - } else { - list_free(*to); - *to = *from; - *from = NULL; - } - } else if (!FRAG_NEEDED(lsp->pdu, frag_thold, tlvsize + 2)) { - /* fit all we can */ - count = FRAG_THOLD(lsp->pdu, frag_thold) - 2 - - (STREAM_SIZE(lsp->pdu) - STREAM_REMAIN(lsp->pdu)); - count = count / tlvsize; - if (count > (int)listcount(*from)) - count = listcount(*from); - for (i = 0; i < count; i++) { - listnode_add(*to, listgetdata(listhead(*from))); - listnode_delete(*from, listgetdata(listhead(*from))); - } - tlv_build_func(*to, lsp->pdu); - } - lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu)); - return; -} - static u_int16_t lsp_rem_lifetime(struct isis_area *area, int level) { u_int16_t rem_lifetime; @@ -1204,155 +730,90 @@ static u_int16_t lsp_refresh_time(struct isis_lsp *lsp, u_int16_t rem_lifetime) return refresh_time; } -static struct isis_lsp *lsp_next_frag(u_char frag_num, struct isis_lsp *lsp0, - struct isis_area *area, int level) -{ - struct isis_lsp *lsp; - u_char frag_id[ISIS_SYS_ID_LEN + 2]; - - memcpy(frag_id, lsp0->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 1); - LSP_FRAGMENT(frag_id) = frag_num; - /* FIXME add authentication TLV for fragment LSPs */ - lsp = lsp_search(frag_id, area->lspdb[level - 1]); - if (lsp) { - /* Clear the TLVs */ - lsp_clear_data(lsp); - return lsp; - } - lsp = lsp_new(area, frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0, - lsp_bits_generate(level, area->overload_bit, - area->attached_bit), - 0, level); - lsp->area = area; - lsp->own_lsp = 1; - lsp_insert(lsp, area->lspdb[level - 1]); - listnode_add(lsp0->lspu.frags, lsp); - lsp->lspu.zero_lsp = lsp0; - return lsp; -} - static void lsp_build_ext_reach_ipv4(struct isis_lsp *lsp, - struct isis_area *area, - struct tlvs *tlv_data) + struct isis_area *area) { - struct route_table *er_table; - struct route_node *rn; - struct prefix_ipv4 *ipv4; - struct isis_ext_info *info; - struct ipv4_reachability *ipreach; - struct te_ipv4_reachability *te_ipreach; - - er_table = get_ext_reach(area, AF_INET, lsp->level); + struct route_table *er_table = get_ext_reach(area, AF_INET, lsp->level); if (!er_table) return; - for (rn = route_top(er_table); rn; rn = route_next(rn)) { + for (struct route_node *rn = route_top(er_table); rn; + rn = route_next(rn)) { if (!rn->info) continue; - ipv4 = (struct prefix_ipv4 *)&rn->p; - info = rn->info; - if (area->oldmetric) { - if (tlv_data->ipv4_ext_reachs == NULL) { - tlv_data->ipv4_ext_reachs = list_new(); - tlv_data->ipv4_ext_reachs->del = free_tlv; - } - ipreach = XMALLOC(MTYPE_ISIS_TLV, sizeof(*ipreach)); - - ipreach->prefix.s_addr = ipv4->prefix.s_addr; - masklen2ip(ipv4->prefixlen, &ipreach->mask); - ipreach->prefix.s_addr &= ipreach->mask.s_addr; - - if ((info->metric & 0x3f) != info->metric) - ipreach->metrics.metric_default = 0x3f; - else - ipreach->metrics.metric_default = info->metric; - ipreach->metrics.metric_expense = METRICS_UNSUPPORTED; - ipreach->metrics.metric_error = METRICS_UNSUPPORTED; - ipreach->metrics.metric_delay = METRICS_UNSUPPORTED; - listnode_add(tlv_data->ipv4_ext_reachs, ipreach); - } - if (area->newmetric) { - if (tlv_data->te_ipv4_reachs == NULL) { - tlv_data->te_ipv4_reachs = list_new(); - tlv_data->te_ipv4_reachs->del = free_tlv; - } - te_ipreach = XCALLOC(MTYPE_ISIS_TLV, - sizeof(*te_ipreach) - 1 - + PSIZE(ipv4->prefixlen)); - if (info->metric > MAX_WIDE_PATH_METRIC) - te_ipreach->te_metric = - htonl(MAX_WIDE_PATH_METRIC); - else - te_ipreach->te_metric = htonl(info->metric); - te_ipreach->control = ipv4->prefixlen & 0x3f; - memcpy(&te_ipreach->prefix_start, &ipv4->prefix.s_addr, - PSIZE(ipv4->prefixlen)); - listnode_add(tlv_data->te_ipv4_reachs, te_ipreach); - } - } -} + struct prefix_ipv4 *ipv4 = (struct prefix_ipv4 *)&rn->p; + struct isis_ext_info *info = rn->info; -static struct list *tlv_get_ipv6_reach_list(struct isis_area *area, - struct tlvs *tlv_data) -{ - uint16_t mtid = isis_area_ipv6_topology(area); - if (mtid == ISIS_MT_IPV4_UNICAST) { - if (!tlv_data->ipv6_reachs) { - tlv_data->ipv6_reachs = list_new(); - tlv_data->ipv6_reachs->del = free_tlv; - } - return tlv_data->ipv6_reachs; - } + uint32_t metric = info->metric; + if (metric > MAX_WIDE_PATH_METRIC) + metric = MAX_WIDE_PATH_METRIC; + if (area->oldmetric && metric > 0x3f) + metric = 0x3f; - struct tlv_mt_ipv6_reachs *reachs = - tlvs_get_mt_ipv6_reachs(tlv_data, mtid); - return reachs->list; + if (area->oldmetric) + isis_tlvs_add_oldstyle_ip_reach(lsp->tlvs, ipv4, + metric); + if (area->newmetric) + isis_tlvs_add_extended_ip_reach(lsp->tlvs, ipv4, + metric); + } } static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp, - struct isis_area *area, - struct tlvs *tlv_data) + struct isis_area *area) { - struct route_table *er_table; - struct route_node *rn; - struct prefix_ipv6 *ipv6; - struct isis_ext_info *info; - struct ipv6_reachability *ip6reach; - struct list *reach_list = NULL; - - er_table = get_ext_reach(area, AF_INET6, lsp->level); + struct route_table *er_table = + get_ext_reach(area, AF_INET6, lsp->level); if (!er_table) return; - for (rn = route_top(er_table); rn; rn = route_next(rn)) { + for (struct route_node *rn = route_top(er_table); rn; + rn = route_next(rn)) { if (!rn->info) continue; - ipv6 = (struct prefix_ipv6 *)&rn->p; - info = rn->info; - - if (!reach_list) - reach_list = tlv_get_ipv6_reach_list(area, tlv_data); + struct prefix_ipv6 *ipv6 = (struct prefix_ipv6 *)&rn->p; + struct isis_ext_info *info = rn->info; - ip6reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ip6reach)); + uint32_t metric = info->metric; if (info->metric > MAX_WIDE_PATH_METRIC) - ip6reach->metric = htonl(MAX_WIDE_PATH_METRIC); - else - ip6reach->metric = htonl(info->metric); - ip6reach->control_info = DISTRIBUTION_EXTERNAL; - ip6reach->prefix_len = ipv6->prefixlen; - memcpy(ip6reach->prefix, ipv6->prefix.s6_addr, - sizeof(ip6reach->prefix)); - listnode_add(reach_list, ip6reach); + metric = MAX_WIDE_PATH_METRIC; + isis_tlvs_add_ipv6_reach( + lsp->tlvs, isis_area_ipv6_topology(area), ipv6, metric); } } -static void lsp_build_ext_reach(struct isis_lsp *lsp, struct isis_area *area, - struct tlvs *tlv_data) +static void lsp_build_ext_reach(struct isis_lsp *lsp, struct isis_area *area) { - lsp_build_ext_reach_ipv4(lsp, area, tlv_data); - lsp_build_ext_reach_ipv6(lsp, area, tlv_data); + lsp_build_ext_reach_ipv4(lsp, area); + lsp_build_ext_reach_ipv6(lsp, area); +} + +static struct isis_lsp *lsp_next_frag(uint8_t frag_num, struct isis_lsp *lsp0, + struct isis_area *area, int level) +{ + struct isis_lsp *lsp; + uint8_t frag_id[ISIS_SYS_ID_LEN + 2]; + + memcpy(frag_id, lsp0->hdr.lsp_id, ISIS_SYS_ID_LEN + 1); + LSP_FRAGMENT(frag_id) = frag_num; + + lsp = lsp_search(frag_id, area->lspdb[level - 1]); + if (lsp) { + lsp_clear_data(lsp); + return lsp; + } + + lsp = lsp_new(area, frag_id, lsp0->hdr.rem_lifetime, 0, + lsp_bits_generate(level, area->overload_bit, + area->attached_bit), + 0, level); + lsp->own_lsp = 1; + lsp_insert(lsp, area->lspdb[level - 1]); + listnode_add(lsp0->lspu.frags, lsp); + lsp->lspu.zero_lsp = lsp0; + return lsp; } /* @@ -1361,126 +822,69 @@ static void lsp_build_ext_reach(struct isis_lsp *lsp, struct isis_area *area, */ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) { - struct is_neigh *is_neigh; - struct te_is_neigh *te_is_neigh; - struct listnode *node, *ipnode; int level = lsp->level; - struct isis_circuit *circuit; - struct prefix_ipv4 *ipv4; - struct ipv4_reachability *ipreach; - struct te_ipv4_reachability *te_ipreach; - struct isis_adjacency *nei; - struct prefix_ipv6 *ipv6, ip6prefix; - struct list *ipv6_reachs = NULL; - struct ipv6_reachability *ip6reach; - struct tlvs tlv_data; - struct isis_lsp *lsp0 = lsp; - struct in_addr *routerid; - uint32_t expected = 0, found = 0; - uint32_t metric; - u_char zero_id[ISIS_SYS_ID_LEN + 1]; - int retval = ISIS_OK; - char buf[BUFSIZ]; + char buf[PREFIX2STR_BUFFER]; + struct listnode *node; + struct isis_lsp *frag; + + lsp_clear_data(lsp); + for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) + lsp_clear_data(frag); + lsp->tlvs = isis_alloc_tlvs(); lsp_debug("ISIS (%s): Constructing local system LSP for level %d", area->area_tag, level); - /* - * Building the zero lsp - */ - memset(zero_id, 0, ISIS_SYS_ID_LEN + 1); - - /* Reset stream endp. Stream is always there and on every LSP refresh - * only - * TLV part of it is overwritten. So we must seek past header we will - * not - * touch. */ - stream_reset(lsp->pdu); - stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); - - /* - * Add the authentication info if its present - */ - lsp_auth_add(lsp); + lsp->hdr.lsp_bits = lsp_bits_generate(level, area->overload_bit, + area->attached_bit); - /* - * First add the tlvs related to area - */ + lsp_add_auth(lsp); - /* Area addresses */ - if (lsp->tlv_data.area_addrs == NULL) - lsp->tlv_data.area_addrs = list_new(); - list_add_list(lsp->tlv_data.area_addrs, area->area_addrs); - if (listcount(lsp->tlv_data.area_addrs) > 0) - tlv_add_area_addrs(lsp->tlv_data.area_addrs, lsp->pdu); + isis_tlvs_add_area_addresses(lsp->tlvs, area->area_addrs); /* Protocols Supported */ if (area->ip_circuits > 0 || area->ipv6_circuits > 0) { - lsp->tlv_data.nlpids = - XCALLOC(MTYPE_ISIS_TLV, sizeof(struct nlpids)); - lsp->tlv_data.nlpids->count = 0; + struct nlpids nlpids = {.count = 0}; if (area->ip_circuits > 0) { lsp_debug( "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs", area->area_tag); - lsp->tlv_data.nlpids->count++; - lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP; + nlpids.nlpids[nlpids.count] = NLPID_IP; + nlpids.count++; } if (area->ipv6_circuits > 0) { lsp_debug( "ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs", area->area_tag); - lsp->tlv_data.nlpids->count++; - lsp->tlv_data.nlpids - ->nlpids[lsp->tlv_data.nlpids->count - 1] = - NLPID_IPV6; + nlpids.nlpids[nlpids.count] = NLPID_IPV6; + nlpids.count++; } - tlv_add_nlpid(lsp->tlv_data.nlpids, lsp->pdu); + isis_tlvs_set_protocols_supported(lsp->tlvs, &nlpids); } if (area_is_mt(area)) { lsp_debug("ISIS (%s): Adding MT router tlv...", area->area_tag); - lsp->tlv_data.mt_router_info = list_new(); - lsp->tlv_data.mt_router_info->del = free_tlv; struct isis_area_mt_setting **mt_settings; unsigned int mt_count; mt_settings = area_mt_settings(area, &mt_count); for (unsigned int i = 0; i < mt_count; i++) { - struct mt_router_info *info; - - info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info)); - info->mtid = mt_settings[i]->mtid; - info->overload = mt_settings[i]->overload; - listnode_add(lsp->tlv_data.mt_router_info, info); + isis_tlvs_add_mt_router_info( + lsp->tlvs, mt_settings[i]->mtid, + mt_settings[i]->overload, false); lsp_debug("ISIS (%s): MT %s", area->area_tag, - isis_mtid2str(info->mtid)); + isis_mtid2str(mt_settings[i]->mtid)); } - tlv_add_mt_router_info(lsp->tlv_data.mt_router_info, lsp->pdu); } else { lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)", area->area_tag); } /* Dynamic Hostname */ if (area->dynhostname) { - const char *hostname = unix_hostname(); - size_t hostname_len = strlen(hostname); - - lsp->tlv_data.hostname = - XMALLOC(MTYPE_ISIS_TLV, sizeof(struct hostname)); - - strncpy((char *)lsp->tlv_data.hostname->name, hostname, - sizeof(lsp->tlv_data.hostname->name)); - if (hostname_len <= MAX_TLV_LEN) - lsp->tlv_data.hostname->namelen = hostname_len; - else - lsp->tlv_data.hostname->namelen = MAX_TLV_LEN; - - lsp_debug("ISIS (%s): Adding dynamic hostname '%.*s'", - area->area_tag, lsp->tlv_data.hostname->namelen, - lsp->tlv_data.hostname->name); - tlv_add_dynamic_hostname(lsp->tlv_data.hostname, lsp->pdu); + isis_tlvs_set_dynamic_hostname(lsp->tlvs, unix_hostname()); + lsp_debug("ISIS (%s): Adding dynamic hostname '%s'", + area->area_tag, unix_hostname()); } else { lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)", area->area_tag); @@ -1491,45 +895,31 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) * into * LSP and this address is same as router id. */ if (isis->router_id != 0) { - inet_ntop(AF_INET, &isis->router_id, buf, sizeof(buf)); + struct in_addr id = {.s_addr = isis->router_id}; + inet_ntop(AF_INET, &id, buf, sizeof(buf)); lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.", area->area_tag, buf); - if (lsp->tlv_data.ipv4_addrs == NULL) { - lsp->tlv_data.ipv4_addrs = list_new(); - lsp->tlv_data.ipv4_addrs->del = free_tlv; - } - - routerid = XMALLOC(MTYPE_ISIS_TLV, sizeof(struct in_addr)); - routerid->s_addr = isis->router_id; - listnode_add(lsp->tlv_data.ipv4_addrs, routerid); - tlv_add_in_addr(routerid, lsp->pdu, IPV4_ADDR); + isis_tlvs_add_ipv4_address(lsp->tlvs, &id); /* Exactly same data is put into TE router ID TLV, but only if * new style * TLV's are in use. */ if (area->newmetric) { + lsp_debug( "ISIS (%s): Adding router ID also as TE router ID tlv.", area->area_tag); - lsp->tlv_data.router_id = - XMALLOC(MTYPE_ISIS_TLV, sizeof(struct in_addr)); - lsp->tlv_data.router_id->id.s_addr = isis->router_id; - tlv_add_in_addr(&lsp->tlv_data.router_id->id, lsp->pdu, - TE_ROUTER_ID); + isis_tlvs_set_te_router_id(lsp->tlvs, &id); } } else { lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.", area->area_tag); } - memset(&tlv_data, 0, sizeof(struct tlvs)); - lsp_debug("ISIS (%s): Adding circuit specific information.", area->area_tag); - /* - * Then build lists of tlvs related to circuits - */ + struct isis_circuit *circuit; for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) { if (!circuit->interface) lsp_debug( @@ -1549,245 +939,94 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) continue; } - /* - * Add IPv4 internal reachability of this circuit - */ + uint32_t metric = area->oldmetric + ? circuit->metric[level - 1] + : circuit->te_metric[level - 1]; + if (circuit->ip_router && circuit->ip_addrs && circuit->ip_addrs->count > 0) { lsp_debug( "ISIS (%s): Circuit has IPv4 active, adding respective TLVs.", area->area_tag); - if (area->oldmetric) { - if (tlv_data.ipv4_int_reachs == NULL) { - tlv_data.ipv4_int_reachs = list_new(); - tlv_data.ipv4_int_reachs->del = - free_tlv; - } - for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, - ipnode, ipv4)) { - ipreach = XMALLOC( - MTYPE_ISIS_TLV, - sizeof(struct - ipv4_reachability)); - ipreach->metrics.metric_default = - circuit->metric[level - 1]; - ipreach->metrics.metric_expense = - METRICS_UNSUPPORTED; - ipreach->metrics.metric_error = - METRICS_UNSUPPORTED; - ipreach->metrics.metric_delay = - METRICS_UNSUPPORTED; - masklen2ip(ipv4->prefixlen, - &ipreach->mask); - ipreach->prefix.s_addr = - ((ipreach->mask.s_addr) - & (ipv4->prefix.s_addr)); - inet_ntop(AF_INET, - &ipreach->prefix.s_addr, buf, - sizeof(buf)); + struct listnode *ipnode; + struct prefix_ipv4 *ipv4; + for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, ipnode, + ipv4)) { + if (area->oldmetric) { lsp_debug( - "ISIS (%s): Adding old-style IP reachability for %s/%d", - area->area_tag, buf, - ipv4->prefixlen); - listnode_add(tlv_data.ipv4_int_reachs, - ipreach); - } - } - if (area->newmetric) { - if (tlv_data.te_ipv4_reachs == NULL) { - tlv_data.te_ipv4_reachs = list_new(); - tlv_data.te_ipv4_reachs->del = free_tlv; + "ISIS (%s): Adding old-style IP reachability for %s", + area->area_tag, + prefix2str(ipv4, buf, + sizeof(buf))); + isis_tlvs_add_oldstyle_ip_reach( + lsp->tlvs, ipv4, metric); } - for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, - ipnode, ipv4)) { - /* FIXME All this assumes that we have - * no sub TLVs. */ - te_ipreach = XCALLOC( - MTYPE_ISIS_TLV, - sizeof(struct - te_ipv4_reachability) - + ((ipv4->prefixlen + 7) - / 8) - - 1); - - if (area->oldmetric) - te_ipreach->te_metric = htonl( - circuit->metric[level - - 1]); - else - te_ipreach->te_metric = htonl( - circuit->te_metric - [level - 1]); - - te_ipreach->control = - (ipv4->prefixlen & 0x3F); - memcpy(&te_ipreach->prefix_start, - &ipv4->prefix.s_addr, - (ipv4->prefixlen + 7) / 8); - inet_ntop(AF_INET, &ipv4->prefix.s_addr, - buf, sizeof(buf)); + + if (area->newmetric) { lsp_debug( - "ISIS (%s): Adding te-style IP reachability for %s/%d", - area->area_tag, buf, - ipv4->prefixlen); - listnode_add(tlv_data.te_ipv4_reachs, - te_ipreach); + "ISIS (%s): Adding te-style IP reachability for %s", + area->area_tag, + prefix2str(ipv4, buf, + sizeof(buf))); + isis_tlvs_add_extended_ip_reach( + lsp->tlvs, ipv4, metric); } } } - /* - * Add IPv6 reachability of this circuit - */ if (circuit->ipv6_router && circuit->ipv6_non_link && circuit->ipv6_non_link->count > 0) { - if (!ipv6_reachs) - ipv6_reachs = tlv_get_ipv6_reach_list( - area, &tlv_data); - + struct listnode *ipnode; + struct prefix_ipv6 *ipv6; for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, ipnode, ipv6)) { - ip6reach = XCALLOC( - MTYPE_ISIS_TLV, - sizeof(struct ipv6_reachability)); - - if (area->oldmetric) - ip6reach->metric = htonl( - circuit->metric[level - 1]); - else - ip6reach->metric = htonl( - circuit->te_metric[level - 1]); - - ip6reach->control_info = 0; - ip6reach->prefix_len = ipv6->prefixlen; - memcpy(&ip6prefix, ipv6, sizeof(ip6prefix)); - apply_mask_ipv6(&ip6prefix); - - inet_ntop(AF_INET6, &ip6prefix.prefix.s6_addr, - buf, sizeof(buf)); lsp_debug( - "ISIS (%s): Adding IPv6 reachability for %s/%d", - area->area_tag, buf, ipv6->prefixlen); - - memcpy(ip6reach->prefix, - ip6prefix.prefix.s6_addr, - sizeof(ip6reach->prefix)); - listnode_add(ipv6_reachs, ip6reach); + "ISIS (%s): Adding IPv6 reachability for %s", + area->area_tag, + prefix2str(ipv6, buf, sizeof(buf))); + isis_tlvs_add_ipv6_reach( + lsp->tlvs, + isis_area_ipv6_topology(area), ipv6, + metric); } } switch (circuit->circ_type) { case CIRCUIT_T_BROADCAST: if (level & circuit->is_type) { - if (area->oldmetric) { - if (tlv_data.is_neighs == NULL) { - tlv_data.is_neighs = list_new(); - tlv_data.is_neighs->del = - free_tlv; - } - is_neigh = XCALLOC( - MTYPE_ISIS_TLV, - sizeof(struct is_neigh)); - if (level == IS_LEVEL_1) - memcpy(is_neigh->neigh_id, - circuit->u.bc - .l1_desig_is, - ISIS_SYS_ID_LEN + 1); - else - memcpy(is_neigh->neigh_id, - circuit->u.bc - .l2_desig_is, - ISIS_SYS_ID_LEN + 1); - is_neigh->metrics.metric_default = - circuit->metric[level - 1]; - is_neigh->metrics.metric_expense = - METRICS_UNSUPPORTED; - is_neigh->metrics.metric_error = - METRICS_UNSUPPORTED; - is_neigh->metrics.metric_delay = - METRICS_UNSUPPORTED; - if (!memcmp(is_neigh->neigh_id, zero_id, - ISIS_SYS_ID_LEN + 1)) { - XFREE(MTYPE_ISIS_TLV, is_neigh); - lsp_debug( - "ISIS (%s): No DIS for circuit, not adding old-style IS neighbor.", - area->area_tag); - } else { - listnode_add(tlv_data.is_neighs, - is_neigh); + uint8_t *ne_id = + (level == IS_LEVEL_1) + ? circuit->u.bc.l1_desig_is + : circuit->u.bc.l2_desig_is; + + if (LSP_PSEUDO_ID(ne_id)) { + if (area->oldmetric) { lsp_debug( "ISIS (%s): Adding DIS %s.%02x as old-style neighbor", area->area_tag, - sysid_print( - is_neigh->neigh_id), - LSP_PSEUDO_ID( - is_neigh->neigh_id)); + sysid_print(ne_id), + LSP_PSEUDO_ID(ne_id)); + isis_tlvs_add_oldstyle_reach( + lsp->tlvs, ne_id, + metric); } - } - if (area->newmetric) { - if (tlv_data.te_is_neighs == NULL) { - tlv_data.te_is_neighs = - list_new(); - tlv_data.te_is_neighs->del = - free_tlv; - } - te_is_neigh = XCALLOC( - MTYPE_ISIS_TLV, - sizeof(struct te_is_neigh)); - if (level == IS_LEVEL_1) - memcpy(te_is_neigh->neigh_id, - circuit->u.bc - .l1_desig_is, - ISIS_SYS_ID_LEN + 1); - else - memcpy(te_is_neigh->neigh_id, - circuit->u.bc - .l2_desig_is, - ISIS_SYS_ID_LEN + 1); - if (area->oldmetric) - metric = circuit->metric[level - - 1]; - else - metric = - circuit->te_metric[level - - 1]; - SET_TE_METRIC(te_is_neigh, metric); - if (!memcmp(te_is_neigh->neigh_id, - zero_id, - ISIS_SYS_ID_LEN + 1)) { - XFREE(MTYPE_ISIS_TLV, - te_is_neigh); - lsp_debug( - "ISIS (%s): No DIS for circuit, not adding te-style IS neighbor.", - area->area_tag); - } else { - /* Check if MPLS_TE is activate - */ + if (area->newmetric) { + uint8_t subtlvs[256]; + uint8_t subtlv_len; + if (IS_MPLS_TE(isisMplsTE) && HAS_LINK_PARAMS( circuit->interface)) - /* Add SubTLVs & Adjust - * real size of SubTLVs - */ - te_is_neigh - ->sub_tlvs_length = add_te_subtlvs( - te_is_neigh - ->sub_tlvs, + subtlv_len = add_te_subtlvs( + subtlvs, circuit->mtc); else - /* Or keep only TE - * metric with no - * SubTLVs if MPLS_TE is - * off */ - te_is_neigh - ->sub_tlvs_length = - 0; + subtlv_len = 0; tlvs_add_mt_bcast( - &tlv_data, circuit, - level, te_is_neigh); - XFREE(MTYPE_ISIS_TLV, - te_is_neigh); + lsp->tlvs, circuit, + level, ne_id, metric, + subtlvs, subtlv_len); } } } else { @@ -1796,53 +1035,25 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) area->area_tag); } break; - case CIRCUIT_T_P2P: - nei = circuit->u.p2p.neighbor; + case CIRCUIT_T_P2P: { + struct isis_adjacency *nei = circuit->u.p2p.neighbor; if (nei && (level & nei->circuit_t)) { + uint8_t ne_id[7]; + memcpy(ne_id, nei->sysid, ISIS_SYS_ID_LEN); + LSP_PSEUDO_ID(ne_id) = 0; + if (area->oldmetric) { - if (tlv_data.is_neighs == NULL) { - tlv_data.is_neighs = list_new(); - tlv_data.is_neighs->del = - free_tlv; - } - is_neigh = XCALLOC( - MTYPE_ISIS_TLV, - sizeof(struct is_neigh)); - memcpy(is_neigh->neigh_id, nei->sysid, - ISIS_SYS_ID_LEN); - is_neigh->metrics.metric_default = - circuit->metric[level - 1]; - is_neigh->metrics.metric_expense = - METRICS_UNSUPPORTED; - is_neigh->metrics.metric_error = - METRICS_UNSUPPORTED; - is_neigh->metrics.metric_delay = - METRICS_UNSUPPORTED; - listnode_add(tlv_data.is_neighs, - is_neigh); lsp_debug( "ISIS (%s): Adding old-style is reach for %s", area->area_tag, - sysid_print( - is_neigh->neigh_id)); + sysid_print(ne_id)); + isis_tlvs_add_oldstyle_reach( + lsp->tlvs, ne_id, metric); } if (area->newmetric) { - uint32_t metric; + uint8_t subtlvs[256]; + uint8_t subtlv_len; - if (tlv_data.te_is_neighs == NULL) { - tlv_data.te_is_neighs = - list_new(); - tlv_data.te_is_neighs->del = - free_tlv; - } - te_is_neigh = XCALLOC( - MTYPE_ISIS_TLV, - sizeof(struct te_is_neigh)); - memcpy(te_is_neigh->neigh_id, - nei->sysid, ISIS_SYS_ID_LEN); - metric = circuit->te_metric[level - 1]; - SET_TE_METRIC(te_is_neigh, metric); - /* Check if MPLS_TE is activate */ if (IS_MPLS_TE(isisMplsTE) && HAS_LINK_PARAMS( circuit->interface)) @@ -1861,28 +1072,24 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) /* Add SubTLVs & Adjust real * size of SubTLVs */ - te_is_neigh->sub_tlvs_length = - add_te_subtlvs( - te_is_neigh - ->sub_tlvs, - circuit->mtc); + subtlv_len = add_te_subtlvs( + subtlvs, circuit->mtc); else /* Or keep only TE metric with * no SubTLVs if MPLS_TE is off */ - te_is_neigh->sub_tlvs_length = - 0; + subtlv_len = 0; - tlvs_add_mt_p2p(&tlv_data, circuit, - te_is_neigh); - XFREE(MTYPE_ISIS_TLV, te_is_neigh); + tlvs_add_mt_p2p(lsp->tlvs, circuit, + ne_id, metric, subtlvs, + subtlv_len); } } else { lsp_debug( "ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors", area->area_tag); } - break; + } break; case CIRCUIT_T_LOOPBACK: break; default: @@ -1890,169 +1097,36 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) } } - lsp_build_ext_reach(lsp, area, &tlv_data); - - lsp_debug("ISIS (%s): LSP construction is complete. Serializing...", - area->area_tag); - - while (tlv_data.ipv4_int_reachs - && listcount(tlv_data.ipv4_int_reachs)) { - if (lsp->tlv_data.ipv4_int_reachs == NULL) - lsp->tlv_data.ipv4_int_reachs = list_new(); - lsp_tlv_fit(lsp, &tlv_data.ipv4_int_reachs, - &lsp->tlv_data.ipv4_int_reachs, IPV4_REACH_LEN, - area->lsp_frag_threshold, tlv_add_ipv4_int_reachs); - if (tlv_data.ipv4_int_reachs - && listcount(tlv_data.ipv4_int_reachs)) - lsp = lsp_next_frag( - LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0, - area, level); - } - - while (tlv_data.ipv4_ext_reachs - && listcount(tlv_data.ipv4_ext_reachs)) { - if (lsp->tlv_data.ipv4_ext_reachs == NULL) - lsp->tlv_data.ipv4_ext_reachs = list_new(); - lsp_tlv_fit(lsp, &tlv_data.ipv4_ext_reachs, - &lsp->tlv_data.ipv4_ext_reachs, IPV4_REACH_LEN, - area->lsp_frag_threshold, tlv_add_ipv4_ext_reachs); - if (tlv_data.ipv4_ext_reachs - && listcount(tlv_data.ipv4_ext_reachs)) - lsp = lsp_next_frag( - LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0, - area, level); - } - - while (tlv_data.te_ipv4_reachs && listcount(tlv_data.te_ipv4_reachs)) { - if (lsp->tlv_data.te_ipv4_reachs == NULL) - lsp->tlv_data.te_ipv4_reachs = list_new(); - _lsp_tlv_fit(lsp, &tlv_data.te_ipv4_reachs, - &lsp->tlv_data.te_ipv4_reachs, - area->lsp_frag_threshold, tlv_add_te_ipv4_reachs, - NULL); - if (tlv_data.te_ipv4_reachs - && listcount(tlv_data.te_ipv4_reachs)) - lsp = lsp_next_frag( - LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0, - area, level); - } + lsp_build_ext_reach(lsp, area); - struct tlv_mt_ipv4_reachs *mt_ipv4_reachs; - for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_ipv4_reachs, node, - mt_ipv4_reachs)) { - while (mt_ipv4_reachs->list - && listcount(mt_ipv4_reachs->list)) { - struct tlv_mt_ipv4_reachs *frag_mt_ipv4_reachs; - - frag_mt_ipv4_reachs = tlvs_get_mt_ipv4_reachs( - &lsp->tlv_data, mt_ipv4_reachs->mtid); - _lsp_tlv_fit(lsp, &mt_ipv4_reachs->list, - &frag_mt_ipv4_reachs->list, - area->lsp_frag_threshold, - tlv_add_te_ipv4_reachs, - &mt_ipv4_reachs->mtid); - if (mt_ipv4_reachs->list - && listcount(mt_ipv4_reachs->list)) - lsp = lsp_next_frag( - LSP_FRAGMENT(lsp->lsp_header->lsp_id) - + 1, - lsp0, area, level); - } - } + struct isis_tlvs *tlvs = lsp->tlvs; + lsp->tlvs = NULL; - while (tlv_data.ipv6_reachs && listcount(tlv_data.ipv6_reachs)) { - if (lsp->tlv_data.ipv6_reachs == NULL) - lsp->tlv_data.ipv6_reachs = list_new(); - _lsp_tlv_fit( - lsp, &tlv_data.ipv6_reachs, &lsp->tlv_data.ipv6_reachs, - area->lsp_frag_threshold, tlv_add_ipv6_reachs, NULL); - if (tlv_data.ipv6_reachs && listcount(tlv_data.ipv6_reachs)) - lsp = lsp_next_frag( - LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0, - area, level); - } - - struct tlv_mt_ipv6_reachs *mt_ipv6_reachs; - for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_ipv6_reachs, node, - mt_ipv6_reachs)) { - while (mt_ipv6_reachs->list - && listcount(mt_ipv6_reachs->list)) { - struct tlv_mt_ipv6_reachs *frag_mt_ipv6_reachs; - - frag_mt_ipv6_reachs = tlvs_get_mt_ipv6_reachs( - &lsp->tlv_data, mt_ipv6_reachs->mtid); - _lsp_tlv_fit(lsp, &mt_ipv6_reachs->list, - &frag_mt_ipv6_reachs->list, - area->lsp_frag_threshold, - tlv_add_ipv6_reachs, - &mt_ipv6_reachs->mtid); - if (mt_ipv6_reachs->list - && listcount(mt_ipv6_reachs->list)) - lsp = lsp_next_frag( - LSP_FRAGMENT(lsp->lsp_header->lsp_id) - + 1, - lsp0, area, level); - } - } - - while (tlv_data.is_neighs && listcount(tlv_data.is_neighs)) { - if (lsp->tlv_data.is_neighs == NULL) - lsp->tlv_data.is_neighs = list_new(); - lsp_tlv_fit(lsp, &tlv_data.is_neighs, &lsp->tlv_data.is_neighs, - IS_NEIGHBOURS_LEN, area->lsp_frag_threshold, - tlv_add_is_neighs); - if (tlv_data.is_neighs && listcount(tlv_data.is_neighs)) - lsp = lsp_next_frag( - LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0, - area, level); - } + lsp_pack_pdu(lsp); + size_t tlv_space = STREAM_WRITEABLE(lsp->pdu) - LLC_LEN; + lsp_clear_data(lsp); - while (tlv_data.te_is_neighs && listcount(tlv_data.te_is_neighs)) { - if (lsp->tlv_data.te_is_neighs == NULL) - lsp->tlv_data.te_is_neighs = list_new(); - _lsp_tlv_fit(lsp, &tlv_data.te_is_neighs, - &lsp->tlv_data.te_is_neighs, - area->lsp_frag_threshold, tlv_add_te_is_neighs, - NULL); - if (tlv_data.te_is_neighs && listcount(tlv_data.te_is_neighs)) - lsp = lsp_next_frag( - LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0, - area, level); + struct list *fragments = isis_fragment_tlvs(tlvs, tlv_space); + if (!fragments) { + zlog_warn("BUG: could not fragment own LSP:"); + log_multiline(LOG_WARNING, " ", "%s", isis_format_tlvs(tlvs)); + isis_free_tlvs(tlvs); + return; } + isis_free_tlvs(tlvs); - struct tlv_mt_neighbors *mt_neighs; - for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_is_neighs, node, mt_neighs)) { - while (mt_neighs->list && listcount(mt_neighs->list)) { - struct tlv_mt_neighbors *frag_mt_neighs; - - frag_mt_neighs = tlvs_get_mt_neighbors(&lsp->tlv_data, - mt_neighs->mtid); - _lsp_tlv_fit(lsp, &mt_neighs->list, - &frag_mt_neighs->list, - area->lsp_frag_threshold, - tlv_add_te_is_neighs, &mt_neighs->mtid); - if (mt_neighs->list && listcount(mt_neighs->list)) - lsp = lsp_next_frag( - LSP_FRAGMENT(lsp->lsp_header->lsp_id) - + 1, - lsp0, area, level); + frag = lsp; + for (ALL_LIST_ELEMENTS_RO(fragments, node, tlvs)) { + if (node != listhead(fragments)) { + frag = lsp_next_frag(LSP_FRAGMENT(frag->hdr.lsp_id) + 1, + lsp, area, level); } + frag->tlvs = tlvs; } - - lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu)); - - free_tlvs(&tlv_data); - - /* Validate the LSP */ - retval = parse_tlvs(area->area_tag, - STREAM_DATA(lsp->pdu) + ISIS_FIXED_HDR_LEN - + ISIS_LSP_HDR_LEN, - stream_get_endp(lsp->pdu) - ISIS_FIXED_HDR_LEN - - ISIS_LSP_HDR_LEN, - &expected, &found, &tlv_data, NULL); - assert(retval == ISIS_OK); - + list_delete(fragments); + lsp_debug("ISIS (%s): LSP construction is complete. Serializing...", + area->area_tag); return; } @@ -2076,8 +1150,8 @@ int lsp_generate(struct isis_area *area, int level) oldlsp = lsp_search(lspid, area->lspdb[level - 1]); if (oldlsp) { /* FIXME: we should actually initiate a purge */ - seq_num = ntohl(oldlsp->lsp_header->seq_num); - lsp_search_and_destroy(oldlsp->lsp_header->lsp_id, + seq_num = oldlsp->hdr.seqno; + lsp_search_and_destroy(oldlsp->hdr.lsp_id, area->lspdb[level - 1]); } rem_lifetime = lsp_rem_lifetime(area, level); @@ -2092,7 +1166,7 @@ int lsp_generate(struct isis_area *area, int level) /* build_lsp_data (newlsp, area); */ lsp_build(newlsp, area); /* time to calculate our checksum */ - lsp_seqnum_update(newlsp); + lsp_seqno_update(newlsp); newlsp->last_generated = time(NULL); lsp_set_all_srmflags(newlsp); @@ -2108,15 +1182,14 @@ int lsp_generate(struct isis_area *area, int level) &area->t_lsp_refresh[level - 1]); if (isis->debugs & DEBUG_UPDATE_PACKETS) { - zlog_debug( - "ISIS-Upd (%s): Building L%d LSP %s, len %d, " - "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us", - area->area_tag, level, - rawlspid_print(newlsp->lsp_header->lsp_id), - ntohl(newlsp->lsp_header->pdu_len), - ntohl(newlsp->lsp_header->seq_num), - ntohs(newlsp->lsp_header->checksum), - ntohs(newlsp->lsp_header->rem_lifetime), refresh_time); + zlog_debug("ISIS-Upd (%s): Building L%d LSP %s, len %" PRIu16 + ", seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16 + ", lifetime %" PRIu16 "s refresh %" PRIu16 "s", + area->area_tag, level, + rawlspid_print(newlsp->hdr.lsp_id), + newlsp->hdr.pdu_len, newlsp->hdr.seqno, + newlsp->hdr.checksum, newlsp->hdr.rem_lifetime, + refresh_time); } sched_debug( "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.", @@ -2154,24 +1227,21 @@ static int lsp_regenerate(struct isis_area *area, int level) lsp_clear_data(lsp); lsp_build(lsp, area); - lsp->lsp_header->lsp_bits = lsp_bits_generate(level, area->overload_bit, - area->attached_bit); rem_lifetime = lsp_rem_lifetime(area, level); - lsp->lsp_header->rem_lifetime = htons(rem_lifetime); - lsp_seqnum_update(lsp); - + lsp->hdr.rem_lifetime = rem_lifetime; lsp->last_generated = time(NULL); lsp_set_all_srmflags(lsp); for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) { - frag->lsp_header->lsp_bits = lsp_bits_generate( + frag->hdr.lsp_bits = lsp_bits_generate( level, area->overload_bit, area->attached_bit); /* Set the lifetime values of all the fragments to the same * value, * so that no fragment expires before the lsp is refreshed. */ - frag->lsp_header->rem_lifetime = htons(rem_lifetime); + frag->hdr.rem_lifetime = rem_lifetime; lsp_set_all_srmflags(frag); } + lsp_seqno_update(lsp); refresh_time = lsp_refresh_time(lsp, rem_lifetime); if (level == IS_LEVEL_1) @@ -2184,14 +1254,12 @@ static int lsp_regenerate(struct isis_area *area, int level) if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug( - "ISIS-Upd (%s): Refreshing our L%d LSP %s, len %d, " - "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us", - area->area_tag, level, - rawlspid_print(lsp->lsp_header->lsp_id), - ntohl(lsp->lsp_header->pdu_len), - ntohl(lsp->lsp_header->seq_num), - ntohs(lsp->lsp_header->checksum), - ntohs(lsp->lsp_header->rem_lifetime), refresh_time); + "ISIS-Upd (%s): Refreshed our L%d LSP %s, len %" PRIu16 + ", seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16 + ", lifetime %" PRIu16 "s refresh %" PRIu16 "s", + area->area_tag, level, rawlspid_print(lsp->hdr.lsp_id), + lsp->hdr.pdu_len, lsp->hdr.seqno, lsp->hdr.checksum, + lsp->hdr.rem_lifetime, refresh_time); } sched_debug( "ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.", @@ -2351,164 +1419,89 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit, int level) { struct isis_adjacency *adj; - struct is_neigh *is_neigh; - struct te_is_neigh *te_is_neigh; - struct es_neigh *es_neigh; struct list *adj_list; struct listnode *node; struct isis_area *area = circuit->area; + lsp_clear_data(lsp); + lsp->tlvs = isis_alloc_tlvs(); lsp_debug( "ISIS (%s): Constructing pseudo LSP %s for interface %s level %d", - area->area_tag, rawlspid_print(lsp->lsp_header->lsp_id), + area->area_tag, rawlspid_print(lsp->hdr.lsp_id), circuit->interface->name, level); lsp->level = level; /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */ - lsp->lsp_header->lsp_bits = + lsp->hdr.lsp_bits = lsp_bits_generate(level, 0, circuit->area->attached_bit); /* * add self to IS neighbours */ - if (circuit->area->oldmetric) { - if (lsp->tlv_data.is_neighs == NULL) { - lsp->tlv_data.is_neighs = list_new(); - lsp->tlv_data.is_neighs->del = free_tlv; - } - is_neigh = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct is_neigh)); + uint8_t ne_id[ISIS_SYS_ID_LEN + 1]; - memcpy(&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN); - listnode_add(lsp->tlv_data.is_neighs, is_neigh); + memcpy(ne_id, isis->sysid, ISIS_SYS_ID_LEN); + LSP_PSEUDO_ID(ne_id) = 0; + + if (circuit->area->oldmetric) { + isis_tlvs_add_oldstyle_reach(lsp->tlvs, ne_id, 0); lsp_debug( "ISIS (%s): Adding %s.%02x as old-style neighbor (self)", - area->area_tag, sysid_print(is_neigh->neigh_id), - LSP_PSEUDO_ID(is_neigh->neigh_id)); + area->area_tag, sysid_print(ne_id), + LSP_PSEUDO_ID(ne_id)); } if (circuit->area->newmetric) { - if (lsp->tlv_data.te_is_neighs == NULL) { - lsp->tlv_data.te_is_neighs = list_new(); - lsp->tlv_data.te_is_neighs->del = free_tlv; - } - te_is_neigh = - XCALLOC(MTYPE_ISIS_TLV, sizeof(struct te_is_neigh)); - - memcpy(&te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN); - listnode_add(lsp->tlv_data.te_is_neighs, te_is_neigh); + isis_tlvs_add_extended_reach(lsp->tlvs, ISIS_MT_IPV4_UNICAST, + ne_id, 0, NULL, 0); lsp_debug( "ISIS (%s): Adding %s.%02x as te-style neighbor (self)", - area->area_tag, sysid_print(te_is_neigh->neigh_id), - LSP_PSEUDO_ID(te_is_neigh->neigh_id)); + area->area_tag, sysid_print(ne_id), + LSP_PSEUDO_ID(ne_id)); } adj_list = list_new(); isis_adj_build_up_list(circuit->u.bc.adjdb[level - 1], adj_list); for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj)) { - if (adj->level & level) { - if ((level == IS_LEVEL_1 - && adj->sys_type == ISIS_SYSTYPE_L1_IS) - || (level == IS_LEVEL_1 - && adj->sys_type == ISIS_SYSTYPE_L2_IS - && adj->adj_usage == ISIS_ADJ_LEVEL1AND2) - || (level == IS_LEVEL_2 - && adj->sys_type == ISIS_SYSTYPE_L2_IS)) { - /* an IS neighbour -> add it */ - if (circuit->area->oldmetric) { - is_neigh = XCALLOC( - MTYPE_ISIS_TLV, - sizeof(struct is_neigh)); - - memcpy(&is_neigh->neigh_id, adj->sysid, - ISIS_SYS_ID_LEN); - listnode_add(lsp->tlv_data.is_neighs, - is_neigh); - lsp_debug( - "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)", - area->area_tag, - sysid_print(is_neigh->neigh_id), - LSP_PSEUDO_ID( - is_neigh->neigh_id)); - } - if (circuit->area->newmetric) { - te_is_neigh = XCALLOC( - MTYPE_ISIS_TLV, - sizeof(struct te_is_neigh)); - memcpy(&te_is_neigh->neigh_id, - adj->sysid, ISIS_SYS_ID_LEN); - listnode_add(lsp->tlv_data.te_is_neighs, - te_is_neigh); - lsp_debug( - "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)", - area->area_tag, - sysid_print( - te_is_neigh->neigh_id), - LSP_PSEUDO_ID( - te_is_neigh->neigh_id)); - } - } else if (level == IS_LEVEL_1 - && adj->sys_type == ISIS_SYSTYPE_ES) { - /* an ES neigbour add it, if we are building - * level 1 LSP */ - /* FIXME: the tlv-format is hard to use here */ - if (lsp->tlv_data.es_neighs == NULL) { - lsp->tlv_data.es_neighs = list_new(); - lsp->tlv_data.es_neighs->del = free_tlv; - } - es_neigh = XCALLOC(MTYPE_ISIS_TLV, - sizeof(struct es_neigh)); - - memcpy(&es_neigh->first_es_neigh, adj->sysid, - ISIS_SYS_ID_LEN); - listnode_add(lsp->tlv_data.es_neighs, es_neigh); - lsp_debug( - "ISIS (%s): Adding %s as ES neighbor (peer)", - area->area_tag, - sysid_print(es_neigh->first_es_neigh)); - } else { - lsp_debug( - "ISIS (%s): Ignoring neighbor %s, level does not match", - area->area_tag, - sysid_print(adj->sysid)); - } - } else { + if (!(adj->level & level)) { lsp_debug( "ISIS (%s): Ignoring neighbor %s, level does not intersect", area->area_tag, sysid_print(adj->sysid)); + continue; } - } - list_delete(adj_list); - - lsp_debug("ISIS (%s): Pseudo LSP construction is complete.", - area->area_tag); - - /* Reset endp of stream to overwrite only TLV part of it. */ - stream_reset(lsp->pdu); - stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); - - /* - * Add the authentication info if it's present - */ - lsp_auth_add(lsp); - - if (lsp->tlv_data.is_neighs && listcount(lsp->tlv_data.is_neighs) > 0) - tlv_add_is_neighs(lsp->tlv_data.is_neighs, lsp->pdu); - if (lsp->tlv_data.te_is_neighs - && listcount(lsp->tlv_data.te_is_neighs) > 0) - tlv_add_te_is_neighs(lsp->tlv_data.te_is_neighs, lsp->pdu, - NULL); - - if (lsp->tlv_data.es_neighs && listcount(lsp->tlv_data.es_neighs) > 0) - tlv_add_is_neighs(lsp->tlv_data.es_neighs, lsp->pdu); - - lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu)); - - /* Recompute authentication and checksum information */ - lsp_auth_update(lsp); - fletcher_checksum(STREAM_DATA(lsp->pdu) + 12, - ntohs(lsp->lsp_header->pdu_len) - 12, 12); + if (!(level == IS_LEVEL_1 + && adj->sys_type == ISIS_SYSTYPE_L1_IS) + && !(level == IS_LEVEL_1 + && adj->sys_type == ISIS_SYSTYPE_L2_IS + && adj->adj_usage == ISIS_ADJ_LEVEL1AND2) + && !(level == IS_LEVEL_2 + && adj->sys_type == ISIS_SYSTYPE_L2_IS)) { + lsp_debug( + "ISIS (%s): Ignoring neighbor %s, level does not match", + area->area_tag, sysid_print(adj->sysid)); + continue; + } + memcpy(ne_id, adj->sysid, ISIS_SYS_ID_LEN); + if (circuit->area->oldmetric) { + isis_tlvs_add_oldstyle_reach(lsp->tlvs, ne_id, 0); + lsp_debug( + "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)", + area->area_tag, sysid_print(ne_id), + LSP_PSEUDO_ID(ne_id)); + } + if (circuit->area->newmetric) { + isis_tlvs_add_extended_reach(lsp->tlvs, + ISIS_MT_IPV4_UNICAST, + ne_id, 0, NULL, 0); + lsp_debug( + "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)", + area->area_tag, sysid_print(ne_id), + LSP_PSEUDO_ID(ne_id)); + } + } + list_delete(adj_list); return; } @@ -2543,7 +1536,7 @@ int lsp_generate_pseudo(struct isis_circuit *circuit, int level) lsp->area = circuit->area; lsp_build_pseudo(lsp, circuit, level); - + lsp_pack_pdu(lsp); lsp->own_lsp = 1; lsp_insert(lsp, lspdb); lsp_set_all_srmflags(lsp); @@ -2562,14 +1555,13 @@ int lsp_generate_pseudo(struct isis_circuit *circuit, int level) if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug( - "ISIS-Upd (%s): Building L%d Pseudo LSP %s, len %d, " - "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us", + "ISIS-Upd (%s): Built L%d Pseudo LSP %s, len %" PRIu16 + ", seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16 + ", lifetime %" PRIu16 "s, refresh %" PRIu16 "s", circuit->area->area_tag, level, - rawlspid_print(lsp->lsp_header->lsp_id), - ntohl(lsp->lsp_header->pdu_len), - ntohl(lsp->lsp_header->seq_num), - ntohs(lsp->lsp_header->checksum), - ntohs(lsp->lsp_header->rem_lifetime), refresh_time); + rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.pdu_len, + lsp->hdr.seqno, lsp->hdr.checksum, + lsp->hdr.rem_lifetime, refresh_time); } return ISIS_OK; @@ -2599,16 +1591,11 @@ static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level) rawlspid_print(lsp_id)); return ISIS_ERROR; } - lsp_clear_data(lsp); - lsp_build_pseudo(lsp, circuit, level); - - /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */ - lsp->lsp_header->lsp_bits = - lsp_bits_generate(level, 0, circuit->area->attached_bit); rem_lifetime = lsp_rem_lifetime(circuit->area, level); - lsp->lsp_header->rem_lifetime = htons(rem_lifetime); - lsp_inc_seqnum(lsp, 0); + lsp->hdr.rem_lifetime = rem_lifetime; + lsp_build_pseudo(lsp, circuit, level); + lsp_inc_seqno(lsp, 0); lsp->last_generated = time(NULL); lsp_set_all_srmflags(lsp); @@ -2624,14 +1611,13 @@ static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level) if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug( - "ISIS-Upd (%s): Refreshing L%d Pseudo LSP %s, len %d, " - "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us", + "ISIS-Upd (%s): Refreshed L%d Pseudo LSP %s, len %" PRIu16 + ", seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16 + ", lifetime %" PRIu16 "s, refresh %" PRIu16 "s", circuit->area->area_tag, level, - rawlspid_print(lsp->lsp_header->lsp_id), - ntohl(lsp->lsp_header->pdu_len), - ntohl(lsp->lsp_header->seq_num), - ntohs(lsp->lsp_header->checksum), - ntohs(lsp->lsp_header->rem_lifetime), refresh_time); + rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.pdu_len, + lsp->hdr.seqno, lsp->hdr.checksum, + lsp->hdr.rem_lifetime, refresh_time); } return ISIS_OK; @@ -2828,8 +1814,7 @@ int lsp_tick(struct thread *thread) * when * the first time rem_lifetime becomes 0. */ - rem_lifetime = - ntohs(lsp->lsp_header->rem_lifetime); + rem_lifetime = lsp->hdr.rem_lifetime; lsp_set_time(lsp); /* @@ -2839,8 +1824,7 @@ int lsp_tick(struct thread *thread) * time. * ISO 10589 - 7.3.16.4 first paragraph. */ - if (rem_lifetime == 1 - && lsp->lsp_header->seq_num != 0) { + if (rem_lifetime == 1 && lsp->hdr.seqno != 0) { /* 7.3.16.4 a) set SRM flags on all */ lsp_set_all_srmflags(lsp); /* 7.3.16.4 b) retain only the header @@ -2857,13 +1841,11 @@ int lsp_tick(struct thread *thread) if (lsp->age_out == 0) { zlog_debug( - "ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out", + "ISIS-Upd (%s): L%u LSP %s seq " + "0x%08" PRIx32 " aged out", area->area_tag, lsp->level, - rawlspid_print( - lsp->lsp_header - ->lsp_id), - ntohl(lsp->lsp_header - ->seq_num)); + rawlspid_print(lsp->hdr.lsp_id), + lsp->hdr.seqno); lsp_destroy(lsp); lsp = NULL; dict_delete_free(area->lspdb[level], @@ -2924,51 +1906,19 @@ int lsp_tick(struct thread *thread) void lsp_purge_pseudo(u_char *id, struct isis_circuit *circuit, int level) { struct isis_lsp *lsp; - u_int16_t seq_num; - u_int8_t lsp_bits; lsp = lsp_search(id, circuit->area->lspdb[level - 1]); if (!lsp) return; - /* store old values */ - seq_num = lsp->lsp_header->seq_num; - lsp_bits = lsp->lsp_header->lsp_bits; - - /* reset stream */ - lsp_clear_data(lsp); - stream_reset(lsp->pdu); - - /* update header */ - lsp->lsp_header->pdu_len = htons(ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); - memcpy(lsp->lsp_header->lsp_id, id, ISIS_SYS_ID_LEN + 2); - lsp->lsp_header->checksum = 0; - lsp->lsp_header->seq_num = seq_num; - lsp->lsp_header->rem_lifetime = 0; - lsp->lsp_header->lsp_bits = lsp_bits; - lsp->level = level; - lsp->age_out = lsp->area->max_lsp_lifetime[level - 1]; - stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); - - /* - * Add and update the authentication info if its present - */ - lsp_auth_add(lsp); - lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu)); - lsp_auth_update(lsp); - fletcher_checksum(STREAM_DATA(lsp->pdu) + 12, - ntohs(lsp->lsp_header->pdu_len) - 12, 12); - - lsp_set_all_srmflags(lsp); - - return; + lsp_purge(lsp, level); } /* * Purge own LSP that is received and we don't have. * -> Do as in 7.3.16.4 */ -void lsp_purge_non_exist(int level, struct isis_link_state_hdr *lsp_hdr, +void lsp_purge_non_exist(int level, struct isis_lsp_hdr *hdr, struct isis_area *area) { struct isis_lsp *lsp; @@ -2980,39 +1930,14 @@ void lsp_purge_non_exist(int level, struct isis_link_state_hdr *lsp_hdr, lsp->area = area; lsp->level = level; lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu); - lsp->isis_header = (struct isis_fixed_hdr *)STREAM_DATA(lsp->pdu); - fill_fixed_hdr(lsp->isis_header, - (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE - : L2_LINK_STATE); - lsp->lsp_header = (struct isis_link_state_hdr *)(STREAM_DATA(lsp->pdu) - + ISIS_FIXED_HDR_LEN); - memcpy(lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN); - stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); - - /* - * Set the remaining lifetime to 0 - */ - lsp->lsp_header->rem_lifetime = 0; + lsp->age_out = ZERO_AGE_LIFETIME; - /* - * Add and update the authentication info if its present - */ - lsp_auth_add(lsp); - lsp_auth_update(lsp); + memcpy(&lsp->hdr, hdr, sizeof(lsp->hdr)); + lsp->hdr.rem_lifetime = 0; - /* - * Update the PDU length to header plus any authentication TLV. - */ - lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu)); + lsp_pack_pdu(lsp); - /* - * Put the lsp into LSPdb - */ lsp_insert(lsp, area->lspdb[lsp->level - 1]); - - /* - * Send in to whole area - */ lsp_set_all_srmflags(lsp); return; diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h index 7bec162719..0f9c749949 100644 --- a/isisd/isis_lsp.h +++ b/isisd/isis_lsp.h @@ -24,19 +24,19 @@ #ifndef _ZEBRA_ISIS_LSP_H #define _ZEBRA_ISIS_LSP_H +#include "isisd/isis_pdu.h" + /* Structure for isis_lsp, this structure will only support the fixed * System ID (Currently 6) (atleast for now). In order to support more * We will have to split the header into two parts, and for readability * sake it should better be avoided */ struct isis_lsp { - struct isis_fixed_hdr *isis_header; /* normally equals pdu */ - struct isis_link_state_hdr *lsp_header; /* pdu + isis_header_len */ - struct stream *pdu; /* full pdu lsp */ + struct isis_lsp_hdr hdr; + struct stream *pdu; /* full pdu lsp */ union { struct list *frags; struct isis_lsp *zero_lsp; } lspu; - u_int32_t auth_tlv_offset; /* authentication TLV position in the pdu */ u_int32_t SRMflags[ISIS_MAX_CIRCUITS]; u_int32_t SSNflags[ISIS_MAX_CIRCUITS]; int level; /* L1 or L2? */ @@ -47,7 +47,7 @@ struct isis_lsp { /* used for 60 second counting when rem_lifetime is zero */ int age_out; struct isis_area *area; - struct tlvs tlv_data; /* Simplifies TLV access */ + struct isis_tlvs *tlvs; }; dict_t *lsp_db_init(void); @@ -59,13 +59,13 @@ int lsp_regenerate_schedule(struct isis_area *area, int level, int all_pseudo); int lsp_generate_pseudo(struct isis_circuit *circuit, int level); int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level); -struct isis_lsp *lsp_new(struct isis_area *area, u_char *lsp_id, - u_int16_t rem_lifetime, u_int32_t seq_num, - u_int8_t lsp_bits, u_int16_t checksum, int level); -struct isis_lsp *lsp_new_from_stream_ptr(struct stream *stream, - u_int16_t pdu_len, - struct isis_lsp *lsp0, - struct isis_area *area, int level); +struct isis_lsp *lsp_new(struct isis_area *area, uint8_t *lsp_id, + uint16_t rem_lifetime, uint32_t seq_num, + uint8_t lsp_bits, uint16_t checksum, int level); +struct isis_lsp *lsp_new_from_recv(struct isis_lsp_hdr *hdr, + struct isis_tlvs *tlvs, + struct stream *stream, struct isis_lsp *lsp0, + struct isis_area *area, int level); void lsp_insert(struct isis_lsp *lsp, dict_t *lspdb); struct isis_lsp *lsp_search(u_char *id, dict_t *lspdb); @@ -73,12 +73,9 @@ void lsp_build_list(u_char *start_id, u_char *stop_id, u_char num_lsps, struct list *list, dict_t *lspdb); void lsp_build_list_nonzero_ht(u_char *start_id, u_char *stop_id, struct list *list, dict_t *lspdb); -void lsp_build_list_ssn(struct isis_circuit *circuit, u_char num_lsps, - struct list *list, dict_t *lspdb); - void lsp_search_and_destroy(u_char *id, dict_t *lspdb); void lsp_purge_pseudo(u_char *id, struct isis_circuit *circuit, int level); -void lsp_purge_non_exist(int level, struct isis_link_state_hdr *lsp_hdr, +void lsp_purge_non_exist(int level, struct isis_lsp_hdr *hdr, struct isis_area *area); #define LSP_EQUAL 1 @@ -92,16 +89,15 @@ void lsp_purge_non_exist(int level, struct isis_link_state_hdr *lsp_hdr, (I)[ISIS_SYS_ID_LEN] = 0; \ (I)[ISIS_SYS_ID_LEN + 1] = 0 int lsp_id_cmp(u_char *id1, u_char *id2); -int lsp_compare(char *areatag, struct isis_lsp *lsp, u_int32_t seq_num, - u_int16_t checksum, u_int16_t rem_lifetime); -void lsp_update(struct isis_lsp *lsp, struct stream *stream, - struct isis_area *area, int level); -void lsp_inc_seqnum(struct isis_lsp *lsp, u_int32_t seq_num); +int lsp_compare(char *areatag, struct isis_lsp *lsp, uint32_t seqno, + uint16_t checksum, uint16_t rem_lifetime); +void lsp_update(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr, + struct isis_tlvs *tlvs, struct stream *stream, + struct isis_area *area, int level, bool confusion); +void lsp_inc_seqno(struct isis_lsp *lsp, uint32_t seqno); void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost); void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost); int lsp_print_all(struct vty *vty, dict_t *lspdb, char detail, char dynhost); -const char *lsp_bits2string(u_char *); - /* sets SRMflags for all active circuits of an lsp */ void lsp_set_all_srmflags(struct isis_lsp *lsp); diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 463e3abcf3..40ceb99fb2 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -52,7 +52,6 @@ #include "isisd/isis_route.h" #include "isisd/isis_routemap.h" #include "isisd/isis_zebra.h" -#include "isisd/isis_tlv.h" #include "isisd/isis_te.h" /* Default configuration file name */ diff --git a/isisd/isis_memory.c b/isisd/isis_memory.c index 4ad26cf91f..7d1ad6b049 100644 --- a/isisd/isis_memory.c +++ b/isisd/isis_memory.c @@ -31,9 +31,9 @@ DEFINE_MTYPE(ISISD, ISIS_TMP, "ISIS TMP") DEFINE_MTYPE(ISISD, ISIS_CIRCUIT, "ISIS circuit") DEFINE_MTYPE(ISISD, ISIS_LSP, "ISIS LSP") DEFINE_MTYPE(ISISD, ISIS_ADJACENCY, "ISIS adjacency") +DEFINE_MTYPE(ISISD, ISIS_ADJACENCY_INFO, "ISIS adjacency info") DEFINE_MTYPE(ISISD, ISIS_AREA, "ISIS area") DEFINE_MTYPE(ISISD, ISIS_AREA_ADDR, "ISIS area address") -DEFINE_MTYPE(ISISD, ISIS_TLV, "ISIS TLV") DEFINE_MTYPE(ISISD, ISIS_DYNHN, "ISIS dyn hostname") DEFINE_MTYPE(ISISD, ISIS_SPFTREE, "ISIS SPFtree") DEFINE_MTYPE(ISISD, ISIS_VERTEX, "ISIS vertex") diff --git a/isisd/isis_memory.h b/isisd/isis_memory.h index 7729ebac33..4078c7a671 100644 --- a/isisd/isis_memory.h +++ b/isisd/isis_memory.h @@ -30,9 +30,9 @@ DECLARE_MTYPE(ISIS_TMP) DECLARE_MTYPE(ISIS_CIRCUIT) DECLARE_MTYPE(ISIS_LSP) DECLARE_MTYPE(ISIS_ADJACENCY) +DECLARE_MTYPE(ISIS_ADJACENCY_INFO) DECLARE_MTYPE(ISIS_AREA) DECLARE_MTYPE(ISIS_AREA_ADDR) -DECLARE_MTYPE(ISIS_TLV) DECLARE_MTYPE(ISIS_DYNHN) DECLARE_MTYPE(ISIS_SPFTREE) DECLARE_MTYPE(ISIS_VERTEX) diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c index 16c789ff59..e8888a5f5b 100644 --- a/isisd/isis_misc.c +++ b/isisd/isis_misc.c @@ -28,6 +28,7 @@ #include "hash.h" #include "if.h" #include "command.h" +#include "log_int.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" @@ -38,7 +39,6 @@ #include "isisd/isisd.h" #include "isisd/isis_misc.h" -#include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_constants.h" #include "isisd/isis_adjacency.h" @@ -46,15 +46,9 @@ /* staticly assigned vars for printing purposes */ struct in_addr new_prefix; -/* len of xxxx.xxxx.xxxx + place for #0 termination */ -char sysid[15]; -/* len of xxxx.xxxx.xxxx + place for #0 termination */ -char snpa[15]; /* len of xx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xx */ -char isonet[51]; /* + place for #0 termination */ -/* len of xxxx.xxxx.xxxx.xx.xx + place for #0 termination */ -char lspid[21]; +char isonet[51]; /* len of xxYxxMxWxdxxhxxmxxs + place for #0 termination */ char datestring[20]; char nlpidstring[30]; @@ -179,6 +173,26 @@ int sysid2buff(u_char *buff, const char *dotted) return len; } +const char *nlpid2str(uint8_t nlpid) +{ + static char buf[4]; + switch (nlpid) { + case NLPID_IP: + return "IPv4"; + case NLPID_IPV6: + return "IPv6"; + case NLPID_SNAP: + return "SNAP"; + case NLPID_CLNP: + return "CLNP"; + case NLPID_ESIS: + return "ES-IS"; + default: + snprintf(buf, sizeof(buf), "%" PRIu8, nlpid); + return buf; + } +} + /* * converts the nlpids struct (filled by TLV #129) * into a string @@ -190,26 +204,7 @@ char *nlpid2string(struct nlpids *nlpids) int i; for (i = 0; i < nlpids->count; i++) { - switch (nlpids->nlpids[i]) { - case NLPID_IP: - pos += sprintf(pos, "IPv4"); - break; - case NLPID_IPV6: - pos += sprintf(pos, "IPv6"); - break; - case NLPID_SNAP: - pos += sprintf(pos, "SNAP"); - break; - case NLPID_CLNP: - pos += sprintf(pos, "CLNP"); - break; - case NLPID_ESIS: - pos += sprintf(pos, "ES-IS"); - break; - default: - pos += sprintf(pos, "unknown"); - break; - } + pos += sprintf(pos, "%s", nlpid2str(nlpids->nlpids[i])); if (nlpids->count - i > 1) pos += sprintf(pos, ", "); } @@ -220,25 +215,6 @@ char *nlpid2string(struct nlpids *nlpids) } /* - * supports the given af ? - */ -int speaks(struct nlpids *nlpids, int family) -{ - int i, speaks = 0; - - if (nlpids == (struct nlpids *)NULL) - return speaks; - for (i = 0; i < nlpids->count; i++) { - if (family == AF_INET && nlpids->nlpids[i] == NLPID_IP) - speaks = 1; - if (family == AF_INET6 && nlpids->nlpids[i] == NLPID_IPV6) - speaks = 1; - } - - return speaks; -} - -/* * Returns 0 on error, IS-IS Circuit Type on ok */ int string2circuit_t(const char *str) @@ -330,71 +306,53 @@ const char *syst2string(int type) */ const char *snpa_print(const u_char *from) { - int i = 0; - u_char *pos = (u_char *)snpa; - - if (!from) - return "unknown"; - - while (i < ETH_ALEN - 1) { - if (i & 1) { - sprintf((char *)pos, "%02x.", *(from + i)); - pos += 3; - } else { - sprintf((char *)pos, "%02x", *(from + i)); - pos += 2; - } - i++; - } + return isis_format_id(from, ISIS_SYS_ID_LEN); +} - sprintf((char *)pos, "%02x", *(from + (ISIS_SYS_ID_LEN - 1))); - pos += 2; - *(pos) = '\0'; +const char *sysid_print(const u_char *from) +{ + return isis_format_id(from, ISIS_SYS_ID_LEN); +} - return snpa; +const char *rawlspid_print(const u_char *from) +{ + return isis_format_id(from, 8); } -const char *sysid_print(const u_char *from) +#define FORMAT_ID_SIZE sizeof("0000.0000.0000.00-00") +const char *isis_format_id(const uint8_t *id, size_t len) { - int i = 0; - char *pos = sysid; +#define FORMAT_BUF_COUNT 4 + static char buf_ring[FORMAT_BUF_COUNT][FORMAT_ID_SIZE]; + static size_t cur_buf = 0; - if (!from) - return "unknown"; + char *rv; - while (i < ISIS_SYS_ID_LEN - 1) { - if (i & 1) { - sprintf(pos, "%02x.", *(from + i)); - pos += 3; - } else { - sprintf(pos, "%02x", *(from + i)); - pos += 2; - } - i++; - } + cur_buf++; + if (cur_buf >= FORMAT_BUF_COUNT) + cur_buf = 0; - sprintf(pos, "%02x", *(from + (ISIS_SYS_ID_LEN - 1))); - pos += 2; - *(pos) = '\0'; + rv = buf_ring[cur_buf]; - return sysid; -} + if (!id) { + snprintf(rv, FORMAT_ID_SIZE, "unknown"); + return rv; + } -const char *rawlspid_print(const u_char *from) -{ - char *pos = lspid; - if (!from) - return "unknown"; - memcpy(pos, sysid_print(from), 15); - pos += 14; - sprintf(pos, ".%02x", LSP_PSEUDO_ID(from)); - pos += 3; - sprintf(pos, "-%02x", LSP_FRAGMENT(from)); - pos += 3; + if (len < 6) { + snprintf(rv, FORMAT_ID_SIZE, "Short ID"); + return rv; + } - *(pos) = '\0'; + snprintf(rv, FORMAT_ID_SIZE, "%02x%02x.%02x%02x.%02x%02x", id[0], id[1], + id[2], id[3], id[4], id[5]); + + if (len > 6) + snprintf(rv + 14, FORMAT_ID_SIZE - 14, ".%02x", id[6]); + if (len > 7) + snprintf(rv + 17, FORMAT_ID_SIZE - 17, "-%02x", id[7]); - return lspid; + return rv; } const char *time2string(u_int32_t time) @@ -508,7 +466,7 @@ const char *print_sys_hostname(const u_char *sysid) dyn = dynhn_find_by_id(sysid); if (dyn) - return (const char *)dyn->name.name; + return dyn->hostname; return sysid_print(sysid); } @@ -572,3 +530,93 @@ void zlog_dump_data(void *data, int len) zlog_debug("[%8.8s] %-50.50s %s", addrstr, hexstr, charstr); return; } + +static char *qasprintf(const char *format, va_list ap) +{ + va_list aq; + va_copy(aq, ap); + + int size = 0; + char *p = NULL; + + size = vsnprintf(p, size, format, ap); + + if (size < 0) { + va_end(aq); + return NULL; + } + + size++; + p = XMALLOC(MTYPE_TMP, size); + + size = vsnprintf(p, size, format, aq); + va_end(aq); + + if (size < 0) { + XFREE(MTYPE_TMP, p); + return NULL; + } + + return p; +} + +void log_multiline(int priority, const char *prefix, const char *format, ...) +{ + va_list ap; + char *p; + + va_start(ap, format); + p = qasprintf(format, ap); + va_end(ap); + + if (!p) + return; + + char *saveptr = NULL; + for (char *line = strtok_r(p, "\n", &saveptr); line; + line = strtok_r(NULL, "\n", &saveptr)) { + zlog(priority, "%s%s", prefix, line); + } + + XFREE(MTYPE_TMP, p); +} + +void vty_multiline(struct vty *vty, const char *prefix, const char *format, ...) +{ + va_list ap; + char *p; + + va_start(ap, format); + p = qasprintf(format, ap); + va_end(ap); + + if (!p) + return; + + char *saveptr = NULL; + for (char *line = strtok_r(p, "\n", &saveptr); line; + line = strtok_r(NULL, "\n", &saveptr)) { + vty_out(vty, "%s%s\n", prefix, line); + } + + XFREE(MTYPE_TMP, p); +} + +void vty_out_timestr(struct vty *vty, time_t uptime) +{ + struct tm *tm; + time_t difftime = time(NULL); + difftime -= uptime; + tm = gmtime(&difftime); + + if (difftime < ONE_DAY_SECOND) + vty_out(vty, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, + tm->tm_sec); + else if (difftime < ONE_WEEK_SECOND) + vty_out(vty, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour, + tm->tm_min); + else + vty_out(vty, "%02dw%dd%02dh", tm->tm_yday / 7, + tm->tm_yday - ((tm->tm_yday / 7) * 7), tm->tm_hour); + vty_out(vty, " ago"); +} diff --git a/isisd/isis_misc.h b/isisd/isis_misc.h index 12ab0fac1c..5a19a1ffa0 100644 --- a/isisd/isis_misc.h +++ b/isisd/isis_misc.h @@ -44,7 +44,9 @@ const char *isonet_print(const u_char *, int len); const char *sysid_print(const u_char *); const char *snpa_print(const u_char *); const char *rawlspid_print(const u_char *); +const char *isis_format_id(const uint8_t *id, size_t len); const char *time2string(u_int32_t); +const char *nlpid2str(uint8_t nlpid); /* typedef struct nlpids nlpids; */ char *nlpid2string(struct nlpids *); const char *print_sys_hostname(const u_char *sysid); @@ -53,7 +55,6 @@ void zlog_dump_data(void *data, int len); /* * misc functions */ -int speaks(struct nlpids *nlpids, int family); unsigned long isis_jitter(unsigned long timer, unsigned long jitter); const char *unix_hostname(void); @@ -77,4 +78,11 @@ enum { ISIS_UI_LEVEL_BRIEF, ISIS_UI_LEVEL_EXTENSIVE, }; +#include "lib/log.h" +void log_multiline(int priority, const char *prefix, const char *format, ...) + PRINTF_ATTRIBUTE(3, 4); +struct vty; +void vty_multiline(struct vty *vty, const char *prefix, const char *format, ...) + PRINTF_ATTRIBUTE(3, 4); +void vty_out_timestr(struct vty *vty, time_t uptime); #endif diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c index 46b57510ac..52646c2624 100644 --- a/isisd/isis_mt.c +++ b/isisd/isis_mt.c @@ -24,19 +24,14 @@ #include "isisd/isis_memory.h" #include "isisd/isis_circuit.h" #include "isisd/isis_adjacency.h" -#include "isisd/isis_tlv.h" #include "isisd/isis_misc.h" #include "isisd/isis_lsp.h" #include "isisd/isis_mt.h" +#include "isisd/isis_tlvs.h" DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting") DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting") DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info") -DEFINE_MTYPE_STATIC(ISISD, MT_NEIGHBORS, "ISIS MT Neighbors for TLV") -DEFINE_MTYPE_STATIC(ISISD, MT_IPV4_REACHS, - "ISIS MT IPv4 Reachabilities for TLV") -DEFINE_MTYPE_STATIC(ISISD, MT_IPV6_REACHS, - "ISIS MT IPv6 Reachabilities for TLV") uint16_t isis_area_ipv6_topology(struct isis_area *area) { @@ -367,7 +362,7 @@ static void adj_mt_set(struct isis_adjacency *adj, unsigned int index, adj->mt_set[index] = mtid; } -bool tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable, +bool tlvs_to_adj_mt_set(struct isis_tlvs *tlvs, bool v4_usable, bool v6_usable, struct isis_adjacency *adj) { struct isis_circuit_mt_setting **mt_settings; @@ -388,17 +383,20 @@ bool tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable, mt_settings = circuit_mt_settings(adj->circuit, &circuit_mt_count); for (unsigned int i = 0; i < circuit_mt_count; i++) { - if (!tlvs->mt_router_info) { + if (!tlvs->mt_router_info.count + && !tlvs->mt_router_info_empty) { /* Other end does not have MT enabled */ if (mt_settings[i]->mtid == ISIS_MT_IPV4_UNICAST && v4_usable) adj_mt_set(adj, intersect_count++, ISIS_MT_IPV4_UNICAST); } else { - struct listnode *node; - struct mt_router_info *info; - for (ALL_LIST_ELEMENTS_RO(tlvs->mt_router_info, node, - info)) { + struct isis_mt_router_info *info_head; + + info_head = (struct isis_mt_router_info *) + tlvs->mt_router_info.head; + for (struct isis_mt_router_info *info = info_head; info; + info = info->next) { if (mt_settings[i]->mtid == info->mtid) { bool usable; switch (info->mtid) { @@ -456,153 +454,6 @@ void adj_mt_finish(struct isis_adjacency *adj) adj->mt_count = 0; } -/* TLV Router info api */ -struct mt_router_info *tlvs_lookup_mt_router_info(struct tlvs *tlvs, - uint16_t mtid) -{ - return lookup_mt_setting(tlvs->mt_router_info, mtid); -} - -/* TLV MT Neighbors api */ -struct tlv_mt_neighbors *tlvs_lookup_mt_neighbors(struct tlvs *tlvs, - uint16_t mtid) -{ - return lookup_mt_setting(tlvs->mt_is_neighs, mtid); -} - -static struct tlv_mt_neighbors *tlvs_new_mt_neighbors(uint16_t mtid) -{ - struct tlv_mt_neighbors *rv; - - rv = XCALLOC(MTYPE_MT_NEIGHBORS, sizeof(*rv)); - rv->mtid = mtid; - rv->list = list_new(); - - return rv; -}; - -static void tlvs_free_mt_neighbors(void *arg) -{ - struct tlv_mt_neighbors *neighbors = arg; - - if (neighbors && neighbors->list) - list_delete(neighbors->list); - XFREE(MTYPE_MT_NEIGHBORS, neighbors); -} - -static void tlvs_add_mt_neighbors(struct tlvs *tlvs, - struct tlv_mt_neighbors *neighbors) -{ - add_mt_setting(&tlvs->mt_is_neighs, neighbors); - tlvs->mt_is_neighs->del = tlvs_free_mt_neighbors; -} - -struct tlv_mt_neighbors *tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid) -{ - struct tlv_mt_neighbors *neighbors; - - neighbors = tlvs_lookup_mt_neighbors(tlvs, mtid); - if (!neighbors) { - neighbors = tlvs_new_mt_neighbors(mtid); - tlvs_add_mt_neighbors(tlvs, neighbors); - } - return neighbors; -} - -/* TLV MT IPv4 reach api */ -struct tlv_mt_ipv4_reachs *tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs, - uint16_t mtid) -{ - return lookup_mt_setting(tlvs->mt_ipv4_reachs, mtid); -} - -static struct tlv_mt_ipv4_reachs *tlvs_new_mt_ipv4_reachs(uint16_t mtid) -{ - struct tlv_mt_ipv4_reachs *rv; - - rv = XCALLOC(MTYPE_MT_IPV4_REACHS, sizeof(*rv)); - rv->mtid = mtid; - rv->list = list_new(); - - return rv; -}; - -static void tlvs_free_mt_ipv4_reachs(void *arg) -{ - struct tlv_mt_ipv4_reachs *reachs = arg; - - if (reachs && reachs->list) - list_delete(reachs->list); - XFREE(MTYPE_MT_IPV4_REACHS, reachs); -} - -static void tlvs_add_mt_ipv4_reachs(struct tlvs *tlvs, - struct tlv_mt_ipv4_reachs *reachs) -{ - add_mt_setting(&tlvs->mt_ipv4_reachs, reachs); - tlvs->mt_ipv4_reachs->del = tlvs_free_mt_ipv4_reachs; -} - -struct tlv_mt_ipv4_reachs *tlvs_get_mt_ipv4_reachs(struct tlvs *tlvs, - uint16_t mtid) -{ - struct tlv_mt_ipv4_reachs *reachs; - - reachs = tlvs_lookup_mt_ipv4_reachs(tlvs, mtid); - if (!reachs) { - reachs = tlvs_new_mt_ipv4_reachs(mtid); - tlvs_add_mt_ipv4_reachs(tlvs, reachs); - } - return reachs; -} - -/* TLV MT IPv6 reach api */ -struct tlv_mt_ipv6_reachs *tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs, - uint16_t mtid) -{ - return lookup_mt_setting(tlvs->mt_ipv6_reachs, mtid); -} - -static struct tlv_mt_ipv6_reachs *tlvs_new_mt_ipv6_reachs(uint16_t mtid) -{ - struct tlv_mt_ipv6_reachs *rv; - - rv = XCALLOC(MTYPE_MT_IPV6_REACHS, sizeof(*rv)); - rv->mtid = mtid; - rv->list = list_new(); - - return rv; -}; - -static void tlvs_free_mt_ipv6_reachs(void *arg) -{ - struct tlv_mt_ipv6_reachs *reachs = arg; - - if (reachs && reachs->list) - list_delete(reachs->list); - XFREE(MTYPE_MT_IPV6_REACHS, reachs); -} - -static void tlvs_add_mt_ipv6_reachs(struct tlvs *tlvs, - struct tlv_mt_ipv6_reachs *reachs) -{ - add_mt_setting(&tlvs->mt_ipv6_reachs, reachs); - tlvs->mt_ipv6_reachs->del = tlvs_free_mt_ipv6_reachs; -} - -struct tlv_mt_ipv6_reachs *tlvs_get_mt_ipv6_reachs(struct tlvs *tlvs, - uint16_t mtid) -{ - struct tlv_mt_ipv6_reachs *reachs; - - reachs = tlvs_lookup_mt_ipv6_reachs(tlvs, mtid); - if (!reachs) { - reachs = tlvs_new_mt_ipv6_reachs(mtid); - tlvs_add_mt_ipv6_reachs(tlvs, reachs); - } - return reachs; -} - static void mt_set_add(uint16_t **mt_set, unsigned int *size, unsigned int *index, uint16_t mtid) { @@ -647,51 +498,46 @@ static uint16_t *circuit_bcast_mt_set(struct isis_circuit *circuit, int level, return rv; } -static void tlvs_add_mt_set(struct isis_area *area, struct tlvs *tlvs, +static void tlvs_add_mt_set(struct isis_area *area, struct isis_tlvs *tlvs, unsigned int mt_count, uint16_t *mt_set, - struct te_is_neigh *neigh) + uint8_t *id, uint32_t metric, uint8_t *subtlvs, + uint8_t subtlv_len) { for (unsigned int i = 0; i < mt_count; i++) { uint16_t mtid = mt_set[i]; - struct te_is_neigh *ne_copy; - - ne_copy = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ne_copy)); - memcpy(ne_copy, neigh, sizeof(*ne_copy)); - if (mt_set[i] == ISIS_MT_IPV4_UNICAST) { - listnode_add(tlvs->te_is_neighs, ne_copy); lsp_debug( "ISIS (%s): Adding %s.%02x as te-style neighbor", - area->area_tag, sysid_print(ne_copy->neigh_id), - LSP_PSEUDO_ID(ne_copy->neigh_id)); + area->area_tag, sysid_print(id), + LSP_PSEUDO_ID(id)); } else { - struct tlv_mt_neighbors *neighbors; - - neighbors = tlvs_get_mt_neighbors(tlvs, mtid); - neighbors->list->del = free_tlv; - listnode_add(neighbors->list, ne_copy); lsp_debug( "ISIS (%s): Adding %s.%02x as mt-style neighbor for %s", - area->area_tag, sysid_print(ne_copy->neigh_id), - LSP_PSEUDO_ID(ne_copy->neigh_id), - isis_mtid2str(mtid)); + area->area_tag, sysid_print(id), + LSP_PSEUDO_ID(id), isis_mtid2str(mtid)); } + isis_tlvs_add_extended_reach(tlvs, mtid, id, metric, subtlvs, + subtlv_len); } } -void tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit, - int level, struct te_is_neigh *neigh) +void tlvs_add_mt_bcast(struct isis_tlvs *tlvs, struct isis_circuit *circuit, + int level, uint8_t *id, uint32_t metric, + uint8_t *subtlvs, uint8_t subtlv_len) { unsigned int mt_count; uint16_t *mt_set = circuit_bcast_mt_set(circuit, level, &mt_count); - tlvs_add_mt_set(circuit->area, tlvs, mt_count, mt_set, neigh); + tlvs_add_mt_set(circuit->area, tlvs, mt_count, mt_set, id, metric, + subtlvs, subtlv_len); } -void tlvs_add_mt_p2p(struct tlvs *tlvs, struct isis_circuit *circuit, - struct te_is_neigh *neigh) +void tlvs_add_mt_p2p(struct isis_tlvs *tlvs, struct isis_circuit *circuit, + uint8_t *id, uint32_t metric, uint8_t *subtlvs, + uint8_t subtlv_len) { struct isis_adjacency *adj = circuit->u.p2p.neighbor; - tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, neigh); + tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, id, + metric, subtlvs, subtlv_len); } diff --git a/isisd/isis_mt.h b/isisd/isis_mt.h index eec089228e..95aa99dba0 100644 --- a/isisd/isis_mt.h +++ b/isisd/isis_mt.h @@ -24,6 +24,7 @@ #define ISIS_MT_MASK 0x0fff #define ISIS_MT_OL_MASK 0x8000 +#define ISIS_MT_AT_MASK 0x4000 #define ISIS_MT_IPV4_UNICAST 0 #define ISIS_MT_IPV4_MGMT 1 @@ -64,21 +65,6 @@ struct isis_circuit_mt_setting { bool enabled; }; -struct tlv_mt_neighbors { - ISIS_MT_INFO_FIELDS - struct list *list; -}; - -struct tlv_mt_ipv4_reachs { - ISIS_MT_INFO_FIELDS - struct list *list; -}; - -struct tlv_mt_ipv6_reachs { - ISIS_MT_INFO_FIELDS - struct list *list; -}; - const char *isis_mtid2str(uint16_t mtid); uint16_t isis_str2mtid(const char *name); @@ -87,27 +73,10 @@ struct isis_area; struct isis_circuit; struct tlvs; struct te_is_neigh; +struct isis_tlvs; uint16_t isis_area_ipv6_topology(struct isis_area *area); -struct mt_router_info *tlvs_lookup_mt_router_info(struct tlvs *tlvs, - uint16_t mtid); - -struct tlv_mt_neighbors *tlvs_lookup_mt_neighbors(struct tlvs *tlvs, - uint16_t mtid); -struct tlv_mt_neighbors *tlvs_get_mt_neighbors(struct tlvs *tlvs, - uint16_t mtid); - -struct tlv_mt_ipv4_reachs *tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs, - uint16_t mtid); -struct tlv_mt_ipv4_reachs *tlvs_get_mt_ipv4_reachs(struct tlvs *tlvs, - uint16_t mtid); - -struct tlv_mt_ipv6_reachs *tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs, - uint16_t mtid); -struct tlv_mt_ipv6_reachs *tlvs_get_mt_ipv6_reachs(struct tlvs *tlvs, - uint16_t mtid); - struct isis_area_mt_setting *area_lookup_mt_setting(struct isis_area *area, uint16_t mtid); struct isis_area_mt_setting *area_new_mt_setting(struct isis_area *area, @@ -137,12 +106,14 @@ circuit_get_mt_setting(struct isis_circuit *circuit, uint16_t mtid); int circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty); struct isis_circuit_mt_setting ** circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count); -bool tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable, +bool tlvs_to_adj_mt_set(struct isis_tlvs *tlvs, bool v4_usable, bool v6_usable, struct isis_adjacency *adj); bool adj_has_mt(struct isis_adjacency *adj, uint16_t mtid); void adj_mt_finish(struct isis_adjacency *adj); -void tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit, - int level, struct te_is_neigh *neigh); -void tlvs_add_mt_p2p(struct tlvs *tlvs, struct isis_circuit *circuit, - struct te_is_neigh *neigh); +void tlvs_add_mt_bcast(struct isis_tlvs *tlvs, struct isis_circuit *circuit, + int level, uint8_t *id, uint32_t metric, + uint8_t *subtlvs, uint8_t subtlv_len); +void tlvs_add_mt_p2p(struct isis_tlvs *tlvs, struct isis_circuit *circuit, + uint8_t *id, uint32_t metric, uint8_t *subtlvs, + uint8_t subtlv_len); #endif diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index a3706179a6..17ef8935d8 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -44,7 +44,6 @@ #include "isisd/isis_network.h" #include "isisd/isis_misc.h" #include "isisd/isis_dr.h" -#include "isisd/isis_tlv.h" #include "isisd/isisd.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_lsp.h" @@ -54,497 +53,122 @@ #include "isisd/isis_events.h" #include "isisd/isis_te.h" #include "isisd/isis_mt.h" +#include "isisd/isis_tlvs.h" -#define ISIS_MINIMUM_FIXED_HDR_LEN 15 -#define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */ - -#ifndef PNBBY -#define PNBBY 8 -#endif /* PNBBY */ - -/* - * HELPER FUNCS - */ - -/* - * Compares two sets of area addresses - */ -static int area_match(struct list *left, struct list *right) +static int ack_lsp(struct isis_lsp_hdr *hdr, struct isis_circuit *circuit, + int level) { - struct area_addr *addr1, *addr2; - struct listnode *node1, *node2; - - for (ALL_LIST_ELEMENTS_RO(left, node1, addr1)) { - for (ALL_LIST_ELEMENTS_RO(right, node2, addr2)) { - if (addr1->addr_len == addr2->addr_len - && !memcmp(addr1->area_addr, addr2->area_addr, - (int)addr1->addr_len)) - return 1; /* match */ - } - } - - return 0; /* mismatch */ -} - -/* - * Checks whether we should accept a PDU of given level - */ -static int accept_level(int level, int circuit_t) -{ - int retval = ((circuit_t & level) == level); /* simple approach */ - - return retval; -} - -/* - * Verify authentication information - * Support cleartext and HMAC MD5 authentication - */ -static int authentication_check(struct isis_passwd *remote, - struct isis_passwd *local, - struct stream *stream, uint32_t auth_tlv_offset) -{ - unsigned char digest[ISIS_AUTH_MD5_SIZE]; - - /* Auth fail () - passwd type mismatch */ - if (local->type != remote->type) - return ISIS_ERROR; - - switch (local->type) { - /* No authentication required */ - case ISIS_PASSWD_TYPE_UNUSED: - break; - - /* Cleartext (ISO 10589) */ - case ISIS_PASSWD_TYPE_CLEARTXT: - /* Auth fail () - passwd len mismatch */ - if (remote->len != local->len) - return ISIS_ERROR; - return memcmp(local->passwd, remote->passwd, local->len); - - /* HMAC MD5 (RFC 3567) */ - case ISIS_PASSWD_TYPE_HMAC_MD5: - /* Auth fail () - passwd len mismatch */ - if (remote->len != ISIS_AUTH_MD5_SIZE) - return ISIS_ERROR; - /* Set the authentication value to 0 before the check */ - memset(STREAM_DATA(stream) + auth_tlv_offset + 3, 0, - ISIS_AUTH_MD5_SIZE); - /* Compute the digest */ - hmac_md5(STREAM_DATA(stream), stream_get_endp(stream), - (unsigned char *)&(local->passwd), local->len, - (unsigned char *)&digest); - /* Copy back the authentication value after the check */ - memcpy(STREAM_DATA(stream) + auth_tlv_offset + 3, - remote->passwd, ISIS_AUTH_MD5_SIZE); - return memcmp(digest, remote->passwd, ISIS_AUTH_MD5_SIZE); + unsigned long lenp; + int retval; + u_int16_t length; + uint8_t pdu_type = + (level == IS_LEVEL_1) ? L1_PARTIAL_SEQ_NUM : L2_PARTIAL_SEQ_NUM; - default: - zlog_err("Unsupported authentication type"); - return ISIS_ERROR; - } + isis_circuit_stream(circuit, &circuit->snd_stream); - /* Authentication pass when no authentication is configured */ - return ISIS_OK; -} + fill_fixed_hdr(pdu_type, circuit->snd_stream); -static int lsp_authentication_check(struct stream *stream, - struct isis_area *area, int level, - struct isis_passwd *passwd) -{ - struct isis_link_state_hdr *hdr; - uint32_t expected = 0, found = 0, auth_tlv_offset = 0; - uint16_t checksum, rem_lifetime, pdu_len; - struct tlvs tlvs; - int retval = ISIS_OK; - - hdr = (struct isis_link_state_hdr *)(STREAM_PNT(stream)); - pdu_len = ntohs(hdr->pdu_len); - expected |= TLVFLAG_AUTH_INFO; - auth_tlv_offset = stream_get_getp(stream) + ISIS_LSP_HDR_LEN; - retval = parse_tlvs(area->area_tag, - STREAM_PNT(stream) + ISIS_LSP_HDR_LEN, - pdu_len - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN, - &expected, &found, &tlvs, &auth_tlv_offset); + lenp = stream_get_endp(circuit->snd_stream); + stream_putw(circuit->snd_stream, 0); /* PDU length */ + stream_put(circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN); + stream_putc(circuit->snd_stream, circuit->idx); + stream_putc(circuit->snd_stream, 9); /* code */ + stream_putc(circuit->snd_stream, 16); /* len */ - if (retval != ISIS_OK) { - zlog_err( - "ISIS-Upd (%s): Parse failed L%d LSP %s, seq 0x%08x, " - "cksum 0x%04x, lifetime %us, len %u", - area->area_tag, level, rawlspid_print(hdr->lsp_id), - ntohl(hdr->seq_num), ntohs(hdr->checksum), - ntohs(hdr->rem_lifetime), pdu_len); - if ((isis->debugs & DEBUG_UPDATE_PACKETS) - && (isis->debugs & DEBUG_PACKET_DUMP)) - zlog_dump_data(STREAM_DATA(stream), - stream_get_endp(stream)); - return retval; - } - - if (!(found & TLVFLAG_AUTH_INFO)) { - zlog_err("No authentication tlv in LSP"); - return ISIS_ERROR; - } + stream_putw(circuit->snd_stream, hdr->rem_lifetime); + stream_put(circuit->snd_stream, hdr->lsp_id, ISIS_SYS_ID_LEN + 2); + stream_putl(circuit->snd_stream, hdr->seqno); + stream_putw(circuit->snd_stream, hdr->checksum); - if (tlvs.auth_info.type != ISIS_PASSWD_TYPE_CLEARTXT - && tlvs.auth_info.type != ISIS_PASSWD_TYPE_HMAC_MD5) { - zlog_err("Unknown authentication type in LSP"); - return ISIS_ERROR; - } + length = (u_int16_t)stream_get_endp(circuit->snd_stream); + /* Update PDU length */ + stream_putw_at(circuit->snd_stream, lenp, length); - /* - * RFC 5304 set checksum and remaining lifetime to zero before - * verification and reset to old values after verification. - */ - checksum = hdr->checksum; - rem_lifetime = hdr->rem_lifetime; - hdr->checksum = 0; - hdr->rem_lifetime = 0; - retval = authentication_check(&tlvs.auth_info, passwd, stream, - auth_tlv_offset); - hdr->checksum = checksum; - hdr->rem_lifetime = rem_lifetime; + retval = circuit->tx(circuit, level); + if (retval != ISIS_OK) + zlog_err("ISIS-Upd (%s): Send L%d LSP PSNP on %s failed", + circuit->area->area_tag, level, + circuit->interface->name); return retval; } /* - * Processing helper functions - */ -static void del_addr(void *val) -{ - XFREE(MTYPE_ISIS_TMP, val); -} - -static void tlvs_to_adj_area_addrs(struct tlvs *tlvs, - struct isis_adjacency *adj) -{ - struct listnode *node; - struct area_addr *area_addr, *malloced; - - if (adj->area_addrs) { - adj->area_addrs->del = del_addr; - list_delete(adj->area_addrs); - } - adj->area_addrs = list_new(); - if (tlvs->area_addrs) { - for (ALL_LIST_ELEMENTS_RO(tlvs->area_addrs, node, area_addr)) { - malloced = XMALLOC(MTYPE_ISIS_TMP, - sizeof(struct area_addr)); - memcpy(malloced, area_addr, sizeof(struct area_addr)); - listnode_add(adj->area_addrs, malloced); - } - } -} - -static int tlvs_to_adj_nlpids(struct tlvs *tlvs, struct isis_adjacency *adj) -{ - int i; - struct nlpids *tlv_nlpids; - - if (tlvs->nlpids) { - - tlv_nlpids = tlvs->nlpids; - if (tlv_nlpids->count > array_size(adj->nlpids.nlpids)) - return 1; - - adj->nlpids.count = tlv_nlpids->count; - - for (i = 0; i < tlv_nlpids->count; i++) { - adj->nlpids.nlpids[i] = tlv_nlpids->nlpids[i]; - } - } - return 0; -} - -static void tlvs_to_adj_ipv4_addrs(struct tlvs *tlvs, - struct isis_adjacency *adj) -{ - struct listnode *node; - struct in_addr *ipv4_addr, *malloced; - - if (adj->ipv4_addrs) { - adj->ipv4_addrs->del = del_addr; - list_delete(adj->ipv4_addrs); - } - adj->ipv4_addrs = list_new(); - if (tlvs->ipv4_addrs) { - for (ALL_LIST_ELEMENTS_RO(tlvs->ipv4_addrs, node, ipv4_addr)) { - malloced = - XMALLOC(MTYPE_ISIS_TMP, sizeof(struct in_addr)); - memcpy(malloced, ipv4_addr, sizeof(struct in_addr)); - listnode_add(adj->ipv4_addrs, malloced); - } - } -} - -static void tlvs_to_adj_ipv6_addrs(struct tlvs *tlvs, - struct isis_adjacency *adj) -{ - struct listnode *node; - struct in6_addr *ipv6_addr, *malloced; - - if (adj->ipv6_addrs) { - adj->ipv6_addrs->del = del_addr; - list_delete(adj->ipv6_addrs); - } - adj->ipv6_addrs = list_new(); - if (tlvs->ipv6_addrs) { - for (ALL_LIST_ELEMENTS_RO(tlvs->ipv6_addrs, node, ipv6_addr)) { - malloced = XMALLOC(MTYPE_ISIS_TMP, - sizeof(struct in6_addr)); - memcpy(malloced, ipv6_addr, sizeof(struct in6_addr)); - listnode_add(adj->ipv6_addrs, malloced); - } - } -} - -/* * RECEIVE SIDE */ -/* - * Process P2P IIH - * ISO - 10589 - * Section 8.2.5 - Receiving point-to-point IIH PDUs - * - */ -static int process_p2p_hello(struct isis_circuit *circuit) -{ - int retval = ISIS_OK; - struct isis_p2p_hello_hdr *hdr; - struct isis_adjacency *adj; - u_int32_t expected = 0, found = 0, auth_tlv_offset = 0; - uint16_t pdu_len; - struct tlvs tlvs; - int v4_usable = 0, v6_usable = 0; - - if (isis->debugs & DEBUG_ADJ_PACKETS) { - zlog_debug( - "ISIS-Adj (%s): Rcvd P2P IIH on %s, cirType %s, cirID %u", - circuit->area->area_tag, circuit->interface->name, - circuit_t2string(circuit->is_type), - circuit->circuit_id); - if (isis->debugs & DEBUG_PACKET_DUMP) - zlog_dump_data(STREAM_DATA(circuit->rcv_stream), - stream_get_endp(circuit->rcv_stream)); - } - - if (circuit->circ_type != CIRCUIT_T_P2P) { - zlog_warn("p2p hello on non p2p circuit"); - return ISIS_WARNING; - } - - if ((stream_get_endp(circuit->rcv_stream) - - stream_get_getp(circuit->rcv_stream)) - < ISIS_P2PHELLO_HDRLEN) { - zlog_warn("Packet too short"); - return ISIS_WARNING; - } - - /* 8.2.5.1 PDU acceptance tests */ - - /* 8.2.5.1 a) external domain untrue */ - /* FIXME: not useful at all? */ - - /* 8.2.5.1 b) ID Length mismatch */ - /* checked at the handle_pdu */ - - /* 8.2.5.2 IIH PDU Processing */ - - /* 8.2.5.2 a) 1) Maximum Area Addresses */ - /* Already checked, and can also be ommited */ - - /* - * Get the header - */ - hdr = (struct isis_p2p_hello_hdr *)STREAM_PNT(circuit->rcv_stream); - pdu_len = ntohs(hdr->pdu_len); - - if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_P2PHELLO_HDRLEN) - || pdu_len > ISO_MTU(circuit) - || pdu_len > stream_get_endp(circuit->rcv_stream)) { - zlog_warn( - "ISIS-Adj (%s): Rcvd P2P IIH from (%s) with " - "invalid pdu length %d", - circuit->area->area_tag, circuit->interface->name, - pdu_len); - return ISIS_WARNING; - } - - /* - * Set the stream endp to PDU length, ignoring additional padding - * introduced by transport chips. - */ - if (pdu_len < stream_get_endp(circuit->rcv_stream)) - stream_set_endp(circuit->rcv_stream, pdu_len); - - stream_forward_getp(circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN); - - /* - * Lets get the TLVS now - */ - expected |= TLVFLAG_AREA_ADDRS; - expected |= TLVFLAG_AUTH_INFO; - expected |= TLVFLAG_NLPID; - expected |= TLVFLAG_IPV4_ADDR; - expected |= TLVFLAG_IPV6_ADDR; - expected |= TLVFLAG_MT_ROUTER_INFORMATION; - - auth_tlv_offset = stream_get_getp(circuit->rcv_stream); - retval = parse_tlvs(circuit->area->area_tag, - STREAM_PNT(circuit->rcv_stream), - pdu_len - ISIS_P2PHELLO_HDRLEN - ISIS_FIXED_HDR_LEN, - &expected, &found, &tlvs, &auth_tlv_offset); - - if (retval > ISIS_WARNING) { - zlog_warn("parse_tlvs() failed"); - free_tlvs(&tlvs); - return retval; - }; - - if (!(found & TLVFLAG_AREA_ADDRS)) { - zlog_warn("No Area addresses TLV in P2P IS to IS hello"); - free_tlvs(&tlvs); - return ISIS_WARNING; - } - - if (!(found & TLVFLAG_NLPID)) { - zlog_warn("No supported protocols TLV in P2P IS to IS hello"); - free_tlvs(&tlvs); - return ISIS_WARNING; - } - - /* 8.2.5.1 c) Authentication */ - if (circuit->passwd.type) { - if (!(found & TLVFLAG_AUTH_INFO) - || authentication_check(&tlvs.auth_info, &circuit->passwd, - circuit->rcv_stream, - auth_tlv_offset)) { - isis_event_auth_failure( - circuit->area->area_tag, - "P2P hello authentication failure", - hdr->source_id); - free_tlvs(&tlvs); - return ISIS_OK; - } - } +struct iih_info { + struct isis_circuit *circuit; + u_char *ssnpa; + int level; - /* - * check if both ends have an IPv4 address - */ - if (circuit->ip_addrs && listcount(circuit->ip_addrs) && tlvs.ipv4_addrs - && listcount(tlvs.ipv4_addrs)) { - v4_usable = 1; - } - - if (found & TLVFLAG_IPV6_ADDR) { - /* TBA: check that we have a linklocal ourselves? */ - struct listnode *node; - struct in6_addr *ip; - for (ALL_LIST_ELEMENTS_RO(tlvs.ipv6_addrs, node, ip)) - if (IN6_IS_ADDR_LINKLOCAL(ip)) { - v6_usable = 1; - break; - } + uint8_t circ_type; + uint8_t sys_id[ISIS_SYS_ID_LEN]; + uint16_t holdtime; + uint16_t pdu_len; - if (!v6_usable) - zlog_warn( - "ISIS-Adj: IPv6 addresses present but no link-local " - "in P2P IIH from %s\n", - circuit->interface->name); - } + uint8_t circuit_id; - if (!(found & (TLVFLAG_IPV4_ADDR | TLVFLAG_IPV6_ADDR))) - zlog_warn( - "ISIS-Adj: neither IPv4 nor IPv6 addr in P2P IIH from %s\n", - circuit->interface->name); + uint8_t priority; + uint8_t dis[ISIS_SYS_ID_LEN + 1]; - if (!v6_usable && !v4_usable) { - free_tlvs(&tlvs); - return ISIS_WARNING; - } + bool v4_usable; + bool v6_usable; - /* - * it's own p2p IIH PDU - discard - */ - if (!memcmp(hdr->source_id, isis->sysid, ISIS_SYS_ID_LEN)) { - zlog_warn("ISIS-Adj (%s): it's own IIH PDU - discarded", - circuit->area->area_tag); - free_tlvs(&tlvs); - return ISIS_WARNING; - } + struct isis_tlvs *tlvs; +}; +static int process_p2p_hello(struct iih_info *iih) +{ /* * My interpertation of the ISO, if no adj exists we will create one for * the circuit */ - adj = circuit->u.p2p.neighbor; + struct isis_adjacency *adj = iih->circuit->u.p2p.neighbor; /* If an adjacency exists, check it is with the source of the hello * packets */ if (adj) { - if (memcmp(hdr->source_id, adj->sysid, ISIS_SYS_ID_LEN)) { + if (memcmp(iih->sys_id, adj->sysid, ISIS_SYS_ID_LEN)) { zlog_debug( "hello source and adjacency do not match, set adj down\n"); isis_adj_state_change(adj, ISIS_ADJ_DOWN, "adj do not exist"); - return 0; + return ISIS_OK; } } - if (!adj || adj->level != hdr->circuit_t) { + if (!adj || adj->level != iih->circ_type) { if (!adj) { - adj = isis_new_adj(hdr->source_id, NULL, hdr->circuit_t, - circuit); - if (adj == NULL) - return ISIS_ERROR; + adj = isis_new_adj(iih->sys_id, NULL, iih->circ_type, + iih->circuit); } else { - adj->level = hdr->circuit_t; + adj->level = iih->circ_type; } - circuit->u.p2p.neighbor = adj; + iih->circuit->u.p2p.neighbor = adj; /* Build lsp with the new neighbor entry when a new * adjacency is formed. Set adjacency circuit type to * IIH PDU header circuit type before lsp is regenerated * when an adjacency is up. This will result in the new * adjacency entry getting added to the lsp tlv neighbor list. */ - adj->circuit_t = hdr->circuit_t; + adj->circuit_t = iih->circ_type; isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING, NULL); adj->sys_type = ISIS_SYSTYPE_UNKNOWN; } /* 8.2.6 Monitoring point-to-point adjacencies */ - adj->hold_time = ntohs(hdr->hold_time); + adj->hold_time = iih->holdtime; adj->last_upd = time(NULL); - /* we do this now because the adj may not survive till the end... */ - tlvs_to_adj_area_addrs(&tlvs, adj); - - /* which protocol are spoken ??? */ - if (tlvs_to_adj_nlpids(&tlvs, adj)) { - free_tlvs(&tlvs); - return ISIS_WARNING; - } - - /* we need to copy addresses to the adj */ - if (found & TLVFLAG_IPV4_ADDR) - tlvs_to_adj_ipv4_addrs(&tlvs, adj); + bool changed; + isis_tlvs_to_adj(iih->tlvs, adj, &changed); + changed |= tlvs_to_adj_mt_set(iih->tlvs, iih->v4_usable, iih->v6_usable, + adj); /* Update MPLS TE Remote IP address parameter if possible */ - if (IS_MPLS_TE(isisMplsTE) && circuit->mtc - && IS_CIRCUIT_TE(circuit->mtc)) - if (adj->ipv4_addrs != NULL - && listcount(adj->ipv4_addrs) != 0) { - struct in_addr *ip_addr; - ip_addr = (struct in_addr *)listgetdata( - (struct listnode *)listhead(adj->ipv4_addrs)); - set_circuitparams_rmt_ipaddr(circuit->mtc, *ip_addr); - } - - if (found & TLVFLAG_IPV6_ADDR) - tlvs_to_adj_ipv6_addrs(&tlvs, adj); - - bool mt_set_changed = - tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj); + if (IS_MPLS_TE(isisMplsTE) && iih->circuit->mtc + && IS_CIRCUIT_TE(iih->circuit->mtc) && adj->ipv4_address_count) + set_circuitparams_rmt_ipaddr(iih->circuit->mtc, + adj->ipv4_addresses[0]); /* lets take care of the expiry */ THREAD_TIMER_OFF(adj->t_expire); @@ -552,10 +176,11 @@ static int process_p2p_hello(struct isis_circuit *circuit) &adj->t_expire); /* 8.2.5.2 a) a match was detected */ - if (area_match(circuit->area->area_addrs, tlvs.area_addrs)) { + if (isis_tlvs_area_addresses_match(iih->tlvs, + iih->circuit->area->area_addrs)) { /* 8.2.5.2 a) 2) If the system is L1 - table 5 */ - if (circuit->area->is_type == IS_LEVEL_1) { - switch (hdr->circuit_t) { + if (iih->circuit->area->is_type == IS_LEVEL_1) { + switch (iih->circ_type) { case IS_LEVEL_1: case IS_LEVEL_1_AND_2: if (adj->adj_state != ISIS_ADJ_UP) { @@ -573,8 +198,7 @@ static int process_p2p_hello(struct isis_circuit *circuit) /* (7) reject - wrong system type event */ zlog_warn("wrongSystemType"); - free_tlvs(&tlvs); - return ISIS_WARNING; /* Reject */ + return ISIS_WARNING; } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { /* (6) down - wrong system */ isis_adj_state_change(adj, @@ -586,8 +210,8 @@ static int process_p2p_hello(struct isis_circuit *circuit) } /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */ - if (circuit->area->is_type == IS_LEVEL_1_AND_2) { - switch (hdr->circuit_t) { + if (iih->circuit->area->is_type == IS_LEVEL_1_AND_2) { + switch (iih->circ_type) { case IS_LEVEL_1: if (adj->adj_state != ISIS_ADJ_UP) { /* (6) adj state up */ @@ -648,15 +272,14 @@ static int process_p2p_hello(struct isis_circuit *circuit) } /* 8.2.5.2 a) 4) If the system is L2 - table 7 */ - if (circuit->area->is_type == IS_LEVEL_2) { - switch (hdr->circuit_t) { + if (iih->circuit->area->is_type == IS_LEVEL_2) { + switch (iih->circ_type) { case IS_LEVEL_1: if (adj->adj_state != ISIS_ADJ_UP) { /* (5) reject - wrong system type event */ zlog_warn("wrongSystemType"); - free_tlvs(&tlvs); - return ISIS_WARNING; /* Reject */ + return ISIS_WARNING; } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) || (adj->adj_usage @@ -689,8 +312,8 @@ static int process_p2p_hello(struct isis_circuit *circuit) } } /* 8.2.5.2 b) if no match was detected */ - else if (listcount(circuit->area->area_addrs) > 0) { - if (circuit->area->is_type == IS_LEVEL_1) { + else if (listcount(iih->circuit->area->area_addrs) > 0) { + if (iih->circuit->area->is_type == IS_LEVEL_1) { /* 8.2.5.2 b) 1) is_type L1 and adj is not up */ if (adj->adj_state != ISIS_ADJ_UP) { isis_adj_state_change(adj, ISIS_ADJ_DOWN, @@ -703,13 +326,12 @@ static int process_p2p_hello(struct isis_circuit *circuit) } /* 8.2.5.2 b 3 If the system is L2 or L1L2 - table 8 */ else { - switch (hdr->circuit_t) { + switch (iih->circ_type) { case IS_LEVEL_1: if (adj->adj_state != ISIS_ADJ_UP) { /* (6) reject - Area Mismatch event */ zlog_warn("AreaMismatch"); - free_tlvs(&tlvs); - return ISIS_WARNING; /* Reject */ + return ISIS_WARNING; } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { /* (7) down - area mismatch */ isis_adj_state_change(adj, @@ -741,7 +363,7 @@ static int process_p2p_hello(struct isis_circuit *circuit) "Wrong System"); } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) { - if (hdr->circuit_t == IS_LEVEL_2) { + if (iih->circ_type == IS_LEVEL_2) { /* (7) down - wrong system */ isis_adj_state_change( adj, ISIS_ADJ_DOWN, @@ -763,7 +385,7 @@ static int process_p2p_hello(struct isis_circuit *circuit) isis_adj_state_change(adj, ISIS_ADJ_DOWN, "Area Mismatch"); } - if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed) { + if (adj->adj_state == ISIS_ADJ_UP && changed) { lsp_regenerate_schedule(adj->circuit->area, isis_adj_usage2levels(adj->adj_usage), 0); @@ -790,387 +412,269 @@ static int process_p2p_hello(struct isis_circuit *circuit) break; } - if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug( "ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s," " cir id %02d, length %d", - circuit->area->area_tag, circuit->interface->name, - circuit_t2string(circuit->is_type), circuit->circuit_id, - pdu_len); + iih->circuit->area->area_tag, + iih->circuit->interface->name, + circuit_t2string(iih->circuit->is_type), + iih->circuit->circuit_id, iih->pdu_len); } - free_tlvs(&tlvs); - - return retval; + return ISIS_OK; } -/* - * Process IS-IS LAN Level 1/2 Hello PDU - */ -static int process_lan_hello(int level, struct isis_circuit *circuit, - const u_char *ssnpa) +static int process_lan_hello(struct iih_info *iih) { - int retval = ISIS_OK; - struct isis_lan_hello_hdr hdr; struct isis_adjacency *adj; - u_int32_t expected = 0, found = 0, auth_tlv_offset = 0; - struct tlvs tlvs; - u_char *snpa; - struct listnode *node; - int v4_usable = 0, v6_usable = 0; + adj = isis_adj_lookup(iih->sys_id, + iih->circuit->u.bc.adjdb[iih->level - 1]); + if ((adj == NULL) || (memcmp(adj->snpa, iih->ssnpa, ETH_ALEN)) + || (adj->level != iih->level)) { + if (!adj) { + /* Do as in 8.4.2.5 */ + adj = isis_new_adj(iih->sys_id, iih->ssnpa, iih->level, + iih->circuit); + } else { + if (iih->ssnpa) { + memcpy(adj->snpa, iih->ssnpa, 6); + } else { + memset(adj->snpa, ' ', 6); + } + adj->level = iih->level; + } + isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING, NULL); - if (isis->debugs & DEBUG_ADJ_PACKETS) { - zlog_debug( - "ISIS-Adj (%s): Rcvd L%d LAN IIH on %s, cirType %s, " - "cirID %u", - circuit->area->area_tag, level, - circuit->interface->name, - circuit_t2string(circuit->is_type), - circuit->circuit_id); - if (isis->debugs & DEBUG_PACKET_DUMP) - zlog_dump_data(STREAM_DATA(circuit->rcv_stream), - stream_get_endp(circuit->rcv_stream)); + if (iih->level == IS_LEVEL_1) + adj->sys_type = ISIS_SYSTYPE_L1_IS; + else + adj->sys_type = ISIS_SYSTYPE_L2_IS; + list_delete_all_node( + iih->circuit->u.bc.lan_neighs[iih->level - 1]); + isis_adj_build_neigh_list( + iih->circuit->u.bc.adjdb[iih->level - 1], + iih->circuit->u.bc.lan_neighs[iih->level - 1]); + } + + if (adj->dis_record[iih->level - 1].dis == ISIS_IS_DIS) { + u_char *dis = (iih->level == 1) + ? iih->circuit->u.bc.l1_desig_is + : iih->circuit->u.bc.l2_desig_is; + + if (memcmp(dis, iih->dis, ISIS_SYS_ID_LEN + 1)) { + thread_add_event(master, isis_event_dis_status_change, + iih->circuit, 0, NULL); + memcpy(dis, iih->dis, ISIS_SYS_ID_LEN + 1); + } } - if (circuit->circ_type != CIRCUIT_T_BROADCAST) { - zlog_warn("lan hello on non broadcast circuit"); - return ISIS_WARNING; - } + adj->circuit_t = iih->circ_type; + adj->hold_time = iih->holdtime; + adj->last_upd = time(NULL); + adj->prio[iih->level - 1] = iih->priority; + memcpy(adj->lanid, iih->dis, ISIS_SYS_ID_LEN + 1); - if ((stream_get_endp(circuit->rcv_stream) - - stream_get_getp(circuit->rcv_stream)) - < ISIS_LANHELLO_HDRLEN) { - zlog_warn("Packet too short"); - return ISIS_WARNING; + bool changed; + isis_tlvs_to_adj(iih->tlvs, adj, &changed); + changed |= tlvs_to_adj_mt_set(iih->tlvs, iih->v4_usable, iih->v6_usable, + adj); + + /* lets take care of the expiry */ + THREAD_TIMER_OFF(adj->t_expire); + thread_add_timer(master, isis_adj_expire, adj, (long)adj->hold_time, + &adj->t_expire); + + /* + * If the snpa for this circuit is found from LAN Neighbours TLV + * we have two-way communication -> adjacency can be put to state "up" + */ + bool own_snpa_found = + isis_tlvs_own_snpa_found(iih->tlvs, iih->circuit->u.bc.snpa); + + if (adj->adj_state != ISIS_ADJ_UP) { + if (own_snpa_found) { + isis_adj_state_change( + adj, ISIS_ADJ_UP, + "own SNPA found in LAN Neighbours TLV"); + } + } else { + if (!own_snpa_found) { + isis_adj_state_change( + adj, ISIS_ADJ_INITIALIZING, + "own SNPA not found in LAN Neighbours TLV"); + } } - if (circuit->ext_domain) { + if (adj->adj_state == ISIS_ADJ_UP && changed) + lsp_regenerate_schedule(adj->circuit->area, iih->level, 0); + + if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug( - "level %d LAN Hello received over circuit with " - "externalDomain = true", - level); - return ISIS_WARNING; + "ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, cirID %u, length %zd", + iih->circuit->area->area_tag, iih->level, + snpa_print(iih->ssnpa), iih->circuit->interface->name, + circuit_t2string(iih->circuit->is_type), + iih->circuit->circuit_id, + stream_get_endp(iih->circuit->rcv_stream)); } + return ISIS_OK; +} - if (!accept_level(level, circuit->is_type)) { - if (isis->debugs & DEBUG_ADJ_PACKETS) { +static int pdu_len_validate(uint16_t pdu_len, struct isis_circuit *circuit) +{ + if (pdu_len < stream_get_getp(circuit->rcv_stream) + || pdu_len > ISO_MTU(circuit) + || pdu_len > stream_get_endp(circuit->rcv_stream)) + return 1; + + if (pdu_len < stream_get_endp(circuit->rcv_stream)) + stream_set_endp(circuit->rcv_stream, pdu_len); + return 0; +} + +static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, + u_char *ssnpa) +{ + bool p2p_hello = (pdu_type == P2P_HELLO); + int level = p2p_hello ? 0 + : (pdu_type == L1_LAN_HELLO) ? ISIS_LEVEL1 + : ISIS_LEVEL2; + const char *pdu_name = + p2p_hello + ? "P2P IIH" + : (level == ISIS_LEVEL1) ? "L1 LAN IIH" : "L2 LAN IIH"; + + if (isis->debugs & DEBUG_ADJ_PACKETS) { + zlog_debug("ISIS-Adj (%s): Rcvd %s on %s, cirType %s, cirID %u", + circuit->area->area_tag, pdu_name, + circuit->interface->name, + circuit_t2string(circuit->is_type), + circuit->circuit_id); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data(STREAM_DATA(circuit->rcv_stream), + stream_get_endp(circuit->rcv_stream)); + } + + if (p2p_hello) { + if (circuit->circ_type != CIRCUIT_T_P2P) { + zlog_warn("p2p hello on non p2p circuit"); + return ISIS_WARNING; + } + } else { + if (circuit->circ_type != CIRCUIT_T_BROADCAST) { + zlog_warn("lan hello on non broadcast circuit"); + return ISIS_WARNING; + } + + if (circuit->ext_domain) { zlog_debug( - "ISIS-Adj (%s): Interface level mismatch, %s", - circuit->area->area_tag, - circuit->interface->name); + "level %d LAN Hello received over circuit with externalDomain = true", + level); + return ISIS_WARNING; + } + + if (!(circuit->is_type & level)) { + if (isis->debugs & DEBUG_ADJ_PACKETS) { + zlog_debug( + "ISIS-Adj (%s): Interface level mismatch, %s", + circuit->area->area_tag, + circuit->interface->name); + } + return ISIS_WARNING; } - return ISIS_WARNING; } -#if 0 - /* Cisco's debug message compatability */ - if (!accept_level (level, circuit->area->is_type)) - { - if (isis->debugs & DEBUG_ADJ_PACKETS) - { - zlog_debug ("ISIS-Adj (%s): is type mismatch", - circuit->area->area_tag); + struct iih_info iih = { + .circuit = circuit, .ssnpa = ssnpa, .level = level}; + + /* Generic IIH Header */ + iih.circ_type = stream_getc(circuit->rcv_stream) & 0x03; + stream_get(iih.sys_id, circuit->rcv_stream, ISIS_SYS_ID_LEN); + iih.holdtime = stream_getw(circuit->rcv_stream); + iih.pdu_len = stream_getw(circuit->rcv_stream); + + if (p2p_hello) { + iih.circuit_id = stream_getc(circuit->rcv_stream); + } else { + iih.priority = stream_getc(circuit->rcv_stream); + stream_get(iih.dis, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1); } - return ISIS_WARNING; - } -#endif - /* - * Fill the header - */ - hdr.circuit_t = stream_getc(circuit->rcv_stream); - stream_get(hdr.source_id, circuit->rcv_stream, ISIS_SYS_ID_LEN); - hdr.hold_time = stream_getw(circuit->rcv_stream); - hdr.pdu_len = stream_getw(circuit->rcv_stream); - hdr.prio = stream_getc(circuit->rcv_stream); - stream_get(hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1); - if (hdr.pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LANHELLO_HDRLEN) - || hdr.pdu_len > ISO_MTU(circuit) - || hdr.pdu_len > stream_get_endp(circuit->rcv_stream)) { + if (pdu_len_validate(iih.pdu_len, circuit)) { zlog_warn( - "ISIS-Adj (%s): Rcvd LAN IIH from (%s) with " - "invalid pdu length %d", - circuit->area->area_tag, circuit->interface->name, - hdr.pdu_len); + "ISIS-Adj (%s): Rcvd %s from (%s) with invalid pdu length %" PRIu16, + circuit->area->area_tag, pdu_name, + circuit->interface->name, iih.pdu_len); return ISIS_WARNING; } - /* - * Set the stream endp to PDU length, ignoring additional padding - * introduced by transport chips. - */ - if (hdr.pdu_len < stream_get_endp(circuit->rcv_stream)) - stream_set_endp(circuit->rcv_stream, hdr.pdu_len); - - if (hdr.circuit_t != IS_LEVEL_1 && hdr.circuit_t != IS_LEVEL_2 - && hdr.circuit_t != IS_LEVEL_1_AND_2 - && (level & hdr.circuit_t) == 0) { + if (!p2p_hello && !(level & iih.circ_type)) { zlog_err("Level %d LAN Hello with Circuit Type %d", level, - hdr.circuit_t); + iih.circ_type); return ISIS_ERROR; } - /* - * Then get the tlvs - */ - expected |= TLVFLAG_AUTH_INFO; - expected |= TLVFLAG_AREA_ADDRS; - expected |= TLVFLAG_LAN_NEIGHS; - expected |= TLVFLAG_NLPID; - expected |= TLVFLAG_IPV4_ADDR; - expected |= TLVFLAG_IPV6_ADDR; - expected |= TLVFLAG_MT_ROUTER_INFORMATION; - - auth_tlv_offset = stream_get_getp(circuit->rcv_stream); - retval = parse_tlvs( - circuit->area->area_tag, STREAM_PNT(circuit->rcv_stream), - hdr.pdu_len - ISIS_LANHELLO_HDRLEN - ISIS_FIXED_HDR_LEN, - &expected, &found, &tlvs, &auth_tlv_offset); - - if (retval > ISIS_WARNING) { - zlog_warn("parse_tlvs() failed"); + const char *error_log; + int retval = ISIS_WARNING; + + if (isis_unpack_tlvs(STREAM_READABLE(circuit->rcv_stream), + circuit->rcv_stream, &iih.tlvs, &error_log)) { + zlog_warn("isis_unpack_tlvs() failed: %s", error_log); goto out; } - if (!(found & TLVFLAG_AREA_ADDRS)) { - zlog_warn( - "No Area addresses TLV in Level %d LAN IS to IS hello", - level); - retval = ISIS_WARNING; + if (!iih.tlvs->area_addresses.count) { + zlog_warn("No Area addresses TLV in %s", pdu_name); goto out; } - if (!(found & TLVFLAG_NLPID)) { - zlog_warn( - "No supported protocols TLV in Level %d LAN IS to IS hello", - level); - retval = ISIS_WARNING; + if (!iih.tlvs->protocols_supported.count) { + zlog_warn("No supported protocols TLV in %s", pdu_name); goto out; } - /* Verify authentication, either cleartext of HMAC MD5 */ - if (circuit->passwd.type) { - if (!(found & TLVFLAG_AUTH_INFO) - || authentication_check(&tlvs.auth_info, &circuit->passwd, - circuit->rcv_stream, - auth_tlv_offset)) { - isis_event_auth_failure( - circuit->area->area_tag, - "LAN hello authentication failure", - hdr.source_id); - retval = ISIS_WARNING; - goto out; - } + if (!isis_tlvs_auth_is_valid(iih.tlvs, &circuit->passwd, + circuit->rcv_stream, false)) { + isis_event_auth_failure(circuit->area->area_tag, + "IIH authentication failure", + iih.sys_id); + goto out; } - if (!memcmp(hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN)) { - zlog_warn("ISIS-Adj (%s): duplicate system ID on interface %s", - circuit->area->area_tag, circuit->interface->name); - return ISIS_WARNING; + if (!memcmp(iih.sys_id, isis->sysid, ISIS_SYS_ID_LEN)) { + zlog_warn( + "ISIS-Adj (%s): Received IIH with own sysid - discard", + circuit->area->area_tag); + goto out; } - /* - * Accept the level 1 adjacency only if a match between local and - * remote area addresses is found - */ - if (listcount(circuit->area->area_addrs) == 0 - || (level == IS_LEVEL_1 - && area_match(circuit->area->area_addrs, tlvs.area_addrs) - == 0)) { + if (!p2p_hello + && (listcount(circuit->area->area_addrs) == 0 + || (level == ISIS_LEVEL1 + && !isis_tlvs_area_addresses_match( + iih.tlvs, circuit->area->area_addrs)))) { if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug( "ISIS-Adj (%s): Area mismatch, level %d IIH on %s", circuit->area->area_tag, level, circuit->interface->name); } - retval = ISIS_OK; goto out; } - /* - * it's own IIH PDU - discard silently - */ - if (!memcmp(circuit->u.bc.snpa, ssnpa, ETH_ALEN)) { - zlog_debug("ISIS-Adj (%s): it's own IIH PDU - discarded", - circuit->area->area_tag); - - retval = ISIS_OK; - goto out; - } + iih.v4_usable = (circuit->ip_addrs && listcount(circuit->ip_addrs) + && iih.tlvs->ipv4_address.count); - /* - * check if both ends have an IPv4 address - */ - if (circuit->ip_addrs && listcount(circuit->ip_addrs) && tlvs.ipv4_addrs - && listcount(tlvs.ipv4_addrs)) { - v4_usable = 1; - } - - if (found & TLVFLAG_IPV6_ADDR) { - /* TBA: check that we have a linklocal ourselves? */ - struct listnode *node; - struct in6_addr *ip; - for (ALL_LIST_ELEMENTS_RO(tlvs.ipv6_addrs, node, ip)) - if (IN6_IS_ADDR_LINKLOCAL(ip)) { - v6_usable = 1; - break; - } + iih.v6_usable = (circuit->ipv6_link && listcount(circuit->ipv6_link) + && iih.tlvs->ipv6_address.count); - if (!v6_usable) - zlog_warn( - "ISIS-Adj: IPv6 addresses present but no link-local " - "in LAN IIH from %s\n", - circuit->interface->name); - } - - if (!(found & (TLVFLAG_IPV4_ADDR | TLVFLAG_IPV6_ADDR))) - zlog_warn( - "ISIS-Adj: neither IPv4 nor IPv6 addr in LAN IIH from %s\n", - circuit->interface->name); - - if (!v6_usable && !v4_usable) { - free_tlvs(&tlvs); - return ISIS_WARNING; - } - - - adj = isis_adj_lookup(hdr.source_id, circuit->u.bc.adjdb[level - 1]); - if ((adj == NULL) || (memcmp(adj->snpa, ssnpa, ETH_ALEN)) - || (adj->level != level)) { - if (!adj) { - /* - * Do as in 8.4.2.5 - */ - adj = isis_new_adj(hdr.source_id, ssnpa, level, - circuit); - if (adj == NULL) { - retval = ISIS_ERROR; - goto out; - } - } else { - if (ssnpa) { - memcpy(adj->snpa, ssnpa, 6); - } else { - memset(adj->snpa, ' ', 6); - } - adj->level = level; - } - isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING, NULL); - - if (level == IS_LEVEL_1) - adj->sys_type = ISIS_SYSTYPE_L1_IS; - else - adj->sys_type = ISIS_SYSTYPE_L2_IS; - list_delete_all_node(circuit->u.bc.lan_neighs[level - 1]); - isis_adj_build_neigh_list(circuit->u.bc.adjdb[level - 1], - circuit->u.bc.lan_neighs[level - 1]); - } - - if (adj->dis_record[level - 1].dis == ISIS_IS_DIS) - switch (level) { - case 1: - if (memcmp(circuit->u.bc.l1_desig_is, hdr.lan_id, - ISIS_SYS_ID_LEN + 1)) { - thread_add_event(master, - isis_event_dis_status_change, - circuit, 0, NULL); - memcpy(&circuit->u.bc.l1_desig_is, hdr.lan_id, - ISIS_SYS_ID_LEN + 1); - } - break; - case 2: - if (memcmp(circuit->u.bc.l2_desig_is, hdr.lan_id, - ISIS_SYS_ID_LEN + 1)) { - thread_add_event(master, - isis_event_dis_status_change, - circuit, 0, NULL); - memcpy(&circuit->u.bc.l2_desig_is, hdr.lan_id, - ISIS_SYS_ID_LEN + 1); - } - break; - } - - adj->hold_time = hdr.hold_time; - adj->last_upd = time(NULL); - adj->prio[level - 1] = hdr.prio; - - memcpy(adj->lanid, hdr.lan_id, ISIS_SYS_ID_LEN + 1); - - tlvs_to_adj_area_addrs(&tlvs, adj); - - /* which protocol are spoken ??? */ - if (tlvs_to_adj_nlpids(&tlvs, adj)) { - retval = ISIS_WARNING; + if (!iih.v4_usable && !iih.v6_usable) goto out; - } - - /* we need to copy addresses to the adj */ - if (found & TLVFLAG_IPV4_ADDR) - tlvs_to_adj_ipv4_addrs(&tlvs, adj); - - if (found & TLVFLAG_IPV6_ADDR) - tlvs_to_adj_ipv6_addrs(&tlvs, adj); - - adj->circuit_t = hdr.circuit_t; - - bool mt_set_changed = - tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj); - - /* lets take care of the expiry */ - THREAD_TIMER_OFF(adj->t_expire); - thread_add_timer(master, isis_adj_expire, adj, (long)adj->hold_time, - &adj->t_expire); - - /* - * If the snpa for this circuit is found from LAN Neighbours TLV - * we have two-way communication -> adjacency can be put to state "up" - */ - - if (found & TLVFLAG_LAN_NEIGHS) { - if (adj->adj_state != ISIS_ADJ_UP) { - for (ALL_LIST_ELEMENTS_RO(tlvs.lan_neighs, node, - snpa)) { - if (!memcmp(snpa, circuit->u.bc.snpa, - ETH_ALEN)) { - isis_adj_state_change( - adj, ISIS_ADJ_UP, - "own SNPA found in LAN Neighbours TLV"); - } - } - } else { - int found = 0; - for (ALL_LIST_ELEMENTS_RO(tlvs.lan_neighs, node, snpa)) - if (!memcmp(snpa, circuit->u.bc.snpa, - ETH_ALEN)) { - found = 1; - break; - } - if (found == 0) - isis_adj_state_change( - adj, ISIS_ADJ_INITIALIZING, - "own SNPA not found in LAN Neighbours TLV"); - } - } else if (adj->adj_state == ISIS_ADJ_UP) { - isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING, - "no LAN Neighbours TLV found"); - } - - if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed) - lsp_regenerate_schedule(adj->circuit->area, level, 0); + retval = p2p_hello ? process_p2p_hello(&iih) : process_lan_hello(&iih); out: - if (isis->debugs & DEBUG_ADJ_PACKETS) { - zlog_debug( - "ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, " - "cirID %u, length %zd", - circuit->area->area_tag, level, snpa_print(ssnpa), - circuit->interface->name, - circuit_t2string(circuit->is_type), circuit->circuit_id, - stream_get_endp(circuit->rcv_stream)); - } - - free_tlvs(&tlvs); + isis_free_tlvs(iih.tlvs); return retval; } @@ -1180,17 +684,10 @@ out: * ISO - 10589 * Section 7.3.15.1 - Action on receipt of a link state PDU */ -static int process_lsp(int level, struct isis_circuit *circuit, +static int process_lsp(uint8_t pdu_type, struct isis_circuit *circuit, const u_char *ssnpa) { - struct isis_link_state_hdr *hdr; - struct isis_adjacency *adj = NULL; - struct isis_lsp *lsp, *lsp0 = NULL; - int retval = ISIS_OK, comp = 0; - u_char lspid[ISIS_SYS_ID_LEN + 2]; - struct isis_passwd *passwd; - uint16_t pdu_len; - int lsp_confusion; + int level = (pdu_type == L1_LINK_STATE) ? ISIS_LEVEL1 : ISIS_LEVEL2; if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug( @@ -1204,65 +701,50 @@ static int process_lsp(int level, struct isis_circuit *circuit, stream_get_endp(circuit->rcv_stream)); } - if ((stream_get_endp(circuit->rcv_stream) - - stream_get_getp(circuit->rcv_stream)) - < ISIS_LSP_HDR_LEN) { - zlog_warn("Packet too short"); - return ISIS_WARNING; - } - - /* Reference the header */ - hdr = (struct isis_link_state_hdr *)STREAM_PNT(circuit->rcv_stream); - pdu_len = ntohs(hdr->pdu_len); - - /* lsp length check */ - if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN) - || pdu_len > ISO_MTU(circuit) - || pdu_len > stream_get_endp(circuit->rcv_stream)) { - zlog_debug("ISIS-Upd (%s): LSP %s invalid LSP length %d", - circuit->area->area_tag, rawlspid_print(hdr->lsp_id), - pdu_len); + struct isis_lsp_hdr hdr = {}; + hdr.pdu_len = stream_getw(circuit->rcv_stream); + hdr.rem_lifetime = stream_getw(circuit->rcv_stream); + stream_get(hdr.lsp_id, circuit->rcv_stream, sizeof(hdr.lsp_id)); + hdr.seqno = stream_getl(circuit->rcv_stream); + hdr.checksum = stream_getw(circuit->rcv_stream); + hdr.lsp_bits = stream_getc(circuit->rcv_stream); + + if (pdu_len_validate(hdr.pdu_len, circuit)) { + zlog_debug("ISIS-Upd (%s): LSP %s invalid LSP length %" PRIu16, + circuit->area->area_tag, rawlspid_print(hdr.lsp_id), + hdr.pdu_len); return ISIS_WARNING; } - /* - * Set the stream endp to PDU length, ignoring additional padding - * introduced by transport chips. - */ - if (pdu_len < stream_get_endp(circuit->rcv_stream)) - stream_set_endp(circuit->rcv_stream, pdu_len); - if (isis->debugs & DEBUG_UPDATE_PACKETS) { - zlog_debug( - "ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, " - "lifetime %us, len %u, on %s", - circuit->area->area_tag, level, - rawlspid_print(hdr->lsp_id), ntohl(hdr->seq_num), - ntohs(hdr->checksum), ntohs(hdr->rem_lifetime), pdu_len, - circuit->interface->name); + zlog_debug("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08" PRIx32 + ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 + "s, len %" PRIu16 ", on %s", + circuit->area->area_tag, level, + rawlspid_print(hdr.lsp_id), hdr.seqno, hdr.checksum, + hdr.rem_lifetime, hdr.pdu_len, + circuit->interface->name); } /* lsp is_type check */ - if ((hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1 - && (hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1_AND_2) { - zlog_debug("ISIS-Upd (%s): LSP %s invalid LSP is type %x", - circuit->area->area_tag, rawlspid_print(hdr->lsp_id), - hdr->lsp_bits); + if ((hdr.lsp_bits & IS_LEVEL_1) != IS_LEVEL_1) { + zlog_debug( + "ISIS-Upd (%s): LSP %s invalid LSP is type 0x%" PRIx8, + circuit->area->area_tag, rawlspid_print(hdr.lsp_id), + hdr.lsp_bits & IS_LEVEL_1_AND_2); /* continue as per RFC1122 Be liberal in what you accept, and * conservative in what you send */ } /* Checksum sanity check - FIXME: move to correct place */ /* 12 = sysid+pdu+remtime */ - if (iso_csum_verify(STREAM_PNT(circuit->rcv_stream) + 4, pdu_len - 12, - hdr->checksum, - offsetof(struct isis_link_state_hdr, checksum) - - 4)) { - zlog_debug("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x", - circuit->area->area_tag, rawlspid_print(hdr->lsp_id), - ntohs(hdr->checksum)); - + if (iso_csum_verify(STREAM_DATA(circuit->rcv_stream) + 12, + hdr.pdu_len - 12, hdr.checksum, 12)) { + zlog_debug( + "ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04" PRIx16, + circuit->area->area_tag, rawlspid_print(hdr.lsp_id), + hdr.checksum); return ISIS_WARNING; } @@ -1271,46 +753,56 @@ static int process_lsp(int level, struct isis_circuit *circuit, zlog_debug( "ISIS-Upd (%s): LSP %s received at level %d over circuit with " "externalDomain = true", - circuit->area->area_tag, rawlspid_print(hdr->lsp_id), + circuit->area->area_tag, rawlspid_print(hdr.lsp_id), level); - return ISIS_WARNING; } /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */ - if (!accept_level(level, circuit->is_type)) { + if (!(circuit->is_type & level)) { zlog_debug( "ISIS-Upd (%s): LSP %s received at level %d over circuit of" " type %s", - circuit->area->area_tag, rawlspid_print(hdr->lsp_id), + circuit->area->area_tag, rawlspid_print(hdr.lsp_id), level, circuit_t2string(circuit->is_type)); - return ISIS_WARNING; } + struct isis_tlvs *tlvs = NULL; + int retval = ISIS_WARNING; + const char *error_log; + + if (isis_unpack_tlvs(STREAM_READABLE(circuit->rcv_stream), + circuit->rcv_stream, &tlvs, &error_log)) { + zlog_warn("Something went wrong unpacking the LSP: %s", + error_log); + goto out; + } + /* 7.3.15.1 a) 4 - need to make sure IDLength matches */ /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use * 3 */ /* 7.3.15.1 a) 7 - password check */ - (level == IS_LEVEL_1) ? (passwd = &circuit->area->area_passwd) - : (passwd = &circuit->area->domain_passwd); - if (passwd->type) { - if (lsp_authentication_check(circuit->rcv_stream, circuit->area, - level, passwd)) { - isis_event_auth_failure(circuit->area->area_tag, - "LSP authentication failure", - hdr->lsp_id); - return ISIS_WARNING; - } + struct isis_passwd *passwd = (level == ISIS_LEVEL1) + ? &circuit->area->area_passwd + : &circuit->area->domain_passwd; + if (!isis_tlvs_auth_is_valid(tlvs, passwd, circuit->rcv_stream, true)) { + isis_event_auth_failure(circuit->area->area_tag, + "LSP authentication failure", + hdr.lsp_id); + goto out; } + /* Find the LSP in our database and compare it to this Link State header */ - lsp = lsp_search(hdr->lsp_id, circuit->area->lspdb[level - 1]); + struct isis_lsp *lsp = + lsp_search(hdr.lsp_id, circuit->area->lspdb[level - 1]); + int comp = 0; if (lsp) - comp = lsp_compare(circuit->area->area_tag, lsp, hdr->seq_num, - hdr->checksum, hdr->rem_lifetime); + comp = lsp_compare(circuit->area->area_tag, lsp, hdr.seqno, + hdr.checksum, hdr.rem_lifetime); if (lsp && (lsp->own_lsp)) goto dontcheckadj; @@ -1319,25 +811,24 @@ static int process_lsp(int level, struct isis_circuit *circuit, /* for broadcast circuits, snpa should be compared */ if (circuit->circ_type == CIRCUIT_T_BROADCAST) { - adj = isis_adj_lookup_snpa(ssnpa, - circuit->u.bc.adjdb[level - 1]); - if (!adj) { - zlog_debug( - "(%s): DS ======= LSP %s, seq 0x%08x, cksum 0x%04x, " - "lifetime %us on %s", - circuit->area->area_tag, - rawlspid_print(hdr->lsp_id), - ntohl(hdr->seq_num), ntohs(hdr->checksum), - ntohs(hdr->rem_lifetime), - circuit->interface->name); - return ISIS_WARNING; /* Silently discard */ + if (!isis_adj_lookup_snpa(ssnpa, + circuit->u.bc.adjdb[level - 1])) { + zlog_debug("(%s): DS ======= LSP %s, seq 0x%08" PRIx32 + ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 + "s on %s", + circuit->area->area_tag, + rawlspid_print(hdr.lsp_id), hdr.seqno, + hdr.checksum, hdr.rem_lifetime, + circuit->interface->name); + goto out; /* Silently discard */ } } /* for non broadcast, we just need to find same level adj */ else { /* If no adj, or no sharing of level */ if (!circuit->u.p2p.neighbor) { - return ISIS_OK; /* Silently discard */ + retval = ISIS_OK; + goto out; } else { if (((level == IS_LEVEL_1) && (circuit->u.p2p.neighbor->adj_usage @@ -1345,10 +836,12 @@ static int process_lsp(int level, struct isis_circuit *circuit, || ((level == IS_LEVEL_2) && (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL1))) - return ISIS_WARNING; /* Silently discard */ + goto out; } } + bool lsp_confusion; + dontcheckadj: /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented */ @@ -1360,33 +853,36 @@ dontcheckadj: /* 7.3.16.2 - If this is an LSP from another IS with identical seq_num * but * wrong checksum, initiate a purge. */ - if (lsp && (lsp->lsp_header->seq_num == hdr->seq_num) - && (lsp->lsp_header->checksum != hdr->checksum)) { - zlog_warn( - "ISIS-Upd (%s): LSP %s seq 0x%08x with confused checksum received.", - circuit->area->area_tag, rawlspid_print(hdr->lsp_id), - ntohl(hdr->seq_num)); - hdr->rem_lifetime = 0; - lsp_confusion = 1; + if (lsp && (lsp->hdr.seqno == hdr.seqno) + && (lsp->hdr.checksum != hdr.checksum)) { + zlog_warn("ISIS-Upd (%s): LSP %s seq 0x%08" PRIx32 + " with confused checksum received.", + circuit->area->area_tag, rawlspid_print(hdr.lsp_id), + hdr.seqno); + hdr.rem_lifetime = 0; + lsp_confusion = true; } else - lsp_confusion = 0; + lsp_confusion = false; /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */ - if (hdr->rem_lifetime == 0) { + if (hdr.rem_lifetime == 0) { if (!lsp) { /* 7.3.16.4 a) 1) No LSP in db -> send an ack, but don't * save */ /* only needed on explicit update, eg - p2p */ if (circuit->circ_type == CIRCUIT_T_P2P) - ack_lsp(hdr, circuit, level); - return retval; /* FIXME: do we need a purge? */ + ack_lsp(&hdr, circuit, level); + goto out; /* FIXME: do we need a purge? */ } else { - if (memcmp(hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN)) { + if (memcmp(hdr.lsp_id, isis->sysid, ISIS_SYS_ID_LEN)) { /* LSP by some other system -> do 7.3.16.4 b) */ /* 7.3.16.4 b) 1) */ if (comp == LSP_NEWER) { - lsp_update(lsp, circuit->rcv_stream, - circuit->area, level); + lsp_update(lsp, &hdr, tlvs, + circuit->rcv_stream, + circuit->area, level, + lsp_confusion); + tlvs = NULL; /* ii */ lsp_set_all_srmflags(lsp); /* v */ @@ -1427,11 +923,10 @@ dontcheckadj: ISIS_SET_FLAG(lsp->SRMflags, circuit); ISIS_CLEAR_FLAG(lsp->SSNflags, circuit); } - } else if (lsp->lsp_header->rem_lifetime != 0) { + } else if (lsp->hdr.rem_lifetime != 0) { /* our own LSP -> 7.3.16.4 c) */ if (comp == LSP_NEWER) { - lsp_inc_seqnum(lsp, - ntohl(hdr->seq_num)); + lsp_inc_seqno(lsp, hdr.seqno); lsp_set_all_srmflags(lsp); } else { ISIS_SET_FLAG(lsp->SRMflags, circuit); @@ -1439,23 +934,22 @@ dontcheckadj: } if (isis->debugs & DEBUG_UPDATE_PACKETS) zlog_debug( - "ISIS-Upd (%s): (1) re-originating LSP %s new " - "seq 0x%08x", + "ISIS-Upd (%s): (1) re-originating LSP %s new seq 0x%08" PRIx32, circuit->area->area_tag, - rawlspid_print(hdr->lsp_id), - ntohl(lsp->lsp_header - ->seq_num)); + rawlspid_print(hdr.lsp_id), + lsp->hdr.seqno); } } - return retval; + goto out; } /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a * purge */ - if (memcmp(hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN) == 0) { + if (memcmp(hdr.lsp_id, isis->sysid, ISIS_SYS_ID_LEN) == 0) { if (!lsp) { /* 7.3.16.4: initiate a purge */ - lsp_purge_non_exist(level, hdr, circuit->area); - return ISIS_OK; + lsp_purge_non_exist(level, &hdr, circuit->area); + retval = ISIS_OK; + goto out; } /* 7.3.15.1 d) - If this is our own lsp and we have it */ @@ -1465,16 +959,15 @@ dontcheckadj: * is * "greater" than that held by S, ... */ - if (ntohl(hdr->seq_num) > ntohl(lsp->lsp_header->seq_num)) { + if (hdr.seqno > lsp->hdr.seqno) { /* 7.3.16.1 */ - lsp_inc_seqnum(lsp, ntohl(hdr->seq_num)); + lsp_inc_seqno(lsp, hdr.seqno); if (isis->debugs & DEBUG_UPDATE_PACKETS) zlog_debug( - "ISIS-Upd (%s): (2) re-originating LSP %s new seq " - "0x%08x", + "ISIS-Upd (%s): (2) re-originating LSP %s new seq 0x%08" PRIx32, circuit->area->area_tag, - rawlspid_print(hdr->lsp_id), - ntohl(lsp->lsp_header->seq_num)); + rawlspid_print(hdr.lsp_id), + lsp->hdr.seqno); } /* If the received LSP is older or equal, * resend the LSP which will act as ACK */ @@ -1489,8 +982,10 @@ dontcheckadj: * If this lsp is a frag, need to see if we have zero * lsp present */ - if (LSP_FRAGMENT(hdr->lsp_id) != 0) { - memcpy(lspid, hdr->lsp_id, ISIS_SYS_ID_LEN + 1); + struct isis_lsp *lsp0 = NULL; + if (LSP_FRAGMENT(hdr.lsp_id) != 0) { + uint8_t lspid[ISIS_SYS_ID_LEN + 2]; + memcpy(lspid, hdr.lsp_id, ISIS_SYS_ID_LEN + 1); LSP_FRAGMENT(lspid) = 0; lsp0 = lsp_search( lspid, circuit->area->lspdb[level - 1]); @@ -1502,15 +997,17 @@ dontcheckadj: } /* i */ if (!lsp) { - lsp = lsp_new_from_stream_ptr( - circuit->rcv_stream, pdu_len, lsp0, + lsp = lsp_new_from_recv( + &hdr, tlvs, circuit->rcv_stream, lsp0, circuit->area, level); + tlvs = NULL; lsp_insert(lsp, circuit->area->lspdb[level - 1]); } else /* exists, so we overwrite */ { - lsp_update(lsp, circuit->rcv_stream, - circuit->area, level); + lsp_update(lsp, &hdr, tlvs, circuit->rcv_stream, + circuit->area, level, false); + tlvs = NULL; } /* ii */ lsp_set_all_srmflags(lsp); @@ -1525,8 +1022,9 @@ dontcheckadj: /* 7.3.15.1 e) 2) LSP equal to the one in db */ else if (comp == LSP_EQUAL) { ISIS_CLEAR_FLAG(lsp->SRMflags, circuit); - lsp_update(lsp, circuit->rcv_stream, circuit->area, - level); + lsp_update(lsp, &hdr, tlvs, circuit->rcv_stream, + circuit->area, level, false); + tlvs = NULL; if (circuit->circ_type != CIRCUIT_T_BROADCAST) ISIS_SET_FLAG(lsp->SSNflags, circuit); } @@ -1536,6 +1034,11 @@ dontcheckadj: ISIS_CLEAR_FLAG(lsp->SSNflags, circuit); } } + + retval = ISIS_OK; + +out: + isis_free_tlvs(tlvs); return retval; } @@ -1545,60 +1048,48 @@ dontcheckadj: * Section 7.3.15.2 - Action on receipt of a sequence numbers PDU */ -static int process_snp(int snp_type, int level, struct isis_circuit *circuit, +static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit, const u_char *ssnpa) { - int retval = ISIS_OK; - int cmp, own_lsp; - char typechar = ' '; - uint16_t pdu_len; - struct isis_adjacency *adj; - struct isis_complete_seqnum_hdr *chdr = NULL; - struct isis_partial_seqnum_hdr *phdr = NULL; - uint32_t found = 0, expected = 0, auth_tlv_offset = 0; - struct isis_lsp *lsp; - struct lsp_entry *entry; - struct listnode *node, *nnode; - struct listnode *node2, *nnode2; - struct tlvs tlvs; - struct list *lsp_list = NULL; - struct isis_passwd *passwd; - - if (snp_type == ISIS_SNP_CSNP_FLAG) { - /* getting the header info */ - typechar = 'C'; - chdr = (struct isis_complete_seqnum_hdr *)STREAM_PNT( - circuit->rcv_stream); - stream_forward_getp(circuit->rcv_stream, ISIS_CSNP_HDRLEN); - pdu_len = ntohs(chdr->pdu_len); - if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_CSNP_HDRLEN) - || pdu_len > ISO_MTU(circuit) - || pdu_len > stream_get_endp(circuit->rcv_stream)) { - zlog_warn("Received a CSNP with bogus length %d", - pdu_len); - return ISIS_WARNING; - } - } else { - typechar = 'P'; - phdr = (struct isis_partial_seqnum_hdr *)STREAM_PNT( - circuit->rcv_stream); - stream_forward_getp(circuit->rcv_stream, ISIS_PSNP_HDRLEN); - pdu_len = ntohs(phdr->pdu_len); - if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_PSNP_HDRLEN) - || pdu_len > ISO_MTU(circuit) - || pdu_len > stream_get_endp(circuit->rcv_stream)) { - zlog_warn("Received a PSNP with bogus length %d", - pdu_len); - return ISIS_WARNING; - } + bool is_csnp = (pdu_type == L1_COMPLETE_SEQ_NUM + || pdu_type == L2_COMPLETE_SEQ_NUM); + char typechar = is_csnp ? 'C' : 'P'; + int level = (pdu_type == L1_COMPLETE_SEQ_NUM + || pdu_type == L1_PARTIAL_SEQ_NUM) + ? ISIS_LEVEL1 + : ISIS_LEVEL2; + + uint16_t pdu_len = stream_getw(circuit->rcv_stream); + uint8_t rem_sys_id[ISIS_SYS_ID_LEN]; + stream_get(rem_sys_id, circuit->rcv_stream, ISIS_SYS_ID_LEN); + stream_forward_getp(circuit->rcv_stream, 1); /* Circuit ID - unused */ + + uint8_t start_lsp_id[ISIS_SYS_ID_LEN + 2] = {}; + uint8_t stop_lsp_id[ISIS_SYS_ID_LEN + 2] = {}; + + if (is_csnp) { + stream_get(start_lsp_id, circuit->rcv_stream, + ISIS_SYS_ID_LEN + 2); + stream_get(stop_lsp_id, circuit->rcv_stream, + ISIS_SYS_ID_LEN + 2); + } + + if (pdu_len_validate(pdu_len, circuit)) { + zlog_warn("Received a CSNP with bogus length %d", pdu_len); + return ISIS_WARNING; } - /* - * Set the stream endp to PDU length, ignoring additional padding - * introduced by transport chips. - */ - if (pdu_len < stream_get_endp(circuit->rcv_stream)) - stream_set_endp(circuit->rcv_stream, pdu_len); + if (isis->debugs & DEBUG_SNP_PACKETS) { + zlog_debug( + "ISIS-Snp (%s): Rcvd L%d %cSNP on %s, cirType %s, cirID %u", + circuit->area->area_tag, level, typechar, + circuit->interface->name, + circuit_t2string(circuit->is_type), + circuit->circuit_id); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data(STREAM_DATA(circuit->rcv_stream), + stream_get_endp(circuit->rcv_stream)); + } /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */ if (circuit->ext_domain) { @@ -1613,8 +1104,7 @@ static int process_snp(int snp_type, int level, struct isis_circuit *circuit, } /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */ - if (!accept_level(level, circuit->is_type)) { - + if (!(circuit->is_type & level)) { zlog_debug( "ISIS-Snp (%s): Rcvd L%d %cSNP on %s, " "skipping: circuit type %s does not match level %d", @@ -1626,9 +1116,8 @@ static int process_snp(int snp_type, int level, struct isis_circuit *circuit, } /* 7.3.15.2 a) 4 - not applicable for CSNP only PSNPs on broadcast */ - if ((snp_type == ISIS_SNP_PSNP_FLAG) - && (circuit->circ_type == CIRCUIT_T_BROADCAST) - && (!circuit->u.bc.is_dr[level - 1])) { + if (!is_csnp && (circuit->circ_type == CIRCUIT_T_BROADCAST) + && !circuit->u.bc.is_dr[level - 1]) { zlog_debug( "ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, " "skipping: we are not the DIS", @@ -1650,15 +1139,8 @@ static int process_snp(int snp_type, int level, struct isis_circuit *circuit, /* for broadcast circuits, snpa should be compared */ /* FIXME : Do we need to check SNPA? */ if (circuit->circ_type == CIRCUIT_T_BROADCAST) { - if (snp_type == ISIS_SNP_CSNP_FLAG) { - adj = isis_adj_lookup(chdr->source_id, - circuit->u.bc.adjdb[level - 1]); - } else { - /* a psnp on a broadcast, how lovely of Juniper :) */ - adj = isis_adj_lookup(phdr->source_id, - circuit->u.bc.adjdb[level - 1]); - } - if (!adj) + if (!isis_adj_lookup(rem_sys_id, + circuit->u.bc.adjdb[level - 1])) return ISIS_OK; /* Silently discard */ } else { if (!circuit->u.p2p.neighbor) { @@ -1668,164 +1150,128 @@ static int process_snp(int snp_type, int level, struct isis_circuit *circuit, } } - /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented */ + struct isis_tlvs *tlvs; + int retval = ISIS_WARNING; + const char *error_log; - /* 7.3.15.2 a) 9 - Passwords for level 2 - not implemented */ - - memset(&tlvs, 0, sizeof(struct tlvs)); - - /* parse the SNP */ - expected |= TLVFLAG_LSP_ENTRIES; - expected |= TLVFLAG_AUTH_INFO; - - auth_tlv_offset = stream_get_getp(circuit->rcv_stream); - retval = parse_tlvs(circuit->area->area_tag, - STREAM_PNT(circuit->rcv_stream), - pdu_len - stream_get_getp(circuit->rcv_stream), - &expected, &found, &tlvs, &auth_tlv_offset); - - if (retval > ISIS_WARNING) { - zlog_warn("something went very wrong processing SNP"); - free_tlvs(&tlvs); - return retval; + if (isis_unpack_tlvs(STREAM_READABLE(circuit->rcv_stream), + circuit->rcv_stream, &tlvs, &error_log)) { + zlog_warn("Something went wrong unpacking the SNP: %s", + error_log); + goto out; } - if (level == IS_LEVEL_1) - passwd = &circuit->area->area_passwd; - else - passwd = &circuit->area->domain_passwd; - - if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV)) { - if (passwd->type) { - if (!(found & TLVFLAG_AUTH_INFO) - || authentication_check(&tlvs.auth_info, passwd, - circuit->rcv_stream, - auth_tlv_offset)) { - isis_event_auth_failure(circuit->area->area_tag, - "SNP authentication" - " failure", - phdr ? phdr->source_id - : chdr->source_id); - free_tlvs(&tlvs); - return ISIS_OK; - } - } + struct isis_passwd *passwd = (level == IS_LEVEL_1) + ? &circuit->area->area_passwd + : &circuit->area->domain_passwd; + if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV) + && !isis_tlvs_auth_is_valid(tlvs, passwd, circuit->rcv_stream, + false)) { + isis_event_auth_failure(circuit->area->area_tag, + "SNP authentication failure", + rem_sys_id); + goto out; } + struct isis_lsp_entry *entry_head = + (struct isis_lsp_entry *)tlvs->lsp_entries.head; + /* debug isis snp-packets */ if (isis->debugs & DEBUG_SNP_PACKETS) { zlog_debug("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s", circuit->area->area_tag, level, typechar, snpa_print(ssnpa), circuit->interface->name); - if (tlvs.lsp_entries) { - for (ALL_LIST_ELEMENTS_RO(tlvs.lsp_entries, node, - entry)) { - zlog_debug( - "ISIS-Snp (%s): %cSNP entry %s, seq 0x%08x," - " cksum 0x%04x, lifetime %us", - circuit->area->area_tag, typechar, - rawlspid_print(entry->lsp_id), - ntohl(entry->seq_num), - ntohs(entry->checksum), - ntohs(entry->rem_lifetime)); - } + for (struct isis_lsp_entry *entry = entry_head; entry; + entry = entry->next) { + zlog_debug( + "ISIS-Snp (%s): %cSNP entry %s, seq 0x%08" PRIx32 + ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 "s", + circuit->area->area_tag, typechar, + rawlspid_print(entry->id), entry->seqno, + entry->checksum, entry->rem_lifetime); } } /* 7.3.15.2 b) Actions on LSP_ENTRIES reported */ - if (tlvs.lsp_entries) { - for (ALL_LIST_ELEMENTS_RO(tlvs.lsp_entries, node, entry)) { - lsp = lsp_search(entry->lsp_id, - circuit->area->lspdb[level - 1]); - own_lsp = !memcmp(entry->lsp_id, isis->sysid, - ISIS_SYS_ID_LEN); - if (lsp) { - /* 7.3.15.2 b) 1) is this LSP newer */ - cmp = lsp_compare(circuit->area->area_tag, lsp, - entry->seq_num, - entry->checksum, - entry->rem_lifetime); - /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p - */ - if (cmp == LSP_EQUAL) { + for (struct isis_lsp_entry *entry = entry_head; entry; + entry = entry->next) { + struct isis_lsp *lsp = + lsp_search(entry->id, circuit->area->lspdb[level - 1]); + bool own_lsp = !memcmp(entry->id, isis->sysid, ISIS_SYS_ID_LEN); + if (lsp) { + /* 7.3.15.2 b) 1) is this LSP newer */ + int cmp = lsp_compare(circuit->area->area_tag, lsp, + entry->seqno, entry->checksum, + entry->rem_lifetime); + /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */ + if (cmp == LSP_EQUAL) { + /* if (circuit->circ_type != + * CIRCUIT_T_BROADCAST) */ + ISIS_CLEAR_FLAG(lsp->SRMflags, circuit); + } + /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM + */ + else if (cmp == LSP_OLDER) { + ISIS_CLEAR_FLAG(lsp->SSNflags, circuit); + ISIS_SET_FLAG(lsp->SRMflags, circuit); + } + /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM + on p2p */ + else { + if (own_lsp) { + lsp_inc_seqno(lsp, entry->seqno); + ISIS_SET_FLAG(lsp->SRMflags, circuit); + } else { + ISIS_SET_FLAG(lsp->SSNflags, circuit); /* if (circuit->circ_type != * CIRCUIT_T_BROADCAST) */ ISIS_CLEAR_FLAG(lsp->SRMflags, circuit); } - /* 7.3.15.2 b) 3) if it is older, clear SSN and - set SRM */ - else if (cmp == LSP_OLDER) { - ISIS_CLEAR_FLAG(lsp->SSNflags, circuit); - ISIS_SET_FLAG(lsp->SRMflags, circuit); - } - /* 7.3.15.2 b) 4) if it is newer, set SSN and - clear SRM on p2p */ - else { - if (own_lsp) { - lsp_inc_seqnum( - lsp, - ntohl(entry->seq_num)); - ISIS_SET_FLAG(lsp->SRMflags, - circuit); - } else { - ISIS_SET_FLAG(lsp->SSNflags, - circuit); - /* if (circuit->circ_type != - * CIRCUIT_T_BROADCAST) */ - ISIS_CLEAR_FLAG(lsp->SRMflags, - circuit); - } - } - } else { - /* 7.3.15.2 b) 5) if it was not found, and all - * of those are not 0, - * insert it and set SSN on it */ - if (entry->rem_lifetime && entry->checksum - && entry->seq_num - && memcmp(entry->lsp_id, isis->sysid, - ISIS_SYS_ID_LEN)) { - lsp = lsp_new( - circuit->area, entry->lsp_id, - ntohs(entry->rem_lifetime), 0, - 0, entry->checksum, level); - lsp_insert(lsp, - circuit->area - ->lspdb[level - 1]); - ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags); - ISIS_SET_FLAG(lsp->SSNflags, circuit); - } + } + } else { + /* 7.3.15.2 b) 5) if it was not found, and all of those + * are not 0, + * insert it and set SSN on it */ + if (entry->rem_lifetime && entry->checksum + && entry->seqno && memcmp(entry->id, isis->sysid, + ISIS_SYS_ID_LEN)) { + struct isis_lsp *lsp = + lsp_new(circuit->area, entry->id, + entry->rem_lifetime, 0, 0, + entry->checksum, level); + lsp_insert(lsp, + circuit->area->lspdb[level - 1]); + ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags); + ISIS_SET_FLAG(lsp->SSNflags, circuit); } } } /* 7.3.15.2 c) on CSNP set SRM for all in range which were not reported */ - if (snp_type == ISIS_SNP_CSNP_FLAG) { + if (is_csnp) { /* * Build a list from our own LSP db bounded with * start_lsp_id and stop_lsp_id */ - lsp_list = list_new(); - lsp_build_list_nonzero_ht(chdr->start_lsp_id, chdr->stop_lsp_id, - lsp_list, + struct list *lsp_list = list_new(); + lsp_build_list_nonzero_ht(start_lsp_id, stop_lsp_id, lsp_list, circuit->area->lspdb[level - 1]); /* Fixme: Find a better solution */ - if (tlvs.lsp_entries) { - for (ALL_LIST_ELEMENTS(tlvs.lsp_entries, node, nnode, - entry)) { - for (ALL_LIST_ELEMENTS(lsp_list, node2, nnode2, - lsp)) { - if (lsp_id_cmp(lsp->lsp_header->lsp_id, - entry->lsp_id) - == 0) { - list_delete_node(lsp_list, - node2); - break; - } + struct listnode *node, *nnode; + struct isis_lsp *lsp; + for (struct isis_lsp_entry *entry = entry_head; entry; + entry = entry->next) { + for (ALL_LIST_ELEMENTS(lsp_list, node, nnode, lsp)) { + if (lsp_id_cmp(lsp->hdr.lsp_id, entry->id) + == 0) { + list_delete_node(lsp_list, node); + break; } } } + /* on remaining LSPs we set SRM (neighbor knew not of) */ for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) ISIS_SET_FLAG(lsp->SRMflags, circuit); @@ -1833,59 +1279,39 @@ static int process_snp(int snp_type, int level, struct isis_circuit *circuit, list_delete(lsp_list); } - free_tlvs(&tlvs); + retval = ISIS_OK; +out: + isis_free_tlvs(tlvs); return retval; } -static int process_csnp(int level, struct isis_circuit *circuit, - const u_char *ssnpa) -{ - if (isis->debugs & DEBUG_SNP_PACKETS) { - zlog_debug( - "ISIS-Snp (%s): Rcvd L%d CSNP on %s, cirType %s, cirID %u", - circuit->area->area_tag, level, - circuit->interface->name, - circuit_t2string(circuit->is_type), - circuit->circuit_id); - if (isis->debugs & DEBUG_PACKET_DUMP) - zlog_dump_data(STREAM_DATA(circuit->rcv_stream), - stream_get_endp(circuit->rcv_stream)); - } - - /* Sanity check - FIXME: move to correct place */ - if ((stream_get_endp(circuit->rcv_stream) - - stream_get_getp(circuit->rcv_stream)) - < ISIS_CSNP_HDRLEN) { - zlog_warn("Packet too short ( < %d)", ISIS_CSNP_HDRLEN); - return ISIS_WARNING; - } - - return process_snp(ISIS_SNP_CSNP_FLAG, level, circuit, ssnpa); -} - -static int process_psnp(int level, struct isis_circuit *circuit, - const u_char *ssnpa) +static int pdu_size(uint8_t pdu_type, uint8_t *size) { - if (isis->debugs & DEBUG_SNP_PACKETS) { - zlog_debug( - "ISIS-Snp (%s): Rcvd L%d PSNP on %s, cirType %s, cirID %u", - circuit->area->area_tag, level, - circuit->interface->name, - circuit_t2string(circuit->is_type), - circuit->circuit_id); - if (isis->debugs & DEBUG_PACKET_DUMP) - zlog_dump_data(STREAM_DATA(circuit->rcv_stream), - stream_get_endp(circuit->rcv_stream)); - } - - if ((stream_get_endp(circuit->rcv_stream) - - stream_get_getp(circuit->rcv_stream)) - < ISIS_PSNP_HDRLEN) { - zlog_warn("Packet too short ( < %d)", ISIS_PSNP_HDRLEN); - return ISIS_WARNING; + switch (pdu_type) { + case L1_LAN_HELLO: + case L2_LAN_HELLO: + *size = ISIS_LANHELLO_HDRLEN; + break; + case P2P_HELLO: + *size = ISIS_P2PHELLO_HDRLEN; + break; + case L1_LINK_STATE: + case L2_LINK_STATE: + *size = ISIS_LSP_HDR_LEN; + break; + case L1_COMPLETE_SEQ_NUM: + case L2_COMPLETE_SEQ_NUM: + *size = ISIS_CSNP_HDRLEN; + break; + case L1_PARTIAL_SEQ_NUM: + case L2_PARTIAL_SEQ_NUM: + *size = ISIS_PSNP_HDRLEN; + break; + default: + return 1; } - - return process_snp(ISIS_SNP_PSNP_FLAG, level, circuit, ssnpa); + *size += ISIS_FIXED_HDR_LEN; + return 0; } /* @@ -1894,53 +1320,68 @@ static int process_psnp(int level, struct isis_circuit *circuit, static int isis_handle_pdu(struct isis_circuit *circuit, u_char *ssnpa) { - struct isis_fixed_hdr *hdr; - int retval = ISIS_OK; - /* - * Let's first read data from stream to the header - */ - hdr = (struct isis_fixed_hdr *)STREAM_DATA(circuit->rcv_stream); + /* Verify that at least the 8 bytes fixed header have been received */ + if (stream_get_endp(circuit->rcv_stream) < ISIS_FIXED_HDR_LEN) { + zlog_err("PDU is too short to be IS-IS."); + return ISIS_ERROR; + } - if ((hdr->idrp != ISO10589_ISIS) && (hdr->idrp != ISO9542_ESIS)) { - zlog_err("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp); + uint8_t idrp = stream_getc(circuit->rcv_stream); + uint8_t length = stream_getc(circuit->rcv_stream); + uint8_t version1 = stream_getc(circuit->rcv_stream); + uint8_t id_len = stream_getc(circuit->rcv_stream); + uint8_t pdu_type = stream_getc(circuit->rcv_stream) + & 0x1f; /* bits 6-8 are reserved */ + uint8_t version2 = stream_getc(circuit->rcv_stream); + stream_forward_getp(circuit->rcv_stream, 1); /* reserved */ + uint8_t max_area_addrs = stream_getc(circuit->rcv_stream); + + if (idrp == ISO9542_ESIS) { + zlog_err("No support for ES-IS packet IDRP=%" PRIx8, idrp); return ISIS_ERROR; } - /* now we need to know if this is an ISO 9542 packet and - * take real good care of it, waaa! - */ - if (hdr->idrp == ISO9542_ESIS) { - zlog_err("No support for ES-IS packet IDRP=%02x", hdr->idrp); + if (idrp != ISO10589_ISIS) { + zlog_err("Not an IS-IS packet IDRP=%" PRIx8, idrp); return ISIS_ERROR; } - stream_set_getp(circuit->rcv_stream, ISIS_FIXED_HDR_LEN); - /* - * and then process it - */ + if (version1 != 1) { + zlog_warn("Unsupported ISIS version %" PRIu8, version1); + return ISIS_WARNING; + } - if (hdr->length < ISIS_MINIMUM_FIXED_HDR_LEN) { - zlog_err("Fixed header length = %d", hdr->length); + if (id_len != 0 && id_len != ISIS_SYS_ID_LEN) { + zlog_err( + "IDFieldLengthMismatch: ID Length field in a received PDU %" PRIu8 + ", while the parameter for this IS is %u", + id_len, ISIS_SYS_ID_LEN); return ISIS_ERROR; } - if (hdr->version1 != 1) { - zlog_warn("Unsupported ISIS version %u", hdr->version1); + uint8_t expected_length; + if (pdu_size(pdu_type, &expected_length)) { + zlog_warn("Unsupported ISIS PDU %" PRIu8, pdu_type); return ISIS_WARNING; } - /* either 6 or 0 */ - if ((hdr->id_len != 0) && (hdr->id_len != ISIS_SYS_ID_LEN)) { + + if (length != expected_length) { + zlog_err("Exepected fixed header length = %" PRIu8 + " but got %" PRIu8, + expected_length, length); + return ISIS_ERROR; + } + + if (stream_get_endp(circuit->rcv_stream) < length) { zlog_err( - "IDFieldLengthMismatch: ID Length field in a received PDU %u, " - "while the parameter for this IS is %u", - hdr->id_len, ISIS_SYS_ID_LEN); + "PDU is too short to contain fixed header of given PDU type."); return ISIS_ERROR; } - if (hdr->version2 != 1) { - zlog_warn("Unsupported ISIS version %u", hdr->version2); + if (version2 != 1) { + zlog_warn("Unsupported ISIS PDU version %" PRIu8, version2); return ISIS_WARNING; } @@ -1951,42 +1392,29 @@ static int isis_handle_pdu(struct isis_circuit *circuit, u_char *ssnpa) } /* either 3 or 0 */ - if ((hdr->max_area_addrs != 0) - && (hdr->max_area_addrs != isis->max_area_addrs)) { + if (max_area_addrs != 0 && max_area_addrs != isis->max_area_addrs) { zlog_err( - "maximumAreaAddressesMismatch: maximumAreaAdresses in a " - "received PDU %u while the parameter for this IS is %u", - hdr->max_area_addrs, isis->max_area_addrs); + "maximumAreaAddressesMismatch: maximumAreaAdresses in a received PDU %" PRIu8 + " while the parameter for this IS is %u", + max_area_addrs, isis->max_area_addrs); return ISIS_ERROR; } - switch (hdr->pdu_type) { + switch (pdu_type) { case L1_LAN_HELLO: - retval = process_lan_hello(ISIS_LEVEL1, circuit, ssnpa); - break; case L2_LAN_HELLO: - retval = process_lan_hello(ISIS_LEVEL2, circuit, ssnpa); - break; case P2P_HELLO: - retval = process_p2p_hello(circuit); + retval = process_hello(pdu_type, circuit, ssnpa); break; case L1_LINK_STATE: - retval = process_lsp(ISIS_LEVEL1, circuit, ssnpa); - break; case L2_LINK_STATE: - retval = process_lsp(ISIS_LEVEL2, circuit, ssnpa); + retval = process_lsp(pdu_type, circuit, ssnpa); break; case L1_COMPLETE_SEQ_NUM: - retval = process_csnp(ISIS_LEVEL1, circuit, ssnpa); - break; case L2_COMPLETE_SEQ_NUM: - retval = process_csnp(ISIS_LEVEL2, circuit, ssnpa); - break; case L1_PARTIAL_SEQ_NUM: - retval = process_psnp(ISIS_LEVEL1, circuit, ssnpa); - break; case L2_PARTIAL_SEQ_NUM: - retval = process_psnp(ISIS_LEVEL2, circuit, ssnpa); + retval = process_snp(pdu_type, circuit, ssnpa); break; default: return ISIS_ERROR; @@ -2025,73 +1453,67 @@ int isis_receive(struct thread *thread) return retval; } -/* filling of the fixed isis header */ -void fill_fixed_hdr(struct isis_fixed_hdr *hdr, u_char pdu_type) -{ - memset(hdr, 0, sizeof(struct isis_fixed_hdr)); - - hdr->idrp = ISO10589_ISIS; - - switch (pdu_type) { - case L1_LAN_HELLO: - case L2_LAN_HELLO: - hdr->length = ISIS_LANHELLO_HDRLEN; - break; - case P2P_HELLO: - hdr->length = ISIS_P2PHELLO_HDRLEN; - break; - case L1_LINK_STATE: - case L2_LINK_STATE: - hdr->length = ISIS_LSP_HDR_LEN; - break; - case L1_COMPLETE_SEQ_NUM: - case L2_COMPLETE_SEQ_NUM: - hdr->length = ISIS_CSNP_HDRLEN; - break; - case L1_PARTIAL_SEQ_NUM: - case L2_PARTIAL_SEQ_NUM: - hdr->length = ISIS_PSNP_HDRLEN; - break; - default: - zlog_warn("fill_fixed_hdr(): unknown pdu type %d", pdu_type); - return; - } - hdr->length += ISIS_FIXED_HDR_LEN; - hdr->pdu_type = pdu_type; - hdr->version1 = 1; - hdr->id_len = 0; /* ISIS_SYS_ID_LEN - 0==6 */ - hdr->version2 = 1; - hdr->max_area_addrs = 0; /* isis->max_area_addrs - 0==3 */ -} - /* * SEND SIDE */ -static void fill_fixed_hdr_andstream(struct isis_fixed_hdr *hdr, - u_char pdu_type, struct stream *stream) +void fill_fixed_hdr(uint8_t pdu_type, struct stream *stream) { - fill_fixed_hdr(hdr, pdu_type); - - stream_putc(stream, hdr->idrp); - stream_putc(stream, hdr->length); - stream_putc(stream, hdr->version1); - stream_putc(stream, hdr->id_len); - stream_putc(stream, hdr->pdu_type); - stream_putc(stream, hdr->version2); - stream_putc(stream, hdr->reserved); - stream_putc(stream, hdr->max_area_addrs); - - return; + uint8_t length; + + if (pdu_size(pdu_type, &length)) + assert(!"Unknown PDU Type"); + + stream_putc(stream, ISO10589_ISIS); /* IDRP */ + stream_putc(stream, length); /* Length of fixed header */ + stream_putc(stream, 1); /* Version/Protocol ID Extension 1 */ + stream_putc(stream, 0); /* ID Length, 0 => 6 */ + stream_putc(stream, pdu_type); + stream_putc(stream, 1); /* Subversion */ + stream_putc(stream, 0); /* Reserved */ + stream_putc(stream, 0); /* Max Area Addresses 0 => 3 */ +} + +static void put_hello_hdr(struct isis_circuit *circuit, int level, + size_t *len_pointer) +{ + uint8_t pdu_type; + + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + pdu_type = (level == IS_LEVEL_1) ? L1_LAN_HELLO : L2_LAN_HELLO; + else + pdu_type = P2P_HELLO; + + isis_circuit_stream(circuit, &circuit->snd_stream); + fill_fixed_hdr(pdu_type, circuit->snd_stream); + + stream_putc(circuit->snd_stream, circuit->is_type); + stream_put(circuit->snd_stream, circuit->area->isis->sysid, + ISIS_SYS_ID_LEN); + + uint32_t holdtime = circuit->hello_multiplier[level - 1] + * circuit->hello_interval[level - 1]; + + if (holdtime > 0xffff) + holdtime = 0xffff; + + stream_putw(circuit->snd_stream, holdtime); + *len_pointer = stream_get_endp(circuit->snd_stream); + stream_putw(circuit->snd_stream, 0); /* length is filled in later */ + + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + u_char *desig_is = (level == IS_LEVEL_1) + ? circuit->u.bc.l1_desig_is + : circuit->u.bc.l2_desig_is; + stream_putc(circuit->snd_stream, circuit->priority[level - 1]); + stream_put(circuit->snd_stream, desig_is, ISIS_SYS_ID_LEN + 1); + } else { + stream_putc(circuit->snd_stream, circuit->circuit_id); + } } int 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; - unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; - size_t len_pointer, length, auth_tlv_offset = 0; - u_int32_t interval; + size_t len_pointer; int retval; if (circuit->is_passive) @@ -2102,113 +1524,21 @@ int send_hello(struct isis_circuit *circuit, int level) return ISIS_WARNING; } - isis_circuit_stream(circuit, &circuit->snd_stream); - - if (circuit->circ_type == CIRCUIT_T_BROADCAST) - if (level == IS_LEVEL_1) - fill_fixed_hdr_andstream(&fixed_hdr, L1_LAN_HELLO, - circuit->snd_stream); - else - fill_fixed_hdr_andstream(&fixed_hdr, L2_LAN_HELLO, - circuit->snd_stream); - else - fill_fixed_hdr_andstream(&fixed_hdr, P2P_HELLO, - circuit->snd_stream); - - /* - * Fill LAN Level 1 or 2 Hello PDU header - */ - memset(&hello_hdr, 0, sizeof(struct isis_lan_hello_hdr)); - interval = circuit->hello_multiplier[level - 1] - * circuit->hello_interval[level - 1]; - if (interval > USHRT_MAX) - interval = USHRT_MAX; - hello_hdr.circuit_t = circuit->is_type; - memcpy(hello_hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN); - hello_hdr.hold_time = htons((u_int16_t)interval); - - hello_hdr.pdu_len = 0; /* Update the PDU Length later */ - len_pointer = - stream_get_endp(circuit->snd_stream) + 3 + ISIS_SYS_ID_LEN; - - /* copy the shared part of the hello to the p2p hello if needed */ - if (circuit->circ_type == CIRCUIT_T_P2P) { - memcpy(&p2p_hello_hdr, &hello_hdr, 5 + ISIS_SYS_ID_LEN); - p2p_hello_hdr.local_id = circuit->circuit_id; - /* FIXME: need better understanding */ - stream_put(circuit->snd_stream, &p2p_hello_hdr, - ISIS_P2PHELLO_HDRLEN); - } else { - hello_hdr.prio = circuit->priority[level - 1]; - if (level == IS_LEVEL_1) { - memcpy(hello_hdr.lan_id, circuit->u.bc.l1_desig_is, - ISIS_SYS_ID_LEN + 1); - } else if (level == IS_LEVEL_2) { - memcpy(hello_hdr.lan_id, circuit->u.bc.l2_desig_is, - ISIS_SYS_ID_LEN + 1); - } - stream_put(circuit->snd_stream, &hello_hdr, - ISIS_LANHELLO_HDRLEN); - } - - /* - * Then the variable length part. - */ - - /* add circuit password */ - switch (circuit->passwd.type) { - /* Cleartext */ - case ISIS_PASSWD_TYPE_CLEARTXT: - if (tlv_add_authinfo(circuit->passwd.type, circuit->passwd.len, - circuit->passwd.passwd, - circuit->snd_stream)) - return ISIS_WARNING; - break; + put_hello_hdr(circuit, level, &len_pointer); - /* HMAC MD5 */ - case ISIS_PASSWD_TYPE_HMAC_MD5: - /* Remember where TLV is written so we can later overwrite the - * MD5 hash */ - auth_tlv_offset = stream_get_endp(circuit->snd_stream); - memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); - if (tlv_add_authinfo(circuit->passwd.type, ISIS_AUTH_MD5_SIZE, - hmac_md5_hash, circuit->snd_stream)) - return ISIS_WARNING; - break; + struct isis_tlvs *tlvs = isis_alloc_tlvs(); - default: - break; - } + isis_tlvs_add_auth(tlvs, &circuit->passwd); - /* Area Addresses TLV */ - if (listcount(circuit->area->area_addrs) == 0) - return ISIS_WARNING; - if (tlv_add_area_addrs(circuit->area->area_addrs, circuit->snd_stream)) + if (!listcount(circuit->area->area_addrs)) return ISIS_WARNING; + isis_tlvs_add_area_addresses(tlvs, circuit->area->area_addrs); - /* LAN Neighbors TLV */ - if (circuit->circ_type == CIRCUIT_T_BROADCAST) { - if (level == IS_LEVEL_1 && circuit->u.bc.lan_neighs[0] - && listcount(circuit->u.bc.lan_neighs[0]) > 0) - if (tlv_add_lan_neighs(circuit->u.bc.lan_neighs[0], - circuit->snd_stream)) - return ISIS_WARNING; - if (level == IS_LEVEL_2 && circuit->u.bc.lan_neighs[1] - && listcount(circuit->u.bc.lan_neighs[1]) > 0) - if (tlv_add_lan_neighs(circuit->u.bc.lan_neighs[1], - 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; - /* IP interface Address TLV */ - if (circuit->ip_router && circuit->ip_addrs - && listcount(circuit->ip_addrs) > 0) - if (tlv_add_ip_addrs(circuit->ip_addrs, circuit->snd_stream)) - return ISIS_WARNING; + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + isis_tlvs_add_lan_neighbors( + tlvs, circuit->u.bc.lan_neighs[level - 1]); + + isis_tlvs_set_protocols_supported(tlvs, &circuit->nlpids); /* * MT Supported TLV @@ -2221,48 +1551,26 @@ int send_hello(struct isis_circuit *circuit, int level) unsigned int mt_count; mt_settings = circuit_mt_settings(circuit, &mt_count); - if ((mt_count == 0 && area_is_mt(circuit->area)) - || (mt_count == 1 && mt_settings[0]->mtid != ISIS_MT_IPV4_UNICAST) - || (mt_count > 1)) { - struct list *mt_info = list_new(); - mt_info->del = free_tlv; - - for (unsigned int i = 0; i < mt_count; i++) { - struct mt_router_info *info; - - info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info)); - info->mtid = mt_settings[i]->mtid; - /* overload info is not valid in IIH, so it's not - * included here */ - listnode_add(mt_info, info); - } - tlv_add_mt_router_info(mt_info, circuit->snd_stream); - list_free(mt_info); + if (mt_count == 0 && area_is_mt(circuit->area)) { + tlvs->mt_router_info_empty = true; + } else if ((mt_count == 1 + && mt_settings[0]->mtid != ISIS_MT_IPV4_UNICAST) + || (mt_count > 1)) { + for (unsigned int i = 0; i < mt_count; i++) + isis_tlvs_add_mt_router_info(tlvs, mt_settings[i]->mtid, + false, false); } - /* IPv6 Interface Address TLV */ - if (circuit->ipv6_router && circuit->ipv6_link - && listcount(circuit->ipv6_link) > 0) - if (tlv_add_ipv6_addrs(circuit->ipv6_link, circuit->snd_stream)) - return ISIS_WARNING; + if (circuit->ip_router && circuit->ip_addrs) + isis_tlvs_add_ipv4_addresses(tlvs, circuit->ip_addrs); - if (circuit->pad_hellos) - if (tlv_add_padding(circuit->snd_stream)) - return ISIS_WARNING; - - length = stream_get_endp(circuit->snd_stream); - /* Update PDU length */ - stream_putw_at(circuit->snd_stream, len_pointer, (u_int16_t)length); + if (circuit->ipv6_router && circuit->ipv6_link) + isis_tlvs_add_ipv6_addresses(tlvs, circuit->ipv6_link); - /* For HMAC MD5 we need to compute the md5 hash and store it */ - if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) { - hmac_md5(STREAM_DATA(circuit->snd_stream), - 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(STREAM_DATA(circuit->snd_stream) + auth_tlv_offset + 3, - hmac_md5_hash, ISIS_AUTH_MD5_SIZE); + if (isis_pack_tlvs(tlvs, circuit->snd_stream, len_pointer, + circuit->pad_hellos, false)) { + isis_free_tlvs(tlvs); + return ISIS_WARNING; /* XXX: Maybe Log TLV structure? */ } if (isis->debugs & DEBUG_ADJ_PACKETS) { @@ -2270,18 +1578,22 @@ int send_hello(struct isis_circuit *circuit, int level) zlog_debug( "ISIS-Adj (%s): Sending L%d LAN IIH on %s, length %zd", circuit->area->area_tag, level, - circuit->interface->name, length); + circuit->interface->name, + stream_get_endp(circuit->snd_stream)); } else { zlog_debug( "ISIS-Adj (%s): Sending P2P IIH on %s, length %zd", circuit->area->area_tag, - circuit->interface->name, length); + circuit->interface->name, + stream_get_endp(circuit->snd_stream)); } if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data(STREAM_DATA(circuit->snd_stream), stream_get_endp(circuit->snd_stream)); } + isis_free_tlvs(tlvs); + retval = circuit->tx(circuit, level); if (retval != ISIS_OK) zlog_err("ISIS-Adj (%s): Send L%d IIH on %s failed", @@ -2366,101 +1678,10 @@ int send_p2p_hello(struct thread *thread) return ISIS_OK; } -static int build_csnp(int level, u_char *start, u_char *stop, struct list *lsps, - struct isis_circuit *circuit) -{ - struct isis_fixed_hdr fixed_hdr; - struct isis_passwd *passwd; - unsigned long lenp; - u_int16_t length; - unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; - unsigned long auth_tlv_offset = 0; - int retval = ISIS_OK; - - isis_circuit_stream(circuit, &circuit->snd_stream); - - if (level == IS_LEVEL_1) - fill_fixed_hdr_andstream(&fixed_hdr, L1_COMPLETE_SEQ_NUM, - circuit->snd_stream); - else - fill_fixed_hdr_andstream(&fixed_hdr, L2_COMPLETE_SEQ_NUM, - circuit->snd_stream); - - /* - * Fill Level 1 or 2 Complete Sequence Numbers header - */ - - lenp = stream_get_endp(circuit->snd_stream); - stream_putw(circuit->snd_stream, 0); /* PDU length - when we know it */ - /* no need to send the source here, it is always us if we csnp */ - stream_put(circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN); - /* with zero circuit id - ref 9.10, 9.11 */ - stream_putc(circuit->snd_stream, 0x00); - - stream_put(circuit->snd_stream, start, ISIS_SYS_ID_LEN + 2); - stream_put(circuit->snd_stream, stop, ISIS_SYS_ID_LEN + 2); - - /* - * And TLVs - */ - if (level == IS_LEVEL_1) - passwd = &circuit->area->area_passwd; - else - passwd = &circuit->area->domain_passwd; - - if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) { - switch (passwd->type) { - /* Cleartext */ - case ISIS_PASSWD_TYPE_CLEARTXT: - if (tlv_add_authinfo(ISIS_PASSWD_TYPE_CLEARTXT, - passwd->len, passwd->passwd, - circuit->snd_stream)) - return ISIS_WARNING; - break; - - /* HMAC MD5 */ - case ISIS_PASSWD_TYPE_HMAC_MD5: - /* Remember where TLV is written so we can later - * overwrite the MD5 hash */ - auth_tlv_offset = 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; - break; - - default: - break; - } - } - - retval = tlv_add_lsp_entries(lsps, circuit->snd_stream); - if (retval != ISIS_OK) - return retval; - - length = (u_int16_t)stream_get_endp(circuit->snd_stream); - /* Update PU length */ - stream_putw_at(circuit->snd_stream, lenp, length); - - /* For HMAC MD5 we need to compute the md5 hash and store it */ - if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) - && passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5) { - hmac_md5(STREAM_DATA(circuit->snd_stream), - stream_get_endp(circuit->snd_stream), - (unsigned char *)&passwd->passwd, passwd->len, - (unsigned char *)&hmac_md5_hash); - /* Copy the hash into the stream */ - memcpy(STREAM_DATA(circuit->snd_stream) + auth_tlv_offset + 3, - hmac_md5_hash, ISIS_AUTH_MD5_SIZE); - } - - return retval; -} - /* * Count the maximum number of lsps that can be accomodated by a given size. */ +#define LSP_ENTRIES_LEN (10 + ISIS_SYS_ID_LEN) static uint16_t get_max_lsp_count(uint16_t size) { uint16_t tlv_count; @@ -2479,109 +1700,81 @@ static uint16_t get_max_lsp_count(uint16_t size) return lsp_count; } -/* - * Calculate the length of Authentication Info. TLV. - */ -static uint16_t auth_tlv_length(int level, struct isis_circuit *circuit) +int send_csnp(struct isis_circuit *circuit, int level) { - struct isis_passwd *passwd; - uint16_t length; + if (circuit->area->lspdb[level - 1] == NULL + || dict_count(circuit->area->lspdb[level - 1]) == 0) + return ISIS_OK; - if (level == IS_LEVEL_1) - passwd = &circuit->area->area_passwd; - else - passwd = &circuit->area->domain_passwd; - - /* Also include the length of TLV header */ - length = AUTH_INFO_HDRLEN; - if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) { - switch (passwd->type) { - /* Cleartext */ - case ISIS_PASSWD_TYPE_CLEARTXT: - length += passwd->len; - break; - - /* HMAC MD5 */ - case ISIS_PASSWD_TYPE_HMAC_MD5: - length += ISIS_AUTH_MD5_SIZE; - break; - - default: - break; - } - } + isis_circuit_stream(circuit, &circuit->snd_stream); + fill_fixed_hdr((level == ISIS_LEVEL1) ? L1_COMPLETE_SEQ_NUM + : L2_COMPLETE_SEQ_NUM, + circuit->snd_stream); - return length; -} + size_t len_pointer = stream_get_endp(circuit->snd_stream); + stream_putw(circuit->snd_stream, 0); + stream_put(circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN); + /* with zero circuit id - ref 9.10, 9.11 */ + stream_putc(circuit->snd_stream, 0); -/* - * Calculate the maximum number of lsps that can be accomodated in a CSNP/PSNP. - */ -static uint16_t max_lsps_per_snp(int snp_type, int level, - struct isis_circuit *circuit) -{ - int snp_hdr_len; - int auth_tlv_len; - uint16_t lsp_count; + size_t start_pointer = stream_get_endp(circuit->snd_stream); + stream_put(circuit->snd_stream, 0, ISIS_SYS_ID_LEN + 2); + size_t end_pointer = stream_get_endp(circuit->snd_stream); + stream_put(circuit->snd_stream, 0, ISIS_SYS_ID_LEN + 2); - snp_hdr_len = ISIS_FIXED_HDR_LEN; - if (snp_type == ISIS_SNP_CSNP_FLAG) - snp_hdr_len += ISIS_CSNP_HDRLEN; - else - snp_hdr_len += ISIS_PSNP_HDRLEN; + struct isis_passwd *passwd = (level == ISIS_LEVEL1) + ? &circuit->area->area_passwd + : &circuit->area->domain_passwd; - auth_tlv_len = auth_tlv_length(level, circuit); - lsp_count = get_max_lsp_count(stream_get_size(circuit->snd_stream) - - snp_hdr_len - auth_tlv_len); - return lsp_count; -} + struct isis_tlvs *tlvs = isis_alloc_tlvs(); -/* - * FIXME: support multiple CSNPs - */ + if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) + isis_tlvs_add_auth(tlvs, passwd); -int send_csnp(struct isis_circuit *circuit, int level) -{ - u_char start[ISIS_SYS_ID_LEN + 2]; - u_char stop[ISIS_SYS_ID_LEN + 2]; - struct list *list = NULL; - struct listnode *node; - struct isis_lsp *lsp; - u_char num_lsps, loop = 1; - int i, retval = ISIS_OK; + size_t tlv_start = stream_get_endp(circuit->snd_stream); + if (isis_pack_tlvs(tlvs, circuit->snd_stream, len_pointer, false, + false)) { + isis_free_tlvs(tlvs); + return ISIS_WARNING; + } + isis_free_tlvs(tlvs); - if (circuit->area->lspdb[level - 1] == NULL - || dict_count(circuit->area->lspdb[level - 1]) == 0) - return retval; + uint16_t num_lsps = + get_max_lsp_count(STREAM_WRITEABLE(circuit->snd_stream)); + uint8_t start[ISIS_SYS_ID_LEN + 2]; memset(start, 0x00, ISIS_SYS_ID_LEN + 2); + uint8_t stop[ISIS_SYS_ID_LEN + 2]; memset(stop, 0xff, ISIS_SYS_ID_LEN + 2); - num_lsps = max_lsps_per_snp(ISIS_SNP_CSNP_FLAG, level, circuit); - + bool loop = true; while (loop) { - list = list_new(); - lsp_build_list(start, stop, num_lsps, list, - circuit->area->lspdb[level - 1]); + tlvs = isis_alloc_tlvs(); + if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) + isis_tlvs_add_auth(tlvs, passwd); + + struct isis_lsp *last_lsp; + isis_tlvs_add_csnp_entries(tlvs, start, stop, num_lsps, + circuit->area->lspdb[level - 1], + &last_lsp); /* * Update the stop lsp_id before encoding this CSNP. */ - if (listcount(list) < num_lsps) { + if (tlvs->lsp_entries.count < num_lsps) { memset(stop, 0xff, ISIS_SYS_ID_LEN + 2); } else { - node = listtail(list); - lsp = listgetdata(node); - memcpy(stop, lsp->lsp_header->lsp_id, - ISIS_SYS_ID_LEN + 2); + memcpy(stop, last_lsp->hdr.lsp_id, sizeof(stop)); } - retval = build_csnp(level, start, stop, list, circuit); - if (retval != ISIS_OK) { - zlog_err("ISIS-Snp (%s): Build L%d CSNP on %s failed", - circuit->area->area_tag, level, - circuit->interface->name); - list_delete(list); - return retval; + memcpy(STREAM_DATA(circuit->snd_stream) + start_pointer, start, + ISIS_SYS_ID_LEN + 2); + memcpy(STREAM_DATA(circuit->snd_stream) + end_pointer, stop, + ISIS_SYS_ID_LEN + 2); + stream_set_endp(circuit->snd_stream, tlv_start); + if (isis_pack_tlvs(tlvs, circuit->snd_stream, len_pointer, + false, false)) { + isis_free_tlvs(tlvs); + return ISIS_WARNING; } if (isis->debugs & DEBUG_SNP_PACKETS) { @@ -2590,28 +1783,20 @@ int send_csnp(struct isis_circuit *circuit, int level) circuit->area->area_tag, level, circuit->interface->name, stream_get_endp(circuit->snd_stream)); - for (ALL_LIST_ELEMENTS_RO(list, node, lsp)) { - zlog_debug( - "ISIS-Snp (%s): CSNP entry %s, seq 0x%08x," - " cksum 0x%04x, lifetime %us", - circuit->area->area_tag, - rawlspid_print(lsp->lsp_header->lsp_id), - ntohl(lsp->lsp_header->seq_num), - ntohs(lsp->lsp_header->checksum), - ntohs(lsp->lsp_header->rem_lifetime)); - } + log_multiline(LOG_DEBUG, " ", "%s", + isis_format_tlvs(tlvs)); if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data( STREAM_DATA(circuit->snd_stream), stream_get_endp(circuit->snd_stream)); } - retval = circuit->tx(circuit, level); + int retval = circuit->tx(circuit, level); if (retval != ISIS_OK) { zlog_err("ISIS-Snp (%s): Send L%d CSNP on %s failed", circuit->area->area_tag, level, circuit->interface->name); - list_delete(list); + isis_free_tlvs(tlvs); return retval; } @@ -2621,7 +1806,7 @@ int send_csnp(struct isis_circuit *circuit, int level) */ memcpy(start, stop, ISIS_SYS_ID_LEN + 2); loop = 0; - for (i = ISIS_SYS_ID_LEN + 1; i >= 0; --i) { + for (int i = ISIS_SYS_ID_LEN + 1; i >= 0; --i) { if (start[i] < (u_char)0xff) { start[i] += 1; loop = 1; @@ -2629,10 +1814,10 @@ int send_csnp(struct isis_circuit *circuit, int level) } } memset(stop, 0xff, ISIS_SYS_ID_LEN + 2); - list_delete(list); + isis_free_tlvs(tlvs); } - return retval; + return ISIS_OK; } int send_l1_csnp(struct thread *thread) @@ -2679,120 +1864,12 @@ int send_l2_csnp(struct thread *thread) return retval; } -static int build_psnp(int level, struct isis_circuit *circuit, - struct list *lsps) -{ - struct isis_fixed_hdr fixed_hdr; - unsigned long lenp; - u_int16_t length; - struct isis_lsp *lsp; - struct isis_passwd *passwd; - struct listnode *node; - unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; - unsigned long auth_tlv_offset = 0; - int retval = ISIS_OK; - - isis_circuit_stream(circuit, &circuit->snd_stream); - - if (level == IS_LEVEL_1) - fill_fixed_hdr_andstream(&fixed_hdr, L1_PARTIAL_SEQ_NUM, - circuit->snd_stream); - else - fill_fixed_hdr_andstream(&fixed_hdr, L2_PARTIAL_SEQ_NUM, - circuit->snd_stream); - - /* - * Fill Level 1 or 2 Partial Sequence Numbers header - */ - lenp = stream_get_endp(circuit->snd_stream); - stream_putw(circuit->snd_stream, 0); /* PDU length - when we know it */ - stream_put(circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN); - stream_putc(circuit->snd_stream, circuit->idx); - - /* - * And TLVs - */ - - if (level == IS_LEVEL_1) - passwd = &circuit->area->area_passwd; - else - passwd = &circuit->area->domain_passwd; - - if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) { - switch (passwd->type) { - /* Cleartext */ - case ISIS_PASSWD_TYPE_CLEARTXT: - if (tlv_add_authinfo(ISIS_PASSWD_TYPE_CLEARTXT, - passwd->len, passwd->passwd, - circuit->snd_stream)) - return ISIS_WARNING; - break; - - /* HMAC MD5 */ - case ISIS_PASSWD_TYPE_HMAC_MD5: - /* Remember where TLV is written so we can later - * overwrite the MD5 hash */ - auth_tlv_offset = 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; - break; - - default: - break; - } - } - - retval = tlv_add_lsp_entries(lsps, circuit->snd_stream); - if (retval != ISIS_OK) - return retval; - - if (isis->debugs & DEBUG_SNP_PACKETS) { - for (ALL_LIST_ELEMENTS_RO(lsps, node, lsp)) { - zlog_debug( - "ISIS-Snp (%s): PSNP entry %s, seq 0x%08x," - " cksum 0x%04x, lifetime %us", - circuit->area->area_tag, - rawlspid_print(lsp->lsp_header->lsp_id), - ntohl(lsp->lsp_header->seq_num), - ntohs(lsp->lsp_header->checksum), - ntohs(lsp->lsp_header->rem_lifetime)); - } - } - - length = (u_int16_t)stream_get_endp(circuit->snd_stream); - /* Update PDU length */ - stream_putw_at(circuit->snd_stream, lenp, length); - - /* For HMAC MD5 we need to compute the md5 hash and store it */ - if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) - && passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5) { - hmac_md5(STREAM_DATA(circuit->snd_stream), - stream_get_endp(circuit->snd_stream), - (unsigned char *)&passwd->passwd, passwd->len, - (unsigned char *)&hmac_md5_hash); - /* Copy the hash into the stream */ - memcpy(STREAM_DATA(circuit->snd_stream) + auth_tlv_offset + 3, - hmac_md5_hash, ISIS_AUTH_MD5_SIZE); - } - - return ISIS_OK; -} - /* * 7.3.15.4 action on expiration of partial SNP interval * level 1 */ static int send_psnp(int level, struct isis_circuit *circuit) { - struct isis_lsp *lsp; - struct list *list = NULL; - struct listnode *node; - u_char num_lsps; - int retval = ISIS_OK; - if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[level - 1]) return ISIS_OK; @@ -2804,25 +1881,64 @@ static int send_psnp(int level, struct isis_circuit *circuit) if (!circuit->snd_stream) return ISIS_ERROR; - num_lsps = max_lsps_per_snp(ISIS_SNP_PSNP_FLAG, level, circuit); + isis_circuit_stream(circuit, &circuit->snd_stream); + fill_fixed_hdr((level == ISIS_LEVEL1) ? L1_PARTIAL_SEQ_NUM + : L2_PARTIAL_SEQ_NUM, + circuit->snd_stream); + + size_t len_pointer = stream_get_endp(circuit->snd_stream); + stream_putw(circuit->snd_stream, 0); /* length is filled in later */ + stream_put(circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN); + stream_putc(circuit->snd_stream, circuit->idx); + + struct isis_passwd *passwd = (level == ISIS_LEVEL1) + ? &circuit->area->area_passwd + : &circuit->area->domain_passwd; + + struct isis_tlvs *tlvs = isis_alloc_tlvs(); + + if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) + isis_tlvs_add_auth(tlvs, passwd); + + size_t tlv_start = stream_get_endp(circuit->snd_stream); + if (isis_pack_tlvs(tlvs, circuit->snd_stream, len_pointer, false, + false)) { + isis_free_tlvs(tlvs); + return ISIS_WARNING; + } + isis_free_tlvs(tlvs); + + uint16_t num_lsps = + get_max_lsp_count(STREAM_WRITEABLE(circuit->snd_stream)); while (1) { - list = list_new(); - lsp_build_list_ssn(circuit, num_lsps, list, - circuit->area->lspdb[level - 1]); + tlvs = isis_alloc_tlvs(); + if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) + isis_tlvs_add_auth(tlvs, passwd); + + for (dnode_t *dnode = + dict_first(circuit->area->lspdb[level - 1]); + dnode; dnode = dict_next(circuit->area->lspdb[level - 1], + dnode)) { + struct isis_lsp *lsp = dnode_get(dnode); - if (listcount(list) == 0) { - list_delete(list); + if (ISIS_CHECK_FLAG(lsp->SSNflags, circuit)) + isis_tlvs_add_lsp_entry(tlvs, lsp); + + if (tlvs->lsp_entries.count == num_lsps) + break; + } + + if (!tlvs->lsp_entries.count) { + isis_free_tlvs(tlvs); return ISIS_OK; } - retval = build_psnp(level, circuit, list); - if (retval != ISIS_OK) { - zlog_err("ISIS-Snp (%s): Build L%d PSNP on %s failed", - circuit->area->area_tag, level, - circuit->interface->name); - list_delete(list); - return retval; + stream_set_endp(circuit->snd_stream, tlv_start); + if (isis_pack_tlvs(tlvs, circuit->snd_stream, len_pointer, + false, false)) { + isis_free_tlvs(tlvs); + return ISIS_WARNING; } if (isis->debugs & DEBUG_SNP_PACKETS) { @@ -2831,18 +1947,20 @@ static int send_psnp(int level, struct isis_circuit *circuit) circuit->area->area_tag, level, circuit->interface->name, stream_get_endp(circuit->snd_stream)); + log_multiline(LOG_DEBUG, " ", "%s", + isis_format_tlvs(tlvs)); if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data( STREAM_DATA(circuit->snd_stream), stream_get_endp(circuit->snd_stream)); } - retval = circuit->tx(circuit, level); + int retval = circuit->tx(circuit, level); if (retval != ISIS_OK) { zlog_err("ISIS-Snp (%s): Send L%d PSNP on %s failed", circuit->area->area_tag, level, circuit->interface->name); - list_delete(list); + isis_free_tlvs(tlvs); return retval; } @@ -2850,12 +1968,15 @@ static int send_psnp(int level, struct isis_circuit *circuit) * sending succeeded, we can clear SSN flags of this circuit * for the LSPs in list */ - for (ALL_LIST_ELEMENTS_RO(list, node, lsp)) - ISIS_CLEAR_FLAG(lsp->SSNflags, circuit); - list_delete(list); + struct isis_lsp_entry *entry_head; + entry_head = (struct isis_lsp_entry *)tlvs->lsp_entries.head; + for (struct isis_lsp_entry *entry = entry_head; entry; + entry = entry->next) + ISIS_CLEAR_FLAG(entry->lsp->SSNflags, circuit); + isis_free_tlvs(tlvs); } - return retval; + return ISIS_OK; } int send_l1_psnp(struct thread *thread) @@ -2963,14 +2084,12 @@ int send_lsp(struct thread *thread) * the circuit's MTU. So handle and log this case here. */ if (stream_get_endp(lsp->pdu) > stream_get_size(circuit->snd_stream)) { zlog_err( - "ISIS-Upd (%s): Can't send L%d LSP %s, seq 0x%08x," - " cksum 0x%04x, lifetime %us on %s. LSP Size is %zu" - " while interface stream size is %zu.", + "ISIS-Upd (%s): Can't send L%d LSP %s, seq 0x%08" PRIx32 + ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 + "s on %s. LSP Size is %zu while interface stream size is %zu.", 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), + rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.seqno, + lsp->hdr.checksum, lsp->hdr.rem_lifetime, circuit->interface->name, stream_get_endp(lsp->pdu), stream_get_size(circuit->snd_stream)); if (isis->debugs & DEBUG_PACKET_DUMP) @@ -2984,15 +2103,13 @@ int send_lsp(struct thread *thread) stream_copy(circuit->snd_stream, lsp->pdu); if (isis->debugs & DEBUG_UPDATE_PACKETS) { - zlog_debug( - "ISIS-Upd (%s): Sending 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); + zlog_debug("ISIS-Upd (%s): Sending L%d LSP %s, seq 0x%08" PRIx32 + ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 + "s on %s", + circuit->area->area_tag, lsp->level, + rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.seqno, + lsp->hdr.checksum, lsp->hdr.rem_lifetime, + circuit->interface->name); if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data(STREAM_DATA(circuit->snd_stream), stream_get_endp(circuit->snd_stream)); @@ -3026,47 +2143,3 @@ out: return retval; } - -int ack_lsp(struct isis_link_state_hdr *hdr, struct isis_circuit *circuit, - int level) -{ - unsigned long lenp; - int retval; - u_int16_t length; - struct isis_fixed_hdr fixed_hdr; - - isis_circuit_stream(circuit, &circuit->snd_stream); - - // fill_llc_hdr (stream); - if (level == IS_LEVEL_1) - fill_fixed_hdr_andstream(&fixed_hdr, L1_PARTIAL_SEQ_NUM, - circuit->snd_stream); - else - fill_fixed_hdr_andstream(&fixed_hdr, L2_PARTIAL_SEQ_NUM, - circuit->snd_stream); - - - lenp = stream_get_endp(circuit->snd_stream); - stream_putw(circuit->snd_stream, 0); /* PDU length */ - stream_put(circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN); - stream_putc(circuit->snd_stream, circuit->idx); - stream_putc(circuit->snd_stream, 9); /* code */ - stream_putc(circuit->snd_stream, 16); /* len */ - - stream_putw(circuit->snd_stream, ntohs(hdr->rem_lifetime)); - stream_put(circuit->snd_stream, hdr->lsp_id, ISIS_SYS_ID_LEN + 2); - stream_putl(circuit->snd_stream, ntohl(hdr->seq_num)); - stream_putw(circuit->snd_stream, ntohs(hdr->checksum)); - - length = (u_int16_t)stream_get_endp(circuit->snd_stream); - /* Update PDU length */ - stream_putw_at(circuit->snd_stream, lenp, length); - - retval = circuit->tx(circuit, level); - if (retval != ISIS_OK) - zlog_err("ISIS-Upd (%s): Send L%d LSP PSNP on %s failed", - circuit->area->area_tag, level, - circuit->interface->name); - - return retval; -} diff --git a/isisd/isis_pdu.h b/isisd/isis_pdu.h index fa8006cda0..7096761879 100644 --- a/isisd/isis_pdu.h +++ b/isisd/isis_pdu.h @@ -65,36 +65,6 @@ struct esis_fixed_hdr { #define ISH_PDU 4 #define RD_PDU 5 -/* - * IS to IS Fixed Header - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | Intradomain Routeing Protocol Discriminator | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | Length Indicator | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | Version/Protocol ID extension | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | R | R | R | PDU Type | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | Version | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | Reserved | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | Maximum Area Addresses | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - */ - -struct isis_fixed_hdr { - u_char idrp; - u_char length; - u_char version1; - u_char id_len; - u_char pdu_type; - u_char version2; - u_char reserved; - u_char max_area_addrs; -} __attribute__((packed)); - #define ISIS_FIXED_HDR_LEN 8 /* @@ -155,30 +125,14 @@ struct isis_p2p_hello_hdr { #define L1_LINK_STATE 18 #define L2_LINK_STATE 20 -/* - * L1 and L2 IS to IS link state PDU header - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * + PDU Length + 2 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * + Remaining Lifetime + 2 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | LSP ID | id_len + 2 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * + Sequence Number + 4 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * + Checksum + 2 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | P | ATT |LSPDBOL| ISTYPE | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - */ -struct isis_link_state_hdr { - u_int16_t pdu_len; - u_int16_t rem_lifetime; - u_char lsp_id[ISIS_SYS_ID_LEN + 2]; - u_int32_t seq_num; - u_int16_t checksum; - u_int8_t lsp_bits; -} __attribute__((packed)); +struct isis_lsp_hdr { + uint16_t pdu_len; + uint16_t rem_lifetime; + uint8_t lsp_id[ISIS_SYS_ID_LEN + 2]; + uint32_t seqno; + uint16_t checksum; + uint8_t lsp_bits; +}; #define ISIS_LSP_HDR_LEN 19 /* @@ -259,9 +213,7 @@ int send_l2_csnp(struct thread *thread); int send_l1_psnp(struct thread *thread); int send_l2_psnp(struct thread *thread); int send_lsp(struct thread *thread); -int ack_lsp(struct isis_link_state_hdr *hdr, struct isis_circuit *circuit, - int level); -void fill_fixed_hdr(struct isis_fixed_hdr *hdr, u_char pdu_type); +void fill_fixed_hdr(uint8_t pdu_type, struct stream *stream); int send_hello(struct isis_circuit *circuit, int level); #endif /* _ZEBRA_ISIS_PDU_H */ diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c index 8e329494dd..ea94b65805 100644 --- a/isisd/isis_redist.c +++ b/isisd/isis_redist.c @@ -37,7 +37,6 @@ #include "isisd/isis_flags.h" #include "isisd/isis_misc.h" #include "isisd/isis_circuit.h" -#include "isisd/isis_tlv.h" #include "isisd/isisd.h" #include "isisd/isis_lsp.h" #include "isisd/isis_route.h" diff --git a/isisd/isis_route.c b/isisd/isis_route.c index afc4f65128..267e72002f 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -42,7 +42,6 @@ #include "isis_misc.h" #include "isis_adjacency.h" #include "isis_circuit.h" -#include "isis_tlv.h" #include "isis_pdu.h" #include "isis_lsp.h" #include "isis_spf.h" @@ -208,13 +207,12 @@ static void nexthops6_print(struct list *nhs6) static void adjinfo2nexthop(struct list *nexthops, struct isis_adjacency *adj) { struct isis_nexthop *nh; - struct listnode *node; - struct in_addr *ipv4_addr; - if (adj->ipv4_addrs == NULL) + if (!adj->ipv4_address_count) return; - for (ALL_LIST_ELEMENTS_RO(adj->ipv4_addrs, node, ipv4_addr)) { + for (unsigned int i = 0; i < adj->ipv4_address_count; i++) { + struct in_addr *ipv4_addr = &adj->ipv4_addresses[i]; if (!nexthoplookup(nexthops, ipv4_addr, adj->circuit->interface->ifindex)) { nh = isis_nexthop_create( @@ -227,14 +225,13 @@ static void adjinfo2nexthop(struct list *nexthops, struct isis_adjacency *adj) static void adjinfo2nexthop6(struct list *nexthops6, struct isis_adjacency *adj) { - struct listnode *node; - struct in6_addr *ipv6_addr; struct isis_nexthop6 *nh6; - if (!adj->ipv6_addrs) + if (!adj->ipv6_address_count) return; - for (ALL_LIST_ELEMENTS_RO(adj->ipv6_addrs, node, ipv6_addr)) { + for (unsigned int i = 0; i < adj->ipv6_address_count; i++) { + struct in6_addr *ipv6_addr = &adj->ipv6_addresses[i]; if (!nexthop6lookup(nexthops6, ipv6_addr, adj->circuit->interface->ifindex)) { nh6 = isis_nexthop6_create( diff --git a/isisd/isis_routemap.c b/isisd/isis_routemap.c index 44d7fa0403..d92207d57c 100644 --- a/isisd/isis_routemap.c +++ b/isisd/isis_routemap.c @@ -42,7 +42,6 @@ #include "isis_misc.h" #include "isis_adjacency.h" #include "isis_circuit.h" -#include "isis_tlv.h" #include "isis_pdu.h" #include "isis_lsp.h" #include "isis_spf.h" diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 615c2eeaa2..9acbc21838 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -35,6 +35,7 @@ #include "if.h" #include "table.h" #include "spf_backoff.h" +#include "jhash.h" #include "isis_constants.h" #include "isis_common.h" @@ -44,7 +45,6 @@ #include "isis_misc.h" #include "isis_adjacency.h" #include "isis_circuit.h" -#include "isis_tlv.h" #include "isis_pdu.h" #include "isis_lsp.h" #include "isis_dynhn.h" @@ -52,9 +52,178 @@ #include "isis_route.h" #include "isis_csm.h" #include "isis_mt.h" +#include "isis_tlvs.h" DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info"); +enum vertextype { + VTYPE_PSEUDO_IS = 1, + VTYPE_PSEUDO_TE_IS, + VTYPE_NONPSEUDO_IS, + VTYPE_NONPSEUDO_TE_IS, + VTYPE_ES, + VTYPE_IPREACH_INTERNAL, + VTYPE_IPREACH_EXTERNAL, + VTYPE_IPREACH_TE, + VTYPE_IP6REACH_INTERNAL, + VTYPE_IP6REACH_EXTERNAL +}; + +#define VTYPE_IS(t) ((t) >= VTYPE_PSEUDO_IS && (t) <= VTYPE_NONPSEUDO_TE_IS) +#define VTYPE_ES(t) ((t) == VTYPE_ES) +#define VTYPE_IP(t) ((t) >= VTYPE_IPREACH_INTERNAL && (t) <= VTYPE_IP6REACH_EXTERNAL) + +/* + * Triple <N, d(N), {Adj(N)}> + */ +struct isis_vertex { + enum vertextype type; + + union { + u_char id[ISIS_SYS_ID_LEN + 1]; + struct prefix prefix; + } N; + + u_int32_t d_N; /* d(N) Distance from this IS */ + u_int16_t depth; /* The depth in the imaginary tree */ + struct list *Adj_N; /* {Adj(N)} next hop or neighbor list */ + struct list *parents; /* list of parents for ECMP */ + struct list *children; /* list of children used for tree dump */ +}; + +/* Vertex Queue and associated functions */ + +struct isis_vertex_queue { + struct list *list; + struct hash *hash; +}; + +static unsigned isis_vertex_queue_hash_key(void *vp) +{ + struct isis_vertex *vertex = vp; + + if (VTYPE_IP(vertex->type)) + return prefix_hash_key(&vertex->N.prefix); + + return jhash(vertex->N.id, ISIS_SYS_ID_LEN + 1, 0x55aa5a5a); +} + +static int isis_vertex_queue_hash_cmp(const void *a, const void *b) +{ + const struct isis_vertex *va = a, *vb = b; + + if (va->type != vb->type) + return 0; + + if (VTYPE_IP(va->type)) + return prefix_cmp(&va->N.prefix, &vb->N.prefix) == 0; + + return memcmp(va->N.id, vb->N.id, ISIS_SYS_ID_LEN + 1) == 0; +} + +static void isis_vertex_queue_init(struct isis_vertex_queue *queue, const char *name) +{ + queue->list = list_new(); + queue->hash = hash_create(isis_vertex_queue_hash_key, + isis_vertex_queue_hash_cmp, + name); +} + +static void isis_vertex_del(struct isis_vertex *vertex); + +static void isis_vertex_queue_clear(struct isis_vertex_queue *queue) +{ + hash_clean(queue->hash, NULL); + + queue->list->del = (void (*)(void *))isis_vertex_del; + list_delete_all_node(queue->list); + queue->list->del = NULL; +} + +static void isis_vertex_queue_free(struct isis_vertex_queue *queue) +{ + isis_vertex_queue_clear(queue); + + hash_free(queue->hash); + queue->hash = NULL; + + list_delete(queue->list); + queue->list = NULL; +} + +static unsigned int isis_vertex_queue_count(struct isis_vertex_queue *queue) +{ + return listcount(queue->list); +} + +static void isis_vertex_queue_add(struct isis_vertex_queue *queue, + struct isis_vertex *vertex) +{ + listnode_add(queue->list, vertex); + + struct isis_vertex *inserted; + + inserted = hash_get(queue->hash, vertex, hash_alloc_intern); + assert(inserted == vertex); +} + +static struct isis_vertex *isis_vertex_queue_pop(struct isis_vertex_queue *queue) +{ + struct listnode *node; + + node = listhead(queue->list); + if (!node) + return NULL; + + struct isis_vertex *rv = listgetdata(node); + + list_delete_node(queue->list, node); + hash_release(queue->hash, rv); + + return rv; +} + +static void isis_vertex_queue_delete(struct isis_vertex_queue *queue, + struct isis_vertex *vertex) +{ + listnode_delete(queue->list, vertex); + hash_release(queue->hash, vertex); +} + +#define ALL_QUEUE_ELEMENTS_RO(queue, node, data) \ + ALL_LIST_ELEMENTS_RO((queue)->list, node, data) + + +/* End of vertex queue definitions */ + +struct isis_spftree { + struct isis_vertex_queue paths; /* the SPT */ + struct isis_vertex_queue tents; /* TENT */ + struct isis_area *area; /* back pointer to area */ + unsigned int runcount; /* number of runs since uptime */ + time_t last_run_timestamp; /* last run timestamp for scheduling */ + time_t last_run_duration; /* last run duration in msec */ + + uint16_t mtid; + int family; + int level; +}; + + +/* + * supports the given af ? + */ +static bool speaks(uint8_t *protocols, uint8_t count, int family) +{ + for (uint8_t i = 0; i < count; i++) { + if (family == AF_INET && protocols[i] == NLPID_IP) + return true; + if (family == AF_INET6 && protocols[i] == NLPID_IPV6) + return true; + } + return false; +} + struct isis_spf_run { struct isis_area *area; int level; @@ -160,12 +329,8 @@ static const char *vid2string(struct isis_vertex *vertex, char *buff, int size) return "UNKNOWN"; } -static struct isis_vertex *isis_vertex_new(void *id, enum vertextype vtype) +static void isis_vertex_id_init(struct isis_vertex *vertex, void *id, enum vertextype vtype) { - struct isis_vertex *vertex; - - vertex = XCALLOC(MTYPE_ISIS_VERTEX, sizeof(struct isis_vertex)); - vertex->type = vtype; if (VTYPE_IS(vtype) || VTYPE_ES(vtype)) { @@ -176,6 +341,15 @@ static struct isis_vertex *isis_vertex_new(void *id, enum vertextype vtype) } else { zlog_err("WTF!"); } +} + +static struct isis_vertex *isis_vertex_new(void *id, enum vertextype vtype) +{ + struct isis_vertex *vertex; + + vertex = XCALLOC(MTYPE_ISIS_VERTEX, sizeof(struct isis_vertex)); + + isis_vertex_id_init(vertex, id, vtype); vertex->Adj_N = list_new(); vertex->parents = list_new(); @@ -223,8 +397,8 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area) return NULL; } - tree->tents = list_new(); - tree->paths = list_new(); + isis_vertex_queue_init(&tree->tents, "IS-IS SPF tents"); + isis_vertex_queue_init(&tree->paths, "IS-IS SPF paths"); tree->area = area; tree->last_run_timestamp = 0; tree->last_run_duration = 0; @@ -234,15 +408,8 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area) void isis_spftree_del(struct isis_spftree *spftree) { - - spftree->tents->del = (void (*)(void *))isis_vertex_del; - list_delete(spftree->tents); - spftree->tents = NULL; - - spftree->paths->del = (void (*)(void *))isis_vertex_del; - list_delete(spftree->paths); - spftree->paths = NULL; - + isis_vertex_queue_free(&spftree->tents); + isis_vertex_queue_free(&spftree->paths); XFREE(MTYPE_ISIS_SPFTREE, spftree); return; @@ -252,12 +419,13 @@ static void isis_spftree_adj_del(struct isis_spftree *spftree, struct isis_adjacency *adj) { struct listnode *node; + struct isis_vertex *v; if (!adj) return; - for (node = listhead(spftree->tents); node; node = listnextnode(node)) - isis_vertex_adj_del(listgetdata(node), adj); - for (node = listhead(spftree->paths); node; node = listnextnode(node)) - isis_vertex_adj_del(listgetdata(node), adj); + for (ALL_QUEUE_ELEMENTS_RO(&spftree->tents, node, v)) + isis_vertex_adj_del(v, adj); + for (ALL_QUEUE_ELEMENTS_RO(&spftree->paths, node, v)) + isis_vertex_adj_del(v, adj); return; } @@ -340,7 +508,7 @@ static struct isis_lsp *isis_root_system_lsp(struct isis_area *area, int level, LSP_PSEUDO_ID(lspid) = 0; LSP_FRAGMENT(lspid) = 0; lsp = lsp_search(lspid, area->lspdb[level - 1]); - if (lsp && lsp->lsp_header->rem_lifetime != 0) + if (lsp && lsp->hdr.rem_lifetime != 0) return lsp; return NULL; } @@ -370,7 +538,7 @@ static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree, spftree->area->oldmetric ? VTYPE_NONPSEUDO_IS : VTYPE_NONPSEUDO_TE_IS); - listnode_add(spftree->paths, vertex); + isis_vertex_queue_add(&spftree->paths, vertex); #ifdef EXTREME_DEBUG zlog_debug("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS", @@ -382,35 +550,13 @@ static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree, return vertex; } -static struct isis_vertex *isis_find_vertex(struct list *list, void *id, +static struct isis_vertex *isis_find_vertex(struct isis_vertex_queue *queue, void *id, enum vertextype vtype) { - struct listnode *node; - struct isis_vertex *vertex; - struct prefix *p1, *p2; + struct isis_vertex querier; - for (ALL_LIST_ELEMENTS_RO(list, node, vertex)) { - if (vertex->type != vtype) - continue; - if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type)) { - if (memcmp((u_char *)id, vertex->N.id, - ISIS_SYS_ID_LEN + 1) - == 0) - return vertex; - } - if (VTYPE_IP(vertex->type)) { - p1 = (struct prefix *)id; - p2 = (struct prefix *)&vertex->N.id; - if (p1->family == p2->family - && p1->prefixlen == p2->prefixlen - && !memcmp(&p1->u.prefix, &p2->u.prefix, - PSIZE(p1->prefixlen))) { - return vertex; - } - } - } - - return NULL; + isis_vertex_id_init(&querier, id, vtype); + return hash_lookup(queue->hash, &querier); } /* @@ -428,6 +574,30 @@ static bool tent_cmp(struct isis_vertex *current, struct isis_vertex *candidate) return false; } +static void isis_vertex_queue_insert(struct isis_vertex_queue *queue, + struct isis_vertex *vertex) +{ + struct listnode *node; + struct isis_vertex *v; + + /* XXX: This cant use the standard ALL_LIST_ELEMENTS macro */ + for (node = listhead(queue->list); node; node = listnextnode(node)) { + v = listgetdata(node); + if (tent_cmp(v, vertex)) { + listnode_add_before(queue->list, node, vertex); + break; + } + } + + if (node == NULL) + listnode_add(queue->list, vertex); + + struct isis_vertex *inserted; + + inserted = hash_get(queue->hash, vertex, hash_alloc_intern); + assert(inserted == vertex); +} + /* * Add a vertex to TENT sorted by cost and by vertextype on tie break situation */ @@ -437,15 +607,15 @@ static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree, struct isis_adjacency *adj, struct isis_vertex *parent) { - struct isis_vertex *vertex, *v; + struct isis_vertex *vertex; struct listnode *node; struct isis_adjacency *parent_adj; #ifdef EXTREME_DEBUG char buff[PREFIX2STR_BUFFER]; #endif - assert(isis_find_vertex(spftree->paths, id, vtype) == NULL); - assert(isis_find_vertex(spftree->tents, id, vtype) == NULL); + assert(isis_find_vertex(&spftree->paths, id, vtype) == NULL); + assert(isis_find_vertex(&spftree->tents, id, vtype) == NULL); vertex = isis_vertex_new(id, vtype); vertex->d_N = cost; vertex->depth = depth; @@ -471,23 +641,7 @@ static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree, vertex->d_N, listcount(vertex->Adj_N)); #endif /* EXTREME_DEBUG */ - if (list_isempty(spftree->tents)) { - listnode_add(spftree->tents, vertex); - return vertex; - } - - /* XXX: This cant use the standard ALL_LIST_ELEMENTS macro */ - for (node = listhead(spftree->tents); node; node = listnextnode(node)) { - v = listgetdata(node); - if (tent_cmp(v, vertex)) { - listnode_add_before(spftree->tents, node, vertex); - break; - } - } - - if (node == NULL) - listnode_add(spftree->tents, vertex); - + isis_vertex_queue_insert(&spftree->tents, vertex); return vertex; } @@ -498,7 +652,7 @@ static void isis_spf_add_local(struct isis_spftree *spftree, { struct isis_vertex *vertex; - vertex = isis_find_vertex(spftree->tents, id, vtype); + vertex = isis_find_vertex(&spftree->tents, id, vtype); if (vertex) { /* C.2.5 c) */ @@ -522,7 +676,7 @@ static void isis_spf_add_local(struct isis_spftree *spftree, /* f) */ struct listnode *pnode, *pnextnode; struct isis_vertex *pvertex; - listnode_delete(spftree->tents, vertex); + isis_vertex_queue_delete(&spftree->tents, vertex); assert(listcount(vertex->children) == 0); for (ALL_LIST_ELEMENTS(vertex->parents, pnode, pnextnode, pvertex)) @@ -546,6 +700,13 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype, assert(spftree && parent); + struct prefix p; + if (vtype >= VTYPE_IPREACH_INTERNAL) { + prefix_copy(&p, id); + apply_mask(&p); + id = &p; + } + /* RFC3787 section 5.1 */ if (spftree->area->newmetric == 1) { if (dist > MAX_WIDE_PATH_METRIC) @@ -558,7 +719,7 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype, } /* c) */ - vertex = isis_find_vertex(spftree->paths, id, vtype); + vertex = isis_find_vertex(&spftree->paths, id, vtype); if (vertex) { #ifdef EXTREME_DEBUG zlog_debug( @@ -570,7 +731,7 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype, return; } - vertex = isis_find_vertex(spftree->tents, id, vtype); + vertex = isis_find_vertex(&spftree->tents, id, vtype); /* d) */ if (vertex) { /* 1) */ @@ -605,7 +766,7 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype, } else { struct listnode *pnode, *pnextnode; struct isis_vertex *pvertex; - listnode_delete(spftree->tents, vertex); + isis_vertex_queue_delete(&spftree->tents, vertex); assert(listcount(vertex->children) == 0); for (ALL_LIST_ELEMENTS(vertex->parents, pnode, pnextnode, pvertex)) @@ -632,30 +793,35 @@ static int isis_spf_process_lsp(struct isis_spftree *spftree, uint16_t depth, u_char *root_sysid, struct isis_vertex *parent) { - bool pseudo_lsp = LSP_PSEUDO_ID(lsp->lsp_header->lsp_id); - struct listnode *node, *fragnode = NULL; + bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id); + struct listnode *fragnode = NULL; uint32_t dist; - struct is_neigh *is_neigh; - struct te_is_neigh *te_is_neigh; - struct ipv4_reachability *ipreach; - struct te_ipv4_reachability *te_ipv4_reach; enum vertextype vtype; - struct prefix prefix; - struct ipv6_reachability *ip6reach; static const u_char null_sysid[ISIS_SYS_ID_LEN]; - struct mt_router_info *mt_router_info = NULL; + struct isis_mt_router_info *mt_router_info = NULL; + + if (!lsp->tlvs) + return ISIS_OK; if (spftree->mtid != ISIS_MT_IPV4_UNICAST) - mt_router_info = tlvs_lookup_mt_router_info(&lsp->tlv_data, - spftree->mtid); + mt_router_info = isis_tlvs_lookup_mt_router_info(lsp->tlvs, + spftree->mtid); if (!pseudo_lsp && (spftree->mtid == ISIS_MT_IPV4_UNICAST - && !speaks(lsp->tlv_data.nlpids, spftree->family)) + && !speaks(lsp->tlvs->protocols_supported.protocols, + lsp->tlvs->protocols_supported.count, + spftree->family)) && !mt_router_info) return ISIS_OK; + /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */ + bool no_overload = (pseudo_lsp + || (spftree->mtid == ISIS_MT_IPV4_UNICAST + && !ISIS_MASK_LSP_OL_BIT(lsp->hdr.lsp_bits)) + || (mt_router_info && !mt_router_info->overload)); + lspfragloop: - if (lsp->lsp_header->seq_num == 0) { + if (lsp->hdr.seqno == 0) { zlog_warn( "isis_spf_process_lsp(): lsp with 0 seq_num - ignore"); return ISIS_WARNING; @@ -663,142 +829,117 @@ lspfragloop: #ifdef EXTREME_DEBUG zlog_debug("ISIS-Spf: process_lsp %s", - print_sys_hostname(lsp->lsp_header->lsp_id)); + print_sys_hostname(lsp->hdr.lsp_id)); #endif /* EXTREME_DEBUG */ - /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */ - if (pseudo_lsp || (spftree->mtid == ISIS_MT_IPV4_UNICAST - && !ISIS_MASK_LSP_OL_BIT(lsp->lsp_header->lsp_bits)) - || (mt_router_info && !mt_router_info->overload)) - - { + if (no_overload) { if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST) { - for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.is_neighs, node, - is_neigh)) { + struct isis_oldstyle_reach *r; + for (r = (struct isis_oldstyle_reach *) + lsp->tlvs->oldstyle_reach.head; + r; r = r->next) { /* C.2.6 a) */ /* Two way connectivity */ - if (!memcmp(is_neigh->neigh_id, root_sysid, - ISIS_SYS_ID_LEN)) + if (!memcmp(r->id, root_sysid, ISIS_SYS_ID_LEN)) continue; if (!pseudo_lsp - && !memcmp(is_neigh->neigh_id, null_sysid, + && !memcmp(r->id, null_sysid, ISIS_SYS_ID_LEN)) continue; - dist = cost + is_neigh->metrics.metric_default; + dist = cost + r->metric; process_N(spftree, - LSP_PSEUDO_ID(is_neigh->neigh_id) + LSP_PSEUDO_ID(r->id) ? VTYPE_PSEUDO_IS : VTYPE_NONPSEUDO_IS, - (void *)is_neigh->neigh_id, dist, - depth + 1, parent); + (void *)r->id, dist, depth + 1, + parent); } } - struct list *te_is_neighs = NULL; - if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST) { - te_is_neighs = lsp->tlv_data.te_is_neighs; - } else { - struct tlv_mt_neighbors *mt_neighbors; - mt_neighbors = tlvs_lookup_mt_neighbors(&lsp->tlv_data, - spftree->mtid); - if (mt_neighbors) - te_is_neighs = mt_neighbors->list; - } - for (ALL_LIST_ELEMENTS_RO(te_is_neighs, node, te_is_neigh)) { - if (!memcmp(te_is_neigh->neigh_id, root_sysid, - ISIS_SYS_ID_LEN)) + struct isis_item_list *te_neighs = NULL; + if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST) + te_neighs = &lsp->tlvs->extended_reach; + else + te_neighs = isis_lookup_mt_items(&lsp->tlvs->mt_reach, + spftree->mtid); + + struct isis_extended_reach *er; + for (er = te_neighs + ? (struct isis_extended_reach *) + te_neighs->head + : NULL; + er; er = er->next) { + if (!memcmp(er->id, root_sysid, ISIS_SYS_ID_LEN)) continue; if (!pseudo_lsp - && !memcmp(te_is_neigh->neigh_id, null_sysid, - ISIS_SYS_ID_LEN)) + && !memcmp(er->id, null_sysid, ISIS_SYS_ID_LEN)) continue; - dist = cost + GET_TE_METRIC(te_is_neigh); + dist = cost + er->metric; process_N(spftree, - LSP_PSEUDO_ID(te_is_neigh->neigh_id) - ? VTYPE_PSEUDO_TE_IS - : VTYPE_NONPSEUDO_TE_IS, - (void *)te_is_neigh->neigh_id, dist, - depth + 1, parent); + LSP_PSEUDO_ID(er->id) ? VTYPE_PSEUDO_TE_IS + : VTYPE_NONPSEUDO_TE_IS, + (void *)er->id, dist, depth + 1, parent); } } if (!pseudo_lsp && spftree->family == AF_INET && spftree->mtid == ISIS_MT_IPV4_UNICAST) { - struct list *reachs[] = {lsp->tlv_data.ipv4_int_reachs, - lsp->tlv_data.ipv4_ext_reachs}; + struct isis_item_list *reachs[] = { + &lsp->tlvs->oldstyle_ip_reach, + &lsp->tlvs->oldstyle_ip_reach_ext}; - prefix.family = AF_INET; for (unsigned int i = 0; i < array_size(reachs); i++) { - vtype = (reachs[i] == lsp->tlv_data.ipv4_int_reachs) - ? VTYPE_IPREACH_INTERNAL - : VTYPE_IPREACH_EXTERNAL; - for (ALL_LIST_ELEMENTS_RO(reachs[i], node, ipreach)) { - dist = cost + ipreach->metrics.metric_default; - prefix.u.prefix4 = ipreach->prefix; - prefix.prefixlen = ip_masklen(ipreach->mask); - apply_mask(&prefix); - process_N(spftree, vtype, (void *)&prefix, dist, - depth + 1, parent); + vtype = i ? VTYPE_IPREACH_EXTERNAL + : VTYPE_IPREACH_INTERNAL; + + struct isis_oldstyle_ip_reach *r; + for (r = (struct isis_oldstyle_ip_reach *)reachs[i] + ->head; + r; r = r->next) { + dist = cost + r->metric; + process_N(spftree, vtype, (void *)&r->prefix, + dist, depth + 1, parent); } } } if (!pseudo_lsp && spftree->family == AF_INET) { - struct list *ipv4reachs = NULL; - - if (spftree->mtid == ISIS_MT_IPV4_UNICAST) { - ipv4reachs = lsp->tlv_data.te_ipv4_reachs; - } else { - struct tlv_mt_ipv4_reachs *mt_reachs; - mt_reachs = tlvs_lookup_mt_ipv4_reachs(&lsp->tlv_data, - spftree->mtid); - if (mt_reachs) - ipv4reachs = mt_reachs->list; - } - - prefix.family = AF_INET; - for (ALL_LIST_ELEMENTS_RO(ipv4reachs, node, te_ipv4_reach)) { - assert((te_ipv4_reach->control & 0x3F) - <= IPV4_MAX_BITLEN); - - dist = cost + ntohl(te_ipv4_reach->te_metric); - prefix.u.prefix4 = - newprefix2inaddr(&te_ipv4_reach->prefix_start, - te_ipv4_reach->control); - prefix.prefixlen = (te_ipv4_reach->control & 0x3F); - apply_mask(&prefix); - process_N(spftree, VTYPE_IPREACH_TE, (void *)&prefix, + struct isis_item_list *ipv4_reachs; + if (spftree->mtid == ISIS_MT_IPV4_UNICAST) + ipv4_reachs = &lsp->tlvs->extended_ip_reach; + else + ipv4_reachs = isis_lookup_mt_items( + &lsp->tlvs->mt_ip_reach, spftree->mtid); + + struct isis_extended_ip_reach *r; + for (r = ipv4_reachs + ? (struct isis_extended_ip_reach *) + ipv4_reachs->head + : NULL; + r; r = r->next) { + dist = cost + r->metric; + process_N(spftree, VTYPE_IPREACH_TE, (void *)&r->prefix, dist, depth + 1, parent); } } if (!pseudo_lsp && spftree->family == AF_INET6) { - struct list *ipv6reachs = NULL; - - if (spftree->mtid == ISIS_MT_IPV4_UNICAST) { - ipv6reachs = lsp->tlv_data.ipv6_reachs; - } else { - struct tlv_mt_ipv6_reachs *mt_reachs; - mt_reachs = tlvs_lookup_mt_ipv6_reachs(&lsp->tlv_data, - spftree->mtid); - if (mt_reachs) - ipv6reachs = mt_reachs->list; - } - - prefix.family = AF_INET6; - for (ALL_LIST_ELEMENTS_RO(ipv6reachs, node, ip6reach)) { - assert(ip6reach->prefix_len <= IPV6_MAX_BITLEN); - - dist = cost + ntohl(ip6reach->metric); - vtype = (ip6reach->control_info - & CTRL_INFO_DISTRIBUTION) - ? VTYPE_IP6REACH_EXTERNAL - : VTYPE_IP6REACH_INTERNAL; - prefix.prefixlen = ip6reach->prefix_len; - memcpy(&prefix.u.prefix6.s6_addr, ip6reach->prefix, - PSIZE(ip6reach->prefix_len)); - apply_mask(&prefix); - process_N(spftree, vtype, (void *)&prefix, dist, + struct isis_item_list *ipv6_reachs; + if (spftree->mtid == ISIS_MT_IPV4_UNICAST) + ipv6_reachs = &lsp->tlvs->ipv6_reach; + else + ipv6_reachs = isis_lookup_mt_items( + &lsp->tlvs->mt_ipv6_reach, spftree->mtid); + + struct isis_ipv6_reach *r; + for (r = ipv6_reachs + ? (struct isis_ipv6_reach *)ipv6_reachs->head + : NULL; + r; r = r->next) { + dist = cost + r->metric; + vtype = r->external ? VTYPE_IP6REACH_EXTERNAL + : VTYPE_IP6REACH_INTERNAL; + process_N(spftree, vtype, (void *)&r->prefix, dist, depth + 1, parent); } } @@ -893,7 +1034,9 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree, if (!adj_has_mt(adj, spftree->mtid)) continue; if (spftree->mtid == ISIS_MT_IPV4_UNICAST - && !speaks(&adj->nlpids, spftree->family)) + && !speaks(adj->nlpids.nlpids, + adj->nlpids.count, + spftree->family)) continue; switch (adj->sys_type) { case ISIS_SYSTYPE_ES: @@ -928,8 +1071,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree, ->lspdb[spftree->level - 1]); if (lsp == NULL - || lsp->lsp_header->rem_lifetime - == 0) + || lsp->hdr.rem_lifetime == 0) zlog_warn( "ISIS-Spf: No LSP %s found for IS adjacency " "L%d on %s (ID %u)", @@ -979,7 +1121,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree, lsp = lsp_search( lsp_id, spftree->area->lspdb[spftree->level - 1]); - if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0) { + if (lsp == NULL || lsp->hdr.rem_lifetime == 0) { zlog_warn( "ISIS-Spf: No lsp (%p) found from root " "to L%d DR %s on %s (ID %d)", @@ -1015,7 +1157,9 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree, LSP_PSEUDO_ID(lsp_id) = 0; LSP_FRAGMENT(lsp_id) = 0; if (spftree->mtid != ISIS_MT_IPV4_UNICAST - || speaks(&adj->nlpids, spftree->family)) + || speaks(adj->nlpids.nlpids, + adj->nlpids.count, + spftree->family)) isis_spf_add_local( spftree, spftree->area->oldmetric @@ -1052,9 +1196,9 @@ static void add_to_paths(struct isis_spftree *spftree, { char buff[PREFIX2STR_BUFFER]; - if (isis_find_vertex(spftree->paths, vertex->N.id, vertex->type)) + if (isis_find_vertex(&spftree->paths, vertex->N.id, vertex->type)) return; - listnode_add(spftree->paths, vertex); + isis_vertex_queue_add(&spftree->paths, vertex); #ifdef EXTREME_DEBUG zlog_debug("ISIS-Spf: added %s %s %s depth %d dist %d to PATHS", @@ -1083,11 +1227,8 @@ static void add_to_paths(struct isis_spftree *spftree, static void init_spt(struct isis_spftree *spftree, int mtid, int level, int family) { - spftree->tents->del = spftree->paths->del = - (void (*)(void *))isis_vertex_del; - list_delete_all_node(spftree->tents); - list_delete_all_node(spftree->paths); - spftree->tents->del = spftree->paths->del = NULL; + isis_vertex_queue_clear(&spftree->tents); + isis_vertex_queue_clear(&spftree->paths); spftree->mtid = mtid; spftree->level = level; @@ -1099,7 +1240,6 @@ static int isis_run_spf(struct isis_area *area, int level, int family, u_char *sysid) { int retval = ISIS_OK; - struct listnode *node; struct isis_vertex *vertex; struct isis_vertex *root_vertex; struct isis_spftree *spftree = NULL; @@ -1154,15 +1294,14 @@ static int isis_run_spf(struct isis_area *area, int level, int family, /* * C.2.7 Step 2 */ - if (listcount(spftree->tents) == 0) { + if (isis_vertex_queue_count(&spftree->tents) == 0) { zlog_warn("ISIS-Spf: TENT is empty SPF-root:%s", print_sys_hostname(sysid)); goto out; } - while (listcount(spftree->tents) > 0) { - node = listhead(spftree->tents); - vertex = listgetdata(node); + while (isis_vertex_queue_count(&spftree->tents)) { + vertex = isis_vertex_queue_pop(&spftree->tents); #ifdef EXTREME_DEBUG zlog_debug( @@ -1171,14 +1310,12 @@ static int isis_run_spf(struct isis_area *area, int level, int family, vtype2string(vertex->type), vertex->depth, vertex->d_N); #endif /* EXTREME_DEBUG */ - /* Remove from tent list and add to paths list */ - list_delete_node(spftree->tents, node); add_to_paths(spftree, vertex); if (VTYPE_IS(vertex->type)) { 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]); - if (lsp && lsp->lsp_header->rem_lifetime != 0) { + if (lsp && lsp->hdr.rem_lifetime != 0) { isis_spf_process_lsp(spftree, lsp, vertex->d_N, vertex->depth, sysid, vertex); @@ -1299,7 +1436,7 @@ int isis_spf_schedule(struct isis_area *area, int level) return ISIS_OK; } -static void isis_print_paths(struct vty *vty, struct list *paths, +static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, u_char *root_sysid) { struct listnode *node; @@ -1311,7 +1448,7 @@ static void isis_print_paths(struct vty *vty, struct list *paths, vty_out(vty, "Vertex Type Metric Next-Hop Interface Parent\n"); - for (ALL_LIST_ELEMENTS_RO(paths, node, vertex)) { + for (ALL_QUEUE_ELEMENTS_RO(queue, node, vertex)) { if (memcmp(vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) { vty_out(vty, "%-20s %-12s %-6s", print_sys_hostname(root_sysid), "", ""); @@ -1395,22 +1532,22 @@ DEFUN (show_isis_topology, continue; if (area->ip_circuits > 0 && area->spftree[level - 1] - && area->spftree[level - 1]->paths->count > 0) { + && isis_vertex_queue_count(&area->spftree[level - 1]->paths) > 0) { vty_out(vty, "IS-IS paths to level-%d routers that speak IP\n", level); isis_print_paths( - vty, area->spftree[level - 1]->paths, + vty, &area->spftree[level - 1]->paths, isis->sysid); vty_out(vty, "\n"); } if (area->ipv6_circuits > 0 && area->spftree6[level - 1] - && area->spftree6[level - 1]->paths->count > 0) { + && isis_vertex_queue_count(&area->spftree6[level - 1]->paths) > 0) { vty_out(vty, "IS-IS paths to level-%d routers that speak IPv6\n", level); isis_print_paths( - vty, area->spftree6[level - 1]->paths, + vty, &area->spftree6[level - 1]->paths, isis->sysid); vty_out(vty, "\n"); } @@ -1426,3 +1563,16 @@ void isis_spf_cmds_init() { install_element(VIEW_NODE, &show_isis_topology_cmd); } + +void isis_spf_print(struct isis_spftree *spftree, struct vty *vty) +{ + vty_out(vty, " last run elapsed : "); + vty_out_timestr(vty, spftree->last_run_timestamp); + vty_out(vty, "\n"); + + vty_out(vty, " last run duration : %u usec\n", + (u_int32_t)spftree->last_run_duration); + + vty_out(vty, " run count : %u\n", + spftree->runcount); +} diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index c7a505489f..84e07861d2 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -24,53 +24,7 @@ #ifndef _ZEBRA_ISIS_SPF_H #define _ZEBRA_ISIS_SPF_H -enum vertextype { - VTYPE_PSEUDO_IS = 1, - VTYPE_PSEUDO_TE_IS, - VTYPE_NONPSEUDO_IS, - VTYPE_NONPSEUDO_TE_IS, - VTYPE_ES, - VTYPE_IPREACH_INTERNAL, - VTYPE_IPREACH_EXTERNAL, - VTYPE_IPREACH_TE, - VTYPE_IP6REACH_INTERNAL, - VTYPE_IP6REACH_EXTERNAL -}; - -#define VTYPE_IS(t) ((t) >= VTYPE_PSEUDO_IS && (t) <= VTYPE_NONPSEUDO_TE_IS) -#define VTYPE_ES(t) ((t) == VTYPE_ES) -#define VTYPE_IP(t) ((t) >= VTYPE_IPREACH_INTERNAL && (t) <= VTYPE_IP6REACH_EXTERNAL) - -/* - * Triple <N, d(N), {Adj(N)}> - */ -struct isis_vertex { - enum vertextype type; - - union { - u_char id[ISIS_SYS_ID_LEN + 1]; - struct prefix prefix; - } N; - - u_int32_t d_N; /* d(N) Distance from this IS */ - u_int16_t depth; /* The depth in the imaginary tree */ - struct list *Adj_N; /* {Adj(N)} next hop or neighbor list */ - struct list *parents; /* list of parents for ECMP */ - struct list *children; /* list of children used for tree dump */ -}; - -struct isis_spftree { - struct list *paths; /* the SPT */ - struct list *tents; /* TENT */ - struct isis_area *area; /* back pointer to area */ - unsigned int runcount; /* number of runs since uptime */ - time_t last_run_timestamp; /* last run timestamp for scheduling */ - time_t last_run_duration; /* last run duration in msec */ - - uint16_t mtid; - int family; - int level; -}; +struct isis_spftree; struct isis_spftree *isis_spftree_new(struct isis_area *area); void isis_spftree_del(struct isis_spftree *spftree); @@ -79,4 +33,5 @@ void spftree_area_del(struct isis_area *area); void spftree_area_adj_del(struct isis_area *area, struct isis_adjacency *adj); int isis_spf_schedule(struct isis_area *area, int level); void isis_spf_cmds_init(void); +void isis_spf_print(struct isis_spftree *spftree, struct vty *vty); #endif /* _ZEBRA_ISIS_SPF_H */ diff --git a/isisd/isis_te.c b/isisd/isis_te.c index 5296d99480..70afef1a86 100644 --- a/isisd/isis_te.c +++ b/isisd/isis_te.c @@ -41,6 +41,7 @@ #include "md5.h" #include "sockunion.h" #include "network.h" +#include "sbuf.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" @@ -48,7 +49,6 @@ #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isisd.h" -#include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_pdu.h" #include "isisd/isis_dynhn.h" @@ -100,9 +100,9 @@ struct mpls_te_circuit *mpls_te_circuit_new() /* Copy SUB TLVs parameters into a buffer - No space verification are performed */ /* Caller must verify before that there is enough free space in the buffer */ -u_char add_te_subtlvs(u_char *buf, struct mpls_te_circuit *mtc) +uint8_t add_te_subtlvs(uint8_t *buf, struct mpls_te_circuit *mtc) { - u_char size, *tlvs = buf; + uint8_t size, *tlvs = buf; zlog_debug("ISIS MPLS-TE: Add TE Sub TLVs to buffer"); @@ -232,7 +232,7 @@ u_char add_te_subtlvs(u_char *buf, struct mpls_te_circuit *mtc) } /* Compute total Sub-TLVs size */ -u_char subtlvs_len(struct mpls_te_circuit *mtc) +uint8_t subtlvs_len(struct mpls_te_circuit *mtc) { int length = 0; @@ -306,7 +306,7 @@ u_char subtlvs_len(struct mpls_te_circuit *mtc) return 0; } - mtc->length = (u_char)length; + mtc->length = (uint8_t)length; return mtc->length; } @@ -546,13 +546,9 @@ void isis_link_params_update(struct isis_circuit *circuit, if ((SUBTLV_TYPE(mtc->rmt_ipaddr) == 0) && (circuit->circ_type == CIRCUIT_T_P2P)) { struct isis_adjacency *adj = circuit->u.p2p.neighbor; - if (adj->ipv4_addrs != NULL - && listcount(adj->ipv4_addrs) != 0) { - struct in_addr *ip_addr; - ip_addr = (struct in_addr *)listgetdata( - (struct listnode *)listhead( - adj->ipv4_addrs)); - set_circuitparams_rmt_ipaddr(mtc, *ip_addr); + if (adj->ipv4_address_count) { + set_circuitparams_rmt_ipaddr( + mtc, adj->ipv4_addresses[0]); } } @@ -670,163 +666,116 @@ void isis_mpls_te_update(struct interface *ifp) * Followings are vty session control functions. *------------------------------------------------------------------------*/ -static u_char show_vty_subtlv_admin_grp(struct vty *vty, - struct te_subtlv_admin_grp *tlv) +static u_char print_subtlv_admin_grp(struct sbuf *buf, int indent, + struct te_subtlv_admin_grp *tlv) { - - if (vty != NULL) - vty_out(vty, " Administrative Group: 0x%x\n", - (u_int32_t)ntohl(tlv->value)); - else - zlog_debug(" Administrative Group: 0x%x", - (u_int32_t)ntohl(tlv->value)); - + sbuf_push(buf, indent, "Administrative Group: 0x%" PRIx32 "\n", + ntohl(tlv->value)); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } -static u_char show_vty_subtlv_llri(struct vty *vty, struct te_subtlv_llri *tlv) +static u_char print_subtlv_llri(struct sbuf *buf, int indent, + struct te_subtlv_llri *tlv) { - if (vty != NULL) { - vty_out(vty, " Link Local ID: %d\n", - (u_int32_t)ntohl(tlv->local)); - vty_out(vty, " Link Remote ID: %d\n", - (u_int32_t)ntohl(tlv->remote)); - } else { - zlog_debug(" Link Local ID: %d", - (u_int32_t)ntohl(tlv->local)); - zlog_debug(" Link Remote ID: %d", - (u_int32_t)ntohl(tlv->remote)); - } + sbuf_push(buf, indent, "Link Local ID: %" PRIu32 "\n", + ntohl(tlv->local)); + sbuf_push(buf, indent, "Link Remote ID: %" PRIu32 "\n", + ntohl(tlv->remote)); return (SUBTLV_HDR_SIZE + TE_SUBTLV_LLRI_SIZE); } -static u_char show_vty_subtlv_local_ipaddr(struct vty *vty, - struct te_subtlv_local_ipaddr *tlv) +static u_char print_subtlv_local_ipaddr(struct sbuf *buf, int indent, + struct te_subtlv_local_ipaddr *tlv) { - if (vty != NULL) - vty_out(vty, " Local Interface IP Address(es): %s\n", - inet_ntoa(tlv->value)); - else - zlog_debug(" Local Interface IP Address(es): %s", - inet_ntoa(tlv->value)); + sbuf_push(buf, indent, "Local Interface IP Address(es): %s\n", + inet_ntoa(tlv->value)); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } -static u_char show_vty_subtlv_rmt_ipaddr(struct vty *vty, - struct te_subtlv_rmt_ipaddr *tlv) +static u_char print_subtlv_rmt_ipaddr(struct sbuf *buf, int indent, + struct te_subtlv_rmt_ipaddr *tlv) { - if (vty != NULL) - vty_out(vty, " Remote Interface IP Address(es): %s\n", - inet_ntoa(tlv->value)); - else - zlog_debug(" Remote Interface IP Address(es): %s", - inet_ntoa(tlv->value)); + sbuf_push(buf, indent, "Remote Interface IP Address(es): %s\n", + inet_ntoa(tlv->value)); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } -static u_char show_vty_subtlv_max_bw(struct vty *vty, - struct te_subtlv_max_bw *tlv) +static u_char print_subtlv_max_bw(struct sbuf *buf, int indent, + struct te_subtlv_max_bw *tlv) { float fval; fval = ntohf(tlv->value); - if (vty != NULL) - vty_out(vty, " Maximum Bandwidth: %g (Bytes/sec)\n", fval); - else - zlog_debug(" Maximum Bandwidth: %g (Bytes/sec)", fval); + sbuf_push(buf, indent, "Maximum Bandwidth: %g (Bytes/sec)\n", fval); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } -static u_char show_vty_subtlv_max_rsv_bw(struct vty *vty, - struct te_subtlv_max_rsv_bw *tlv) +static u_char print_subtlv_max_rsv_bw(struct sbuf *buf, int indent, + struct te_subtlv_max_rsv_bw *tlv) { float fval; fval = ntohf(tlv->value); - if (vty != NULL) - vty_out(vty, - " Maximum Reservable Bandwidth: %g (Bytes/sec)\n", - fval); - else - zlog_debug(" Maximum Reservable Bandwidth: %g (Bytes/sec)", - fval); + sbuf_push(buf, indent, "Maximum Reservable Bandwidth: %g (Bytes/sec)\n", fval); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } -static u_char show_vty_subtlv_unrsv_bw(struct vty *vty, - struct te_subtlv_unrsv_bw *tlv) +static u_char print_subtlv_unrsv_bw(struct sbuf *buf, int indent, + struct te_subtlv_unrsv_bw *tlv) { float fval1, fval2; int i; - if (vty != NULL) - vty_out(vty, " Unreserved Bandwidth:\n"); - else - zlog_debug(" Unreserved Bandwidth:"); + sbuf_push(buf, indent, "Unreserved Bandwidth:\n"); for (i = 0; i < MAX_CLASS_TYPE; i += 2) { fval1 = ntohf(tlv->value[i]); fval2 = ntohf(tlv->value[i + 1]); - if (vty != NULL) - vty_out(vty, - " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n", - i, fval1, i + 1, fval2); - else - zlog_debug( - " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)", - i, fval1, i + 1, fval2); + sbuf_push(buf, indent + 2, "[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n", + i, fval1, i + 1, fval2); } return (SUBTLV_HDR_SIZE + TE_SUBTLV_UNRSV_SIZE); } -static u_char show_vty_subtlv_te_metric(struct vty *vty, - struct te_subtlv_te_metric *tlv) +static u_char print_subtlv_te_metric(struct sbuf *buf, int indent, + struct te_subtlv_te_metric *tlv) { u_int32_t te_metric; te_metric = tlv->value[2] | tlv->value[1] << 8 | tlv->value[0] << 16; - if (vty != NULL) - vty_out(vty, " Traffic Engineering Metric: %u\n", te_metric); - else - zlog_debug(" Traffic Engineering Metric: %u", te_metric); + sbuf_push(buf, indent, "Traffic Engineering Metric: %u\n", te_metric); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } -static u_char show_vty_subtlv_ras(struct vty *vty, struct te_subtlv_ras *tlv) +static u_char print_subtlv_ras(struct sbuf *buf, int indent, + struct te_subtlv_ras *tlv) { - if (vty != NULL) - vty_out(vty, " Inter-AS TE Remote AS number: %u\n", - ntohl(tlv->value)); - else - zlog_debug(" Inter-AS TE Remote AS number: %u", - ntohl(tlv->value)); + sbuf_push(buf, indent, "Inter-AS TE Remote AS number: %" PRIu32 "\n", + ntohl(tlv->value)); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } -static u_char show_vty_subtlv_rip(struct vty *vty, struct te_subtlv_rip *tlv) +static u_char print_subtlv_rip(struct sbuf *buf, int indent, + struct te_subtlv_rip *tlv) { - if (vty != NULL) - vty_out(vty, " Inter-AS TE Remote ASBR IP address: %s\n", - inet_ntoa(tlv->value)); - else - zlog_debug(" Inter-AS TE Remote ASBR IP address: %s", - inet_ntoa(tlv->value)); + sbuf_push(buf, indent, "Inter-AS TE Remote ASBR IP address: %s\n", + inet_ntoa(tlv->value)); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } -static u_char show_vty_subtlv_av_delay(struct vty *vty, - struct te_subtlv_av_delay *tlv) +static u_char print_subtlv_av_delay(struct sbuf *buf, int indent, + struct te_subtlv_av_delay *tlv) { u_int32_t delay; u_int32_t A; @@ -834,18 +783,14 @@ static u_char show_vty_subtlv_av_delay(struct vty *vty, delay = (u_int32_t)ntohl(tlv->value) & TE_EXT_MASK; A = (u_int32_t)ntohl(tlv->value) & TE_EXT_ANORMAL; - if (vty != NULL) - vty_out(vty, " %s Average Link Delay: %d (micro-sec)\n", - A ? "Anomalous" : "Normal", delay); - else - zlog_debug(" %s Average Link Delay: %d (micro-sec)", - A ? "Anomalous" : "Normal", delay); + sbuf_push(buf, indent, "%s Average Link Delay: %" PRIu32 " (micro-sec)\n", + A ? "Anomalous" : "Normal", delay); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } -static u_char show_vty_subtlv_mm_delay(struct vty *vty, - struct te_subtlv_mm_delay *tlv) +static u_char print_subtlv_mm_delay(struct sbuf *buf, int indent, + struct te_subtlv_mm_delay *tlv) { u_int32_t low, high; u_int32_t A; @@ -854,33 +799,26 @@ static u_char show_vty_subtlv_mm_delay(struct vty *vty, A = (u_int32_t)ntohl(tlv->low) & TE_EXT_ANORMAL; high = (u_int32_t)ntohl(tlv->high) & TE_EXT_MASK; - if (vty != NULL) - vty_out(vty, " %s Min/Max Link Delay: %d / %d (micro-sec)\n", - A ? "Anomalous" : "Normal", low, high); - else - zlog_debug(" %s Min/Max Link Delay: %d / %d (micro-sec)", - A ? "Anomalous" : "Normal", low, high); + sbuf_push(buf, indent, "%s Min/Max Link Delay: %" PRIu32 " / %" PRIu32 " (micro-sec)\n", + A ? "Anomalous" : "Normal", low, high); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } -static u_char show_vty_subtlv_delay_var(struct vty *vty, - struct te_subtlv_delay_var *tlv) +static u_char print_subtlv_delay_var(struct sbuf *buf, int indent, + struct te_subtlv_delay_var *tlv) { u_int32_t jitter; jitter = (u_int32_t)ntohl(tlv->value) & TE_EXT_MASK; - if (vty != NULL) - vty_out(vty, " Delay Variation: %d (micro-sec)\n", jitter); - else - zlog_debug(" Delay Variation: %d (micro-sec)", jitter); + sbuf_push(buf, indent, "Delay Variation: %" PRIu32 " (micro-sec)\n", jitter); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } -static u_char show_vty_subtlv_pkt_loss(struct vty *vty, - struct te_subtlv_pkt_loss *tlv) +static u_char print_subtlv_pkt_loss(struct sbuf *buf, int indent, + struct te_subtlv_pkt_loss *tlv) { u_int32_t loss; u_int32_t A; @@ -890,189 +828,162 @@ static u_char show_vty_subtlv_pkt_loss(struct vty *vty, fval = (float)(loss * LOSS_PRECISION); A = (u_int32_t)ntohl(tlv->value) & TE_EXT_ANORMAL; - if (vty != NULL) - vty_out(vty, " %s Link Packet Loss: %g (%%)\n", - A ? "Anomalous" : "Normal", fval); - else - zlog_debug(" %s Link Packet Loss: %g (%%)", - A ? "Anomalous" : "Normal", fval); + sbuf_push(buf, indent, "%s Link Packet Loss: %g (%%)\n", + A ? "Anomalous" : "Normal", fval); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } -static u_char show_vty_subtlv_res_bw(struct vty *vty, - struct te_subtlv_res_bw *tlv) +static u_char print_subtlv_res_bw(struct sbuf *buf, int indent, + struct te_subtlv_res_bw *tlv) { float fval; fval = ntohf(tlv->value); - if (vty != NULL) - vty_out(vty, - " Unidirectional Residual Bandwidth: %g (Bytes/sec)\n", - fval); - else - zlog_debug( - " Unidirectional Residual Bandwidth: %g (Bytes/sec)", - fval); + sbuf_push(buf, indent, "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n", + fval); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } -static u_char show_vty_subtlv_ava_bw(struct vty *vty, - struct te_subtlv_ava_bw *tlv) +static u_char print_subtlv_ava_bw(struct sbuf *buf, int indent, + struct te_subtlv_ava_bw *tlv) { float fval; fval = ntohf(tlv->value); - if (vty != NULL) - vty_out(vty, - " Unidirectional Available Bandwidth: %g (Bytes/sec)\n", - fval); - else - zlog_debug( - " Unidirectional Available Bandwidth: %g (Bytes/sec)", - fval); + sbuf_push(buf, indent, "Unidirectional Available Bandwidth: %g (Bytes/sec)\n", + fval); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } -static u_char show_vty_subtlv_use_bw(struct vty *vty, - struct te_subtlv_use_bw *tlv) +static u_char print_subtlv_use_bw(struct sbuf *buf, int indent, + struct te_subtlv_use_bw *tlv) { float fval; fval = ntohf(tlv->value); - if (vty != NULL) - vty_out(vty, - " Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n", - fval); - else - zlog_debug( - " Unidirectional Utilized Bandwidth: %g (Bytes/sec)", - fval); + sbuf_push(buf, indent, "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n", + fval); return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE); } -static u_char show_vty_unknown_tlv(struct vty *vty, struct subtlv_header *tlvh) +static u_char print_unknown_tlv(struct sbuf *buf, int indent, + struct subtlv_header *tlvh) { int i, rtn = 1; u_char *v = (u_char *)tlvh; - if (vty != NULL) { - if (tlvh->length != 0) { - vty_out(vty, - " Unknown TLV: [type(%#.2x), length(%#.2x)]\n", - tlvh->type, tlvh->length); - vty_out(vty, " Dump: [00]"); - rtn = 1; /* initialize end of line counter */ - for (i = 0; i < tlvh->length; i++) { - vty_out(vty, " %#.2x", v[i]); - if (rtn == 8) { - vty_out(vty, "\n [%.2x]", - i + 1); - rtn = 1; - } else - rtn++; - } - vty_out(vty, "\n"); - } else - vty_out(vty, - " Unknown TLV: [type(%#.2x), length(%#.2x)]\n", - tlvh->type, tlvh->length); + if (tlvh->length != 0) { + sbuf_push(buf, indent, + "Unknown TLV: [type(%#.2x), length(%#.2x)]\n", + tlvh->type, tlvh->length); + sbuf_push(buf, indent + 2, "Dump: [00]"); + rtn = 1; /* initialize end of line counter */ + for (i = 0; i < tlvh->length; i++) { + sbuf_push(buf, 0, " %#.2x", v[i]); + if (rtn == 8) { + sbuf_push(buf, 0, "\n"); + sbuf_push(buf, indent + 8, + "[%.2x]", i + 1); + rtn = 1; + } else + rtn++; + } + sbuf_push(buf, 0, "\n"); } else { - zlog_debug(" Unknown TLV: [type(%#.2x), length(%#.2x)]", - tlvh->type, tlvh->length); + sbuf_push(buf, indent, + "Unknown TLV: [type(%#.2x), length(%#.2x)]\n", + tlvh->type, tlvh->length); } return SUBTLV_SIZE(tlvh); } /* Main Show function */ -void mpls_te_print_detail(struct vty *vty, struct te_is_neigh *te) +void mpls_te_print_detail(struct sbuf *buf, int indent, + uint8_t *subtlvs, uint8_t subtlv_len) { - struct subtlv_header *tlvh; - u_int16_t sum = 0; - - zlog_debug("ISIS MPLS-TE: Show database TE detail"); + struct subtlv_header *tlvh = (struct subtlv_header *)subtlvs; + uint16_t sum = 0; - tlvh = (struct subtlv_header *)te->sub_tlvs; - - for (; sum < te->sub_tlvs_length; tlvh = SUBTLV_HDR_NEXT(tlvh)) { + for (; sum < subtlv_len; tlvh = SUBTLV_HDR_NEXT(tlvh)) { switch (tlvh->type) { case TE_SUBTLV_ADMIN_GRP: - sum += show_vty_subtlv_admin_grp( - vty, (struct te_subtlv_admin_grp *)tlvh); + sum += print_subtlv_admin_grp(buf, indent, + (struct te_subtlv_admin_grp *)tlvh); break; case TE_SUBTLV_LLRI: - sum += show_vty_subtlv_llri( - vty, (struct te_subtlv_llri *)tlvh); + sum += print_subtlv_llri(buf, indent, + (struct te_subtlv_llri *)tlvh); break; case TE_SUBTLV_LOCAL_IPADDR: - sum += show_vty_subtlv_local_ipaddr( - vty, (struct te_subtlv_local_ipaddr *)tlvh); + sum += print_subtlv_local_ipaddr(buf, indent, + (struct te_subtlv_local_ipaddr *)tlvh); break; case TE_SUBTLV_RMT_IPADDR: - sum += show_vty_subtlv_rmt_ipaddr( - vty, (struct te_subtlv_rmt_ipaddr *)tlvh); + sum += print_subtlv_rmt_ipaddr(buf, indent, + (struct te_subtlv_rmt_ipaddr *)tlvh); break; case TE_SUBTLV_MAX_BW: - sum += show_vty_subtlv_max_bw( - vty, (struct te_subtlv_max_bw *)tlvh); + sum += print_subtlv_max_bw(buf, indent, + (struct te_subtlv_max_bw *)tlvh); break; case TE_SUBTLV_MAX_RSV_BW: - sum += show_vty_subtlv_max_rsv_bw( - vty, (struct te_subtlv_max_rsv_bw *)tlvh); + sum += print_subtlv_max_rsv_bw(buf, indent, + (struct te_subtlv_max_rsv_bw *)tlvh); break; case TE_SUBTLV_UNRSV_BW: - sum += show_vty_subtlv_unrsv_bw( - vty, (struct te_subtlv_unrsv_bw *)tlvh); + sum += print_subtlv_unrsv_bw(buf, indent, + (struct te_subtlv_unrsv_bw *)tlvh); break; case TE_SUBTLV_TE_METRIC: - sum += show_vty_subtlv_te_metric( - vty, (struct te_subtlv_te_metric *)tlvh); + sum += print_subtlv_te_metric(buf, indent, + (struct te_subtlv_te_metric *)tlvh); break; case TE_SUBTLV_RAS: - sum += show_vty_subtlv_ras( - vty, (struct te_subtlv_ras *)tlvh); + sum += print_subtlv_ras(buf, indent, + (struct te_subtlv_ras *)tlvh); break; case TE_SUBTLV_RIP: - sum += show_vty_subtlv_rip( - vty, (struct te_subtlv_rip *)tlvh); + sum += print_subtlv_rip(buf, indent, + (struct te_subtlv_rip *)tlvh); break; case TE_SUBTLV_AV_DELAY: - sum += show_vty_subtlv_av_delay( - vty, (struct te_subtlv_av_delay *)tlvh); + sum += print_subtlv_av_delay(buf, indent, + (struct te_subtlv_av_delay *)tlvh); break; case TE_SUBTLV_MM_DELAY: - sum += show_vty_subtlv_mm_delay( - vty, (struct te_subtlv_mm_delay *)tlvh); + sum += print_subtlv_mm_delay(buf, indent, + (struct te_subtlv_mm_delay *)tlvh); break; case TE_SUBTLV_DELAY_VAR: - sum += show_vty_subtlv_delay_var( - vty, (struct te_subtlv_delay_var *)tlvh); + sum += print_subtlv_delay_var(buf, indent, + (struct te_subtlv_delay_var *)tlvh); break; case TE_SUBTLV_PKT_LOSS: - sum += show_vty_subtlv_pkt_loss( - vty, (struct te_subtlv_pkt_loss *)tlvh); + sum += print_subtlv_pkt_loss(buf, indent, + (struct te_subtlv_pkt_loss *)tlvh); break; case TE_SUBTLV_RES_BW: - sum += show_vty_subtlv_res_bw( - vty, (struct te_subtlv_res_bw *)tlvh); + sum += print_subtlv_res_bw(buf, indent, + (struct te_subtlv_res_bw *)tlvh); break; case TE_SUBTLV_AVA_BW: - sum += show_vty_subtlv_ava_bw( - vty, (struct te_subtlv_ava_bw *)tlvh); + sum += print_subtlv_ava_bw(buf, indent, + (struct te_subtlv_ava_bw *)tlvh); break; case TE_SUBTLV_USE_BW: - sum += show_vty_subtlv_use_bw( - vty, (struct te_subtlv_use_bw *)tlvh); + sum += print_subtlv_use_bw(buf, indent, + (struct te_subtlv_use_bw *)tlvh); break; default: - sum += show_vty_unknown_tlv(vty, tlvh); + sum += print_unknown_tlv(buf, indent, tlvh); break; } } @@ -1256,6 +1167,9 @@ DEFUN (show_isis_mpls_te_router, static void show_mpls_te_sub(struct vty *vty, struct interface *ifp) { struct mpls_te_circuit *mtc; + struct sbuf buf; + + sbuf_init(&buf, NULL, 0); if ((IS_MPLS_TE(isisMplsTE)) && ((mtc = lookup_mpls_params_by_ifp(ifp)) != NULL)) { @@ -1280,38 +1194,42 @@ static void show_mpls_te_sub(struct vty *vty, struct interface *ifp) ifp->name); } - show_vty_subtlv_admin_grp(vty, &mtc->admin_grp); + sbuf_reset(&buf); + print_subtlv_admin_grp(&buf, 4, &mtc->admin_grp); if (SUBTLV_TYPE(mtc->local_ipaddr) != 0) - show_vty_subtlv_local_ipaddr(vty, &mtc->local_ipaddr); + print_subtlv_local_ipaddr(&buf, 4, &mtc->local_ipaddr); if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0) - show_vty_subtlv_rmt_ipaddr(vty, &mtc->rmt_ipaddr); + print_subtlv_rmt_ipaddr(&buf, 4, &mtc->rmt_ipaddr); - show_vty_subtlv_max_bw(vty, &mtc->max_bw); - show_vty_subtlv_max_rsv_bw(vty, &mtc->max_rsv_bw); - show_vty_subtlv_unrsv_bw(vty, &mtc->unrsv_bw); - show_vty_subtlv_te_metric(vty, &mtc->te_metric); + print_subtlv_max_bw(&buf, 4, &mtc->max_bw); + print_subtlv_max_rsv_bw(&buf, 4, &mtc->max_rsv_bw); + print_subtlv_unrsv_bw(&buf, 4, &mtc->unrsv_bw); + print_subtlv_te_metric(&buf, 4, &mtc->te_metric); if (IS_INTER_AS(mtc->type)) { if (SUBTLV_TYPE(mtc->ras) != 0) - show_vty_subtlv_ras(vty, &mtc->ras); + print_subtlv_ras(&buf, 4, &mtc->ras); if (SUBTLV_TYPE(mtc->rip) != 0) - show_vty_subtlv_rip(vty, &mtc->rip); + print_subtlv_rip(&buf, 4, &mtc->rip); } - show_vty_subtlv_av_delay(vty, &mtc->av_delay); - show_vty_subtlv_mm_delay(vty, &mtc->mm_delay); - show_vty_subtlv_delay_var(vty, &mtc->delay_var); - show_vty_subtlv_pkt_loss(vty, &mtc->pkt_loss); - show_vty_subtlv_res_bw(vty, &mtc->res_bw); - show_vty_subtlv_ava_bw(vty, &mtc->ava_bw); - show_vty_subtlv_use_bw(vty, &mtc->use_bw); + print_subtlv_av_delay(&buf, 4, &mtc->av_delay); + print_subtlv_mm_delay(&buf, 4, &mtc->mm_delay); + print_subtlv_delay_var(&buf, 4, &mtc->delay_var); + print_subtlv_pkt_loss(&buf, 4, &mtc->pkt_loss); + print_subtlv_res_bw(&buf, 4, &mtc->res_bw); + print_subtlv_ava_bw(&buf, 4, &mtc->ava_bw); + print_subtlv_use_bw(&buf, 4, &mtc->use_bw); + + vty_multiline(vty, "", "%s", sbuf_buf(&buf)); vty_out(vty, "---------------\n\n"); } else { vty_out(vty, " %s: MPLS-TE is disabled on this interface\n", ifp->name); } + sbuf_free(&buf); return; } diff --git a/isisd/isis_te.h b/isisd/isis_te.h index 0bd076af19..9b29792e2b 100644 --- a/isisd/isis_te.h +++ b/isisd/isis_te.h @@ -81,6 +81,8 @@ struct subtlv_header { u_char length; /* Value portion only, in byte */ }; +#define MAX_SUBTLV_SIZE 256 + #define SUBTLV_HDR_SIZE 2 /* (sizeof (struct sub_tlv_header)) */ #define SUBTLV_SIZE(stlvh) (SUBTLV_HDR_SIZE + (stlvh)->length) @@ -306,12 +308,13 @@ struct mpls_te_circuit { /* Prototypes. */ void isis_mpls_te_init(void); struct mpls_te_circuit *mpls_te_circuit_new(void); -void mpls_te_print_detail(struct vty *, struct te_is_neigh *); +struct sbuf; +void mpls_te_print_detail(struct sbuf *buf, int indent, uint8_t *subtlvs, uint8_t subtlv_len); void set_circuitparams_local_ipaddr(struct mpls_te_circuit *, struct in_addr); void set_circuitparams_rmt_ipaddr(struct mpls_te_circuit *, struct in_addr); -u_char subtlvs_len(struct mpls_te_circuit *); -u_char add_te_subtlvs(u_char *, struct mpls_te_circuit *); -u_char build_te_subtlvs(u_char *, struct isis_circuit *); +uint8_t subtlvs_len(struct mpls_te_circuit *); +uint8_t add_te_subtlvs(uint8_t *, struct mpls_te_circuit *); +uint8_t build_te_subtlvs(uint8_t *, struct isis_circuit *); void isis_link_params_update(struct isis_circuit *, struct interface *); void isis_mpls_te_update(struct interface *); void isis_mpls_te_config_write_router(struct vty *); diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c deleted file mode 100644 index a295f4dd3f..0000000000 --- a/isisd/isis_tlv.c +++ /dev/null @@ -1,1453 +0,0 @@ -/* - * IS-IS Rout(e)ing protocol - isis_tlv.c - * IS-IS TLV related routines - * - * Copyright (C) 2001,2002 Sampo Saaristo - * Tampere University of Technology - * Institute of Communications Engineering - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public Licenseas published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program 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 this program; see the file COPYING; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <zebra.h> - -#include "log.h" -#include "linklist.h" -#include "stream.h" -#include "memory.h" -#include "prefix.h" -#include "vty.h" -#include "if.h" - -#include "isisd/dict.h" -#include "isisd/isis_constants.h" -#include "isisd/isis_common.h" -#include "isisd/isis_flags.h" -#include "isisd/isis_circuit.h" -#include "isisd/isis_tlv.h" -#include "isisd/isisd.h" -#include "isisd/isis_dynhn.h" -#include "isisd/isis_misc.h" -#include "isisd/isis_pdu.h" -#include "isisd/isis_lsp.h" -#include "isisd/isis_te.h" -#include "isisd/isis_mt.h" - -void free_tlv(void *val) -{ - XFREE(MTYPE_ISIS_TLV, val); - - return; -} - -/* - * Called after parsing of a PDU. There shouldn't be any tlv's left, so this - * is only a caution to avoid memory leaks - */ -void free_tlvs(struct tlvs *tlvs) -{ - if (tlvs->area_addrs) - list_delete(tlvs->area_addrs); - if (tlvs->mt_router_info) - list_delete(tlvs->mt_router_info); - if (tlvs->is_neighs) - list_delete(tlvs->is_neighs); - if (tlvs->te_is_neighs) - list_delete(tlvs->te_is_neighs); - if (tlvs->mt_is_neighs) - list_delete(tlvs->mt_is_neighs); - if (tlvs->es_neighs) - list_delete(tlvs->es_neighs); - if (tlvs->lsp_entries) - list_delete(tlvs->lsp_entries); - if (tlvs->prefix_neighs) - list_delete(tlvs->prefix_neighs); - if (tlvs->lan_neighs) - list_delete(tlvs->lan_neighs); - if (tlvs->ipv4_addrs) - list_delete(tlvs->ipv4_addrs); - if (tlvs->ipv4_int_reachs) - list_delete(tlvs->ipv4_int_reachs); - if (tlvs->ipv4_ext_reachs) - list_delete(tlvs->ipv4_ext_reachs); - if (tlvs->te_ipv4_reachs) - list_delete(tlvs->te_ipv4_reachs); - if (tlvs->mt_ipv4_reachs) - list_delete(tlvs->mt_ipv4_reachs); - if (tlvs->ipv6_addrs) - list_delete(tlvs->ipv6_addrs); - if (tlvs->ipv6_reachs) - list_delete(tlvs->ipv6_reachs); - if (tlvs->mt_ipv6_reachs) - list_delete(tlvs->mt_ipv6_reachs); - - memset(tlvs, 0, sizeof(struct tlvs)); - - return; -} - -static int parse_mtid(uint16_t *mtid, bool read_mtid, unsigned int *length, - u_char **pnt) -{ - if (!read_mtid) { - *mtid = ISIS_MT_IPV4_UNICAST; - return ISIS_OK; - } - - uint16_t mtid_buf; - - if (*length < sizeof(mtid_buf)) { - zlog_warn("ISIS-TLV: mt tlv too short to contain MT id"); - return ISIS_WARNING; - } - - memcpy(&mtid_buf, *pnt, sizeof(mtid_buf)); - *pnt += sizeof(mtid_buf); - *length -= sizeof(mtid_buf); - - *mtid = ntohs(mtid_buf) & ISIS_MT_MASK; - return ISIS_OK; -} - -static int parse_mt_is_neighs(struct tlvs *tlvs, bool read_mtid, - unsigned int length, u_char *pnt) -{ - struct list *neigh_list; - uint16_t mtid; - int rv; - - rv = parse_mtid(&mtid, read_mtid, &length, &pnt); - if (rv != ISIS_OK) - return rv; - - if (mtid == ISIS_MT_IPV4_UNICAST) { - if (!tlvs->te_is_neighs) { - tlvs->te_is_neighs = list_new(); - tlvs->te_is_neighs->del = free_tlv; - } - neigh_list = tlvs->te_is_neighs; - } else { - struct tlv_mt_neighbors *neighbors; - - neighbors = tlvs_get_mt_neighbors(tlvs, mtid); - neighbors->list->del = free_tlv; - neigh_list = neighbors->list; - } - - while (length >= IS_NEIGHBOURS_LEN) { - struct te_is_neigh *neigh = - XCALLOC(MTYPE_ISIS_TLV, sizeof(*neigh)); - - memcpy(neigh, pnt, IS_NEIGHBOURS_LEN); - pnt += IS_NEIGHBOURS_LEN; - length -= IS_NEIGHBOURS_LEN; - - if (neigh->sub_tlvs_length > length) { - zlog_warn( - "ISIS-TLV: neighbor subtlv length exceeds TLV size"); - XFREE(MTYPE_ISIS_TLV, neigh); - return ISIS_WARNING; - } - - memcpy(neigh->sub_tlvs, pnt, neigh->sub_tlvs_length); - pnt += neigh->sub_tlvs_length; - length -= neigh->sub_tlvs_length; - - listnode_add(neigh_list, neigh); - } - - if (length) { - zlog_warn("ISIS-TLV: TE/MT neighor TLV has trailing data"); - return ISIS_WARNING; - } - - return ISIS_OK; -} - -static int parse_mt_ipv4_reachs(struct tlvs *tlvs, bool read_mtid, - unsigned int length, u_char *pnt) -{ - struct list *reach_list; - uint16_t mtid; - int rv; - - rv = parse_mtid(&mtid, read_mtid, &length, &pnt); - if (rv != ISIS_OK) - return rv; - - if (mtid == ISIS_MT_IPV4_UNICAST) { - if (!tlvs->te_ipv4_reachs) { - tlvs->te_ipv4_reachs = list_new(); - tlvs->te_ipv4_reachs->del = free_tlv; - } - reach_list = tlvs->te_ipv4_reachs; - } else { - struct tlv_mt_ipv4_reachs *reachs; - - reachs = tlvs_get_mt_ipv4_reachs(tlvs, mtid); - reachs->list->del = free_tlv; - reach_list = reachs->list; - } - - while (length >= 5) /* Metric + Control */ - { - struct te_ipv4_reachability *reach = - XCALLOC(MTYPE_ISIS_TLV, TE_IPV4_REACH_LEN); - - memcpy(reach, pnt, 5); /* Metric + Control */ - pnt += 5; - length -= 5; - - unsigned char prefixlen = reach->control & 0x3F; - - if (prefixlen > IPV4_MAX_BITLEN) { - zlog_warn( - "ISIS-TLV: invalid IPv4 extended reachability prefix length %d", - prefixlen); - XFREE(MTYPE_ISIS_TLV, reach); - return ISIS_WARNING; - } - - if (length < (unsigned int)PSIZE(prefixlen)) { - zlog_warn( - "ISIS-TLV: invalid IPv4 extended reachability prefix too long for tlv"); - XFREE(MTYPE_ISIS_TLV, reach); - return ISIS_WARNING; - } - - memcpy(&reach->prefix_start, pnt, PSIZE(prefixlen)); - pnt += PSIZE(prefixlen); - length -= PSIZE(prefixlen); - - if (reach->control & TE_IPV4_HAS_SUBTLV) { - if (length < 1) { - zlog_warn( - "ISIS-TLV: invalid IPv4 extended reachability SubTLV missing"); - XFREE(MTYPE_ISIS_TLV, reach); - return ISIS_WARNING; - } - - u_char subtlv_len = *pnt; - pnt++; - length--; - - if (length < subtlv_len) { - zlog_warn( - "ISIS-TLV: invalid IPv4 extended reachability SubTLVs have oversize"); - XFREE(MTYPE_ISIS_TLV, reach); - return ISIS_WARNING; - } - - /* Skip Sub-TLVs for now */ - pnt += subtlv_len; - length -= subtlv_len; - } - listnode_add(reach_list, reach); - } - - if (length) { - zlog_warn( - "ISIS-TLV: TE/MT ipv4 reachability TLV has trailing data"); - return ISIS_WARNING; - } - - return ISIS_OK; -} - -static int parse_mt_ipv6_reachs(struct tlvs *tlvs, bool read_mtid, - unsigned int length, u_char *pnt) -{ - struct list *reach_list; - uint16_t mtid; - int rv; - - rv = parse_mtid(&mtid, read_mtid, &length, &pnt); - if (rv != ISIS_OK) - return rv; - - if (mtid == ISIS_MT_IPV4_UNICAST) { - if (!tlvs->ipv6_reachs) { - tlvs->ipv6_reachs = list_new(); - tlvs->ipv6_reachs->del = free_tlv; - } - reach_list = tlvs->ipv6_reachs; - } else { - struct tlv_mt_ipv6_reachs *reachs; - - reachs = tlvs_get_mt_ipv6_reachs(tlvs, mtid); - reachs->list->del = free_tlv; - reach_list = reachs->list; - } - - while (length >= 6) /* Metric + Control + Prefixlen */ - { - struct ipv6_reachability *reach = - XCALLOC(MTYPE_ISIS_TLV, sizeof(*reach)); - - memcpy(reach, pnt, 6); /* Metric + Control + Prefixlen */ - pnt += 6; - length -= 6; - - if (reach->prefix_len > IPV6_MAX_BITLEN) { - zlog_warn( - "ISIS-TLV: invalid IPv6 reachability prefix length %d", - reach->prefix_len); - XFREE(MTYPE_ISIS_TLV, reach); - return ISIS_WARNING; - } - - if (length < (unsigned int)PSIZE(reach->prefix_len)) { - zlog_warn( - "ISIS-TLV: invalid IPv6 reachability prefix too long for tlv"); - XFREE(MTYPE_ISIS_TLV, reach); - return ISIS_WARNING; - } - - memcpy(&reach->prefix, pnt, PSIZE(reach->prefix_len)); - pnt += PSIZE(reach->prefix_len); - length -= PSIZE(reach->prefix_len); - - if (reach->control_info & CTRL_INFO_SUBTLVS) { - if (length < 1) { - zlog_warn( - "ISIS-TLV: invalid IPv6 reachability SubTLV missing"); - XFREE(MTYPE_ISIS_TLV, reach); - return ISIS_WARNING; - } - - u_char subtlv_len = *pnt; - pnt++; - length--; - - if (length < subtlv_len) { - zlog_warn( - "ISIS-TLV: invalid IPv6 reachability SubTLVs have oversize"); - XFREE(MTYPE_ISIS_TLV, reach); - return ISIS_WARNING; - } - - /* Skip Sub-TLVs for now */ - pnt += subtlv_len; - length -= subtlv_len; - } - listnode_add(reach_list, reach); - } - - if (length) { - zlog_warn( - "ISIS-TLV: (MT) IPv6 reachability TLV has trailing data"); - return ISIS_WARNING; - } - - return ISIS_OK; -} - -/* - * Parses the tlvs found in the variant length part of the PDU. - * Caller tells with flags in "expected" which TLV's it is interested in. - */ -int parse_tlvs(char *areatag, u_char *stream, int size, u_int32_t *expected, - u_int32_t *found, struct tlvs *tlvs, u_int32_t *auth_tlv_offset) -{ - u_char type, length; - struct lan_neigh *lan_nei; - struct area_addr *area_addr; - struct is_neigh *is_nei; - struct es_neigh *es_nei; - struct lsp_entry *lsp_entry; - struct in_addr *ipv4_addr; - struct ipv4_reachability *ipv4_reach; - struct in6_addr *ipv6_addr; - int value_len, retval = ISIS_OK; - u_char *start = stream, *pnt = stream; - - *found = 0; - memset(tlvs, 0, sizeof(struct tlvs)); - - while (pnt < stream + size - 2) { - type = *pnt; - length = *(pnt + 1); - pnt += 2; - value_len = 0; - if (pnt + length > stream + size) { - zlog_warn( - "ISIS-TLV (%s): TLV (type %d, length %d) exceeds packet " - "boundaries", - areatag, type, length); - retval = ISIS_WARNING; - break; - } - switch (type) { - case AREA_ADDRESSES: - /* +-------+-------+-------+-------+-------+-------+-------+-------+ - * | Address Length | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | Area Address | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * : : - */ - *found |= TLVFLAG_AREA_ADDRS; -#ifdef EXTREME_TLV_DEBUG - zlog_debug("TLV Area Adresses len %d", length); -#endif /* EXTREME_TLV_DEBUG */ - if (*expected & TLVFLAG_AREA_ADDRS) { - while (length > value_len) { - area_addr = (struct area_addr *)pnt; - value_len += area_addr->addr_len + 1; - pnt += area_addr->addr_len + 1; - if (!tlvs->area_addrs) - tlvs->area_addrs = list_new(); - listnode_add(tlvs->area_addrs, - area_addr); - } - } else { - pnt += length; - } - break; - - case IS_NEIGHBOURS: - *found |= TLVFLAG_IS_NEIGHS; -#ifdef EXTREME_TLV_DEBUG - zlog_debug("ISIS-TLV (%s): IS Neighbours length %d", - areatag, length); -#endif /* EXTREME_TLV_DEBUG */ - if (TLVFLAG_IS_NEIGHS & *expected) { - /* +-------+-------+-------+-------+-------+-------+-------+-------+ - * | Virtual Flag | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - */ - pnt++; - value_len++; - /* +-------+-------+-------+-------+-------+-------+-------+-------+ - * | 0 | I/E | Default - * Metric | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | S | I/E | Delay Metric - * | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | S | I/E | Expense - * Metric | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | S | I/E | Error Metric - * | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | Neighbour ID | - * +---------------------------------------------------------------+ - * : : - */ - while (length > value_len) { - is_nei = (struct is_neigh *)pnt; - value_len += 4 + ISIS_SYS_ID_LEN + 1; - pnt += 4 + ISIS_SYS_ID_LEN + 1; - if (!tlvs->is_neighs) - tlvs->is_neighs = list_new(); - listnode_add(tlvs->is_neighs, is_nei); - } - } else { - pnt += length; - } - break; - - case TE_IS_NEIGHBOURS: - *found |= TLVFLAG_TE_IS_NEIGHS; -#ifdef EXTREME_TLV_DEBUG - zlog_debug( - "ISIS-TLV (%s): Extended IS Neighbours length %d", - areatag, length); -#endif /* EXTREME_TLV_DEBUG */ - if (TLVFLAG_TE_IS_NEIGHS & *expected) - retval = parse_mt_is_neighs(tlvs, false, length, - pnt); - pnt += length; - break; - - case MT_IS_NEIGHBOURS: - *found |= TLVFLAG_TE_IS_NEIGHS; -#ifdef EXTREME_TLV_DEBUG - zlog_debug("ISIS-TLV (%s): MT IS Neighbours length %d", - areatag, length); -#endif - if (TLVFLAG_TE_IS_NEIGHS & *expected) - retval = parse_mt_is_neighs(tlvs, true, length, - pnt); - pnt += length; - break; - - case ES_NEIGHBOURS: -/* +-------+-------+-------+-------+-------+-------+-------+-------+ - * | 0 | I/E | Default Metric | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | S | I/E | Delay Metric | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | S | I/E | Expense Metric | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | S | I/E | Error Metric | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | Neighbour ID | - * +---------------------------------------------------------------+ - * | Neighbour ID | - * +---------------------------------------------------------------+ - * : : - */ -#ifdef EXTREME_TLV_DEBUG - zlog_debug("ISIS-TLV (%s): ES Neighbours length %d", - areatag, length); -#endif /* EXTREME_TLV_DEBUG */ - *found |= TLVFLAG_ES_NEIGHS; - if (*expected & TLVFLAG_ES_NEIGHS) { - es_nei = (struct es_neigh *)pnt; - value_len += 4; - pnt += 4; - while (length > value_len) { - /* FIXME FIXME FIXME - add to the list - */ - /* sys_id->id = pnt; */ - value_len += ISIS_SYS_ID_LEN; - pnt += ISIS_SYS_ID_LEN; - /* if (!es_nei->neigh_ids) - * es_nei->neigh_ids = sysid; */ - } - if (!tlvs->es_neighs) - tlvs->es_neighs = list_new(); - listnode_add(tlvs->es_neighs, es_nei); - } else { - pnt += length; - } - break; - - case LAN_NEIGHBOURS: - /* +-------+-------+-------+-------+-------+-------+-------+-------+ - * | LAN Address | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * : : - */ - *found |= TLVFLAG_LAN_NEIGHS; -#ifdef EXTREME_TLV_DEBUG - zlog_debug("ISIS-TLV (%s): LAN Neigbours length %d", - areatag, length); -#endif /* EXTREME_TLV_DEBUG */ - if (TLVFLAG_LAN_NEIGHS & *expected) { - while (length > value_len) { - lan_nei = (struct lan_neigh *)pnt; - if (!tlvs->lan_neighs) - tlvs->lan_neighs = list_new(); - listnode_add(tlvs->lan_neighs, lan_nei); - value_len += ETH_ALEN; - pnt += ETH_ALEN; - } - } else { - pnt += length; - } - break; - - case PADDING: -#ifdef EXTREME_TLV_DEBUG - zlog_debug("TLV padding %d", length); -#endif /* EXTREME_TLV_DEBUG */ - pnt += length; - break; - - case LSP_ENTRIES: -/* +-------+-------+-------+-------+-------+-------+-------+-------+ - * | Remaining Lifetime | 2 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | LSP ID | id+2 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | LSP Sequence Number | 4 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | Checksum | 2 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - */ -#ifdef EXTREME_TLV_DEBUG - zlog_debug("ISIS-TLV (%s): LSP Entries length %d", - areatag, length); -#endif /* EXTREME_TLV_DEBUG */ - *found |= TLVFLAG_LSP_ENTRIES; - if (TLVFLAG_LSP_ENTRIES & *expected) { - while (length > value_len) { - lsp_entry = (struct lsp_entry *)pnt; - value_len += 10 + ISIS_SYS_ID_LEN; - pnt += 10 + ISIS_SYS_ID_LEN; - if (!tlvs->lsp_entries) - tlvs->lsp_entries = list_new(); - listnode_add(tlvs->lsp_entries, - lsp_entry); - } - } else { - pnt += length; - } - break; - - case CHECKSUM: - /* +-------+-------+-------+-------+-------+-------+-------+-------+ - * | 16 bit fletcher CHECKSUM | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * : : - */ - *found |= TLVFLAG_CHECKSUM; -#ifdef EXTREME_TLV_DEBUG - zlog_debug("ISIS-TLV (%s): Checksum length %d", areatag, - length); -#endif /* EXTREME_TLV_DEBUG */ - if (*expected & TLVFLAG_CHECKSUM) { - tlvs->checksum = (struct checksum *)pnt; - } - pnt += length; - break; - - case PROTOCOLS_SUPPORTED: - /* +-------+-------+-------+-------+-------+-------+-------+-------+ - * | NLPID | - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * : : - */ - *found |= TLVFLAG_NLPID; -#ifdef EXTREME_TLV_DEBUG - zlog_debug( - "ISIS-TLV (%s): Protocols Supported length %d", - areatag, length); -#endif /* EXTREME_TLV_DEBUG */ - if (*expected & TLVFLAG_NLPID) { - tlvs->nlpids = (struct nlpids *)(pnt - 1); - } - pnt += length; - break; - - case IPV4_ADDR: - /* +-------+-------+-------+-------+-------+-------+-------+-------+ - * + IP version 4 address + 4 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * : : - */ - *found |= TLVFLAG_IPV4_ADDR; -#ifdef EXTREME_TLV_DEBUG - zlog_debug("ISIS-TLV (%s): IPv4 Address length %d", - areatag, length); -#endif /* EXTREME_TLV_DEBUG */ - if (*expected & TLVFLAG_IPV4_ADDR) { - while (length > value_len) { - ipv4_addr = (struct in_addr *)pnt; -#ifdef EXTREME_TLV_DEBUG - zlog_debug( - "ISIS-TLV (%s) : IP ADDR %s, pnt %p", - areatag, inet_ntoa(*ipv4_addr), - pnt); -#endif /* EXTREME_TLV_DEBUG */ - if (!tlvs->ipv4_addrs) - tlvs->ipv4_addrs = list_new(); - listnode_add(tlvs->ipv4_addrs, - ipv4_addr); - value_len += 4; - pnt += 4; - } - } else { - pnt += length; - } - break; - - case AUTH_INFO: - *found |= TLVFLAG_AUTH_INFO; -#ifdef EXTREME_TLV_DEBUG - zlog_debug( - "ISIS-TLV (%s): IS-IS Authentication Information", - areatag); -#endif - if (*expected & TLVFLAG_AUTH_INFO) { - tlvs->auth_info.type = *pnt; - if (length == 0) { - zlog_warn( - "ISIS-TLV (%s): TLV (type %d, length %d) " - "incorrect.", - areatag, type, length); - return ISIS_WARNING; - } - --length; - tlvs->auth_info.len = length; - pnt++; - memcpy(tlvs->auth_info.passwd, pnt, length); - /* Return the authentication tlv pos for later - * computation - * of MD5 (RFC 5304, 2) - */ - if (auth_tlv_offset) - *auth_tlv_offset += (pnt - start - 3); - pnt += length; - } else { - pnt += length; - } - break; - - case DYNAMIC_HOSTNAME: - *found |= TLVFLAG_DYN_HOSTNAME; -#ifdef EXTREME_TLV_DEBUG - zlog_debug("ISIS-TLV (%s): Dynamic Hostname length %d", - areatag, length); -#endif /* EXTREME_TLV_DEBUG */ - if (*expected & TLVFLAG_DYN_HOSTNAME) { - /* the length is also included in the pointed - * struct */ - tlvs->hostname = (struct hostname *)(pnt - 1); - } - pnt += length; - break; - - case TE_ROUTER_ID: - /* +---------------------------------------------------------------+ - * + Router ID + 4 - * +---------------------------------------------------------------+ - */ - *found |= TLVFLAG_TE_ROUTER_ID; -#ifdef EXTREME_TLV_DEBUG - zlog_debug("ISIS-TLV (%s): TE Router ID %d", areatag, - length); -#endif /* EXTREME_TLV_DEBUG */ - if (*expected & TLVFLAG_TE_ROUTER_ID) - tlvs->router_id = (struct te_router_id *)(pnt); - pnt += length; - break; - - case IPV4_INT_REACHABILITY: - /* +-------+-------+-------+-------+-------+-------+-------+-------+ - * | 0 | I/E | Default Metric | 1 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | S | I/E | Delay Metric | 1 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | S | I/E | Expense Metric | 1 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | S | I/E | Error Metric | 1 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | ip address | 4 - * +---------------------------------------------------------------+ - * | address mask | 4 - * +---------------------------------------------------------------+ - * : : - */ - *found |= TLVFLAG_IPV4_INT_REACHABILITY; -#ifdef EXTREME_TLV_DEBUG - zlog_debug( - "ISIS-TLV (%s): IPv4 internal Reachability length %d", - areatag, length); -#endif /* EXTREME_TLV_DEBUG */ - if (*expected & TLVFLAG_IPV4_INT_REACHABILITY) { - while (length > value_len) { - ipv4_reach = - (struct ipv4_reachability *)pnt; - if (!tlvs->ipv4_int_reachs) - tlvs->ipv4_int_reachs = - list_new(); - listnode_add(tlvs->ipv4_int_reachs, - ipv4_reach); - value_len += 12; - pnt += 12; - } - } else { - pnt += length; - } - break; - - case IPV4_EXT_REACHABILITY: - /* +-------+-------+-------+-------+-------+-------+-------+-------+ - * | 0 | I/E | Default Metric | 1 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | S | I/E | Delay Metric | 1 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | S | I/E | Expense Metric | 1 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | S | I/E | Error Metric | 1 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | ip address | 4 - * +---------------------------------------------------------------+ - * | address mask | 4 - * +---------------------------------------------------------------+ - * : : - */ - *found |= TLVFLAG_IPV4_EXT_REACHABILITY; -#ifdef EXTREME_TLV_DEBUG - zlog_debug( - "ISIS-TLV (%s): IPv4 external Reachability length %d", - areatag, length); -#endif /* EXTREME_TLV_DEBUG */ - if (*expected & TLVFLAG_IPV4_EXT_REACHABILITY) { - while (length > value_len) { - ipv4_reach = - (struct ipv4_reachability *)pnt; - if (!tlvs->ipv4_ext_reachs) - tlvs->ipv4_ext_reachs = - list_new(); - listnode_add(tlvs->ipv4_ext_reachs, - ipv4_reach); - value_len += 12; - pnt += 12; - } - } else { - pnt += length; - } - break; - - case TE_IPV4_REACHABILITY: - *found |= TLVFLAG_TE_IPV4_REACHABILITY; -#ifdef EXTREME_TLV_DEBUG - zlog_debug( - "ISIS-TLV (%s): IPv4 extended Reachability length %d", - areatag, length); -#endif /* EXTREME_TLV_DEBUG */ - if (*expected & TLVFLAG_TE_IPV4_REACHABILITY) - retval = parse_mt_ipv4_reachs(tlvs, false, - length, pnt); - pnt += length; - break; - case MT_IPV4_REACHABILITY: - *found |= TLVFLAG_TE_IPV4_REACHABILITY; -#ifdef EXTREME_TLV_DEBUG - zlog_debug( - "ISIS-TLV (%s): IPv4 MT Reachability length %d", - areatag, length); -#endif /* EXTREME_TLV_DEBUG */ - if (*expected & TLVFLAG_TE_IPV4_REACHABILITY) - retval = parse_mt_ipv4_reachs(tlvs, true, - length, pnt); - pnt += length; - break; - case IPV6_ADDR: - /* +-------+-------+-------+-------+-------+-------+-------+-------+ - * + IP version 6 address + 16 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * : : - */ - *found |= TLVFLAG_IPV6_ADDR; -#ifdef EXTREME_TLV_DEBUG - zlog_debug("ISIS-TLV (%s): IPv6 Address length %d", - areatag, length); -#endif /* EXTREME_TLV_DEBUG */ - if (*expected & TLVFLAG_IPV6_ADDR) { - while (length > value_len) { - ipv6_addr = (struct in6_addr *)pnt; - if (!tlvs->ipv6_addrs) - tlvs->ipv6_addrs = list_new(); - listnode_add(tlvs->ipv6_addrs, - ipv6_addr); - value_len += 16; - pnt += 16; - } - } else { - pnt += length; - } - break; - - case IPV6_REACHABILITY: - *found |= TLVFLAG_IPV6_REACHABILITY; -#ifdef EXTREME_TLV_DEBUG - zlog_debug("ISIS-TLV (%s): IPv6 Reachability length %d", - areatag, length); -#endif /* EXTREME_TLV_DEBUG */ - if (*expected & TLVFLAG_IPV6_REACHABILITY) - retval = parse_mt_ipv6_reachs(tlvs, false, - length, pnt); - pnt += length; - break; - case MT_IPV6_REACHABILITY: - *found |= TLVFLAG_IPV6_REACHABILITY; -#ifdef EXTREME_TLV_DEBUG - zlog_debug("ISIS-TLV (%s): IPv6 Reachability length %d", - areatag, length); -#endif /* EXTREME_TLV_DEBUG */ - if (*expected & TLVFLAG_IPV6_REACHABILITY) - retval = parse_mt_ipv6_reachs(tlvs, true, - length, pnt); - pnt += length; - break; - case WAY3_HELLO: - /* +---------------------------------------------------------------+ - * | Adjacency state | 1 - * +---------------------------------------------------------------+ - * | Extended Local Circuit ID | 4 - * +---------------------------------------------------------------+ - * | Neighbor System ID (If known) - * | 0-8 - * (probably 6) - * +---------------------------------------------------------------+ - * | Neighbor Local Circuit ID (If - * known) | 4 - * +---------------------------------------------------------------+ - */ - *found |= TLVFLAG_3WAY_HELLO; - if (*expected & TLVFLAG_3WAY_HELLO) { - while (length > value_len) { - /* FIXME: make this work */ - /* Adjacency State (one - octet): - 0 = Up - 1 = Initializing - 2 = Down - Extended Local Circuit ID - (four octets) - Neighbor System ID if known - (zero to eight octets) - Neighbor Extended Local - Circuit ID (four octets, if Neighbor - System ID is present) */ - pnt += length; - value_len += length; - } - } else { - pnt += length; - } - - break; - case GRACEFUL_RESTART: - /* +-------+-------+-------+-------+-------+-------+-------+-------+ - * | Reserved | SA | RA - * | RR | 1 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | Remaining Time | 2 - * +---------------------------------------------------------------+ - * | Restarting Neighbor ID (If known) - * | 0-8 - * +---------------------------------------------------------------+ - */ - *found |= TLVFLAG_GRACEFUL_RESTART; - if (*expected & TLVFLAG_GRACEFUL_RESTART) { - /* FIXME: make this work */ - } - pnt += length; - break; - - case MT_ROUTER_INFORMATION: - *found |= TLVFLAG_MT_ROUTER_INFORMATION; - if (*expected & TLVFLAG_MT_ROUTER_INFORMATION) { - if (!tlvs->mt_router_info) { - tlvs->mt_router_info = list_new(); - tlvs->mt_router_info->del = free_tlv; - } - while (length > value_len) { - uint16_t mt_info; - struct mt_router_info *info; - - if (value_len + sizeof(mt_info) - > length) { - zlog_warn( - "ISIS-TLV (%s): TLV 229 is truncated.", - areatag); - pnt += length - value_len; - break; - } - - memcpy(&mt_info, pnt, sizeof(mt_info)); - pnt += sizeof(mt_info); - value_len += sizeof(mt_info); - - mt_info = ntohs(mt_info); - info = XCALLOC(MTYPE_ISIS_TLV, - sizeof(*info)); - info->mtid = mt_info & ISIS_MT_MASK; - info->overload = - mt_info & ISIS_MT_OL_MASK; - listnode_add(tlvs->mt_router_info, - info); - } - } else { - pnt += length; - } - break; - default: - zlog_warn( - "ISIS-TLV (%s): unsupported TLV type %d, length %d", - areatag, type, length); - - pnt += length; - break; - } - /* Abort Parsing if error occured */ - if (retval != ISIS_OK) - return retval; - } - - return retval; -} - -int add_tlv(u_char tag, u_char len, u_char *value, struct stream *stream) -{ - if ((stream_get_size(stream) - stream_get_endp(stream)) - < (((unsigned)len) + 2)) { - zlog_warn( - "No room for TLV of type %d " - "(total size %d available %d required %d)", - tag, (int)stream_get_size(stream), - (int)(stream_get_size(stream) - - stream_get_endp(stream)), - len + 2); - return ISIS_WARNING; - } - - stream_putc(stream, tag); /* TAG */ - stream_putc(stream, len); /* LENGTH */ - stream_put(stream, value, (int)len); /* VALUE */ - -#ifdef EXTREME_DEBUG - zlog_debug("Added TLV %d len %d", tag, len); -#endif /* EXTREME DEBUG */ - return ISIS_OK; -} - -int tlv_add_mt_router_info(struct list *mt_router_info, struct stream *stream) -{ - struct listnode *node; - struct mt_router_info *info; - - uint16_t value[127]; - uint16_t *pos = value; - - for (ALL_LIST_ELEMENTS_RO(mt_router_info, node, info)) { - uint16_t mt_info; - - mt_info = info->mtid; - if (info->overload) - mt_info |= ISIS_MT_OL_MASK; - - *pos = htons(mt_info); - pos++; - } - - return add_tlv(MT_ROUTER_INFORMATION, (pos - value) * sizeof(*pos), - (u_char *)value, stream); -} - -int tlv_add_area_addrs(struct list *area_addrs, struct stream *stream) -{ - struct listnode *node; - struct area_addr *area_addr; - - u_char value[255]; - u_char *pos = value; - - for (ALL_LIST_ELEMENTS_RO(area_addrs, node, area_addr)) { - if (pos - value + area_addr->addr_len > 255) - goto err; - *pos = area_addr->addr_len; - pos++; - memcpy(pos, area_addr->area_addr, (int)area_addr->addr_len); - pos += area_addr->addr_len; - } - - return add_tlv(AREA_ADDRESSES, pos - value, value, stream); - -err: - zlog_warn("tlv_add_area_addrs(): TLV longer than 255"); - return ISIS_WARNING; -} - -int tlv_add_is_neighs(struct list *is_neighs, struct stream *stream) -{ - struct listnode *node; - struct is_neigh *is_neigh; - u_char value[255]; - u_char *pos = value; - int retval; - - *pos = 0; /*is_neigh->virtual; */ - pos++; - - for (ALL_LIST_ELEMENTS_RO(is_neighs, node, is_neigh)) { - if (pos - value + IS_NEIGHBOURS_LEN > 255) { - retval = add_tlv(IS_NEIGHBOURS, pos - value, value, - stream); - if (retval != ISIS_OK) - return retval; - pos = value; - } - *pos = is_neigh->metrics.metric_default; - pos++; - *pos = is_neigh->metrics.metric_delay; - pos++; - *pos = is_neigh->metrics.metric_expense; - pos++; - *pos = is_neigh->metrics.metric_error; - pos++; - memcpy(pos, is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1); - pos += ISIS_SYS_ID_LEN + 1; - } - - return add_tlv(IS_NEIGHBOURS, pos - value, value, stream); -} - -static size_t max_tlv_size(struct stream *stream) -{ - size_t avail = stream_get_size(stream) - stream_get_endp(stream); - - if (avail < 2) - return 0; - - if (avail < 257) - return avail - 2; - - return 255; -} - -unsigned int tlv_add_te_is_neighs(struct list *te_is_neighs, - struct stream *stream, void *arg) -{ - struct listnode *node; - struct te_is_neigh *te_is_neigh; - u_char value[255]; - u_char *pos = value; - uint16_t mtid = arg ? *(uint16_t *)arg : ISIS_MT_IPV4_UNICAST; - unsigned int consumed = 0; - size_t max_size = max_tlv_size(stream); - - if (mtid != ISIS_MT_IPV4_UNICAST) { - uint16_t mtid_conversion = ntohs(mtid); - memcpy(pos, &mtid_conversion, sizeof(mtid_conversion)); - pos += sizeof(mtid_conversion); - } - - for (ALL_LIST_ELEMENTS_RO(te_is_neighs, node, te_is_neigh)) { - /* FIXME: Check if Total SubTLVs size doesn't exceed 255 */ - if ((size_t)(pos - value) + IS_NEIGHBOURS_LEN - + te_is_neigh->sub_tlvs_length - > max_size) - break; - - memcpy(pos, te_is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1); - pos += ISIS_SYS_ID_LEN + 1; - memcpy(pos, te_is_neigh->te_metric, 3); - pos += 3; - /* Set the total size of Sub TLVs */ - *pos = te_is_neigh->sub_tlvs_length; - pos++; - /* Copy Sub TLVs if any */ - if (te_is_neigh->sub_tlvs_length > 0) { - memcpy(pos, te_is_neigh->sub_tlvs, - te_is_neigh->sub_tlvs_length); - pos += te_is_neigh->sub_tlvs_length; - } - consumed++; - } - - if (consumed) { - int rv = add_tlv((mtid != ISIS_MT_IPV4_UNICAST) - ? MT_IS_NEIGHBOURS - : TE_IS_NEIGHBOURS, - pos - value, value, stream); - assert(rv == ISIS_OK); - } - return consumed; -} - -int tlv_add_lan_neighs(struct list *lan_neighs, struct stream *stream) -{ - struct listnode *node; - u_char *snpa; - u_char value[255]; - u_char *pos = value; - int retval; - - for (ALL_LIST_ELEMENTS_RO(lan_neighs, node, snpa)) { - if (pos - value + ETH_ALEN > 255) { - retval = add_tlv(LAN_NEIGHBOURS, pos - value, value, - stream); - if (retval != ISIS_OK) - return retval; - pos = value; - } - memcpy(pos, snpa, ETH_ALEN); - pos += ETH_ALEN; - } - - return add_tlv(LAN_NEIGHBOURS, pos - value, value, stream); -} - -int tlv_add_nlpid(struct nlpids *nlpids, struct stream *stream) -{ - return add_tlv(PROTOCOLS_SUPPORTED, nlpids->count, nlpids->nlpids, - stream); -} - -int tlv_add_authinfo(u_char auth_type, u_char auth_len, u_char *auth_value, - struct stream *stream) -{ - u_char value[255]; - u_char *pos = value; - *pos++ = auth_type; - memcpy(pos, auth_value, auth_len); - - return add_tlv(AUTH_INFO, auth_len + 1, value, stream); -} - -int tlv_add_checksum(struct checksum *checksum, struct stream *stream) -{ - u_char value[255]; - u_char *pos = value; - return add_tlv(CHECKSUM, pos - value, value, stream); -} - -int tlv_add_ip_addrs(struct list *ip_addrs, struct stream *stream) -{ - struct listnode *node; - struct prefix_ipv4 *ipv4; - u_char value[255]; - u_char *pos = value; - - for (ALL_LIST_ELEMENTS_RO(ip_addrs, node, ipv4)) { - if (pos - value + IPV4_MAX_BYTELEN > 255) { - /* RFC 1195 s4.2: only one tuple of 63 allowed. */ - zlog_warn( - "tlv_add_ip_addrs(): cutting off at 63 IP addresses"); - break; - } - *(u_int32_t *)pos = ipv4->prefix.s_addr; - pos += IPV4_MAX_BYTELEN; - } - - return add_tlv(IPV4_ADDR, pos - value, value, stream); -} - -/* Used to add TLV containing just one IPv4 address - either IPv4 address TLV - * (in case of LSP) or TE router ID TLV. */ -int tlv_add_in_addr(struct in_addr *addr, struct stream *stream, u_char tag) -{ - u_char value[255]; - u_char *pos = value; - - memcpy(pos, addr, IPV4_MAX_BYTELEN); - pos += IPV4_MAX_BYTELEN; - - return add_tlv(tag, pos - value, value, stream); -} - -int tlv_add_dynamic_hostname(struct hostname *hostname, struct stream *stream) -{ - return add_tlv(DYNAMIC_HOSTNAME, hostname->namelen, hostname->name, - stream); -} - -int tlv_add_lsp_entries(struct list *lsps, struct stream *stream) -{ - struct listnode *node; - struct isis_lsp *lsp; - u_char value[255]; - u_char *pos = value; - int retval; - - for (ALL_LIST_ELEMENTS_RO(lsps, node, lsp)) { - if (pos - value + LSP_ENTRIES_LEN > 255) { - retval = add_tlv(LSP_ENTRIES, pos - value, value, - stream); - if (retval != ISIS_OK) - return retval; - pos = value; - } - *((u_int16_t *)pos) = lsp->lsp_header->rem_lifetime; - pos += 2; - memcpy(pos, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2); - pos += ISIS_SYS_ID_LEN + 2; - *((u_int32_t *)pos) = lsp->lsp_header->seq_num; - pos += 4; - *((u_int16_t *)pos) = lsp->lsp_header->checksum; - pos += 2; - } - - return add_tlv(LSP_ENTRIES, pos - value, value, stream); -} - -static int tlv_add_ipv4_reachs(u_char tag, struct list *ipv4_reachs, - struct stream *stream) -{ - struct listnode *node; - struct ipv4_reachability *reach; - u_char value[255]; - u_char *pos = value; - int retval; - - for (ALL_LIST_ELEMENTS_RO(ipv4_reachs, node, reach)) { - if (pos - value + IPV4_REACH_LEN > 255) { - retval = add_tlv(tag, pos - value, value, stream); - if (retval != ISIS_OK) - return retval; - pos = value; - } - *pos = reach->metrics.metric_default; - pos++; - *pos = reach->metrics.metric_delay; - pos++; - *pos = reach->metrics.metric_expense; - pos++; - *pos = reach->metrics.metric_error; - pos++; - *(u_int32_t *)pos = reach->prefix.s_addr; - pos += IPV4_MAX_BYTELEN; - *(u_int32_t *)pos = reach->mask.s_addr; - pos += IPV4_MAX_BYTELEN; - } - - return add_tlv(tag, pos - value, value, stream); -} - -int tlv_add_ipv4_int_reachs(struct list *ipv4_reachs, struct stream *stream) -{ - return tlv_add_ipv4_reachs(IPV4_INT_REACHABILITY, ipv4_reachs, stream); -} - -int tlv_add_ipv4_ext_reachs(struct list *ipv4_reachs, struct stream *stream) -{ - return tlv_add_ipv4_reachs(IPV4_EXT_REACHABILITY, ipv4_reachs, stream); -} - - -unsigned int tlv_add_te_ipv4_reachs(struct list *te_ipv4_reachs, - struct stream *stream, void *arg) -{ - struct listnode *node; - struct te_ipv4_reachability *te_reach; - u_char value[255]; - u_char *pos = value; - uint16_t mtid = arg ? *(uint16_t *)arg : ISIS_MT_IPV4_UNICAST; - unsigned int consumed = 0; - size_t max_size = max_tlv_size(stream); - - if (mtid != ISIS_MT_IPV4_UNICAST) { - uint16_t mtid_conversion = ntohs(mtid); - memcpy(pos, &mtid_conversion, sizeof(mtid_conversion)); - pos += sizeof(mtid_conversion); - } - - for (ALL_LIST_ELEMENTS_RO(te_ipv4_reachs, node, te_reach)) { - unsigned char prefixlen = te_reach->control & 0x3F; - - if ((size_t)(pos - value) + 5 + PSIZE(prefixlen) > max_size) - break; - - *(u_int32_t *)pos = te_reach->te_metric; - pos += 4; - *pos = te_reach->control; - pos++; - memcpy(pos, &te_reach->prefix_start, PSIZE(prefixlen)); - pos += PSIZE(prefixlen); - consumed++; - } - - if (consumed) { - int rv = add_tlv((mtid != ISIS_MT_IPV4_UNICAST) - ? MT_IPV4_REACHABILITY - : TE_IPV4_REACHABILITY, - pos - value, value, stream); - assert(rv == ISIS_OK); - } - - return consumed; -} - -int tlv_add_ipv6_addrs(struct list *ipv6_addrs, struct stream *stream) -{ - struct listnode *node; - struct prefix_ipv6 *ipv6; - u_char value[255]; - u_char *pos = value; - int retval; - - for (ALL_LIST_ELEMENTS_RO(ipv6_addrs, node, ipv6)) { - if (pos - value + IPV6_MAX_BYTELEN > 255) { - retval = add_tlv(IPV6_ADDR, pos - value, value, stream); - if (retval != ISIS_OK) - return retval; - pos = value; - } - memcpy(pos, ipv6->prefix.s6_addr, IPV6_MAX_BYTELEN); - pos += IPV6_MAX_BYTELEN; - } - - return add_tlv(IPV6_ADDR, pos - value, value, stream); -} - -unsigned int tlv_add_ipv6_reachs(struct list *ipv6_reachs, - struct stream *stream, void *arg) -{ - struct listnode *node; - struct ipv6_reachability *ip6reach; - u_char value[255]; - u_char *pos = value; - uint16_t mtid = arg ? *(uint16_t *)arg : ISIS_MT_IPV4_UNICAST; - unsigned int consumed = 0; - size_t max_size = max_tlv_size(stream); - - if (mtid != ISIS_MT_IPV4_UNICAST) { - uint16_t mtid_conversion = ntohs(mtid); - memcpy(pos, &mtid_conversion, sizeof(mtid_conversion)); - pos += sizeof(mtid_conversion); - } - - for (ALL_LIST_ELEMENTS_RO(ipv6_reachs, node, ip6reach)) { - if ((size_t)(pos - value) + 6 + PSIZE(ip6reach->prefix_len) - > max_size) - break; - - *(uint32_t *)pos = ip6reach->metric; - pos += 4; - *pos = ip6reach->control_info; - pos++; - *pos = ip6reach->prefix_len; - pos++; - memcpy(pos, ip6reach->prefix, PSIZE(ip6reach->prefix_len)); - pos += PSIZE(ip6reach->prefix_len); - consumed++; - } - - if (consumed) { - int rv = add_tlv((mtid != ISIS_MT_IPV4_UNICAST) - ? MT_IPV6_REACHABILITY - : IPV6_REACHABILITY, - pos - value, value, stream); - assert(rv == ISIS_OK); - } - - return consumed; -} - -int tlv_add_padding(struct stream *stream) -{ - int fullpads, i, left; - - /* - * How many times can we add full padding ? - */ - fullpads = (stream_get_size(stream) - stream_get_endp(stream)) / 257; - for (i = 0; i < fullpads; i++) { - if (!stream_putc(stream, (u_char)PADDING)) /* TAG */ - goto err; - if (!stream_putc(stream, (u_char)255)) /* LENGHT */ - goto err; - stream_put(stream, NULL, 255); /* zero padding */ - } - - left = stream_get_size(stream) - stream_get_endp(stream); - - if (left < 2) - return ISIS_OK; - - if (left == 2) { - stream_putc(stream, PADDING); - stream_putc(stream, 0); - return ISIS_OK; - } - - stream_putc(stream, PADDING); - stream_putc(stream, left - 2); - stream_put(stream, NULL, left - 2); - - return ISIS_OK; - -err: - zlog_warn("tlv_add_padding(): no room for tlv"); - return ISIS_WARNING; -} diff --git a/isisd/isis_tlv.h b/isisd/isis_tlv.h deleted file mode 100644 index d06548519f..0000000000 --- a/isisd/isis_tlv.h +++ /dev/null @@ -1,340 +0,0 @@ -/* - * IS-IS Rout(e)ing protocol - isis_tlv.h - * IS-IS TLV related routines - * - * Copyright (C) 2001,2002 Sampo Saaristo - * Tampere University of Technology - * Institute of Communications Engineering - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public Licenseas published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program 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 this program; see the file COPYING; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef _ZEBRA_ISIS_TLV_H -#define _ZEBRA_ISIS_TLV_H - -#include "isisd/isis_mt.h" - -/* - * The list of TLVs we (should) support. - * ____________________________________________________________________________ - * Name Value IIH LSP SNP Status - * LAN - * ____________________________________________________________________________ - * - * Area Addresses 1 y y n ISO10589 - * IIS Neighbors 2 n y n ISO10589 - * ES Neighbors 3 n y n ISO10589 - * IIS Neighbors 6 y n n ISO10589 - * Padding 8 y n n ISO10589 - * LSP Entries 9 n n y ISO10589 - * Authentication 10 y y y ISO10589, RFC3567 - * Checksum 12 y n y RFC3358 - * Extended IS Reachability 22 n y n RFC5305 - * IS Alias 24 n y n RFC3786 - * IP Int. Reachability 128 n y n RFC1195 - * Protocols Supported 129 y y n RFC1195 - * IP Ext. Reachability 130 n y n RFC1195 - * IDRPI 131 n y y RFC1195 - * IP Interface Address 132 y y n RFC1195 - * TE Router ID 134 n y n RFC5305 - * Extended IP Reachability 135 n y n RFC5305 - * Dynamic Hostname 137 n y n RFC2763 - * Shared Risk Link Group 138 n y y RFC5307 - * Inter-AS Reachability 141 n y n RFC5316 - * Restart TLV 211 y n n RFC3847 - * MT IS Reachability 222 n y n RFC5120 - * MT Supported 229 y y n RFC5120 - * IPv6 Interface Address 232 y y n RFC5308 - * MT IP Reachability 235 n y n RFC5120 - * IPv6 IP Reachability 236 n y n RFC5308 - * MT IPv6 IP Reachability 237 n y n RFC5120 - * P2P Adjacency State 240 y n n RFC3373 - * IIH Sequence Number 241 y n n draft-shen-isis-iih-sequence - * Router Capability 242 n y n RFC4971 - * - * - * IS Reachability sub-TLVs we support (See isis_te.[c,h]) - * ____________________________________________________________________________ - * Name Value Status - * ____________________________________________________________________________ - * Administartive group (color) 3 RFC5305 - * Link Local/Remote Identifiers 4 RFC5307 - * IPv4 interface address 6 RFC5305 - * IPv4 neighbor address 8 RFC5305 - * Maximum link bandwidth 9 RFC5305 - * Reservable link bandwidth 10 RFC5305 - * Unreserved bandwidth 11 RFC5305 - * TE Default metric 18 RFC5305 - * Link Protection Type 20 RFC5307 - * Interface Switching Capability 21 RFC5307 - * Remote AS number 24 RFC5316 - * IPv4 Remote ASBR identifier 25 RFC5316 - * - * - * IP Reachability sub-TLVs we (should) support. - * ____________________________________________________________________________ - * Name Value Status - * ____________________________________________________________________________ - * 32bit administrative tag 1 RFC5130 - * 64bit administrative tag 2 RFC5130 - * Management prefix color 117 RFC5120 - */ - -#define AREA_ADDRESSES 1 -#define IS_NEIGHBOURS 2 -#define ES_NEIGHBOURS 3 -#define LAN_NEIGHBOURS 6 -#define PADDING 8 -#define LSP_ENTRIES 9 -#define AUTH_INFO 10 -#define CHECKSUM 12 -#define TE_IS_NEIGHBOURS 22 -#define IS_ALIAS 24 -#define IPV4_INT_REACHABILITY 128 -#define PROTOCOLS_SUPPORTED 129 -#define IPV4_EXT_REACHABILITY 130 -#define IDRP_INFO 131 -#define IPV4_ADDR 132 -#define TE_ROUTER_ID 134 -#define TE_IPV4_REACHABILITY 135 -#define DYNAMIC_HOSTNAME 137 -#define GRACEFUL_RESTART 211 -#define MT_IS_NEIGHBOURS 222 -#define MT_ROUTER_INFORMATION 229 -#define IPV6_ADDR 232 -#define MT_IPV4_REACHABILITY 235 -#define IPV6_REACHABILITY 236 -#define MT_IPV6_REACHABILITY 237 -#define WAY3_HELLO 240 -#define ROUTER_INFORMATION 242 - -#define AUTH_INFO_HDRLEN 3 - -#define MAX_TLV_LEN 255 - -#define IS_NEIGHBOURS_LEN (ISIS_SYS_ID_LEN + 5) -#define LAN_NEIGHBOURS_LEN 6 -#define LSP_ENTRIES_LEN (10 + ISIS_SYS_ID_LEN) /* FIXME: should be entry */ -#define IPV4_REACH_LEN 12 -#define IPV6_REACH_LEN 22 -#define TE_IPV4_REACH_LEN 9 - -#define MAX_SUBTLV_SIZE 256 - -/* struct for neighbor */ -struct is_neigh { - struct metric metrics; - u_char neigh_id[ISIS_SYS_ID_LEN + 1]; -}; - -/* struct for te metric */ -struct te_is_neigh { - u_char neigh_id[ISIS_SYS_ID_LEN + 1]; - u_char te_metric[3]; - u_char sub_tlvs_length; - /* Theorical Maximum SubTLVs is 256 because the sub_tlvs_length is 8 - * bits */ - /* Practically, 118 bytes are necessary to store all supported TE - * parameters */ - /* FIXME: A pointer will use less memory, but need to be free */ - /* which is hard to fix, especially within free_tlvs() function */ - /* and malloc() / free() as a CPU cost compared to the memory usage */ - u_char sub_tlvs[MAX_SUBTLV_SIZE]; /* SUB TLVs storage */ -}; - -/* Decode and encode three-octet metric into host byte order integer */ -#define GET_TE_METRIC(t) \ - (((unsigned)(t)->te_metric[0] << 16) | ((t)->te_metric[1] << 8) \ - | (t)->te_metric[2]) -#define SET_TE_METRIC(t, m) \ - (((t)->te_metric[0] = (m) >> 16), ((t)->te_metric[1] = (m) >> 8), \ - ((t)->te_metric[2] = (m))) - -/* struct for es neighbors */ -struct es_neigh { - struct metric metrics; - /* approximate position of first, we use the - * length ((uchar*)metric-1) to know all */ - u_char first_es_neigh[ISIS_SYS_ID_LEN]; -}; - -struct partition_desig_level2_is { - struct list *isis_system_ids; -}; - -/* struct for lan neighbors */ -struct lan_neigh { - u_char LAN_addr[6]; -}; - -#ifdef __SUNPRO_C -#pragma pack(1) -#endif - -/* struct for LSP entry */ -struct lsp_entry { - u_int16_t rem_lifetime; - u_char lsp_id[ISIS_SYS_ID_LEN + 2]; - u_int32_t seq_num; - u_int16_t checksum; -} __attribute__((packed)); - -#ifdef __SUNPRO_C -#pragma pack() -#endif - -/* struct for checksum */ -struct checksum { - u_int16_t checksum; -}; - -/* ipv4 reachability */ -struct ipv4_reachability { - struct metric metrics; - struct in_addr prefix; - struct in_addr mask; -}; - -/* te router id */ -struct te_router_id { - struct in_addr id; -}; - -/* te ipv4 reachability */ -struct te_ipv4_reachability { - u_int32_t te_metric; - u_char control; - u_char prefix_start; /* since this is variable length by nature it only - */ -}; /* points to an approximate location */ - -#define TE_IPV4_HAS_SUBTLV (0x40) - -struct idrp_info { - u_char len; - u_char *value; -}; - -struct ipv6_reachability { - u_int32_t metric; - u_char control_info; - u_char prefix_len; - u_char prefix[16]; -}; - -/* bits in control_info */ -#define CTRL_INFO_DIRECTION 0x80 -#define DIRECTION_UP 0x00 -#define DIRECTION_DOWN 0x80 - -#define CTRL_INFO_DISTRIBUTION 0x40 -#define DISTRIBUTION_INTERNAL 0x00 -#define DISTRIBUTION_EXTERNAL 0x40 - -#define CTRL_INFO_SUBTLVS 0x20 - -struct mt_router_info { - ISIS_MT_INFO_FIELDS - bool overload; -}; - -/* - * Pointer to each tlv type, filled by parse_tlvs() - */ -struct tlvs { - struct checksum *checksum; - struct hostname *hostname; - struct nlpids *nlpids; - struct te_router_id *router_id; - struct list *area_addrs; - struct list *mt_router_info; - struct list *is_neighs; - struct list *te_is_neighs; - struct list *mt_is_neighs; - struct list *es_neighs; - struct list *lsp_entries; - struct list *prefix_neighs; - struct list *lan_neighs; - struct list *ipv4_addrs; - struct list *ipv4_int_reachs; - struct list *ipv4_ext_reachs; - struct list *te_ipv4_reachs; - struct list *mt_ipv4_reachs; - struct list *ipv6_addrs; - struct list *ipv6_reachs; - struct list *mt_ipv6_reachs; - struct isis_passwd auth_info; -}; - -/* - * Own definitions - used to bitmask found and expected - */ - -#define TLVFLAG_AREA_ADDRS (1<<0) -#define TLVFLAG_IS_NEIGHS (1<<1) -#define TLVFLAG_ES_NEIGHS (1<<2) -#define TLVFLAG_PARTITION_DESIG_LEVEL2_IS (1<<3) -#define TLVFLAG_PREFIX_NEIGHS (1<<4) -#define TLVFLAG_LAN_NEIGHS (1<<5) -#define TLVFLAG_LSP_ENTRIES (1<<6) -#define TLVFLAG_PADDING (1<<7) -#define TLVFLAG_AUTH_INFO (1<<8) -#define TLVFLAG_IPV4_INT_REACHABILITY (1<<9) -#define TLVFLAG_NLPID (1<<10) -#define TLVFLAG_IPV4_EXT_REACHABILITY (1<<11) -#define TLVFLAG_IPV4_ADDR (1<<12) -#define TLVFLAG_DYN_HOSTNAME (1<<13) -#define TLVFLAG_IPV6_ADDR (1<<14) -#define TLVFLAG_IPV6_REACHABILITY (1<<15) -#define TLVFLAG_TE_IS_NEIGHS (1<<16) -#define TLVFLAG_TE_IPV4_REACHABILITY (1<<17) -#define TLVFLAG_3WAY_HELLO (1<<18) -#define TLVFLAG_TE_ROUTER_ID (1<<19) -#define TLVFLAG_CHECKSUM (1<<20) -#define TLVFLAG_GRACEFUL_RESTART (1<<21) -#define TLVFLAG_MT_ROUTER_INFORMATION (1<<22) - -void init_tlvs(struct tlvs *tlvs, uint32_t expected); -void free_tlvs(struct tlvs *tlvs); -int parse_tlvs(char *areatag, u_char *stream, int size, u_int32_t *expected, - u_int32_t *found, struct tlvs *tlvs, u_int32_t *auth_tlv_offset); -int add_tlv(u_char, u_char, u_char *, struct stream *); -void free_tlv(void *val); - -int tlv_add_mt_router_info(struct list *mt_router_info, struct stream *stream); -int tlv_add_area_addrs(struct list *area_addrs, struct stream *stream); -int tlv_add_is_neighs(struct list *is_neighs, struct stream *stream); -unsigned int tlv_add_te_is_neighs(struct list *te_is_neighs, - struct stream *stream, void *arg); -int tlv_add_lan_neighs(struct list *lan_neighs, struct stream *stream); -int tlv_add_nlpid(struct nlpids *nlpids, struct stream *stream); -int tlv_add_checksum(struct checksum *checksum, struct stream *stream); -int tlv_add_authinfo(u_char auth_type, u_char authlen, u_char *auth_value, - struct stream *stream); -int tlv_add_ip_addrs(struct list *ip_addrs, struct stream *stream); -int tlv_add_in_addr(struct in_addr *, struct stream *stream, u_char tag); -int tlv_add_dynamic_hostname(struct hostname *hostname, struct stream *stream); -int tlv_add_lsp_entries(struct list *lsps, struct stream *stream); -int tlv_add_ipv4_int_reachs(struct list *ipv4_reachs, struct stream *stream); -int tlv_add_ipv4_ext_reachs(struct list *ipv4_reachs, struct stream *stream); -unsigned int tlv_add_te_ipv4_reachs(struct list *te_ipv4_reachs, - struct stream *stream, void *arg); -int tlv_add_ipv6_addrs(struct list *ipv6_addrs, struct stream *stream); -unsigned int tlv_add_ipv6_reachs(struct list *ipv6_reachs, - struct stream *stream, void *arg); - -int tlv_add_padding(struct stream *stream); - -#endif /* _ZEBRA_ISIS_TLV_H */ diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c new file mode 100644 index 0000000000..8efbcd2811 --- /dev/null +++ b/isisd/isis_tlvs.c @@ -0,0 +1,3090 @@ +/* + * IS-IS TLV Serializer/Deserializer + * + * Copyright (C) 2015,2017 Christian Franke + * + * This file is part of FRR. + * + * FRR 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. + * + * FRR 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 FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#include <zebra.h> + +#include "md5.h" +#include "memory.h" +#include "stream.h" +#include "sbuf.h" + +#include "isisd/isisd.h" +#include "isisd/isis_memory.h" +#include "isisd/isis_tlvs.h" +#include "isisd/isis_common.h" +#include "isisd/isis_mt.h" +#include "isisd/isis_misc.h" +#include "isisd/isis_adjacency.h" +#include "isisd/isis_circuit.h" +#include "isisd/isis_pdu.h" +#include "isisd/isis_lsp.h" +#include "isisd/isis_te.h" + +DEFINE_MTYPE_STATIC(ISISD, ISIS_TLV, "ISIS TLVs") +DEFINE_MTYPE_STATIC(ISISD, ISIS_SUBTLV, "ISIS Sub-TLVs") +DEFINE_MTYPE_STATIC(ISISD, ISIS_MT_ITEM_LIST, "ISIS MT Item Lists") + +typedef int (*unpack_tlv_func)(enum isis_tlv_context context, uint8_t tlv_type, + uint8_t tlv_len, struct stream *s, + struct sbuf *log, void *dest, int indent); +typedef int (*pack_item_func)(struct isis_item *item, struct stream *s); +typedef void (*free_item_func)(struct isis_item *i); +typedef int (*unpack_item_func)(uint16_t mtid, uint8_t len, struct stream *s, + struct sbuf *log, void *dest, int indent); +typedef void (*format_item_func)(uint16_t mtid, struct isis_item *i, + struct sbuf *buf, int indent); +typedef struct isis_item *(*copy_item_func)(struct isis_item *i); + +struct tlv_ops { + const char *name; + unpack_tlv_func unpack; + + pack_item_func pack_item; + free_item_func free_item; + unpack_item_func unpack_item; + format_item_func format_item; + copy_item_func copy_item; +}; + +enum how_to_pack { + ISIS_ITEMS, + ISIS_MT_ITEMS, +}; + +struct pack_order_entry { + enum isis_tlv_context context; + enum isis_tlv_type type; + enum how_to_pack how_to_pack; + size_t what_to_pack; +}; +#define PACK_ENTRY(t, h, w) \ + { \ + .context = ISIS_CONTEXT_LSP, .type = ISIS_TLV_##t, \ + .how_to_pack = (h), \ + .what_to_pack = offsetof(struct isis_tlvs, w), \ + } + +static struct pack_order_entry pack_order[] = { + PACK_ENTRY(OLDSTYLE_REACH, ISIS_ITEMS, oldstyle_reach), + PACK_ENTRY(LAN_NEIGHBORS, ISIS_ITEMS, lan_neighbor), + PACK_ENTRY(LSP_ENTRY, ISIS_ITEMS, lsp_entries), + PACK_ENTRY(EXTENDED_REACH, ISIS_ITEMS, extended_reach), + PACK_ENTRY(MT_REACH, ISIS_MT_ITEMS, mt_reach), + PACK_ENTRY(OLDSTYLE_IP_REACH, ISIS_ITEMS, oldstyle_ip_reach), + PACK_ENTRY(OLDSTYLE_IP_REACH_EXT, ISIS_ITEMS, oldstyle_ip_reach_ext), + PACK_ENTRY(IPV4_ADDRESS, ISIS_ITEMS, ipv4_address), + PACK_ENTRY(IPV6_ADDRESS, ISIS_ITEMS, ipv6_address), + PACK_ENTRY(EXTENDED_IP_REACH, ISIS_ITEMS, extended_ip_reach), + PACK_ENTRY(MT_IP_REACH, ISIS_MT_ITEMS, mt_ip_reach), + PACK_ENTRY(IPV6_REACH, ISIS_ITEMS, ipv6_reach), + PACK_ENTRY(MT_IPV6_REACH, ISIS_MT_ITEMS, mt_ipv6_reach)}; + +/* This is a forward definition. The table is actually initialized + * in at the bottom. */ +static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX]; + +/* End of _ops forward definition. */ + +/* Prototypes */ +static void append_item(struct isis_item_list *dest, struct isis_item *item); + +/* Functions for Sub-TVL ??? IPv6 Source Prefix */ + +static struct prefix_ipv6 *copy_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p) +{ + if (!p) + return NULL; + + struct prefix_ipv6 *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv)); + rv->family = p->family; + rv->prefixlen = p->prefixlen; + memcpy(&rv->prefix, &p->prefix, sizeof(rv->prefix)); + return rv; +} + +static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p, + struct sbuf *buf, int indent) +{ + if (!p) + return; + + char prefixbuf[PREFIX2STR_BUFFER]; + sbuf_push(buf, indent, "IPv6 Source Prefix: %s\n", + prefix2str(p, prefixbuf, sizeof(prefixbuf))); +} + +static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p, + struct stream *s) +{ + if (!p) + return 0; + + if (STREAM_WRITEABLE(s) < 3 + (unsigned)PSIZE(p->prefixlen)) + return 1; + + stream_putc(s, ISIS_SUBTLV_IPV6_SOURCE_PREFIX); + stream_putc(s, 1 + PSIZE(p->prefixlen)); + stream_putc(s, p->prefixlen); + stream_put(s, &p->prefix, PSIZE(p->prefixlen)); + return 0; +} + +static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context, + uint8_t tlv_type, uint8_t tlv_len, + struct stream *s, struct sbuf *log, + void *dest, int indent) +{ + struct isis_subtlvs *subtlvs = dest; + struct prefix_ipv6 p = { + .family = AF_INET6, + }; + + sbuf_push(log, indent, "Unpacking IPv6 Source Prefix Sub-TLV...\n"); + + if (tlv_len < 1) { + sbuf_push(log, indent, + "Not enough data left. (expected 1 or more bytes, got %" PRIu8 ")\n", + tlv_len); + return 1; + } + + p.prefixlen = stream_getc(s); + if (p.prefixlen > 128) { + sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv6\n", + p.prefixlen); + return 1; + } + + if (tlv_len != 1 + PSIZE(p.prefixlen)) { + sbuf_push( + log, indent, + "TLV size differs from expected size for the prefixlen. " + "(expected %u but got %" PRIu8 ")\n", + 1 + PSIZE(p.prefixlen), tlv_len); + return 1; + } + + stream_get(&p.prefix, s, PSIZE(p.prefixlen)); + + if (subtlvs->source_prefix) { + sbuf_push( + log, indent, + "WARNING: source prefix Sub-TLV present multiple times.\n"); + /* Ignore all but first occurrence of the source prefix Sub-TLV + */ + return 0; + } + + subtlvs->source_prefix = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(p)); + memcpy(subtlvs->source_prefix, &p, sizeof(p)); + return 0; +} + +/* Functions related to subtlvs */ + +static struct isis_subtlvs *isis_alloc_subtlvs(void) +{ + struct isis_subtlvs *result; + + result = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*result)); + + return result; +} + +static struct isis_subtlvs *copy_subtlvs(struct isis_subtlvs *subtlvs) +{ + if (!subtlvs) + return NULL; + + struct isis_subtlvs *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv)); + + rv->source_prefix = + copy_subtlv_ipv6_source_prefix(subtlvs->source_prefix); + return rv; +} + +static void format_subtlvs(struct isis_subtlvs *subtlvs, struct sbuf *buf, + int indent) +{ + format_subtlv_ipv6_source_prefix(subtlvs->source_prefix, buf, indent); +} + +static void isis_free_subtlvs(struct isis_subtlvs *subtlvs) +{ + if (!subtlvs) + return; + + XFREE(MTYPE_ISIS_SUBTLV, subtlvs->source_prefix); + + XFREE(MTYPE_ISIS_SUBTLV, subtlvs); +} + +static int pack_subtlvs(struct isis_subtlvs *subtlvs, struct stream *s) +{ + int rv; + size_t subtlv_len_pos = stream_get_endp(s); + + if (STREAM_WRITEABLE(s) < 1) + return 1; + + stream_putc(s, 0); /* Put 0 as subtlvs length, filled in later */ + + rv = pack_subtlv_ipv6_source_prefix(subtlvs->source_prefix, s); + if (rv) + return rv; + + size_t subtlv_len = stream_get_endp(s) - subtlv_len_pos - 1; + if (subtlv_len > 255) + return 1; + + stream_putc_at(s, subtlv_len_pos, subtlv_len); + return 0; +} + +static int unpack_tlvs(enum isis_tlv_context context, size_t avail_len, + struct stream *stream, struct sbuf *log, void *dest, + int indent); + +/* Functions related to TLVs 1 Area Addresses */ + +static struct isis_item *copy_item_area_address(struct isis_item *i) +{ + struct isis_area_address *addr = (struct isis_area_address *)i; + struct isis_area_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + + rv->len = addr->len; + memcpy(rv->addr, addr->addr, addr->len); + return (struct isis_item *)rv; +} + +static void format_item_area_address(uint16_t mtid, struct isis_item *i, + struct sbuf *buf, int indent) +{ + struct isis_area_address *addr = (struct isis_area_address *)i; + + sbuf_push(buf, indent, "Area Address: %s\n", + isonet_print(addr->addr, addr->len)); +} + +static void free_item_area_address(struct isis_item *i) +{ + XFREE(MTYPE_ISIS_TLV, i); +} + +static int pack_item_area_address(struct isis_item *i, struct stream *s) +{ + struct isis_area_address *addr = (struct isis_area_address *)i; + + if (STREAM_WRITEABLE(s) < (unsigned)1 + addr->len) + return 1; + stream_putc(s, addr->len); + stream_put(s, addr->addr, addr->len); + return 0; +} + +static int unpack_item_area_address(uint16_t mtid, uint8_t len, + struct stream *s, struct sbuf *log, + void *dest, int indent) +{ + struct isis_tlvs *tlvs = dest; + struct isis_area_address *rv = NULL; + + sbuf_push(log, indent, "Unpack area address...\n"); + if (len < 1) { + sbuf_push( + log, indent, + "Not enough data left. (Expected 1 byte of address length, got %" PRIu8 + ")\n", + len); + goto out; + } + + rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + rv->len = stream_getc(s); + + if (len < 1 + rv->len) { + sbuf_push(log, indent, "Not enough data left. (Expected %" PRIu8 + " bytes of address, got %" PRIu8 ")\n", + rv->len, len - 1); + goto out; + } + + if (rv->len < 1 || rv->len > 20) { + sbuf_push(log, indent, + "Implausible area address length %" PRIu8 "\n", + rv->len); + goto out; + } + + stream_get(rv->addr, s, rv->len); + + format_item_area_address(ISIS_MT_IPV4_UNICAST, (struct isis_item *)rv, + log, indent + 2); + append_item(&tlvs->area_addresses, (struct isis_item *)rv); + return 0; +out: + XFREE(MTYPE_ISIS_TLV, rv); + return 1; +} + +/* Functions related to TLV 2 (Old-Style) IS Reach */ +static struct isis_item *copy_item_oldstyle_reach(struct isis_item *i) +{ + struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i; + struct isis_oldstyle_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + + memcpy(rv->id, r->id, 7); + rv->metric = r->metric; + return (struct isis_item *)rv; +} + +static void format_item_oldstyle_reach(uint16_t mtid, struct isis_item *i, + struct sbuf *buf, int indent) +{ + struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i; + + sbuf_push(buf, indent, "IS Reachability: %s (Metric: %" PRIu8 ")\n", + isis_format_id(r->id, 7), r->metric); +} + +static void free_item_oldstyle_reach(struct isis_item *i) +{ + XFREE(MTYPE_ISIS_TLV, i); +} + +static int pack_item_oldstyle_reach(struct isis_item *i, struct stream *s) +{ + struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i; + + if (STREAM_WRITEABLE(s) < 11) + return 1; + + stream_putc(s, r->metric); + stream_putc(s, 0x80); /* delay metric - unsupported */ + stream_putc(s, 0x80); /* expense metric - unsupported */ + stream_putc(s, 0x80); /* error metric - unsupported */ + stream_put(s, r->id, 7); + + return 0; +} + +static int unpack_item_oldstyle_reach(uint16_t mtid, uint8_t len, + struct stream *s, struct sbuf *log, + void *dest, int indent) +{ + struct isis_tlvs *tlvs = dest; + + sbuf_push(log, indent, "Unpack oldstyle reach...\n"); + if (len < 11) { + sbuf_push( + log, indent, + "Not enough data left.(Expected 11 bytes of reach information, got %" PRIu8 + ")\n", + len); + return 1; + } + + struct isis_oldstyle_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + rv->metric = stream_getc(s); + if ((rv->metric & 0x3f) != rv->metric) { + sbuf_push(log, indent, "Metric has unplausible format\n"); + rv->metric &= 0x3f; + } + stream_forward_getp(s, 3); /* Skip other metrics */ + stream_get(rv->id, s, 7); + + format_item_oldstyle_reach(mtid, (struct isis_item *)rv, log, + indent + 2); + append_item(&tlvs->oldstyle_reach, (struct isis_item *)rv); + return 0; +} + +/* Functions related to TLV 6 LAN Neighbors */ +static struct isis_item *copy_item_lan_neighbor(struct isis_item *i) +{ + struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i; + struct isis_lan_neighbor *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + + memcpy(rv->mac, n->mac, 6); + return (struct isis_item *)rv; +} + +static void format_item_lan_neighbor(uint16_t mtid, struct isis_item *i, + struct sbuf *buf, int indent) +{ + struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i; + + sbuf_push(buf, indent, "LAN Neighbor: %s\n", isis_format_id(n->mac, 6)); +} + +static void free_item_lan_neighbor(struct isis_item *i) +{ + XFREE(MTYPE_ISIS_TLV, i); +} + +static int pack_item_lan_neighbor(struct isis_item *i, struct stream *s) +{ + struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i; + + if (STREAM_WRITEABLE(s) < 6) + return 1; + + stream_put(s, n->mac, 6); + + return 0; +} + +static int unpack_item_lan_neighbor(uint16_t mtid, uint8_t len, + struct stream *s, struct sbuf *log, + void *dest, int indent) +{ + struct isis_tlvs *tlvs = dest; + + sbuf_push(log, indent, "Unpack LAN neighbor...\n"); + if (len < 6) { + sbuf_push( + log, indent, + "Not enough data left.(Expected 6 bytes of mac, got %" PRIu8 + ")\n", + len); + return 1; + } + + struct isis_lan_neighbor *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + stream_get(rv->mac, s, 6); + + format_item_lan_neighbor(mtid, (struct isis_item *)rv, log, indent + 2); + append_item(&tlvs->lan_neighbor, (struct isis_item *)rv); + return 0; +} + +/* Functions related to TLV 9 LSP Entry */ +static struct isis_item *copy_item_lsp_entry(struct isis_item *i) +{ + struct isis_lsp_entry *e = (struct isis_lsp_entry *)i; + struct isis_lsp_entry *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + + rv->rem_lifetime = e->rem_lifetime; + memcpy(rv->id, e->id, sizeof(rv->id)); + rv->seqno = e->seqno; + rv->checksum = e->checksum; + + return (struct isis_item *)rv; +} + +static void format_item_lsp_entry(uint16_t mtid, struct isis_item *i, + struct sbuf *buf, int indent) +{ + struct isis_lsp_entry *e = (struct isis_lsp_entry *)i; + + sbuf_push(buf, indent, "LSP Entry: %s, seq 0x%08" PRIx32 + ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 "s\n", + isis_format_id(e->id, 8), e->seqno, e->checksum, + e->rem_lifetime); +} + +static void free_item_lsp_entry(struct isis_item *i) +{ + XFREE(MTYPE_ISIS_TLV, i); +} + +static int pack_item_lsp_entry(struct isis_item *i, struct stream *s) +{ + struct isis_lsp_entry *e = (struct isis_lsp_entry *)i; + + if (STREAM_WRITEABLE(s) < 16) + return 1; + + stream_putw(s, e->rem_lifetime); + stream_put(s, e->id, 8); + stream_putl(s, e->seqno); + stream_putw(s, e->checksum); + + return 0; +} + +static int unpack_item_lsp_entry(uint16_t mtid, uint8_t len, struct stream *s, + struct sbuf *log, void *dest, int indent) +{ + struct isis_tlvs *tlvs = dest; + + sbuf_push(log, indent, "Unpack LSP entry...\n"); + if (len < 16) { + sbuf_push( + log, indent, + "Not enough data left. (Expected 16 bytes of LSP info, got %" PRIu8, + len); + return 1; + } + + struct isis_lsp_entry *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + rv->rem_lifetime = stream_getw(s); + stream_get(rv->id, s, 8); + rv->seqno = stream_getl(s); + rv->checksum = stream_getw(s); + + format_item_lsp_entry(mtid, (struct isis_item *)rv, log, indent + 2); + append_item(&tlvs->lsp_entries, (struct isis_item *)rv); + return 0; +} + +/* Functions related to TLVs 22/222 Extended Reach/MT Reach */ + +static struct isis_item *copy_item_extended_reach(struct isis_item *i) +{ + struct isis_extended_reach *r = (struct isis_extended_reach *)i; + struct isis_extended_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + + memcpy(rv->id, r->id, 7); + rv->metric = r->metric; + + if (r->subtlvs && r->subtlv_len) { + rv->subtlvs = XCALLOC(MTYPE_ISIS_TLV, r->subtlv_len); + memcpy(rv->subtlvs, r->subtlvs, r->subtlv_len); + rv->subtlv_len = r->subtlv_len; + } + + return (struct isis_item *)rv; +} + +static void format_item_extended_reach(uint16_t mtid, struct isis_item *i, + struct sbuf *buf, int indent) +{ + struct isis_extended_reach *r = (struct isis_extended_reach *)i; + + sbuf_push(buf, indent, "%s Reachability: %s (Metric: %u)", + (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT", + isis_format_id(r->id, 7), r->metric); + if (mtid != ISIS_MT_IPV4_UNICAST) + sbuf_push(buf, 0, " %s", isis_mtid2str(mtid)); + sbuf_push(buf, 0, "\n"); + + if (r->subtlv_len && r->subtlvs) + mpls_te_print_detail(buf, indent + 2, r->subtlvs, r->subtlv_len); +} + +static void free_item_extended_reach(struct isis_item *i) +{ + struct isis_extended_reach *item = (struct isis_extended_reach *)i; + XFREE(MTYPE_ISIS_TLV, item->subtlvs); + XFREE(MTYPE_ISIS_TLV, item); +} + +static int pack_item_extended_reach(struct isis_item *i, struct stream *s) +{ + struct isis_extended_reach *r = (struct isis_extended_reach *)i; + + if (STREAM_WRITEABLE(s) < 11 + (unsigned)r->subtlv_len) + return 1; + stream_put(s, r->id, sizeof(r->id)); + stream_put3(s, r->metric); + stream_putc(s, r->subtlv_len); + stream_put(s, r->subtlvs, r->subtlv_len); + return 0; +} + +static int unpack_item_extended_reach(uint16_t mtid, uint8_t len, + struct stream *s, struct sbuf *log, + void *dest, int indent) +{ + struct isis_tlvs *tlvs = dest; + struct isis_extended_reach *rv = NULL; + uint8_t subtlv_len; + struct isis_item_list *items; + + if (mtid == ISIS_MT_IPV4_UNICAST) { + items = &tlvs->extended_reach; + } else { + items = isis_get_mt_items(&tlvs->mt_reach, mtid); + } + + sbuf_push(log, indent, "Unpacking %s reachability...\n", + (mtid == ISIS_MT_IPV4_UNICAST) ? "extended" : "mt"); + + if (len < 11) { + sbuf_push(log, indent, + "Not enough data left. (expected 11 or more bytes, got %" + PRIu8 ")\n", + len); + goto out; + } + + rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + stream_get(rv->id, s, 7); + rv->metric = stream_get3(s); + subtlv_len = stream_getc(s); + + format_item_extended_reach(mtid, (struct isis_item *)rv, log, + indent + 2); + + if ((size_t)len < ((size_t)11) + subtlv_len) { + sbuf_push(log, indent, + "Not enough data left for subtlv size %" PRIu8 + ", there are only %" PRIu8 " bytes left.\n", + subtlv_len, len - 11); + goto out; + } + + sbuf_push(log, indent, "Storing %" PRIu8 " bytes of subtlvs\n", + subtlv_len); + + if (subtlv_len) { + size_t subtlv_start = stream_get_getp(s); + + if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_NE_REACH, subtlv_len, s, + log, NULL, indent + 4)) { + goto out; + } + + stream_set_getp(s, subtlv_start); + + rv->subtlvs = XCALLOC(MTYPE_ISIS_TLV, subtlv_len); + stream_get(rv->subtlvs, s, subtlv_len); + rv->subtlv_len = subtlv_len; + } + + append_item(items, (struct isis_item *)rv); + return 0; +out: + if (rv) + free_item_extended_reach((struct isis_item *)rv); + + return 1; +} + +/* Functions related to TLV 128 (Old-Style) IP Reach */ +static struct isis_item *copy_item_oldstyle_ip_reach(struct isis_item *i) +{ + struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i; + struct isis_oldstyle_ip_reach *rv = + XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + + rv->metric = r->metric; + rv->prefix = r->prefix; + return (struct isis_item *)rv; +} + +static void format_item_oldstyle_ip_reach(uint16_t mtid, struct isis_item *i, + struct sbuf *buf, int indent) +{ + struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i; + char prefixbuf[PREFIX2STR_BUFFER]; + + sbuf_push(buf, indent, "IP Reachability: %s (Metric: %" PRIu8 ")\n", + prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), r->metric); +} + +static void free_item_oldstyle_ip_reach(struct isis_item *i) +{ + XFREE(MTYPE_ISIS_TLV, i); +} + +static int pack_item_oldstyle_ip_reach(struct isis_item *i, struct stream *s) +{ + struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i; + + if (STREAM_WRITEABLE(s) < 12) + return 1; + + stream_putc(s, r->metric); + stream_putc(s, 0x80); /* delay metric - unsupported */ + stream_putc(s, 0x80); /* expense metric - unsupported */ + stream_putc(s, 0x80); /* error metric - unsupported */ + stream_put(s, &r->prefix.prefix, 4); + + struct in_addr mask; + masklen2ip(r->prefix.prefixlen, &mask); + stream_put(s, &mask, sizeof(mask)); + + return 0; +} + +static int unpack_item_oldstyle_ip_reach(uint16_t mtid, uint8_t len, + struct stream *s, struct sbuf *log, + void *dest, int indent) +{ + sbuf_push(log, indent, "Unpack oldstyle ip reach...\n"); + if (len < 12) { + sbuf_push( + log, indent, + "Not enough data left.(Expected 12 bytes of reach information, got %" PRIu8 + ")\n", + len); + return 1; + } + + struct isis_oldstyle_ip_reach *rv = + XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + rv->metric = stream_getc(s); + if ((rv->metric & 0x7f) != rv->metric) { + sbuf_push(log, indent, "Metric has unplausible format\n"); + rv->metric &= 0x7f; + } + stream_forward_getp(s, 3); /* Skip other metrics */ + rv->prefix.family = AF_INET; + stream_get(&rv->prefix.prefix, s, 4); + + struct in_addr mask; + stream_get(&mask, s, 4); + rv->prefix.prefixlen = ip_masklen(mask); + + format_item_oldstyle_ip_reach(mtid, (struct isis_item *)rv, log, + indent + 2); + append_item(dest, (struct isis_item *)rv); + return 0; +} + + +/* Functions related to TLV 129 protocols supported */ + +static void copy_tlv_protocols_supported(struct isis_protocols_supported *src, + struct isis_protocols_supported *dest) +{ + if (!src->protocols || !src->count) + return; + dest->count = src->count; + dest->protocols = XCALLOC(MTYPE_ISIS_TLV, src->count); + memcpy(dest->protocols, src->protocols, src->count); +} + +static void format_tlv_protocols_supported(struct isis_protocols_supported *p, + struct sbuf *buf, int indent) +{ + if (!p || !p->count || !p->protocols) + return; + + sbuf_push(buf, indent, "Protocols Supported: "); + for (uint8_t i = 0; i < p->count; i++) { + sbuf_push(buf, 0, "%s%s", nlpid2str(p->protocols[i]), + (i + 1 < p->count) ? ", " : ""); + } + sbuf_push(buf, 0, "\n"); +} + +static void free_tlv_protocols_supported(struct isis_protocols_supported *p) +{ + XFREE(MTYPE_ISIS_TLV, p->protocols); +} + +static int pack_tlv_protocols_supported(struct isis_protocols_supported *p, + struct stream *s) +{ + if (!p || !p->count || !p->protocols) + return 0; + + if (STREAM_WRITEABLE(s) < (unsigned)(p->count + 2)) + return 1; + + stream_putc(s, ISIS_TLV_PROTOCOLS_SUPPORTED); + stream_putc(s, p->count); + stream_put(s, p->protocols, p->count); + return 0; +} + +static int unpack_tlv_protocols_supported(enum isis_tlv_context context, + uint8_t tlv_type, uint8_t tlv_len, + struct stream *s, struct sbuf *log, + void *dest, int indent) +{ + struct isis_tlvs *tlvs = dest; + + sbuf_push(log, indent, "Unpacking Protocols Supported TLV...\n"); + if (!tlv_len) { + sbuf_push(log, indent, "WARNING: No protocols included\n"); + return 0; + } + if (tlvs->protocols_supported.protocols) { + sbuf_push( + log, indent, + "WARNING: protocols supported TLV present multiple times.\n"); + stream_forward_getp(s, tlv_len); + return 0; + } + + tlvs->protocols_supported.count = tlv_len; + tlvs->protocols_supported.protocols = XCALLOC(MTYPE_ISIS_TLV, tlv_len); + stream_get(tlvs->protocols_supported.protocols, s, tlv_len); + + format_tlv_protocols_supported(&tlvs->protocols_supported, log, + indent + 2); + return 0; +} + +/* Functions related to TLV 132 IPv4 Interface addresses */ +static struct isis_item *copy_item_ipv4_address(struct isis_item *i) +{ + struct isis_ipv4_address *a = (struct isis_ipv4_address *)i; + struct isis_ipv4_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + + rv->addr = a->addr; + return (struct isis_item *)rv; +} + +static void format_item_ipv4_address(uint16_t mtid, struct isis_item *i, + struct sbuf *buf, int indent) +{ + struct isis_ipv4_address *a = (struct isis_ipv4_address *)i; + char addrbuf[INET_ADDRSTRLEN]; + + inet_ntop(AF_INET, &a->addr, addrbuf, sizeof(addrbuf)); + sbuf_push(buf, indent, "IPv4 Interface Address: %s\n", addrbuf); +} + +static void free_item_ipv4_address(struct isis_item *i) +{ + XFREE(MTYPE_ISIS_TLV, i); +} + +static int pack_item_ipv4_address(struct isis_item *i, struct stream *s) +{ + struct isis_ipv4_address *a = (struct isis_ipv4_address *)i; + + if (STREAM_WRITEABLE(s) < 4) + return 1; + + stream_put(s, &a->addr, 4); + + return 0; +} + +static int unpack_item_ipv4_address(uint16_t mtid, uint8_t len, + struct stream *s, struct sbuf *log, + void *dest, int indent) +{ + struct isis_tlvs *tlvs = dest; + + sbuf_push(log, indent, "Unpack IPv4 Interface address...\n"); + if (len < 4) { + sbuf_push( + log, indent, + "Not enough data left.(Expected 4 bytes of IPv4 address, got %" PRIu8 + ")\n", + len); + return 1; + } + + struct isis_ipv4_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + stream_get(&rv->addr, s, 4); + + format_item_ipv4_address(mtid, (struct isis_item *)rv, log, indent + 2); + append_item(&tlvs->ipv4_address, (struct isis_item *)rv); + return 0; +} + + +/* Functions related to TLV 232 IPv6 Interface addresses */ +static struct isis_item *copy_item_ipv6_address(struct isis_item *i) +{ + struct isis_ipv6_address *a = (struct isis_ipv6_address *)i; + struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + + rv->addr = a->addr; + return (struct isis_item *)rv; +} + +static void format_item_ipv6_address(uint16_t mtid, struct isis_item *i, + struct sbuf *buf, int indent) +{ + struct isis_ipv6_address *a = (struct isis_ipv6_address *)i; + char addrbuf[INET6_ADDRSTRLEN]; + + inet_ntop(AF_INET6, &a->addr, addrbuf, sizeof(addrbuf)); + sbuf_push(buf, indent, "IPv6 Interface Address: %s\n", addrbuf); +} + +static void free_item_ipv6_address(struct isis_item *i) +{ + XFREE(MTYPE_ISIS_TLV, i); +} + +static int pack_item_ipv6_address(struct isis_item *i, struct stream *s) +{ + struct isis_ipv6_address *a = (struct isis_ipv6_address *)i; + + if (STREAM_WRITEABLE(s) < 16) + return 1; + + stream_put(s, &a->addr, 16); + + return 0; +} + +static int unpack_item_ipv6_address(uint16_t mtid, uint8_t len, + struct stream *s, struct sbuf *log, + void *dest, int indent) +{ + struct isis_tlvs *tlvs = dest; + + sbuf_push(log, indent, "Unpack IPv6 Interface address...\n"); + if (len < 16) { + sbuf_push( + log, indent, + "Not enough data left.(Expected 16 bytes of IPv6 address, got %" PRIu8 + ")\n", + len); + return 1; + } + + struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + stream_get(&rv->addr, s, 16); + + format_item_ipv6_address(mtid, (struct isis_item *)rv, log, indent + 2); + append_item(&tlvs->ipv6_address, (struct isis_item *)rv); + return 0; +} + + +/* Functions related to TLV 229 MT Router information */ +static struct isis_item *copy_item_mt_router_info(struct isis_item *i) +{ + struct isis_mt_router_info *info = (struct isis_mt_router_info *)i; + struct isis_mt_router_info *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + + rv->overload = info->overload; + rv->attached = info->attached; + rv->mtid = info->mtid; + return (struct isis_item *)rv; +} + +static void format_item_mt_router_info(uint16_t mtid, struct isis_item *i, + struct sbuf *buf, int indent) +{ + struct isis_mt_router_info *info = (struct isis_mt_router_info *)i; + + sbuf_push(buf, indent, "MT Router Info: %s%s%s\n", + isis_mtid2str(info->mtid), + info->overload ? " Overload" : "", + info->attached ? " Attached" : ""); +} + +static void free_item_mt_router_info(struct isis_item *i) +{ + XFREE(MTYPE_ISIS_TLV, i); +} + +static int pack_item_mt_router_info(struct isis_item *i, struct stream *s) +{ + struct isis_mt_router_info *info = (struct isis_mt_router_info *)i; + + if (STREAM_WRITEABLE(s) < 2) + return 1; + + uint16_t entry = info->mtid; + + if (info->overload) + entry |= ISIS_MT_OL_MASK; + if (info->attached) + entry |= ISIS_MT_AT_MASK; + + stream_putw(s, entry); + + return 0; +} + +static int unpack_item_mt_router_info(uint16_t mtid, uint8_t len, + struct stream *s, struct sbuf *log, + void *dest, int indent) +{ + struct isis_tlvs *tlvs = dest; + + sbuf_push(log, indent, "Unpack MT Router info...\n"); + if (len < 2) { + sbuf_push( + log, indent, + "Not enough data left.(Expected 2 bytes of MT info, got %" PRIu8 + ")\n", + len); + return 1; + } + + struct isis_mt_router_info *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + + uint16_t entry = stream_getw(s); + rv->overload = entry & ISIS_MT_OL_MASK; + rv->attached = entry & ISIS_MT_AT_MASK; + rv->mtid = entry & ISIS_MT_MASK; + + format_item_mt_router_info(mtid, (struct isis_item *)rv, log, + indent + 2); + append_item(&tlvs->mt_router_info, (struct isis_item *)rv); + return 0; +} + +/* Functions related to TLV 134 TE Router ID */ + +static struct in_addr *copy_tlv_te_router_id(const struct in_addr *id) +{ + if (!id) + return NULL; + + struct in_addr *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + memcpy(rv, id, sizeof(*rv)); + return rv; +} + +static void format_tlv_te_router_id(const struct in_addr *id, struct sbuf *buf, + int indent) +{ + if (!id) + return; + + char addrbuf[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, id, addrbuf, sizeof(addrbuf)); + sbuf_push(buf, indent, "TE Router ID: %s\n", addrbuf); +} + +static void free_tlv_te_router_id(struct in_addr *id) +{ + XFREE(MTYPE_ISIS_TLV, id); +} + +static int pack_tlv_te_router_id(const struct in_addr *id, struct stream *s) +{ + if (!id) + return 0; + + if (STREAM_WRITEABLE(s) < (unsigned)(2 + sizeof(*id))) + return 1; + + stream_putc(s, ISIS_TLV_TE_ROUTER_ID); + stream_putc(s, 4); + stream_put(s, id, 4); + return 0; +} + +static int unpack_tlv_te_router_id(enum isis_tlv_context context, + uint8_t tlv_type, uint8_t tlv_len, + struct stream *s, struct sbuf *log, + void *dest, int indent) +{ + struct isis_tlvs *tlvs = dest; + + sbuf_push(log, indent, "Unpacking TE Router ID TLV...\n"); + if (tlv_len != 4) { + sbuf_push(log, indent, "WARNING: Length invalid\n"); + return 1; + } + + if (tlvs->te_router_id) { + sbuf_push(log, indent, + "WARNING: TE Router ID present multiple times.\n"); + stream_forward_getp(s, tlv_len); + return 0; + } + + tlvs->te_router_id = XCALLOC(MTYPE_ISIS_TLV, 4); + stream_get(tlvs->te_router_id, s, 4); + format_tlv_te_router_id(tlvs->te_router_id, log, indent + 2); + return 0; +} + + +/* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */ + +static struct isis_item *copy_item_extended_ip_reach(struct isis_item *i) +{ + struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i; + struct isis_extended_ip_reach *rv = + XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + + rv->metric = r->metric; + rv->down = r->down; + rv->prefix = r->prefix; + + return (struct isis_item *)rv; +} + +static void format_item_extended_ip_reach(uint16_t mtid, struct isis_item *i, + struct sbuf *buf, int indent) +{ + struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i; + char prefixbuf[PREFIX2STR_BUFFER]; + + sbuf_push(buf, indent, "%s IP Reachability: %s (Metric: %u)%s", + (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT", + prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), r->metric, + r->down ? " Down" : ""); + if (mtid != ISIS_MT_IPV4_UNICAST) + sbuf_push(buf, 0, " %s", isis_mtid2str(mtid)); + sbuf_push(buf, 0, "\n"); +} + +static void free_item_extended_ip_reach(struct isis_item *i) +{ + struct isis_extended_ip_reach *item = + (struct isis_extended_ip_reach *)i; + XFREE(MTYPE_ISIS_TLV, item); +} + +static int pack_item_extended_ip_reach(struct isis_item *i, struct stream *s) +{ + struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i; + uint8_t control; + + if (STREAM_WRITEABLE(s) < 5) + return 1; + stream_putl(s, r->metric); + + control = r->down ? ISIS_EXTENDED_IP_REACH_DOWN : 0; + control |= r->prefix.prefixlen; + stream_putc(s, control); + + if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen)) + return 1; + stream_put(s, &r->prefix.prefix.s_addr, PSIZE(r->prefix.prefixlen)); + return 0; +} + +static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len, + struct stream *s, struct sbuf *log, + void *dest, int indent) +{ + struct isis_tlvs *tlvs = dest; + struct isis_extended_ip_reach *rv = NULL; + size_t consume; + uint8_t control, subtlv_len; + struct isis_item_list *items; + + if (mtid == ISIS_MT_IPV4_UNICAST) { + items = &tlvs->extended_ip_reach; + } else { + items = isis_get_mt_items(&tlvs->mt_ip_reach, mtid); + } + + sbuf_push(log, indent, "Unpacking %s IPv4 reachability...\n", + (mtid == ISIS_MT_IPV4_UNICAST) ? "extended" : "mt"); + + consume = 5; + if (len < consume) { + sbuf_push(log, indent, + "Not enough data left. (expected 5 or more bytes, got %" PRIu8 ")\n", + len); + goto out; + } + + rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + + rv->metric = stream_getl(s); + control = stream_getc(s); + rv->down = (control & ISIS_EXTENDED_IP_REACH_DOWN); + rv->prefix.family = AF_INET; + rv->prefix.prefixlen = control & 0x3f; + if (rv->prefix.prefixlen > 32) { + sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv4\n", + rv->prefix.prefixlen); + goto out; + } + + consume += PSIZE(rv->prefix.prefixlen); + if (len < consume) { + sbuf_push(log, indent, + "Expected %u bytes of prefix, but only %u bytes available.\n", + PSIZE(rv->prefix.prefixlen), len - 5); + goto out; + } + stream_get(&rv->prefix.prefix.s_addr, s, PSIZE(rv->prefix.prefixlen)); + in_addr_t orig_prefix = rv->prefix.prefix.s_addr; + apply_mask_ipv4(&rv->prefix); + if (orig_prefix != rv->prefix.prefix.s_addr) + sbuf_push(log, indent + 2, + "WARNING: Prefix had hostbits set.\n"); + format_item_extended_ip_reach(mtid, (struct isis_item *)rv, log, + indent + 2); + + if (control & ISIS_EXTENDED_IP_REACH_SUBTLV) { + consume += 1; + if (len < consume) { + sbuf_push(log, indent, + "Expected 1 byte of subtlv len, but no more data present.\n"); + goto out; + } + subtlv_len = stream_getc(s); + + if (!subtlv_len) { + sbuf_push(log, indent + 2, + " WARNING: subtlv bit is set, but there are no subtlvs.\n"); + } + consume += subtlv_len; + if (len < consume) { + sbuf_push(log, indent, + "Expected %" PRIu8 + " bytes of subtlvs, but only %u bytes available.\n", + subtlv_len, + len - 6 - PSIZE(rv->prefix.prefixlen)); + goto out; + } + sbuf_push(log, indent, "Skipping %" PRIu8 " bytes of subvls", + subtlv_len); + stream_forward_getp(s, subtlv_len); + } + + append_item(items, (struct isis_item *)rv); + return 0; +out: + if (rv) + free_item_extended_ip_reach((struct isis_item *)rv); + return 1; +} + +/* Functions related to TLV 137 Dynamic Hostname */ + +static char *copy_tlv_dynamic_hostname(const char *hostname) +{ + if (!hostname) + return NULL; + + return XSTRDUP(MTYPE_ISIS_TLV, hostname); +} + +static void format_tlv_dynamic_hostname(const char *hostname, struct sbuf *buf, + int indent) +{ + if (!hostname) + return; + + sbuf_push(buf, indent, "Hostname: %s\n", hostname); +} + +static void free_tlv_dynamic_hostname(char *hostname) +{ + XFREE(MTYPE_ISIS_TLV, hostname); +} + +static int pack_tlv_dynamic_hostname(const char *hostname, struct stream *s) +{ + if (!hostname) + return 0; + + uint8_t name_len = strlen(hostname); + + if (STREAM_WRITEABLE(s) < (unsigned)(2 + name_len)) + return 1; + + stream_putc(s, ISIS_TLV_DYNAMIC_HOSTNAME); + stream_putc(s, name_len); + stream_put(s, hostname, name_len); + return 0; +} + +static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context, + uint8_t tlv_type, uint8_t tlv_len, + struct stream *s, struct sbuf *log, + void *dest, int indent) +{ + struct isis_tlvs *tlvs = dest; + + sbuf_push(log, indent, "Unpacking Dynamic Hostname TLV...\n"); + if (!tlv_len) { + sbuf_push(log, indent, "WARNING: No hostname included\n"); + return 0; + } + + if (tlvs->hostname) { + sbuf_push(log, indent, + "WARNING: Hostname present multiple times.\n"); + stream_forward_getp(s, tlv_len); + return 0; + } + + tlvs->hostname = XCALLOC(MTYPE_ISIS_TLV, tlv_len + 1); + stream_get(tlvs->hostname, s, tlv_len); + tlvs->hostname[tlv_len] = '\0'; + + bool sane = true; + for (uint8_t i = 0; i < tlv_len; i++) { + if ((unsigned char)tlvs->hostname[i] > 127 + || !isprint(tlvs->hostname[i])) { + sane = false; + tlvs->hostname[i] = '?'; + } + } + if (!sane) { + sbuf_push( + log, indent, + "WARNING: Hostname contained non-printable/non-ascii characters.\n"); + } + + return 0; +} + +/* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */ + +static struct isis_item *copy_item_ipv6_reach(struct isis_item *i) +{ + struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i; + struct isis_ipv6_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + rv->metric = r->metric; + rv->down = r->down; + rv->external = r->external; + rv->prefix = r->prefix; + rv->subtlvs = copy_subtlvs(r->subtlvs); + + return (struct isis_item *)rv; +} + +static void format_item_ipv6_reach(uint16_t mtid, struct isis_item *i, + struct sbuf *buf, int indent) +{ + struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i; + char prefixbuf[PREFIX2STR_BUFFER]; + + sbuf_push(buf, indent, "%sIPv6 Reachability: %s (Metric: %u)%s%s", + (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "MT ", + prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), + r->metric, + r->down ? " Down" : "", + r->external ? " External" : ""); + if (mtid != ISIS_MT_IPV4_UNICAST) + sbuf_push(buf, 0, " %s", isis_mtid2str(mtid)); + sbuf_push(buf, 0, "\n"); + + if (r->subtlvs) { + sbuf_push(buf, indent, " Subtlvs:\n"); + format_subtlvs(r->subtlvs, buf, indent + 4); + } +} + +static void free_item_ipv6_reach(struct isis_item *i) +{ + struct isis_ipv6_reach *item = (struct isis_ipv6_reach *)i; + + isis_free_subtlvs(item->subtlvs); + XFREE(MTYPE_ISIS_TLV, item); +} + +static int pack_item_ipv6_reach(struct isis_item *i, struct stream *s) +{ + struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i; + uint8_t control; + + if (STREAM_WRITEABLE(s) < 6) + return 1; + stream_putl(s, r->metric); + + control = r->down ? ISIS_IPV6_REACH_DOWN : 0; + control |= r->external ? ISIS_IPV6_REACH_EXTERNAL : 0; + control |= r->subtlvs ? ISIS_IPV6_REACH_SUBTLV : 0; + + stream_putc(s, control); + stream_putc(s, r->prefix.prefixlen); + + if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen)) + return 1; + stream_put(s, &r->prefix.prefix.s6_addr, PSIZE(r->prefix.prefixlen)); + + if (r->subtlvs) + return pack_subtlvs(r->subtlvs, s); + + return 0; +} + +static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s, + struct sbuf *log, void *dest, int indent) +{ + struct isis_tlvs *tlvs = dest; + struct isis_ipv6_reach *rv = NULL; + size_t consume; + uint8_t control, subtlv_len; + struct isis_item_list *items; + + if (mtid == ISIS_MT_IPV4_UNICAST) { + items = &tlvs->ipv6_reach; + } else { + items = isis_get_mt_items(&tlvs->mt_ipv6_reach, mtid); + } + + sbuf_push(log, indent, "Unpacking %sIPv6 reachability...\n", + (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "mt "); + consume = 6; + if (len < consume) { + sbuf_push(log, indent, + "Not enough data left. (expected 6 or more bytes, got %" + PRIu8 ")\n", + len); + goto out; + } + + rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + + rv->metric = stream_getl(s); + control = stream_getc(s); + rv->down = (control & ISIS_IPV6_REACH_DOWN); + rv->external = (control & ISIS_IPV6_REACH_EXTERNAL); + + rv->prefix.family = AF_INET6; + rv->prefix.prefixlen = stream_getc(s); + if (rv->prefix.prefixlen > 128) { + sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv6\n", + rv->prefix.prefixlen); + goto out; + } + + consume += PSIZE(rv->prefix.prefixlen); + if (len < consume) { + sbuf_push(log, indent, + "Expected %u bytes of prefix, but only %u bytes available.\n", + PSIZE(rv->prefix.prefixlen), len - 6); + goto out; + } + stream_get(&rv->prefix.prefix.s6_addr, s, PSIZE(rv->prefix.prefixlen)); + struct in6_addr orig_prefix = rv->prefix.prefix; + apply_mask_ipv6(&rv->prefix); + if (memcmp(&orig_prefix, &rv->prefix.prefix, sizeof(orig_prefix))) + sbuf_push(log, indent + 2, + "WARNING: Prefix had hostbits set.\n"); + format_item_ipv6_reach(mtid, (struct isis_item *)rv, log, indent + 2); + + if (control & ISIS_IPV6_REACH_SUBTLV) { + consume += 1; + if (len < consume) { + sbuf_push(log, indent, + "Expected 1 byte of subtlv len, but no more data persent.\n"); + goto out; + } + subtlv_len = stream_getc(s); + + if (!subtlv_len) { + sbuf_push(log, indent + 2, + " WARNING: subtlv bit set, but there are no subtlvs.\n"); + } + consume += subtlv_len; + if (len < consume) { + sbuf_push(log, indent, + "Expected %" PRIu8 + " bytes of subtlvs, but only %u bytes available.\n", + subtlv_len, + len - 6 - PSIZE(rv->prefix.prefixlen)); + goto out; + } + + rv->subtlvs = isis_alloc_subtlvs(); + if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH, subtlv_len, s, + log, rv->subtlvs, indent + 4)) { + goto out; + } + } + + append_item(items, (struct isis_item *)rv); + return 0; +out: + if (rv) + free_item_ipv6_reach((struct isis_item *)rv); + return 1; +} + +/* Functions related to TLV 10 Authentication */ +static struct isis_item *copy_item_auth(struct isis_item *i) +{ + struct isis_auth *auth = (struct isis_auth *)i; + struct isis_auth *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + + rv->type = auth->type; + rv->length = auth->length; + memcpy(rv->value, auth->value, sizeof(rv->value)); + return (struct isis_item *)rv; +} + +static void format_item_auth(uint16_t mtid, struct isis_item *i, + struct sbuf *buf, int indent) +{ + struct isis_auth *auth = (struct isis_auth *)i; + char obuf[768]; + + sbuf_push(buf, indent, "Authentication:\n"); + switch (auth->type) { + case ISIS_PASSWD_TYPE_CLEARTXT: + zlog_sanitize(obuf, sizeof(obuf), auth->value, auth->length); + sbuf_push(buf, indent, " Password: %s\n", obuf); + break; + case ISIS_PASSWD_TYPE_HMAC_MD5: + for (unsigned int i = 0; i < 16; i++) { + snprintf(obuf + 2 * i, sizeof(obuf) - 2 * i, + "%02" PRIx8, auth->value[i]); + } + sbuf_push(buf, indent, " HMAC-MD5: %s\n", obuf); + break; + default: + sbuf_push(buf, indent, " Unknown (%" PRIu8 ")\n", auth->type); + break; + }; +} + +static void free_item_auth(struct isis_item *i) +{ + XFREE(MTYPE_ISIS_TLV, i); +} + +static int pack_item_auth(struct isis_item *i, struct stream *s) +{ + struct isis_auth *auth = (struct isis_auth *)i; + + if (STREAM_WRITEABLE(s) < 1) + return 1; + stream_putc(s, auth->type); + + switch (auth->type) { + case ISIS_PASSWD_TYPE_CLEARTXT: + if (STREAM_WRITEABLE(s) < auth->length) + return 1; + stream_put(s, auth->passwd, auth->length); + break; + case ISIS_PASSWD_TYPE_HMAC_MD5: + if (STREAM_WRITEABLE(s) < 16) + return 1; + auth->offset = stream_get_endp(s); + stream_put(s, NULL, 16); + break; + default: + return 1; + } + + return 0; +} + +static int unpack_item_auth(uint16_t mtid, uint8_t len, struct stream *s, + struct sbuf *log, void *dest, int indent) +{ + struct isis_tlvs *tlvs = dest; + + sbuf_push(log, indent, "Unpack Auth TLV...\n"); + if (len < 1) { + sbuf_push( + log, indent, + "Not enough data left.(Expected 1 bytes of auth type, got %" PRIu8 + ")\n", + len); + return 1; + } + + struct isis_auth *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + + rv->type = stream_getc(s); + rv->length = len - 1; + + if (rv->type == ISIS_PASSWD_TYPE_HMAC_MD5 && rv->length != 16) { + sbuf_push( + log, indent, + "Unexpected auth length for HMAC-MD5 (expected 16, got %" PRIu8 + ")\n", + rv->length); + XFREE(MTYPE_ISIS_TLV, rv); + return 1; + } + + rv->offset = stream_get_getp(s); + stream_get(rv->value, s, rv->length); + format_item_auth(mtid, (struct isis_item *)rv, log, indent + 2); + append_item(&tlvs->isis_auth, (struct isis_item *)rv); + return 0; +} + +/* Functions relating to item TLVs */ + +static void init_item_list(struct isis_item_list *items) +{ + items->head = NULL; + items->tail = &items->head; + items->count = 0; +} + +static struct isis_item *copy_item(enum isis_tlv_context context, + enum isis_tlv_type type, + struct isis_item *item) +{ + const struct tlv_ops *ops = tlv_table[context][type]; + + if (ops && ops->copy_item) + return ops->copy_item(item); + + assert(!"Unknown item tlv type!"); + return NULL; +} + +static void copy_items(enum isis_tlv_context context, enum isis_tlv_type type, + struct isis_item_list *src, struct isis_item_list *dest) +{ + struct isis_item *item; + + init_item_list(dest); + + for (item = src->head; item; item = item->next) { + append_item(dest, copy_item(context, type, item)); + } +} + +static void format_item(uint16_t mtid, enum isis_tlv_context context, + enum isis_tlv_type type, struct isis_item *i, + struct sbuf *buf, int indent) +{ + const struct tlv_ops *ops = tlv_table[context][type]; + + if (ops && ops->format_item) { + ops->format_item(mtid, i, buf, indent); + return; + } + + assert(!"Unknown item tlv type!"); +} + +static void format_items_(uint16_t mtid, enum isis_tlv_context context, + enum isis_tlv_type type, struct isis_item_list *items, + struct sbuf *buf, int indent) +{ + struct isis_item *i; + + for (i = items->head; i; i = i->next) + format_item(mtid, context, type, i, buf, indent); +} +#define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__) + +static void free_item(enum isis_tlv_context tlv_context, + enum isis_tlv_type tlv_type, struct isis_item *item) +{ + const struct tlv_ops *ops = tlv_table[tlv_context][tlv_type]; + + if (ops && ops->free_item) { + ops->free_item(item); + return; + } + + assert(!"Unknown item tlv type!"); +} + +static void free_items(enum isis_tlv_context context, enum isis_tlv_type type, + struct isis_item_list *items) +{ + struct isis_item *item, *next_item; + + for (item = items->head; item; item = next_item) { + next_item = item->next; + free_item(context, type, item); + } +} + +static int pack_item(enum isis_tlv_context context, enum isis_tlv_type type, + struct isis_item *i, struct stream *s, + struct isis_tlvs **fragment_tlvs, + struct pack_order_entry *pe, uint16_t mtid) +{ + const struct tlv_ops *ops = tlv_table[context][type]; + + if (ops && ops->pack_item) { + return ops->pack_item(i, s); + } + + assert(!"Unknown item tlv type!"); + return 1; +} + +static void add_item_to_fragment(struct isis_item *i, struct pack_order_entry *pe, + struct isis_tlvs *fragment_tlvs, uint16_t mtid) +{ + struct isis_item_list *l; + + if (pe->how_to_pack == ISIS_ITEMS) { + l = (struct isis_item_list *)(((char *)fragment_tlvs) + pe->what_to_pack); + } else { + struct isis_mt_item_list *m; + m = (struct isis_mt_item_list *)(((char *)fragment_tlvs) + pe->what_to_pack); + l = isis_get_mt_items(m, mtid); + } + + append_item(l, copy_item(pe->context, pe->type, i)); +} + +static int pack_items_(uint16_t mtid, enum isis_tlv_context context, + enum isis_tlv_type type, struct isis_item_list *items, + struct stream *s, struct isis_tlvs **fragment_tlvs, + struct pack_order_entry *pe, + struct isis_tlvs *(*new_fragment)(struct list *l), + struct list *new_fragment_arg) +{ + size_t len_pos, last_len, len; + struct isis_item *item = NULL; + int rv; + + if (!items->head) + return 0; + +top: + if (STREAM_WRITEABLE(s) < 2) + goto too_long; + + stream_putc(s, type); + len_pos = stream_get_endp(s); + stream_putc(s, 0); /* Put 0 as length for now */ + + if (context == ISIS_CONTEXT_LSP && IS_COMPAT_MT_TLV(type) + && mtid != ISIS_MT_IPV4_UNICAST) { + if (STREAM_WRITEABLE(s) < 2) + goto too_long; + stream_putw(s, mtid); + } + + if (context == ISIS_CONTEXT_LSP && type == ISIS_TLV_OLDSTYLE_REACH) { + if (STREAM_WRITEABLE(s) < 1) + goto too_long; + stream_putc(s, 0); /* Virtual flag is set to 0 */ + } + + last_len = len = 0; + for (item = item ? item : items->head; item; item = item->next) { + rv = pack_item(context, type, item, s, fragment_tlvs, pe, mtid); + if (rv) + goto too_long; + + len = stream_get_endp(s) - len_pos - 1; + + /* Multiple auths don't go into one TLV, so always break */ + if (context == ISIS_CONTEXT_LSP && type == ISIS_TLV_AUTH) { + item = item->next; + break; + } + + if (len > 255) { + if (!last_len) /* strange, not a single item fit */ + return 1; + /* drop last tlv, otherwise, its too long */ + stream_set_endp(s, len_pos + 1 + last_len); + len = last_len; + break; + } + + if (fragment_tlvs) + add_item_to_fragment(item, pe, *fragment_tlvs, mtid); + + last_len = len; + } + + stream_putc_at(s, len_pos, len); + if (item) + goto top; + + return 0; +too_long: + if (!fragment_tlvs) + return 1; + stream_reset(s); + *fragment_tlvs = new_fragment(new_fragment_arg); + goto top; +} +#define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__) + +static void append_item(struct isis_item_list *dest, struct isis_item *item) +{ + *dest->tail = item; + dest->tail = &(*dest->tail)->next; + dest->count++; +} + +static int unpack_item(uint16_t mtid, enum isis_tlv_context context, + uint8_t tlv_type, uint8_t len, struct stream *s, + struct sbuf *log, void *dest, int indent) +{ + const struct tlv_ops *ops = tlv_table[context][tlv_type]; + + if (ops && ops->unpack_item) + return ops->unpack_item(mtid, len, s, log, dest, indent); + + assert(!"Unknown item tlv type!"); + sbuf_push(log, indent, "Unknown item tlv type!\n"); + return 1; +} + +static int unpack_tlv_with_items(enum isis_tlv_context context, + uint8_t tlv_type, uint8_t tlv_len, + struct stream *s, struct sbuf *log, void *dest, + int indent) +{ + size_t tlv_start; + size_t tlv_pos; + int rv; + uint16_t mtid; + + tlv_start = stream_get_getp(s); + tlv_pos = 0; + + if (context == ISIS_CONTEXT_LSP && IS_COMPAT_MT_TLV(tlv_type)) { + if (tlv_len < 2) { + sbuf_push(log, indent, + "TLV is too short to contain MTID\n"); + return 1; + } + mtid = stream_getw(s) & ISIS_MT_MASK; + tlv_pos += 2; + sbuf_push(log, indent, "Unpacking as MT %s item TLV...\n", + isis_mtid2str(mtid)); + } else { + sbuf_push(log, indent, "Unpacking as item TLV...\n"); + mtid = ISIS_MT_IPV4_UNICAST; + } + + if (context == ISIS_CONTEXT_LSP + && tlv_type == ISIS_TLV_OLDSTYLE_REACH) { + if (tlv_len - tlv_pos < 1) { + sbuf_push(log, indent, + "TLV is too short for old style reach\n"); + return 1; + } + stream_forward_getp(s, 1); + tlv_pos += 1; + } + + if (context == ISIS_CONTEXT_LSP + && tlv_type == ISIS_TLV_OLDSTYLE_IP_REACH) { + struct isis_tlvs *tlvs = dest; + dest = &tlvs->oldstyle_ip_reach; + } else if (context == ISIS_CONTEXT_LSP + && tlv_type == ISIS_TLV_OLDSTYLE_IP_REACH_EXT) { + struct isis_tlvs *tlvs = dest; + dest = &tlvs->oldstyle_ip_reach_ext; + } + + if (context == ISIS_CONTEXT_LSP + && tlv_type == ISIS_TLV_MT_ROUTER_INFO) { + struct isis_tlvs *tlvs = dest; + tlvs->mt_router_info_empty = (tlv_pos >= (size_t)tlv_len); + } + + while (tlv_pos < (size_t)tlv_len) { + rv = unpack_item(mtid, context, tlv_type, tlv_len - tlv_pos, s, + log, dest, indent + 2); + if (rv) + return rv; + + tlv_pos = stream_get_getp(s) - tlv_start; + } + + return 0; +} + +/* Functions to manipulate mt_item_lists */ + +static int isis_mt_item_list_cmp(const struct isis_item_list *a, + const struct isis_item_list *b) +{ + if (a->mtid < b->mtid) + return -1; + if (a->mtid > b->mtid) + return 1; + return 0; +} + +RB_PROTOTYPE(isis_mt_item_list, isis_item_list, mt_tree, isis_mt_item_list_cmp); +RB_GENERATE(isis_mt_item_list, isis_item_list, mt_tree, isis_mt_item_list_cmp); + +struct isis_item_list *isis_get_mt_items(struct isis_mt_item_list *m, + uint16_t mtid) +{ + struct isis_item_list *rv; + + rv = isis_lookup_mt_items(m, mtid); + if (!rv) { + rv = XCALLOC(MTYPE_ISIS_MT_ITEM_LIST, sizeof(*rv)); + init_item_list(rv); + rv->mtid = mtid; + RB_INSERT(isis_mt_item_list, m, rv); + } + + return rv; +} + +struct isis_item_list *isis_lookup_mt_items(struct isis_mt_item_list *m, + uint16_t mtid) +{ + struct isis_item_list key = {.mtid = mtid}; + + return RB_FIND(isis_mt_item_list, m, &key); +} + +static void free_mt_items(enum isis_tlv_context context, + enum isis_tlv_type type, struct isis_mt_item_list *m) +{ + struct isis_item_list *n, *nnext; + + RB_FOREACH_SAFE(n, isis_mt_item_list, m, nnext) + { + free_items(context, type, n); + RB_REMOVE(isis_mt_item_list, m, n); + XFREE(MTYPE_ISIS_MT_ITEM_LIST, n); + } +} + +static void format_mt_items(enum isis_tlv_context context, + enum isis_tlv_type type, + struct isis_mt_item_list *m, struct sbuf *buf, + int indent) +{ + struct isis_item_list *n; + + RB_FOREACH(n, isis_mt_item_list, m) + { + format_items_(n->mtid, context, type, n, buf, indent); + } +} + +static int pack_mt_items(enum isis_tlv_context context, enum isis_tlv_type type, + struct isis_mt_item_list *m, struct stream *s, + struct isis_tlvs **fragment_tlvs, + struct pack_order_entry *pe, + struct isis_tlvs *(*new_fragment)(struct list *l), + struct list *new_fragment_arg) +{ + struct isis_item_list *n; + + RB_FOREACH(n, isis_mt_item_list, m) + { + int rv; + + rv = pack_items_(n->mtid, context, type, n, s, fragment_tlvs, + pe, new_fragment, new_fragment_arg); + if (rv) + return rv; + } + + return 0; +} + +static void copy_mt_items(enum isis_tlv_context context, + enum isis_tlv_type type, + struct isis_mt_item_list *src, + struct isis_mt_item_list *dest) +{ + struct isis_item_list *n; + + RB_INIT(isis_mt_item_list, dest); + + RB_FOREACH(n, isis_mt_item_list, src) + { + copy_items(context, type, n, isis_get_mt_items(dest, n->mtid)); + } +} + +/* Functions related to tlvs in general */ + +struct isis_tlvs *isis_alloc_tlvs(void) +{ + struct isis_tlvs *result; + + result = XCALLOC(MTYPE_ISIS_TLV, sizeof(*result)); + + init_item_list(&result->isis_auth); + init_item_list(&result->area_addresses); + init_item_list(&result->mt_router_info); + init_item_list(&result->oldstyle_reach); + init_item_list(&result->lan_neighbor); + init_item_list(&result->lsp_entries); + init_item_list(&result->extended_reach); + RB_INIT(isis_mt_item_list, &result->mt_reach); + init_item_list(&result->oldstyle_ip_reach); + init_item_list(&result->oldstyle_ip_reach_ext); + init_item_list(&result->ipv4_address); + init_item_list(&result->ipv6_address); + init_item_list(&result->extended_ip_reach); + RB_INIT(isis_mt_item_list, &result->mt_ip_reach); + init_item_list(&result->ipv6_reach); + RB_INIT(isis_mt_item_list, &result->mt_ipv6_reach); + + return result; +} + +struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs) +{ + struct isis_tlvs *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv)); + + copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth, + &rv->isis_auth); + + copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES, + &tlvs->area_addresses, &rv->area_addresses); + + copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO, + &tlvs->mt_router_info, &rv->mt_router_info); + + tlvs->mt_router_info_empty = rv->mt_router_info_empty; + + copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH, + &tlvs->oldstyle_reach, &rv->oldstyle_reach); + + copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS, + &tlvs->lan_neighbor, &rv->lan_neighbor); + + copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries, + &rv->lsp_entries); + + copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH, + &tlvs->extended_reach, &rv->extended_reach); + + copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach, + &rv->mt_reach); + + copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH, + &tlvs->oldstyle_ip_reach, &rv->oldstyle_ip_reach); + + copy_tlv_protocols_supported(&tlvs->protocols_supported, + &rv->protocols_supported); + + copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT, + &tlvs->oldstyle_ip_reach_ext, &rv->oldstyle_ip_reach_ext); + + copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS, &tlvs->ipv4_address, + &rv->ipv4_address); + + copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS, &tlvs->ipv6_address, + &rv->ipv6_address); + + rv->te_router_id = copy_tlv_te_router_id(tlvs->te_router_id); + + copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH, + &tlvs->extended_ip_reach, &rv->extended_ip_reach); + + copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH, + &tlvs->mt_ip_reach, &rv->mt_ip_reach); + + rv->hostname = copy_tlv_dynamic_hostname(tlvs->hostname); + + copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach, + &rv->ipv6_reach); + + copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH, + &tlvs->mt_ipv6_reach, &rv->mt_ipv6_reach); + + return rv; +} + +static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, int indent) +{ + format_tlv_protocols_supported(&tlvs->protocols_supported, buf, indent); + + format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth, buf, + indent); + + format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES, + &tlvs->area_addresses, buf, indent); + + if (tlvs->mt_router_info_empty) { + sbuf_push(buf, indent, "MT Router Info: None\n"); + } else { + format_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO, + &tlvs->mt_router_info, buf, indent); + } + + format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH, + &tlvs->oldstyle_reach, buf, indent); + + format_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS, + &tlvs->lan_neighbor, buf, indent); + + format_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries, + buf, indent); + + format_tlv_dynamic_hostname(tlvs->hostname, buf, indent); + format_tlv_te_router_id(tlvs->te_router_id, buf, indent); + + format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH, + &tlvs->extended_reach, buf, indent); + + format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach, + buf, indent); + + format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH, + &tlvs->oldstyle_ip_reach, buf, indent); + + format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT, + &tlvs->oldstyle_ip_reach_ext, buf, indent); + + format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS, + &tlvs->ipv4_address, buf, indent); + + format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS, + &tlvs->ipv6_address, buf, indent); + + format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH, + &tlvs->extended_ip_reach, buf, indent); + + format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH, + &tlvs->mt_ip_reach, buf, indent); + + format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach, + buf, indent); + + format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH, + &tlvs->mt_ipv6_reach, buf, indent); +} + +const char *isis_format_tlvs(struct isis_tlvs *tlvs) +{ + static struct sbuf buf; + + if (!sbuf_buf(&buf)) + sbuf_init(&buf, NULL, 0); + + sbuf_reset(&buf); + format_tlvs(tlvs, &buf, 0); + return sbuf_buf(&buf); +} + +void isis_free_tlvs(struct isis_tlvs *tlvs) +{ + if (!tlvs) + return; + + free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth); + free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES, + &tlvs->area_addresses); + free_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO, + &tlvs->mt_router_info); + free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH, + &tlvs->oldstyle_reach); + free_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS, + &tlvs->lan_neighbor); + free_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries); + free_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH, + &tlvs->extended_reach); + free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach); + free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH, + &tlvs->oldstyle_ip_reach); + free_tlv_protocols_supported(&tlvs->protocols_supported); + free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT, + &tlvs->oldstyle_ip_reach_ext); + free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS, + &tlvs->ipv4_address); + free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS, + &tlvs->ipv6_address); + free_tlv_te_router_id(tlvs->te_router_id); + free_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH, + &tlvs->extended_ip_reach); + free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH, + &tlvs->mt_ip_reach); + free_tlv_dynamic_hostname(tlvs->hostname); + free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach); + free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH, + &tlvs->mt_ipv6_reach); + + XFREE(MTYPE_ISIS_TLV, tlvs); +} + +static void add_padding(struct stream *s) +{ + while (STREAM_WRITEABLE(s)) { + if (STREAM_WRITEABLE(s) == 1) + break; + uint32_t padding_len = STREAM_WRITEABLE(s) - 2; + + if (padding_len > 255) { + if (padding_len == 256) + padding_len = 254; + else + padding_len = 255; + } + + stream_putc(s, ISIS_TLV_PADDING); + stream_putc(s, padding_len); + stream_put(s, NULL, padding_len); + } +} + +#define LSP_REM_LIFETIME_OFF 10 +#define LSP_CHECKSUM_OFF 24 +static void safe_auth_md5(struct stream *s, uint16_t *checksum, + uint16_t *rem_lifetime) +{ + memcpy(rem_lifetime, STREAM_DATA(s) + LSP_REM_LIFETIME_OFF, + sizeof(*rem_lifetime)); + memset(STREAM_DATA(s) + LSP_REM_LIFETIME_OFF, 0, sizeof(*rem_lifetime)); + memcpy(checksum, STREAM_DATA(s) + LSP_CHECKSUM_OFF, sizeof(*checksum)); + memset(STREAM_DATA(s) + LSP_CHECKSUM_OFF, 0, sizeof(*checksum)); +} + +static void restore_auth_md5(struct stream *s, uint16_t checksum, + uint16_t rem_lifetime) +{ + memcpy(STREAM_DATA(s) + LSP_REM_LIFETIME_OFF, &rem_lifetime, + sizeof(rem_lifetime)); + memcpy(STREAM_DATA(s) + LSP_CHECKSUM_OFF, &checksum, sizeof(checksum)); +} + +static void update_auth_hmac_md5(struct isis_auth *auth, struct stream *s, + bool is_lsp) +{ + uint8_t digest[16]; + uint16_t checksum, rem_lifetime; + + if (is_lsp) + safe_auth_md5(s, &checksum, &rem_lifetime); + + memset(STREAM_DATA(s) + auth->offset, 0, 16); + hmac_md5(STREAM_DATA(s), stream_get_endp(s), auth->passwd, + auth->plength, digest); + memcpy(auth->value, digest, 16); + memcpy(STREAM_DATA(s) + auth->offset, digest, 16); + + if (is_lsp) + restore_auth_md5(s, checksum, rem_lifetime); +} + +static void update_auth(struct isis_tlvs *tlvs, struct stream *s, bool is_lsp) +{ + struct isis_auth *auth_head = (struct isis_auth *)tlvs->isis_auth.head; + + for (struct isis_auth *auth = auth_head; auth; auth = auth->next) { + if (auth->type == ISIS_PASSWD_TYPE_HMAC_MD5) + update_auth_hmac_md5(auth, s, is_lsp); + } +} + +static int handle_pack_entry(struct pack_order_entry *pe, + struct isis_tlvs *tlvs, struct stream *stream, + struct isis_tlvs **fragment_tlvs, + struct isis_tlvs *(*new_fragment)(struct list *l), + struct list *new_fragment_arg) +{ + int rv; + + if (pe->how_to_pack == ISIS_ITEMS) { + struct isis_item_list *l; + l = (struct isis_item_list *)(((char *)tlvs) + + pe->what_to_pack); + rv = pack_items(pe->context, pe->type, l, stream, fragment_tlvs, + pe, new_fragment, new_fragment_arg); + } else { + struct isis_mt_item_list *l; + l = (struct isis_mt_item_list *)(((char *)tlvs) + + pe->what_to_pack); + rv = pack_mt_items(pe->context, pe->type, l, stream, + fragment_tlvs, pe, new_fragment, + new_fragment_arg); + } + + return rv; +} + +static int pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream, + struct isis_tlvs *fragment_tlvs, + struct isis_tlvs *(*new_fragment)(struct list *l), + struct list *new_fragment_arg) +{ + int rv; + + /* When fragmenting, don't add auth as it's already accounted for in the + * size we are given. */ + if (!fragment_tlvs) { + rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth, + stream, NULL, NULL, NULL, NULL); + if (rv) + return rv; + } + + rv = pack_tlv_protocols_supported(&tlvs->protocols_supported, stream); + if (rv) + return rv; + if (fragment_tlvs) { + copy_tlv_protocols_supported( + &tlvs->protocols_supported, + &fragment_tlvs->protocols_supported); + } + + rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES, + &tlvs->area_addresses, stream, NULL, NULL, NULL, NULL); + if (rv) + return rv; + if (fragment_tlvs) { + copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES, + &tlvs->area_addresses, + &fragment_tlvs->area_addresses); + } + + + if (tlvs->mt_router_info_empty) { + if (STREAM_WRITEABLE(stream) < 2) + return 1; + stream_putc(stream, ISIS_TLV_MT_ROUTER_INFO); + stream_putc(stream, 0); + if (fragment_tlvs) + fragment_tlvs->mt_router_info_empty = true; + } else { + rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO, + &tlvs->mt_router_info, stream, NULL, NULL, NULL, + NULL); + if (rv) + return rv; + if (fragment_tlvs) { + copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO, + &tlvs->mt_router_info, + &fragment_tlvs->mt_router_info); + } + } + + rv = pack_tlv_dynamic_hostname(tlvs->hostname, stream); + if (rv) + return rv; + if (fragment_tlvs) + fragment_tlvs->hostname = + copy_tlv_dynamic_hostname(tlvs->hostname); + + rv = pack_tlv_te_router_id(tlvs->te_router_id, stream); + if (rv) + return rv; + if (fragment_tlvs) { + fragment_tlvs->te_router_id = + copy_tlv_te_router_id(tlvs->te_router_id); + } + + for (size_t pack_idx = 0; pack_idx < array_size(pack_order); + pack_idx++) { + rv = handle_pack_entry(&pack_order[pack_idx], tlvs, stream, + fragment_tlvs ? &fragment_tlvs : NULL, + new_fragment, new_fragment_arg); + + if (rv) + return rv; + } + + return 0; +} + +int isis_pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream, + size_t len_pointer, bool pad, bool is_lsp) +{ + int rv; + + rv = pack_tlvs(tlvs, stream, NULL, NULL, NULL); + if (rv) + return rv; + + if (pad) + add_padding(stream); + + if (len_pointer != (size_t)-1) { + stream_putw_at(stream, len_pointer, stream_get_endp(stream)); + } + + update_auth(tlvs, stream, is_lsp); + + return 0; +} + +static struct isis_tlvs *new_fragment(struct list *l) +{ + struct isis_tlvs *rv = isis_alloc_tlvs(); + + listnode_add(l, rv); + return rv; +} + +struct list *isis_fragment_tlvs(struct isis_tlvs *tlvs, size_t size) +{ + struct stream *dummy_stream = stream_new(size); + struct list *rv = list_new(); + struct isis_tlvs *fragment_tlvs = new_fragment(rv); + + if (pack_tlvs(tlvs, dummy_stream, fragment_tlvs, new_fragment, rv)) { + struct listnode *node; + for (ALL_LIST_ELEMENTS_RO(rv, node, fragment_tlvs)) + isis_free_tlvs(fragment_tlvs); + list_delete(rv); + rv = NULL; + } + + stream_free(dummy_stream); + return rv; +} + +static int unpack_tlv_unknown(enum isis_tlv_context context, uint8_t tlv_type, + uint8_t tlv_len, struct stream *s, + struct sbuf *log, int indent) +{ + stream_forward_getp(s, tlv_len); + sbuf_push(log, indent, + "Skipping unknown TLV %" PRIu8 " (%" PRIu8 " bytes)\n", + tlv_type, tlv_len); + return 0; +} + +static int unpack_tlv(enum isis_tlv_context context, size_t avail_len, + struct stream *stream, struct sbuf *log, void *dest, + int indent) +{ + uint8_t tlv_type, tlv_len; + const struct tlv_ops *ops; + + sbuf_push(log, indent, "Unpacking TLV...\n"); + + if (avail_len < 2) { + sbuf_push( + log, indent + 2, + "Available data %zu too short to contain a TLV header.\n", + avail_len); + return 1; + } + + tlv_type = stream_getc(stream); + tlv_len = stream_getc(stream); + + sbuf_push(log, indent + 2, + "Found TLV of type %" PRIu8 " and len %" PRIu8 ".\n", + tlv_type, tlv_len); + + if (avail_len < ((size_t)tlv_len) + 2) { + sbuf_push(log, indent + 2, + "Available data %zu too short for claimed TLV len %" PRIu8 ".\n", + avail_len - 2, tlv_len); + return 1; + } + + ops = tlv_table[context][tlv_type]; + if (ops && ops->unpack) { + return ops->unpack(context, tlv_type, tlv_len, stream, log, + dest, indent + 2); + } + + return unpack_tlv_unknown(context, tlv_type, tlv_len, stream, log, + indent + 2); +} + +static int unpack_tlvs(enum isis_tlv_context context, size_t avail_len, + struct stream *stream, struct sbuf *log, void *dest, + int indent) +{ + int rv; + size_t tlv_start, tlv_pos; + + tlv_start = stream_get_getp(stream); + tlv_pos = 0; + + sbuf_push(log, indent, "Unpacking %zu bytes of %s...\n", avail_len, + (context == ISIS_CONTEXT_LSP) ? "TLVs" : "sub-TLVs"); + + while (tlv_pos < avail_len) { + rv = unpack_tlv(context, avail_len - tlv_pos, stream, log, dest, + indent + 2); + if (rv) + return rv; + + tlv_pos = stream_get_getp(stream) - tlv_start; + } + + return 0; +} + +int isis_unpack_tlvs(size_t avail_len, struct stream *stream, + struct isis_tlvs **dest, const char **log) +{ + static struct sbuf logbuf; + int indent = 0; + int rv; + struct isis_tlvs *result; + + if (!sbuf_buf(&logbuf)) + sbuf_init(&logbuf, NULL, 0); + + sbuf_reset(&logbuf); + if (avail_len > STREAM_READABLE(stream)) { + sbuf_push(&logbuf, indent, + "Stream doesn't contain sufficient data. " + "Claimed %zu, available %zu\n", + avail_len, STREAM_READABLE(stream)); + return 1; + } + + result = isis_alloc_tlvs(); + rv = unpack_tlvs(ISIS_CONTEXT_LSP, avail_len, stream, &logbuf, result, + indent); + + *log = sbuf_buf(&logbuf); + *dest = result; + + return rv; +} + +#define TLV_OPS(_name_, _desc_) \ + static const struct tlv_ops tlv_##_name_##_ops = { \ + .name = _desc_, .unpack = unpack_tlv_##_name_, \ + } + +#define ITEM_TLV_OPS(_name_, _desc_) \ + static const struct tlv_ops tlv_##_name_##_ops = { \ + .name = _desc_, \ + .unpack = unpack_tlv_with_items, \ + \ + .pack_item = pack_item_##_name_, \ + .free_item = free_item_##_name_, \ + .unpack_item = unpack_item_##_name_, \ + .format_item = format_item_##_name_, \ + .copy_item = copy_item_##_name_} + +#define SUBTLV_OPS(_name_, _desc_) \ + static const struct tlv_ops subtlv_##_name_##_ops = { \ + .name = _desc_, .unpack = unpack_subtlv_##_name_, \ + } + +ITEM_TLV_OPS(area_address, "TLV 1 Area Addresses"); +ITEM_TLV_OPS(oldstyle_reach, "TLV 2 IS Reachability"); +ITEM_TLV_OPS(lan_neighbor, "TLV 6 LAN Neighbors"); +ITEM_TLV_OPS(lsp_entry, "TLV 9 LSP Entries"); +ITEM_TLV_OPS(auth, "TLV 10 IS-IS Auth"); +ITEM_TLV_OPS(extended_reach, "TLV 22 Extended Reachability"); +ITEM_TLV_OPS(oldstyle_ip_reach, "TLV 128/130 IP Reachability"); +TLV_OPS(protocols_supported, "TLV 129 Protocols Supported"); +ITEM_TLV_OPS(ipv4_address, "TLV 132 IPv4 Interface Address"); +TLV_OPS(te_router_id, "TLV 134 TE Router ID"); +ITEM_TLV_OPS(extended_ip_reach, "TLV 135 Extended IP Reachability"); +TLV_OPS(dynamic_hostname, "TLV 137 Dynamic Hostname"); +ITEM_TLV_OPS(mt_router_info, "TLV 229 MT Router Information"); +ITEM_TLV_OPS(ipv6_address, "TLV 232 IPv6 Interface Address"); +ITEM_TLV_OPS(ipv6_reach, "TLV 236 IPv6 Reachability"); + +SUBTLV_OPS(ipv6_source_prefix, "Sub-TLV 22 IPv6 Source Prefix"); + +static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = { + [ISIS_CONTEXT_LSP] = { + [ISIS_TLV_AREA_ADDRESSES] = &tlv_area_address_ops, + [ISIS_TLV_OLDSTYLE_REACH] = &tlv_oldstyle_reach_ops, + [ISIS_TLV_LAN_NEIGHBORS] = &tlv_lan_neighbor_ops, + [ISIS_TLV_LSP_ENTRY] = &tlv_lsp_entry_ops, + [ISIS_TLV_AUTH] = &tlv_auth_ops, + [ISIS_TLV_EXTENDED_REACH] = &tlv_extended_reach_ops, + [ISIS_TLV_MT_REACH] = &tlv_extended_reach_ops, + [ISIS_TLV_OLDSTYLE_IP_REACH] = &tlv_oldstyle_ip_reach_ops, + [ISIS_TLV_PROTOCOLS_SUPPORTED] = &tlv_protocols_supported_ops, + [ISIS_TLV_OLDSTYLE_IP_REACH_EXT] = &tlv_oldstyle_ip_reach_ops, + [ISIS_TLV_IPV4_ADDRESS] = &tlv_ipv4_address_ops, + [ISIS_TLV_TE_ROUTER_ID] = &tlv_te_router_id_ops, + [ISIS_TLV_EXTENDED_IP_REACH] = &tlv_extended_ip_reach_ops, + [ISIS_TLV_MT_IP_REACH] = &tlv_extended_ip_reach_ops, + [ISIS_TLV_DYNAMIC_HOSTNAME] = &tlv_dynamic_hostname_ops, + [ISIS_TLV_MT_ROUTER_INFO] = &tlv_mt_router_info_ops, + [ISIS_TLV_IPV6_ADDRESS] = &tlv_ipv6_address_ops, + [ISIS_TLV_IPV6_REACH] = &tlv_ipv6_reach_ops, + [ISIS_TLV_MT_IPV6_REACH] = &tlv_ipv6_reach_ops, + }, + [ISIS_CONTEXT_SUBTLV_NE_REACH] = {}, + [ISIS_CONTEXT_SUBTLV_IP_REACH] = {}, + [ISIS_CONTEXT_SUBTLV_IPV6_REACH] = { + [ISIS_SUBTLV_IPV6_SOURCE_PREFIX] = &subtlv_ipv6_source_prefix_ops, + } +}; + +/* Accessor functions */ + +void isis_tlvs_add_auth(struct isis_tlvs *tlvs, struct isis_passwd *passwd) +{ + free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth); + init_item_list(&tlvs->isis_auth); + + if (passwd->type == ISIS_PASSWD_TYPE_UNUSED) + return; + + struct isis_auth *auth = XCALLOC(MTYPE_ISIS_TLV, sizeof(*auth)); + + auth->type = passwd->type; + + auth->plength = passwd->len; + memcpy(auth->passwd, passwd->passwd, + MIN(sizeof(auth->passwd), sizeof(passwd->passwd))); + + if (auth->type == ISIS_PASSWD_TYPE_CLEARTXT) { + auth->length = passwd->len; + memcpy(auth->value, passwd->passwd, + MIN(sizeof(auth->value), sizeof(passwd->passwd))); + } + + append_item(&tlvs->isis_auth, (struct isis_item *)auth); +} + +void isis_tlvs_add_area_addresses(struct isis_tlvs *tlvs, + struct list *addresses) +{ + struct listnode *node; + struct area_addr *area_addr; + + for (ALL_LIST_ELEMENTS_RO(addresses, node, area_addr)) { + struct isis_area_address *a = + XCALLOC(MTYPE_ISIS_TLV, sizeof(*a)); + + a->len = area_addr->addr_len; + memcpy(a->addr, area_addr->area_addr, 20); + append_item(&tlvs->area_addresses, (struct isis_item *)a); + } +} + +void isis_tlvs_add_lan_neighbors(struct isis_tlvs *tlvs, struct list *neighbors) +{ + struct listnode *node; + u_char *snpa; + + for (ALL_LIST_ELEMENTS_RO(neighbors, node, snpa)) { + struct isis_lan_neighbor *n = + XCALLOC(MTYPE_ISIS_TLV, sizeof(*n)); + + memcpy(n->mac, snpa, 6); + append_item(&tlvs->lan_neighbor, (struct isis_item *)n); + } +} + +void isis_tlvs_set_protocols_supported(struct isis_tlvs *tlvs, + struct nlpids *nlpids) +{ + tlvs->protocols_supported.count = nlpids->count; + if (tlvs->protocols_supported.protocols) + XFREE(MTYPE_ISIS_TLV, tlvs->protocols_supported.protocols); + if (nlpids->count) { + tlvs->protocols_supported.protocols = + XCALLOC(MTYPE_ISIS_TLV, nlpids->count); + memcpy(tlvs->protocols_supported.protocols, nlpids->nlpids, + nlpids->count); + } else { + tlvs->protocols_supported.protocols = NULL; + } +} + +void isis_tlvs_add_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid, + bool overload, bool attached) +{ + struct isis_mt_router_info *i = XCALLOC(MTYPE_ISIS_TLV, sizeof(*i)); + + i->overload = overload; + i->attached = attached; + i->mtid = mtid; + append_item(&tlvs->mt_router_info, (struct isis_item *)i); +} + +void isis_tlvs_add_ipv4_address(struct isis_tlvs *tlvs, struct in_addr *addr) +{ + struct isis_ipv4_address *a = XCALLOC(MTYPE_ISIS_TLV, sizeof(*a)); + a->addr = *addr; + append_item(&tlvs->ipv4_address, (struct isis_item *)a); +} + + +void isis_tlvs_add_ipv4_addresses(struct isis_tlvs *tlvs, + struct list *addresses) +{ + struct listnode *node; + struct prefix_ipv4 *ip_addr; + unsigned int addr_count = 0; + + for (ALL_LIST_ELEMENTS_RO(addresses, node, ip_addr)) { + isis_tlvs_add_ipv4_address(tlvs, &ip_addr->prefix); + addr_count++; + if (addr_count >= 63) + break; + } +} + +void isis_tlvs_add_ipv6_addresses(struct isis_tlvs *tlvs, + struct list *addresses) +{ + struct listnode *node; + struct prefix_ipv6 *ip_addr; + + for (ALL_LIST_ELEMENTS_RO(addresses, node, ip_addr)) { + struct isis_ipv6_address *a = + XCALLOC(MTYPE_ISIS_TLV, sizeof(*a)); + + a->addr = ip_addr->prefix; + append_item(&tlvs->ipv6_address, (struct isis_item *)a); + } +} + +typedef bool (*auth_validator_func)(struct isis_passwd *passwd, + struct stream *stream, + struct isis_auth *auth, bool is_lsp); + +static bool auth_validator_cleartxt(struct isis_passwd *passwd, + struct stream *stream, + struct isis_auth *auth, bool is_lsp) +{ + return (auth->length == passwd->len + && !memcmp(auth->value, passwd->passwd, passwd->len)); +} + +static bool auth_validator_hmac_md5(struct isis_passwd *passwd, + struct stream *stream, + struct isis_auth *auth, bool is_lsp) +{ + uint8_t digest[16]; + uint16_t checksum; + uint16_t rem_lifetime; + + if (is_lsp) + safe_auth_md5(stream, &checksum, &rem_lifetime); + + memset(STREAM_DATA(stream) + auth->offset, 0, 16); + hmac_md5(STREAM_DATA(stream), stream_get_endp(stream), passwd->passwd, + passwd->len, digest); + memcpy(STREAM_DATA(stream) + auth->offset, auth->value, 16); + + bool rv = !memcmp(digest, auth->value, 16); + + if (is_lsp) + restore_auth_md5(stream, checksum, rem_lifetime); + + return rv; +} + +static const auth_validator_func auth_validators[] = { + [ISIS_PASSWD_TYPE_CLEARTXT] = auth_validator_cleartxt, + [ISIS_PASSWD_TYPE_HMAC_MD5] = auth_validator_hmac_md5, +}; + +bool isis_tlvs_auth_is_valid(struct isis_tlvs *tlvs, struct isis_passwd *passwd, + struct stream *stream, bool is_lsp) +{ + /* If no auth is set, always pass authentication */ + if (!passwd->type) + return true; + + /* If we don't known how to validate the auth, return invalid */ + if (passwd->type >= array_size(auth_validators) + || !auth_validators[passwd->type]) + return false; + + struct isis_auth *auth_head = (struct isis_auth *)tlvs->isis_auth.head; + struct isis_auth *auth; + for (auth = auth_head; auth; auth = auth->next) { + if (auth->type == passwd->type) + break; + } + + /* If matching auth TLV could not be found, return invalid */ + if (!auth) + return false; + + /* Perform validation and return result */ + return auth_validators[passwd->type](passwd, stream, auth, is_lsp); +} + +bool isis_tlvs_area_addresses_match(struct isis_tlvs *tlvs, + struct list *addresses) +{ + struct isis_area_address *addr_head; + + addr_head = (struct isis_area_address *)tlvs->area_addresses.head; + for (struct isis_area_address *addr = addr_head; addr; + addr = addr->next) { + struct listnode *node; + struct area_addr *a; + + for (ALL_LIST_ELEMENTS_RO(addresses, node, a)) { + if (a->addr_len == addr->len + && !memcmp(a->area_addr, addr->addr, addr->len)) + return true; + } + } + + return false; +} + +static void tlvs_area_addresses_to_adj(struct isis_tlvs *tlvs, + struct isis_adjacency *adj, + bool *changed) +{ + if (adj->area_address_count != tlvs->area_addresses.count) { + *changed = true; + adj->area_address_count = tlvs->area_addresses.count; + adj->area_addresses = XREALLOC( + MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses, + adj->area_address_count * sizeof(*adj->area_addresses)); + } + + struct isis_area_address *addr = NULL; + for (unsigned int i = 0; i < tlvs->area_addresses.count; i++) { + if (!addr) + addr = (struct isis_area_address *) + tlvs->area_addresses.head; + else + addr = addr->next; + + if (adj->area_addresses[i].addr_len == addr->len + && !memcmp(adj->area_addresses[i].area_addr, addr->addr, + addr->len)) { + continue; + } + + *changed = true; + adj->area_addresses[i].addr_len = addr->len; + memcpy(adj->area_addresses[i].area_addr, addr->addr, addr->len); + } +} + +static void tlvs_protocols_supported_to_adj(struct isis_tlvs *tlvs, + struct isis_adjacency *adj, + bool *changed) +{ + bool ipv4_supported = false, ipv6_supported = false; + + for (uint8_t i = 0; i < tlvs->protocols_supported.count; i++) { + if (tlvs->protocols_supported.protocols[i] == NLPID_IP) + ipv4_supported = true; + if (tlvs->protocols_supported.protocols[i] == NLPID_IPV6) + ipv6_supported = true; + } + + struct nlpids reduced = {}; + + if (ipv4_supported && ipv6_supported) { + reduced.count = 2; + reduced.nlpids[0] = NLPID_IP; + reduced.nlpids[1] = NLPID_IPV6; + } else if (ipv4_supported) { + reduced.count = 1; + reduced.nlpids[0] = NLPID_IP; + } else if (ipv6_supported) { + reduced.count = 1; + reduced.nlpids[1] = NLPID_IPV6; + } else { + reduced.count = 0; + } + + if (adj->nlpids.count == reduced.count + && !memcmp(adj->nlpids.nlpids, reduced.nlpids, reduced.count)) + return; + + *changed = true; + adj->nlpids.count = reduced.count; + memcpy(adj->nlpids.nlpids, reduced.nlpids, reduced.count); +} + +static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs *tlvs, + struct isis_adjacency *adj, + bool *changed) +{ + if (adj->ipv4_address_count != tlvs->ipv4_address.count) { + *changed = true; + adj->ipv4_address_count = tlvs->ipv4_address.count; + adj->ipv4_addresses = XREALLOC( + MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses, + adj->ipv4_address_count * sizeof(*adj->ipv4_addresses)); + } + + struct isis_ipv4_address *addr = NULL; + for (unsigned int i = 0; i < tlvs->ipv4_address.count; i++) { + if (!addr) + addr = (struct isis_ipv4_address *) + tlvs->ipv4_address.head; + else + addr = addr->next; + + if (!memcmp(&adj->ipv4_addresses[i], &addr->addr, + sizeof(addr->addr))) + continue; + + *changed = true; + adj->ipv4_addresses[i] = addr->addr; + } +} + +static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs *tlvs, + struct isis_adjacency *adj, + bool *changed) +{ + if (adj->ipv6_address_count != tlvs->ipv6_address.count) { + *changed = true; + adj->ipv6_address_count = tlvs->ipv6_address.count; + adj->ipv6_addresses = XREALLOC( + MTYPE_ISIS_ADJACENCY_INFO, adj->ipv6_addresses, + adj->ipv6_address_count * sizeof(*adj->ipv6_addresses)); + } + + struct isis_ipv6_address *addr = NULL; + for (unsigned int i = 0; i < tlvs->ipv6_address.count; i++) { + if (!addr) + addr = (struct isis_ipv6_address *) + tlvs->ipv6_address.head; + else + addr = addr->next; + + if (!memcmp(&adj->ipv6_addresses[i], &addr->addr, + sizeof(addr->addr))) + continue; + + *changed = true; + adj->ipv6_addresses[i] = addr->addr; + } +} + +void isis_tlvs_to_adj(struct isis_tlvs *tlvs, struct isis_adjacency *adj, + bool *changed) +{ + *changed = false; + + tlvs_area_addresses_to_adj(tlvs, adj, changed); + tlvs_protocols_supported_to_adj(tlvs, adj, changed); + tlvs_ipv4_addresses_to_adj(tlvs, adj, changed); + tlvs_ipv6_addresses_to_adj(tlvs, adj, changed); +} + +bool isis_tlvs_own_snpa_found(struct isis_tlvs *tlvs, uint8_t *snpa) +{ + struct isis_lan_neighbor *ne_head; + + ne_head = (struct isis_lan_neighbor *)tlvs->lan_neighbor.head; + for (struct isis_lan_neighbor *ne = ne_head; ne; ne = ne->next) { + if (!memcmp(ne->mac, snpa, ETH_ALEN)) + return true; + } + + return false; +} + +void isis_tlvs_add_lsp_entry(struct isis_tlvs *tlvs, struct isis_lsp *lsp) +{ + struct isis_lsp_entry *entry = XCALLOC(MTYPE_ISIS_TLV, sizeof(*entry)); + + entry->rem_lifetime = lsp->hdr.rem_lifetime; + memcpy(entry->id, lsp->hdr.lsp_id, ISIS_SYS_ID_LEN + 2); + entry->checksum = lsp->hdr.checksum; + entry->seqno = lsp->hdr.seqno; + entry->lsp = lsp; + + append_item(&tlvs->lsp_entries, (struct isis_item *)entry); +} + +void isis_tlvs_add_csnp_entries(struct isis_tlvs *tlvs, uint8_t *start_id, + uint8_t *stop_id, uint16_t num_lsps, + dict_t *lspdb, struct isis_lsp **last_lsp) +{ + dnode_t *first = dict_lower_bound(lspdb, start_id); + if (!first) + return; + + dnode_t *last = dict_upper_bound(lspdb, stop_id); + dnode_t *curr = first; + + isis_tlvs_add_lsp_entry(tlvs, first->dict_data); + *last_lsp = first->dict_data; + + while (curr) { + curr = dict_next(lspdb, curr); + if (curr) { + isis_tlvs_add_lsp_entry(tlvs, curr->dict_data); + *last_lsp = curr->dict_data; + } + if (curr == last || tlvs->lsp_entries.count == num_lsps) + break; + } +} + +void isis_tlvs_set_dynamic_hostname(struct isis_tlvs *tlvs, + const char *hostname) +{ + XFREE(MTYPE_ISIS_TLV, tlvs->hostname); + if (hostname) + tlvs->hostname = XSTRDUP(MTYPE_ISIS_TLV, hostname); +} + +void isis_tlvs_set_te_router_id(struct isis_tlvs *tlvs, + const struct in_addr *id) +{ + XFREE(MTYPE_ISIS_TLV, tlvs->te_router_id); + if (!id) + return; + tlvs->te_router_id = XCALLOC(MTYPE_ISIS_TLV, sizeof(*id)); + memcpy(tlvs->te_router_id, id, sizeof(*id)); +} + +void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs, + struct prefix_ipv4 *dest, uint8_t metric) +{ + struct isis_oldstyle_ip_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r)); + + r->metric = metric; + memcpy(&r->prefix, dest, sizeof(*dest)); + apply_mask_ipv4(&r->prefix); + append_item(&tlvs->oldstyle_ip_reach, (struct isis_item *)r); +} + +void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs, + struct prefix_ipv4 *dest, uint32_t metric) +{ + struct isis_extended_ip_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r)); + + r->metric = metric; + memcpy(&r->prefix, dest, sizeof(*dest)); + apply_mask_ipv4(&r->prefix); + append_item(&tlvs->extended_ip_reach, (struct isis_item *)r); +} + +void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid, + struct prefix_ipv6 *dest, uint32_t metric) +{ + struct isis_ipv6_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r)); + + r->metric = metric; + memcpy(&r->prefix, dest, sizeof(*dest)); + apply_mask_ipv6(&r->prefix); + + struct isis_item_list *l; + l = (mtid == ISIS_MT_IPV4_UNICAST) + ? &tlvs->ipv6_reach + : isis_get_mt_items(&tlvs->mt_ipv6_reach, mtid); + append_item(l, (struct isis_item *)r); +} + +void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id, + uint8_t metric) +{ + struct isis_oldstyle_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r)); + + r->metric = metric; + memcpy(r->id, id, sizeof(r->id)); + append_item(&tlvs->oldstyle_reach, (struct isis_item *)r); +} + +void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid, + uint8_t *id, uint32_t metric, + uint8_t *subtlvs, uint8_t subtlv_len) +{ + struct isis_extended_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r)); + + memcpy(r->id, id, sizeof(r->id)); + r->metric = metric; + if (subtlvs && subtlv_len) { + r->subtlvs = XCALLOC(MTYPE_ISIS_TLV, subtlv_len); + memcpy(r->subtlvs, subtlvs, subtlv_len); + r->subtlv_len = subtlv_len; + } + + struct isis_item_list *l; + if (mtid == ISIS_MT_IPV4_UNICAST) + l = &tlvs->extended_reach; + else + l = isis_get_mt_items(&tlvs->mt_reach, mtid); + append_item(l, (struct isis_item *)r); +} + +struct isis_mt_router_info * +isis_tlvs_lookup_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid) +{ + if (tlvs->mt_router_info_empty) + return NULL; + + struct isis_mt_router_info *rv; + for (rv = (struct isis_mt_router_info *)tlvs->mt_router_info.head; rv; + rv = rv->next) { + if (rv->mtid == mtid) + return rv; + } + + return NULL; +} diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h new file mode 100644 index 0000000000..6ade0af28c --- /dev/null +++ b/isisd/isis_tlvs.h @@ -0,0 +1,308 @@ +/* + * IS-IS TLV Serializer/Deserializer + * + * Copyright (C) 2015,2017 Christian Franke + * + * This file is part of FRR. + * + * FRR 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. + * + * FRR 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 FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#ifndef ISIS_TLVS_H +#define ISIS_TLVS_H + +#include "openbsd-tree.h" +#include "prefix.h" +#include "isisd/dict.h" + +struct isis_subtlvs; + +struct isis_area_address; +struct isis_area_address { + struct isis_area_address *next; + + uint8_t addr[20]; + uint8_t len; +}; + +struct isis_oldstyle_reach; +struct isis_oldstyle_reach { + struct isis_oldstyle_reach *next; + + uint8_t id[7]; + uint8_t metric; +}; + +struct isis_oldstyle_ip_reach; +struct isis_oldstyle_ip_reach { + struct isis_oldstyle_ip_reach *next; + + uint8_t metric; + struct prefix_ipv4 prefix; +}; + +struct isis_lsp_entry; +struct isis_lsp_entry { + struct isis_lsp_entry *next; + + uint16_t rem_lifetime; + uint8_t id[8]; + uint16_t checksum; + uint32_t seqno; + + struct isis_lsp *lsp; +}; + +struct isis_extended_reach; +struct isis_extended_reach { + struct isis_extended_reach *next; + + uint8_t id[7]; + uint32_t metric; + + uint8_t *subtlvs; + uint8_t subtlv_len; +}; + +struct isis_extended_ip_reach; +struct isis_extended_ip_reach { + struct isis_extended_ip_reach *next; + + uint32_t metric; + bool down; + struct prefix_ipv4 prefix; +}; + +struct isis_ipv6_reach; +struct isis_ipv6_reach { + struct isis_ipv6_reach *next; + + uint32_t metric; + bool down; + bool external; + + struct prefix_ipv6 prefix; + + struct isis_subtlvs *subtlvs; +}; + +struct isis_protocols_supported { + uint8_t count; + uint8_t *protocols; +}; + +struct isis_item; +struct isis_item { + struct isis_item *next; +}; + +struct isis_lan_neighbor; +struct isis_lan_neighbor { + struct isis_lan_neighbor *next; + + uint8_t mac[6]; +}; + +struct isis_ipv4_address; +struct isis_ipv4_address { + struct isis_ipv4_address *next; + + struct in_addr addr; +}; + +struct isis_ipv6_address; +struct isis_ipv6_address { + struct isis_ipv6_address *next; + + struct in6_addr addr; +}; + +struct isis_mt_router_info; +struct isis_mt_router_info { + struct isis_mt_router_info *next; + + bool overload; + bool attached; + uint16_t mtid; +}; + +struct isis_auth; +struct isis_auth { + struct isis_auth *next; + + uint8_t type; + uint8_t length; + uint8_t value[256]; + + uint8_t plength; + uint8_t passwd[256]; + + size_t offset; /* Only valid after packing */ +}; + +struct isis_item_list; +struct isis_item_list { + struct isis_item *head; + struct isis_item **tail; + + RB_ENTRY(isis_item_list) mt_tree; + uint16_t mtid; + unsigned int count; +}; + +RB_HEAD(isis_mt_item_list, isis_item_list); + +struct isis_item_list *isis_get_mt_items(struct isis_mt_item_list *m, + uint16_t mtid); +struct isis_item_list *isis_lookup_mt_items(struct isis_mt_item_list *m, + uint16_t mtid); + +struct isis_tlvs { + struct isis_item_list isis_auth; + struct isis_item_list area_addresses; + struct isis_item_list oldstyle_reach; + struct isis_item_list lan_neighbor; + struct isis_item_list lsp_entries; + struct isis_item_list extended_reach; + struct isis_mt_item_list mt_reach; + struct isis_item_list oldstyle_ip_reach; + struct isis_protocols_supported protocols_supported; + struct isis_item_list oldstyle_ip_reach_ext; + struct isis_item_list ipv4_address; + struct isis_item_list ipv6_address; + struct isis_item_list mt_router_info; + bool mt_router_info_empty; + struct in_addr *te_router_id; + struct isis_item_list extended_ip_reach; + struct isis_mt_item_list mt_ip_reach; + char *hostname; + struct isis_item_list ipv6_reach; + struct isis_mt_item_list mt_ipv6_reach; +}; + +struct isis_subtlvs { + /* draft-baker-ipv6-isis-dst-src-routing-06 */ + struct prefix_ipv6 *source_prefix; +}; + +enum isis_tlv_context { + ISIS_CONTEXT_LSP, + ISIS_CONTEXT_SUBTLV_NE_REACH, + ISIS_CONTEXT_SUBTLV_IP_REACH, + ISIS_CONTEXT_SUBTLV_IPV6_REACH, + ISIS_CONTEXT_MAX +}; + +enum isis_tlv_type { + ISIS_TLV_AREA_ADDRESSES = 1, + ISIS_TLV_OLDSTYLE_REACH = 2, + ISIS_TLV_LAN_NEIGHBORS = 6, + ISIS_TLV_PADDING = 8, + ISIS_TLV_LSP_ENTRY = 9, + ISIS_TLV_AUTH = 10, + ISIS_TLV_EXTENDED_REACH = 22, + + ISIS_TLV_OLDSTYLE_IP_REACH = 128, + ISIS_TLV_PROTOCOLS_SUPPORTED = 129, + ISIS_TLV_OLDSTYLE_IP_REACH_EXT = 130, + ISIS_TLV_IPV4_ADDRESS = 132, + ISIS_TLV_TE_ROUTER_ID = 134, + ISIS_TLV_EXTENDED_IP_REACH = 135, + ISIS_TLV_DYNAMIC_HOSTNAME = 137, + ISIS_TLV_MT_REACH = 222, + ISIS_TLV_MT_ROUTER_INFO = 229, + ISIS_TLV_IPV6_ADDRESS = 232, + ISIS_TLV_MT_IP_REACH = 235, + ISIS_TLV_IPV6_REACH = 236, + ISIS_TLV_MT_IPV6_REACH = 237, + ISIS_TLV_MAX = 256, + + ISIS_SUBTLV_IPV6_SOURCE_PREFIX = 22 +}; + +#define IS_COMPAT_MT_TLV(tlv_type) \ + ((tlv_type == ISIS_TLV_MT_REACH) || (tlv_type == ISIS_TLV_MT_IP_REACH) \ + || (tlv_type == ISIS_TLV_MT_IPV6_REACH)) + +struct stream; +int isis_pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream, + size_t len_pointer, bool pad, bool is_lsp); +void isis_free_tlvs(struct isis_tlvs *tlvs); +struct isis_tlvs *isis_alloc_tlvs(void); +int isis_unpack_tlvs(size_t avail_len, struct stream *stream, + struct isis_tlvs **dest, const char **error_log); +const char *isis_format_tlvs(struct isis_tlvs *tlvs); +struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs); +struct list *isis_fragment_tlvs(struct isis_tlvs *tlvs, size_t size); + +#define ISIS_EXTENDED_IP_REACH_DOWN 0x80 +#define ISIS_EXTENDED_IP_REACH_SUBTLV 0x40 + +#define ISIS_IPV6_REACH_DOWN 0x80 +#define ISIS_IPV6_REACH_EXTERNAL 0x40 +#define ISIS_IPV6_REACH_SUBTLV 0x20 + +#ifndef ISIS_MT_MASK +#define ISIS_MT_MASK 0x0fff +#define ISIS_MT_OL_MASK 0x8000 +#define ISIS_MT_AT_MASK 0x4000 +#endif + + +void isis_tlvs_add_auth(struct isis_tlvs *tlvs, struct isis_passwd *passwd); +void isis_tlvs_add_area_addresses(struct isis_tlvs *tlvs, + struct list *addresses); +void isis_tlvs_add_lan_neighbors(struct isis_tlvs *tlvs, + struct list *neighbors); +void isis_tlvs_set_protocols_supported(struct isis_tlvs *tlvs, + struct nlpids *nlpids); +void isis_tlvs_add_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid, + bool overload, bool attached); +void isis_tlvs_add_ipv4_address(struct isis_tlvs *tlvs, struct in_addr *addr); +void isis_tlvs_add_ipv4_addresses(struct isis_tlvs *tlvs, + struct list *addresses); +void isis_tlvs_add_ipv6_addresses(struct isis_tlvs *tlvs, + struct list *addresses); +bool isis_tlvs_auth_is_valid(struct isis_tlvs *tlvs, struct isis_passwd *passwd, + struct stream *stream, bool is_lsp); +bool isis_tlvs_area_addresses_match(struct isis_tlvs *tlvs, + struct list *addresses); +struct isis_adjacency; +void isis_tlvs_to_adj(struct isis_tlvs *tlvs, struct isis_adjacency *adj, + bool *changed); +bool isis_tlvs_own_snpa_found(struct isis_tlvs *tlvs, uint8_t *snpa); +void isis_tlvs_add_lsp_entry(struct isis_tlvs *tlvs, struct isis_lsp *lsp); +void isis_tlvs_add_csnp_entries(struct isis_tlvs *tlvs, uint8_t *start_id, + uint8_t *stop_id, uint16_t num_lsps, + dict_t *lspdb, struct isis_lsp **last_lsp); +void isis_tlvs_set_dynamic_hostname(struct isis_tlvs *tlvs, + const char *hostname); +void isis_tlvs_set_te_router_id(struct isis_tlvs *tlvs, + const struct in_addr *id); +void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs, + struct prefix_ipv4 *dest, uint8_t metric); +void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs, + struct prefix_ipv4 *dest, uint32_t metric); +void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid, + struct prefix_ipv6 *dest, uint32_t metric); +void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id, + uint8_t metric); +void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid, + uint8_t *id, uint32_t metric, + uint8_t *subtlvs, uint8_t subtlv_len); + +struct isis_mt_router_info * +isis_tlvs_lookup_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid); +#endif diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 18a59d1fc5..8c6968f8ec 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -42,7 +42,6 @@ #include "isisd/isis_flags.h" #include "isisd/isis_misc.h" #include "isisd/isis_circuit.h" -#include "isisd/isis_tlv.h" #include "isisd/isisd.h" #include "isisd/isis_circuit.h" #include "isisd/isis_csm.h" diff --git a/isisd/isisd.c b/isisd/isisd.c index 8bbb5cf949..60b9367da9 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -49,7 +49,6 @@ #include "isisd/isis_pdu.h" #include "isisd/isis_misc.h" #include "isisd/isis_constants.h" -#include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_spf.h" #include "isisd/isis_route.h" @@ -1232,27 +1231,6 @@ DEFUN (show_hostname, return CMD_SUCCESS; } -static void vty_out_timestr(struct vty *vty, time_t uptime) -{ - struct tm *tm; - time_t difftime = time(NULL); - difftime -= uptime; - tm = gmtime(&difftime); - -#define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND 60*60*24*7 - if (difftime < ONE_DAY_SECOND) - vty_out(vty, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, - tm->tm_sec); - else if (difftime < ONE_WEEK_SECOND) - vty_out(vty, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour, - tm->tm_min); - else - vty_out(vty, "%02dw%dd%02dh", tm->tm_yday / 7, - tm->tm_yday - ((tm->tm_yday / 7) * 7), tm->tm_hour); - vty_out(vty, " ago"); -} - DEFUN (show_isis_spf_ietf, show_isis_spf_ietf_cmd, "show isis spf-delay-ietf", @@ -1309,7 +1287,6 @@ DEFUN (show_isis_summary, { struct listnode *node, *node2; struct isis_area *area; - struct isis_spftree *spftree; int level; if (isis == NULL) { @@ -1350,7 +1327,6 @@ DEFUN (show_isis_summary, continue; vty_out(vty, " Level-%d:\n", level); - spftree = area->spftree[level - 1]; if (area->spf_timer[level - 1]) vty_out(vty, " SPF: (pending)\n"); else @@ -1364,28 +1340,10 @@ DEFUN (show_isis_summary, vty_out(vty, "\n"); vty_out(vty, " IPv4 route computation:\n"); - vty_out(vty, " last run elapsed : "); - vty_out_timestr(vty, spftree->last_run_timestamp); - vty_out(vty, "\n"); + isis_spf_print(area->spftree[level - 1], vty); - vty_out(vty, " last run duration : %u usec\n", - (u_int32_t)spftree->last_run_duration); - - vty_out(vty, " run count : %d\n", - spftree->runcount); - - spftree = area->spftree6[level - 1]; vty_out(vty, " IPv6 route computation:\n"); - - vty_out(vty, " last run elapsed : "); - vty_out_timestr(vty, spftree->last_run_timestamp); - vty_out(vty, "\n"); - - vty_out(vty, " last run duration : %llu msec\n", - (unsigned long long)spftree->last_run_duration); - - vty_out(vty, " run count : %d\n", - spftree->runcount); + isis_spf_print(area->spftree6[level - 1], vty); } } vty_out(vty, "\n"); diff --git a/isisd/isisd.h b/isisd/isisd.h index 1aacea881f..da02854f5c 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -37,7 +37,7 @@ /* uncomment if you are a developer in bug hunt */ /* #define EXTREME_DEBUG */ -/* #define EXTREME_TLV_DEBUG */ +/* #define EXTREME_DICT_DEBUG */ struct isis { u_long process_id; diff --git a/isisd/iso_checksum.c b/isisd/iso_checksum.c index e0a4ba3700..25a870991a 100644 --- a/isisd/iso_checksum.c +++ b/isisd/iso_checksum.c @@ -67,7 +67,7 @@ int iso_csum_verify(u_char *buffer, int len, uint16_t csum, int offset) return 1; checksum = fletcher_checksum(buffer, len, offset); - if (checksum == csum) + if (checksum == htons(csum)) return 0; return 1; } diff --git a/ldpd/address.c b/ldpd/address.c index 584240de84..18ab037760 100644 --- a/ldpd/address.c +++ b/ldpd/address.c @@ -160,7 +160,7 @@ send_mac_withdrawal(struct nbr *nbr, struct map *fec, uint8_t *mac) size = LDP_HDR_SIZE + LDP_MSG_SIZE + ADDR_LIST_SIZE + len_fec_tlv(fec) + TLV_HDR_SIZE; if (mac) - size += ETHER_ADDR_LEN; + size += ETH_ALEN; if ((buf = ibuf_open(size)) == NULL) fatal(__func__); @@ -372,10 +372,10 @@ gen_mac_list_tlv(struct ibuf *buf, uint8_t *mac) memset(&tlv, 0, sizeof(tlv)); tlv.type = htons(TLV_TYPE_MAC_LIST); if (mac) - tlv.length = htons(ETHER_ADDR_LEN); + tlv.length = htons(ETH_ALEN); err = ibuf_add(buf, &tlv, sizeof(tlv)); if (mac) - err |= ibuf_add(buf, mac, ETHER_ADDR_LEN); + err |= ibuf_add(buf, mac, ETH_ALEN); return (err); } diff --git a/ldpd/l2vpn.c b/ldpd/l2vpn.c index f15461d3d2..9bad503b9c 100644 --- a/ldpd/l2vpn.c +++ b/ldpd/l2vpn.c @@ -235,6 +235,7 @@ void l2vpn_pw_init(struct l2vpn_pw *pw) { struct fec fec; + struct zapi_pw zpw; l2vpn_pw_reset(pw); @@ -242,16 +243,23 @@ l2vpn_pw_init(struct l2vpn_pw *pw) lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0, 0, (void *)pw); lde_kernel_update(&fec); + + pw2zpw(pw, &zpw); + lde_imsg_compose_parent(IMSG_KPW_ADD, 0, &zpw, sizeof(zpw)); } void l2vpn_pw_exit(struct l2vpn_pw *pw) { struct fec fec; + struct zapi_pw zpw; l2vpn_pw_fec(pw, &fec); lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0); lde_kernel_update(&fec); + + pw2zpw(pw, &zpw); + lde_imsg_compose_parent(IMSG_KPW_DELETE, 0, &zpw, sizeof(zpw)); } static void @@ -269,7 +277,8 @@ l2vpn_pw_reset(struct l2vpn_pw *pw) { pw->remote_group = 0; pw->remote_mtu = 0; - pw->remote_status = 0; + pw->local_status = PW_FORWARDING; + pw->remote_status = PW_NOT_FORWARDING; if (pw->flags & F_PW_CWORD_CONF) pw->flags |= F_PW_CWORD; @@ -475,6 +484,56 @@ l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm) } } +int +l2vpn_pw_status_update(struct zapi_pw_status *zpw) +{ + struct l2vpn *l2vpn; + struct l2vpn_pw *pw = NULL; + struct lde_nbr *ln; + struct fec fec; + uint32_t local_status; + + RB_FOREACH(l2vpn, l2vpn_head, &ldeconf->l2vpn_tree) { + pw = l2vpn_pw_find(l2vpn, zpw->ifname); + if (pw) + break; + } + if (!pw) { + log_warnx("%s: pseudowire %s not found", __func__, zpw->ifname); + return (1); + } + + if (zpw->status == PW_STATUS_UP) + local_status = PW_FORWARDING; + else + local_status = PW_NOT_FORWARDING; + + /* local status didn't change */ + if (pw->local_status == local_status) + return (0); + pw->local_status = local_status; + + /* notify remote peer about the status update */ + ln = lde_nbr_find_by_lsrid(pw->lsr_id); + if (ln == NULL) + return (0); + l2vpn_pw_fec(pw, &fec); + if (pw->flags & F_PW_STATUSTLV) + l2vpn_send_pw_status(ln, local_status, &fec); + else { + struct fec_node *fn; + fn = (struct fec_node *)fec_find(&ft, &fec); + if (fn) { + if (pw->local_status == PW_FORWARDING) + lde_send_labelmapping(ln, fn, 1); + else + lde_send_labelwithdraw(ln, fn, NULL, NULL); + } + } + + return (0); +} + void l2vpn_pw_ctl(pid_t pid) { @@ -491,7 +550,9 @@ l2vpn_pw_ctl(pid_t pid) sizeof(pwctl.ifname)); pwctl.pwid = pw->pwid; pwctl.lsr_id = pw->lsr_id; - pwctl.status = pw->flags & F_PW_STATUS_UP; + if (pw->local_status == PW_FORWARDING && + pw->remote_status == PW_FORWARDING) + pwctl.status = 1; lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_PW, 0, pid, &pwctl, sizeof(pwctl)); diff --git a/ldpd/lde.c b/ldpd/lde.c index 77643ff48b..588ccd6952 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -472,6 +472,15 @@ lde_dispatch_parent(struct thread *thread) } } break; + case IMSG_PW_UPDATE: + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(struct zapi_pw_status)) + fatalx("PW_UPDATE imsg with wrong len"); + + if (l2vpn_pw_status_update(imsg.data) != 0) + log_warnx("%s: error updating PW status", + __func__); + break; case IMSG_NETWORK_ADD: case IMSG_NETWORK_UPDATE: if (imsg.hdr.len != IMSG_HEADER_SIZE + @@ -712,8 +721,8 @@ lde_update_label(struct fec_node *fn) void lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh) { - struct kroute kr; - struct kpw kpw; + struct kroute kr; + struct zapi_pw zpw; struct l2vpn_pw *pw; switch (fn->fec.type) { @@ -751,19 +760,10 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh) return; pw = (struct l2vpn_pw *) fn->data; - pw->flags |= F_PW_STATUS_UP; - - memset(&kpw, 0, sizeof(kpw)); - kpw.ifindex = pw->ifindex; - kpw.pw_type = fn->fec.u.pwid.type; - kpw.af = pw->af; - kpw.nexthop = pw->addr; - kpw.local_label = fn->local_label; - kpw.remote_label = fnh->remote_label; - kpw.flags = pw->flags; - - lde_imsg_compose_parent(IMSG_KPWLABEL_CHANGE, 0, &kpw, - sizeof(kpw)); + pw2zpw(pw, &zpw); + zpw.local_label = fn->local_label; + zpw.remote_label = fnh->remote_label; + lde_imsg_compose_parent(IMSG_KPW_SET, 0, &zpw, sizeof(zpw)); break; } } @@ -772,7 +772,7 @@ void lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh) { struct kroute kr; - struct kpw kpw; + struct zapi_pw zpw; struct l2vpn_pw *pw; switch (fn->fec.type) { @@ -806,21 +806,10 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh) break; case FEC_TYPE_PWID: pw = (struct l2vpn_pw *) fn->data; - if (!(pw->flags & F_PW_STATUS_UP)) - return; - pw->flags &= ~F_PW_STATUS_UP; - - memset(&kpw, 0, sizeof(kpw)); - kpw.ifindex = pw->ifindex; - kpw.pw_type = fn->fec.u.pwid.type; - kpw.af = pw->af; - kpw.nexthop = pw->addr; - kpw.local_label = fn->local_label; - kpw.remote_label = fnh->remote_label; - kpw.flags = pw->flags; - - lde_imsg_compose_parent(IMSG_KPWLABEL_DELETE, 0, &kpw, - sizeof(kpw)); + pw2zpw(pw, &zpw); + zpw.local_label = fn->local_label; + zpw.remote_label = fnh->remote_label; + lde_imsg_compose_parent(IMSG_KPW_UNSET, 0, &zpw, sizeof(zpw)); break; } } @@ -901,8 +890,12 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single) */ lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); if (lw) { - if (!fec_find(&ln->sent_map_pending, &fn->fec)) + if (!fec_find(&ln->sent_map_pending, &fn->fec)) { + debug_evt("%s: FEC %s: scheduling to send label " + "mapping later (waiting for pending label release)", + __func__, log_fec(&fn->fec)); lde_map_pending_add(ln, fn); + } return; } @@ -948,8 +941,7 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single) map.flags |= F_MAP_PW_CWORD; if (pw->flags & F_PW_STATUSTLV) { map.flags |= F_MAP_PW_STATUS; - /* VPLS are always up */ - map.pw_status = PW_FORWARDING; + map.pw_status = pw->local_status; } break; } diff --git a/ldpd/lde.h b/ldpd/lde.h index 1cce483832..43f1d36481 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -238,6 +238,7 @@ void l2vpn_send_pw_status_wcard(struct lde_nbr *, uint32_t, void l2vpn_recv_pw_status(struct lde_nbr *, struct notify_msg *); void l2vpn_recv_pw_status_wcard(struct lde_nbr *, struct notify_msg *); +int l2vpn_pw_status_update(struct zapi_pw_status *); void l2vpn_pw_ctl(pid_t); void l2vpn_binding_ctl(pid_t); diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index edf686537f..c56b7e33d0 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -396,8 +396,7 @@ lde_kernel_update(struct fec *fec) lde_gc_start_timer(); } else { fn->local_label = lde_update_label(fn); - if (fn->local_label != NO_LABEL && - RB_EMPTY(lde_map_head, &fn->upstream)) + if (fn->local_label != NO_LABEL) /* FEC.1: perform lsr label distribution procedure */ RB_FOREACH(ln, nbr_tree, &lde_nbrs) lde_send_labelmapping(ln, fn, 1); @@ -531,6 +530,8 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln) pw->remote_mtu = map->fec.pwid.ifmtu; if (map->flags & F_MAP_PW_STATUS) pw->remote_status = map->pw_status; + else + pw->remote_status = PW_FORWARDING; fnh->remote_label = map->label; if (l2vpn_pw_ok(pw, fnh)) lde_send_change_klabel(fn, fnh); @@ -774,6 +775,7 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln) pw = (struct l2vpn_pw *) fn->data; if (pw == NULL) continue; + pw->remote_status = PW_NOT_FORWARDING; break; default: break; @@ -802,6 +804,7 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) struct fec_node *fn; struct fec_nh *fnh; struct lde_map *me; + struct l2vpn_pw *pw; /* LWd.2: send label release */ lde_send_labelrelease(ln, NULL, map, map->label); @@ -825,6 +828,9 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) case FEC_TYPE_PWID: if (f->u.pwid.lsr_id.s_addr != ln->id.s_addr) continue; + pw = (struct l2vpn_pw *) fn->data; + if (pw) + pw->remote_status = PW_NOT_FORWARDING; break; default: break; diff --git a/ldpd/ldp.h b/ldpd/ldp.h index c2b64d20c6..cac3da7c55 100644 --- a/ldpd/ldp.h +++ b/ldpd/ldp.h @@ -285,9 +285,6 @@ struct address_list_tlv { #define MAP_TYPE_GENPWID 0x81 #define CONTROL_WORD_FLAG 0x8000 -#define PW_TYPE_ETHERNET_TAGGED 0x0004 -#define PW_TYPE_ETHERNET 0x0005 -#define PW_TYPE_WILDCARD 0x7FFF #define DEFAULT_PW_TYPE PW_TYPE_ETHERNET #define PW_TWCARD_RESERVED_BIT 0x8000 diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c index 7da76185c6..3f39ad926c 100644 --- a/ldpd/ldp_vty_cmds.c +++ b/ldpd/ldp_vty_cmds.c @@ -37,7 +37,7 @@ DEFUN_NOSH(ldp_mpls_ldp, DEFPY (no_ldp_mpls_ldp, no_ldp_mpls_ldp_cmd, "no mpls ldp", - "Negate a command or set its defaults\n" + NO_STR "Global MPLS configuration subcommands\n" "Label Distribution Protocol\n") { @@ -64,7 +64,7 @@ DEFUN_NOSH(ldp_l2vpn, DEFPY (no_ldp_l2vpn, no_ldp_l2vpn_cmd, "no l2vpn WORD$l2vpn_name type vpls", - "Negate a command or set its defaults\n" + NO_STR "Configure l2vpn commands\n" "L2VPN name\n" "L2VPN type\n" @@ -92,7 +92,7 @@ DEFUN_NOSH(ldp_address_family, DEFPY (no_ldp_address_family, no_ldp_address_family_cmd, "no address-family <ipv4|ipv6>$af", - "Negate a command or set its defaults\n" + NO_STR "Configure Address Family and its parameters\n" "IPv4\n" "IPv6\n") @@ -113,7 +113,7 @@ DEFUN_NOSH(ldp_exit_address_family, DEFPY (ldp_discovery_holdtime, ldp_discovery_holdtime_cmd, "[no] discovery <hello|targeted-hello>$hello_type holdtime (1-65535)$holdtime", - "Negate a command or set its defaults\n" + NO_STR "Configure discovery parameters\n" "LDP Link Hellos\n" "LDP Targeted Hellos\n" @@ -126,7 +126,7 @@ DEFPY (ldp_discovery_holdtime, DEFPY (ldp_discovery_interval, ldp_discovery_interval_cmd, "[no] discovery <hello|targeted-hello>$hello_type interval (1-65535)$interval", - "Negate a command or set its defaults\n" + NO_STR "Configure discovery parameters\n" "LDP Link Hellos\n" "LDP Targeted Hellos\n" @@ -139,7 +139,7 @@ DEFPY (ldp_discovery_interval, DEFPY (ldp_dual_stack_transport_connection_prefer_ipv4, ldp_dual_stack_transport_connection_prefer_ipv4_cmd, "[no] dual-stack transport-connection prefer ipv4", - "Negate a command or set its defaults\n" + NO_STR "Configure dual stack parameters\n" "Configure TCP transport parameters\n" "Configure prefered address family for TCP transport connection with neighbor\n" @@ -151,7 +151,7 @@ DEFPY (ldp_dual_stack_transport_connection_prefer_ipv4, DEFPY (ldp_dual_stack_cisco_interop, ldp_dual_stack_cisco_interop_cmd, "[no] dual-stack cisco-interop", - "Negate a command or set its defaults\n" + NO_STR "Configure dual stack parameters\n" "Use Cisco non-compliant format to send and interpret the Dual-Stack capability TLV\n") { @@ -161,7 +161,7 @@ DEFPY (ldp_dual_stack_cisco_interop, DEFPY (ldp_neighbor_password, ldp_neighbor_password_cmd, "[no] neighbor A.B.C.D$neighbor password WORD$password", - "Negate a command or set its defaults\n" + NO_STR "Configure neighbor parameters\n" "LDP Id of neighbor\n" "Configure password for MD5 authentication\n" @@ -173,7 +173,7 @@ DEFPY (ldp_neighbor_password, DEFPY (ldp_neighbor_session_holdtime, ldp_neighbor_session_holdtime_cmd, "[no] neighbor A.B.C.D$neighbor session holdtime (15-65535)$holdtime", - "Negate a command or set its defaults\n" + NO_STR "Configure neighbor parameters\n" "LDP Id of neighbor\n" "Configure session parameters\n" @@ -186,7 +186,7 @@ DEFPY (ldp_neighbor_session_holdtime, DEFPY (ldp_neighbor_ttl_security, ldp_neighbor_ttl_security_cmd, "[no] neighbor A.B.C.D$neighbor ttl-security <disable|hops (1-254)$hops>", - "Negate a command or set its defaults\n" + NO_STR "Configure neighbor parameters\n" "LDP Id of neighbor\n" "LDP ttl security check\n" @@ -200,7 +200,7 @@ DEFPY (ldp_neighbor_ttl_security, DEFPY (ldp_router_id, ldp_router_id_cmd, "[no] router-id A.B.C.D$address", - "Negate a command or set its defaults\n" + NO_STR "Configure router Id\n" "LSR Id (in form of an IPv4 address)\n") { @@ -210,7 +210,7 @@ DEFPY (ldp_router_id, DEFPY (ldp_discovery_targeted_hello_accept, ldp_discovery_targeted_hello_accept_cmd, "[no] discovery targeted-hello accept [from <(1-199)|(1300-2699)|WORD>$from_acl]", - "Negate a command or set its defaults\n" + NO_STR "Configure discovery parameters\n" "LDP Targeted Hellos\n" "Accept and respond to targeted hellos\n" @@ -225,7 +225,7 @@ DEFPY (ldp_discovery_targeted_hello_accept, DEFPY (ldp_discovery_transport_address_ipv4, ldp_discovery_transport_address_ipv4_cmd, "[no] discovery transport-address A.B.C.D$address", - "Negate a command or set its defaults\n" + NO_STR "Configure discovery parameters\n" "Specify transport address for TCP connection\n" "IP address to be used as transport address\n") @@ -236,7 +236,7 @@ DEFPY (ldp_discovery_transport_address_ipv4, DEFPY (ldp_discovery_transport_address_ipv6, ldp_discovery_transport_address_ipv6_cmd, "[no] discovery transport-address X:X::X:X$address", - "Negate a command or set its defaults\n" + NO_STR "Configure discovery parameters\n" "Specify transport address for TCP connection\n" "IPv6 address to be used as transport address\n") @@ -247,7 +247,7 @@ DEFPY (ldp_discovery_transport_address_ipv6, DEFPY (ldp_label_local_advertise, ldp_label_local_advertise_cmd, "[no] label local advertise [{to <(1-199)|(1300-2699)|WORD>$to_acl|for <(1-199)|(1300-2699)|WORD>$for_acl}]", - "Negate a command or set its defaults\n" + NO_STR "Configure label control and policies\n" "Configure local label control and policies\n" "Configure outbound label advertisement control\n" @@ -266,7 +266,7 @@ DEFPY (ldp_label_local_advertise, DEFPY (ldp_label_local_advertise_explicit_null, ldp_label_local_advertise_explicit_null_cmd, "[no] label local advertise explicit-null [for <(1-199)|(1300-2699)|WORD>$for_acl]", - "Negate a command or set its defaults\n" + NO_STR "Configure label control and policies\n" "Configure local label control and policies\n" "Configure outbound label advertisement control\n" @@ -282,7 +282,7 @@ DEFPY (ldp_label_local_advertise_explicit_null, DEFPY (ldp_label_local_allocate, ldp_label_local_allocate_cmd, "[no] label local allocate <host-routes$host_routes|for <(1-199)|(1300-2699)|WORD>$for_acl>", - "Negate a command or set its defaults\n" + NO_STR "Configure label control and policies\n" "Configure local label control and policies\n" "Configure label allocation control\n" @@ -298,7 +298,7 @@ DEFPY (ldp_label_local_allocate, DEFPY (ldp_label_remote_accept, ldp_label_remote_accept_cmd, "[no] label remote accept {from <(1-199)|(1300-2699)|WORD>$from_acl|for <(1-199)|(1300-2699)|WORD>$for_acl}", - "Negate a command or set its defaults\n" + NO_STR "Configure label control and policies\n" "Configure remote/peer label control and policies\n" "Configure inbound label acceptance control\n" @@ -317,7 +317,7 @@ DEFPY (ldp_label_remote_accept, DEFPY (ldp_ttl_security_disable, ldp_ttl_security_disable_cmd, "[no] ttl-security disable", - "Negate a command or set its defaults\n" + NO_STR "LDP ttl security check\n" "Disable ttl security\n") { @@ -327,7 +327,7 @@ DEFPY (ldp_ttl_security_disable, DEFPY (ldp_session_holdtime, ldp_session_holdtime_cmd, "[no] session holdtime (15-65535)$holdtime", - "Negate a command or set its defaults\n" + NO_STR "Configure session parameters\n" "Configure session holdtime\n" "Time (seconds)\n") @@ -353,7 +353,7 @@ DEFUN_NOSH(ldp_interface, DEFPY (no_ldp_interface, no_ldp_interface_cmd, "no interface IFNAME$ifname", - "Negate a command or set its defaults\n" + NO_STR "Enable LDP on an interface and enter interface submode\n" "Interface's name\n") { @@ -363,7 +363,7 @@ DEFPY (no_ldp_interface, DEFPY (ldp_neighbor_ipv4_targeted, ldp_neighbor_ipv4_targeted_cmd, "[no] neighbor A.B.C.D$address targeted", - "Negate a command or set its defaults\n" + NO_STR "Configure neighbor parameters\n" "IP address of neighbor\n" "Establish targeted session\n") @@ -374,7 +374,7 @@ DEFPY (ldp_neighbor_ipv4_targeted, DEFPY (ldp_neighbor_ipv6_targeted, ldp_neighbor_ipv6_targeted_cmd, "[no] neighbor X:X::X:X$address targeted", - "Negate a command or set its defaults\n" + NO_STR "Configure neighbor parameters\n" "IPv6 address of neighbor\n" "Establish targeted session\n") @@ -385,7 +385,7 @@ DEFPY (ldp_neighbor_ipv6_targeted, DEFPY (ldp_bridge, ldp_bridge_cmd, "[no] bridge IFNAME$ifname", - "Negate a command or set its defaults\n" + NO_STR "Bridge interface\n" "Interface's name\n") { @@ -395,7 +395,7 @@ DEFPY (ldp_bridge, DEFPY (ldp_mtu, ldp_mtu_cmd, "[no] mtu (1500-9180)$mtu", - "Negate a command or set its defaults\n" + NO_STR "Set Maximum Transmission Unit\n" "Maximum Transmission Unit value\n") { @@ -405,7 +405,7 @@ DEFPY (ldp_mtu, DEFPY (ldp_member_interface, ldp_member_interface_cmd, "[no] member interface IFNAME$ifname", - "Negate a command or set its defaults\n" + NO_STR "L2VPN member configuration\n" "Local interface\n" "Interface's name\n") @@ -432,7 +432,7 @@ DEFUN_NOSH(ldp_member_pseudowire, DEFPY (no_ldp_member_pseudowire, no_ldp_member_pseudowire_cmd, "no member pseudowire IFNAME$ifname", - "Negate a command or set its defaults\n" + NO_STR "L2VPN member configuration\n" "Pseudowire interface\n" "Interface's name\n") @@ -443,7 +443,7 @@ DEFPY (no_ldp_member_pseudowire, DEFPY (ldp_vc_type, ldp_vc_type_cmd, "[no] vc type <ethernet|ethernet-tagged>$vc_type", - "Negate a command or set its defaults\n" + NO_STR "Virtual Circuit options\n" "Virtual Circuit type to use\n" "Ethernet (type 5)\n" @@ -455,7 +455,7 @@ DEFPY (ldp_vc_type, DEFPY (ldp_control_word, ldp_control_word_cmd, "[no] control-word <exclude|include>$preference", - "Negate a command or set its defaults\n" + NO_STR "Control-word options\n" "Exclude control-word in pseudowire packets\n" "Include control-word in pseudowire packets\n") @@ -466,7 +466,7 @@ DEFPY (ldp_control_word, DEFPY (ldp_neighbor_address, ldp_neighbor_address_cmd, "[no] neighbor address <A.B.C.D|X:X::X:X>$pw_address", - "Negate a command or set its defaults\n" + NO_STR "Remote endpoint configuration\n" "Specify the IPv4 or IPv6 address of the remote endpoint\n" "IPv4 address\n" @@ -478,7 +478,7 @@ DEFPY (ldp_neighbor_address, DEFPY (ldp_neighbor_lsr_id, ldp_neighbor_lsr_id_cmd, "[no] neighbor lsr-id A.B.C.D$address", - "Negate a command or set its defaults\n" + NO_STR "Remote endpoint configuration\n" "Specify the LSR-ID of the remote endpoint\n" "IPv4 address\n") @@ -489,7 +489,7 @@ DEFPY (ldp_neighbor_lsr_id, DEFPY (ldp_pw_id, ldp_pw_id_cmd, "[no] pw-id (1-4294967295)$pwid", - "Negate a command or set its defaults\n" + NO_STR "Set the Virtual Circuit ID\n" "Virtual Circuit ID value\n") { @@ -499,7 +499,7 @@ DEFPY (ldp_pw_id, DEFPY (ldp_pw_status_disable, ldp_pw_status_disable_cmd, "[no] pw-status disable", - "Negate a command or set its defaults\n" + NO_STR "Configure PW status\n" "Disable PW status\n") { @@ -522,7 +522,7 @@ DEFPY (ldp_clear_mpls_ldp_neighbor, DEFPY (ldp_debug_mpls_ldp_discovery_hello, ldp_debug_mpls_ldp_discovery_hello_cmd, "[no] debug mpls ldp discovery hello <recv|sent>$dir", - "Negate a command or set its defaults\n" + NO_STR "Debugging functions\n" "MPLS information\n" "Label Distribution Protocol\n" @@ -537,7 +537,7 @@ DEFPY (ldp_debug_mpls_ldp_discovery_hello, DEFPY (ldp_debug_mpls_ldp_type, ldp_debug_mpls_ldp_type_cmd, "[no] debug mpls ldp <errors|event|zebra>$type", - "Negate a command or set its defaults\n" + NO_STR "Debugging functions\n" "MPLS information\n" "Label Distribution Protocol\n" @@ -551,7 +551,7 @@ DEFPY (ldp_debug_mpls_ldp_type, DEFPY (ldp_debug_mpls_ldp_messages_recv, ldp_debug_mpls_ldp_messages_recv_cmd, "[no] debug mpls ldp messages recv [all]$all", - "Negate a command or set its defaults\n" + NO_STR "Debugging functions\n" "MPLS information\n" "Label Distribution Protocol\n" @@ -565,7 +565,7 @@ DEFPY (ldp_debug_mpls_ldp_messages_recv, DEFPY (ldp_debug_mpls_ldp_messages_sent, ldp_debug_mpls_ldp_messages_sent_cmd, "[no] debug mpls ldp messages sent [all]$all", - "Negate a command or set its defaults\n" + NO_STR "Debugging functions\n" "MPLS information\n" "Label Distribution Protocol\n" diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c index 79fff01c4c..ecc7db8f2e 100644 --- a/ldpd/ldp_zebra.c +++ b/ldpd/ldp_zebra.c @@ -52,6 +52,8 @@ static int ldp_interface_address_delete(int, struct zclient *, zebra_size_t, vrf_id_t); static int ldp_zebra_read_route(int, struct zclient *, zebra_size_t, vrf_id_t); +static int ldp_zebra_read_pw_status_update(int, struct zclient *, + zebra_size_t, vrf_id_t); static void ldp_zebra_connected(struct zclient *); static struct zclient *zclient; @@ -64,7 +66,7 @@ ifp2kif(struct interface *ifp, struct kif *kif) kif->ifindex = ifp->ifindex; kif->operative = if_is_operative(ifp); if (ifp->ll_type == ZEBRA_LLT_ETHER) - memcpy(kif->mac, ifp->hw_addr, ETHER_ADDR_LEN); + memcpy(kif->mac, ifp->hw_addr, ETH_ALEN); } static void @@ -92,6 +94,25 @@ ifc2kaddr(struct interface *ifp, struct connected *ifc, struct kaddr *ka) } } +void +pw2zpw(struct l2vpn_pw *pw, struct zapi_pw *zpw) +{ + memset(zpw, 0, sizeof(*zpw)); + strlcpy(zpw->ifname, pw->ifname, sizeof(zpw->ifname)); + zpw->ifindex = pw->ifindex; + zpw->type = pw->l2vpn->pw_type; + zpw->af = pw->af; + zpw->nexthop.ipv6 = pw->addr.v6; + zpw->local_label = NO_LABEL; + zpw->remote_label = NO_LABEL; + if (pw->flags & F_PW_CWORD) + zpw->flags = F_PSEUDOWIRE_CWORD; + zpw->data.ldp.lsr_id = pw->lsr_id; + zpw->data.ldp.pwid = pw->pwid; + strlcpy(zpw->data.ldp.vpn_name, pw->l2vpn->name, + sizeof(zpw->data.ldp.vpn_name)); +} + static int zebra_send_mpls_labels(int cmd, struct kroute *kr) { @@ -152,17 +173,40 @@ kr_delete(struct kroute *kr) } int -kmpw_set(struct kpw *kpw) +kmpw_add(struct zapi_pw *zpw) { - /* TODO */ - return (0); + debug_zebra_out("pseudowire %s nexthop %s (add)", + zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop)); + + return (zebra_send_pw(zclient, ZEBRA_PW_ADD, zpw)); } int -kmpw_unset(struct kpw *kpw) +kmpw_del(struct zapi_pw *zpw) { - /* TODO */ - return (0); + debug_zebra_out("pseudowire %s nexthop %s (del)", + zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop)); + + return (zebra_send_pw(zclient, ZEBRA_PW_DELETE, zpw)); +} + +int +kmpw_set(struct zapi_pw *zpw) +{ + debug_zebra_out("pseudowire %s nexthop %s labels %u/%u (set)", + zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop), + zpw->local_label, zpw->remote_label); + + return (zebra_send_pw(zclient, ZEBRA_PW_SET, zpw)); +} + +int +kmpw_unset(struct zapi_pw *zpw) +{ + debug_zebra_out("pseudowire %s nexthop %s (unset)", + zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop)); + + return (zebra_send_pw(zclient, ZEBRA_PW_UNSET, zpw)); } void @@ -464,6 +508,25 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length, return (0); } +/* + * Receive PW status update from Zebra and send it to LDE process. + */ +static int +ldp_zebra_read_pw_status_update(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct zapi_pw_status zpw; + + zebra_read_pw_status_update(command, zclient, length, vrf_id, &zpw); + + debug_zebra_in("pseudowire %s status %s", zpw.ifname, + (zpw.status == PW_STATUS_UP) ? "up" : "down"); + + main_imsg_compose_lde(IMSG_PW_UPDATE, 0, &zpw, sizeof(zpw)); + + return (0); +} + static void ldp_zebra_connected(struct zclient *zclient) { @@ -494,6 +557,7 @@ ldp_zebra_init(struct thread_master *master) zclient->redistribute_route_ipv4_del = ldp_zebra_read_route; zclient->redistribute_route_ipv6_add = ldp_zebra_read_route; zclient->redistribute_route_ipv6_del = ldp_zebra_read_route; + zclient->pw_status_update = ldp_zebra_read_pw_status_update; } void diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index abcad79d67..2d7afd5df8 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -578,21 +578,36 @@ main_dispatch_lde(struct thread *thread) if (kr_delete(imsg.data)) log_warnx("%s: error deleting route", __func__); break; - case IMSG_KPWLABEL_CHANGE: + case IMSG_KPW_ADD: + case IMSG_KPW_DELETE: + case IMSG_KPW_SET: + case IMSG_KPW_UNSET: if (imsg.hdr.len - IMSG_HEADER_SIZE != - sizeof(struct kpw)) + sizeof(struct zapi_pw)) fatalx("invalid size of IMSG_KPWLABEL_CHANGE"); - if (kmpw_set(imsg.data)) - log_warnx("%s: error changing pseudowire", - __func__); - break; - case IMSG_KPWLABEL_DELETE: - if (imsg.hdr.len - IMSG_HEADER_SIZE != - sizeof(struct kpw)) - fatalx("invalid size of IMSG_KPWLABEL_DELETE"); - if (kmpw_unset(imsg.data)) - log_warnx("%s: error unsetting pseudowire", - __func__); + + switch (imsg.hdr.type) { + case IMSG_KPW_ADD: + if (kmpw_add(imsg.data)) + log_warnx("%s: error adding " + "pseudowire", __func__); + break; + case IMSG_KPW_DELETE: + if (kmpw_del(imsg.data)) + log_warnx("%s: error deleting " + "pseudowire", __func__); + break; + case IMSG_KPW_SET: + if (kmpw_set(imsg.data)) + log_warnx("%s: error setting " + "pseudowire", __func__); + break; + case IMSG_KPW_UNSET: + if (kmpw_unset(imsg.data)) + log_warnx("%s: error unsetting " + "pseudowire", __func__); + break; + } break; case IMSG_ACL_CHECK: if (imsg.hdr.len != IMSG_HEADER_SIZE + diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 352a7b0d7e..31d0bc69b1 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -30,6 +30,8 @@ #include "prefix.h" #include "filter.h" #include "vty.h" +#include "pw.h" +#include "zclient.h" #include "ldp.h" @@ -44,7 +46,6 @@ #define LDPD_OPT_NOACTION 0x00000004 #define TCP_MD5_KEY_LEN 80 -#define L2VPN_NAME_LEN 32 #define RT_BUF_SIZE 16384 #define MAX_RTSOCK_BUF 128 * 1024 @@ -102,8 +103,10 @@ enum imsg_type { IMSG_CTL_LOG_VERBOSE, IMSG_KLABEL_CHANGE, IMSG_KLABEL_DELETE, - IMSG_KPWLABEL_CHANGE, - IMSG_KPWLABEL_DELETE, + IMSG_KPW_ADD, + IMSG_KPW_DELETE, + IMSG_KPW_SET, + IMSG_KPW_UNSET, IMSG_IFSTATUS, IMSG_NEWADDR, IMSG_DELADDR, @@ -147,7 +150,8 @@ enum imsg_type { IMSG_DEBUG_UPDATE, IMSG_LOG, IMSG_ACL_CHECK, - IMSG_INIT + IMSG_INIT, + IMSG_PW_UPDATE }; struct ldpd_init { @@ -389,7 +393,7 @@ struct l2vpn_if { char ifname[IF_NAMESIZE]; unsigned int ifindex; int operative; - uint8_t mac[ETHER_ADDR_LEN]; + uint8_t mac[ETH_ALEN]; QOBJ_FIELDS }; RB_HEAD(l2vpn_if_head, l2vpn_if); @@ -407,6 +411,7 @@ struct l2vpn_pw { unsigned int ifindex; uint32_t remote_group; uint16_t remote_mtu; + uint32_t local_status; uint32_t remote_status; uint8_t flags; QOBJ_FIELDS @@ -418,8 +423,7 @@ DECLARE_QOBJ_TYPE(l2vpn_pw) #define F_PW_STATUSTLV 0x02 /* status tlv negotiated */ #define F_PW_CWORD_CONF 0x04 /* control word configured */ #define F_PW_CWORD 0x08 /* control word negotiated */ -#define F_PW_STATUS_UP 0x10 /* pseudowire is operational */ -#define F_PW_STATIC_NBR_ADDR 0x20 /* static neighbor address configured */ +#define F_PW_STATIC_NBR_ADDR 0x10 /* static neighbor address configured */ struct l2vpn { RB_ENTRY(l2vpn) entry; @@ -542,16 +546,6 @@ struct kroute { uint16_t flags; }; -struct kpw { - unsigned short ifindex; - int pw_type; - int af; - union ldpd_addr nexthop; - uint32_t local_label; - uint32_t remote_label; - uint8_t flags; -}; - struct kaddr { char ifname[IF_NAMESIZE]; unsigned short ifindex; @@ -566,7 +560,7 @@ struct kif { unsigned short ifindex; int flags; int operative; - uint8_t mac[ETHER_ADDR_LEN]; + uint8_t mac[ETH_ALEN]; int mtu; }; @@ -668,11 +662,14 @@ struct ldpd_conf *parse_config(char *); int cmdline_symset(char *); /* kroute.c */ +void pw2zpw(struct l2vpn_pw *, struct zapi_pw *); void kif_redistribute(const char *); int kr_change(struct kroute *); int kr_delete(struct kroute *); -int kmpw_set(struct kpw *); -int kmpw_unset(struct kpw *); +int kmpw_add(struct zapi_pw *); +int kmpw_del(struct zapi_pw *); +int kmpw_set(struct zapi_pw *); +int kmpw_unset(struct zapi_pw *); /* util.c */ uint8_t mask2prefixlen(in_addr_t); diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c index f8d4b5f5fd..39860a1859 100644 --- a/ldpd/neighbor.c +++ b/ldpd/neighbor.c @@ -289,6 +289,8 @@ nbr_new(struct in_addr id, int af, int ds_tlv, union ldpd_addr *addr, void nbr_del(struct nbr *nbr) { + struct adj *adj; + log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); @@ -314,6 +316,11 @@ nbr_del(struct nbr *nbr) mapping_list_clr(&nbr->release_list); mapping_list_clr(&nbr->abortreq_list); + while ((adj = RB_ROOT(nbr_adj_head, &nbr->adj_tree)) != NULL) { + adj->nbr = NULL; + RB_REMOVE(nbr_adj_head, &nbr->adj_tree, adj); + } + if (nbr->peerid) RB_REMOVE(nbr_pid_head, &nbrs_by_pid, nbr); RB_REMOVE(nbr_id_head, &nbrs_by_id, nbr); diff --git a/lib/.gitignore b/lib/.gitignore index 60cde149f5..94f401ebe6 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -1,4 +1,4 @@ -Makefile +!Makefile Makefile.in *.o *.lo diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 0000000000..62051ac4cc --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. lib/libfrr.la +%: ALWAYS + @$(MAKE) -s -C .. lib/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/lib/Makefile.am b/lib/Makefile.am deleted file mode 100644 index 5847ad4939..0000000000 --- a/lib/Makefile.am +++ /dev/null @@ -1,155 +0,0 @@ -## Process this file with automake to produce Makefile.in. - -include ../common.am - -AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -AM_CFLAGS = $(WERROR) -DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -AM_YFLAGS = -d -Dapi.prefix=@BISON_OPENBRACE@cmd_yy@BISON_CLOSEBRACE@ @BISON_VERBOSE@ - -command_lex.h: command_lex.c - @if test ! -f $@; then rm -f command_lex.c; else :; fi - @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) command_lex.c; else :; fi -command_parse.lo: command_lex.h -clippy-command_parse.$(OBJEXT): command_lex.h - -lib_LTLIBRARIES = libfrr.la -libfrr_la_LDFLAGS = -version-info 0:0:0 - -libfrr_la_SOURCES = \ - network.c pid_output.c getopt.c getopt1.c \ - checksum.c vector.c linklist.c vty.c openbsd-tree.c \ - graph.c command_parse.y command_lex.l command_match.c \ - command_graph.c \ - command.c \ - sockunion.c prefix.c thread.c if.c buffer.c table.c hash.c \ - filter.c routemap.c distribute.c stream.c log.c plist.c \ - zclient.c sockopt.c md5.c if_rmap.c keychain.c privs.c \ - sigevent.c pqueue.c jhash.c workqueue.c nexthop.c json.c \ - ptm_lib.c csv.c bfd.c vrf.c systemd.c ns.c memory.c memory_vty.c \ - imsg-buffer.c imsg.c skiplist.c \ - qobj.c wheel.c \ - event_counter.c \ - grammar_sandbox.c \ - srcdest_table.c \ - spf_backoff.c \ - libfrr.c \ - strlcpy.c \ - strlcat.c \ - sha256.c \ - module.c \ - hook.c \ - frr_pthread.c \ - termtable.c \ - # end - -BUILT_SOURCES = route_types.h gitversion.h command_parse.h command_lex.h - -libfrr_la_LIBADD = @LIBCAP@ - -if SNMP -lib_LTLIBRARIES += libfrrsnmp.la -endif - -libfrrsnmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -libfrrsnmp_la_LDFLAGS = -version-info 0:0:0 -libfrrsnmp_la_LIBADD = libfrr.la $(SNMP_LIBS) -libfrrsnmp_la_SOURCES = \ - agentx.c \ - smux.c \ - snmp.c \ - #end - -pkginclude_HEADERS = \ - frratomic.h \ - buffer.h checksum.h filter.h getopt.h hash.h \ - if.h linklist.h log.h \ - graph.h command_match.h \ - command_graph.h \ - command.h \ - memory.h network.h prefix.h routemap.h distribute.h sockunion.h \ - stream.h table.h thread.h vector.h version.h vty.h zebra.h \ - plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \ - privs.h sigevent.h pqueue.h jhash.h zassert.h \ - workqueue.h route_types.h libospf.h nexthop.h json.h \ - ptm_lib.h csv.h bfd.h vrf.h ns.h systemd.h bitfield.h \ - fifo.h memory_vty.h mpls.h imsg.h openbsd-queue.h openbsd-tree.h \ - skiplist.h qobj.h wheel.h \ - event_counter.h \ - monotime.h \ - spf_backoff.h \ - srcdest_table.h \ - module.h \ - hook.h \ - libfrr.h \ - sha256.h \ - frr_pthread.h \ - vrf_int.h \ - termtable.h \ - vlan.h \ - vxlan.h \ - ipaddr.h \ - # end - -noinst_HEADERS = \ - plist_int.h \ - log_int.h \ - clippy.h \ - # end - -noinst_PROGRAMS = grammar_sandbox -if BUILD_CLIPPY -noinst_PROGRAMS += clippy -endif - -grammar_sandbox_SOURCES = grammar_sandbox_main.c -grammar_sandbox_LDADD = libfrr.la - -clippy_SOURCES = \ - defun_lex.l \ - command_parse.y \ - command_lex.l \ - command_graph.c \ - command_py.c \ - memory.c \ - graph.c \ - vector.c \ - clippy.c \ - # end -clippy_CPPFLAGS = -D_GNU_SOURCE -clippy_CFLAGS = $(PYTHON_CFLAGS) -clippy_LDADD = $(PYTHON_LIBS) -clippy-command_graph.$(OBJEXT): route_types.h - -plist.lo: plist_clippy.c - -EXTRA_DIST = \ - queue.h \ - command_lex.h \ - route_types.pl route_types.txt \ - gitversion.pl - -route_types.h: $(srcdir)/route_types.txt $(srcdir)/route_types.pl - @PERL@ $(srcdir)/route_types.pl < $(srcdir)/route_types.txt > $@ - -if GIT_VERSION - -# bit of a trick here to always have up-to-date git stamps without triggering -# unneccessary rebuilds. .PHONY causes the .tmp file to be rebuilt always, -# but if we use that on gitversion.h it'll ripple through the .c file deps. -# (even if gitversion.h's file timestamp doesn't change, make will think it -# did, because of .PHONY...) - -.PHONY: gitversion.h.tmp -.SILENT: gitversion.h gitversion.h.tmp -GITH=gitversion.h -gitversion.h.tmp: $(srcdir)/../.git - @PERL@ $(srcdir)/gitversion.pl $(srcdir) > ${GITH}.tmp -gitversion.h: gitversion.h.tmp - { test -f ${GITH} && diff -s -q ${GITH}.tmp ${GITH}; } || cp -v ${GITH}.tmp ${GITH} - -else -.PHONY: gitversion.h -gitversion.h: - true -endif diff --git a/lib/command.c b/lib/command.c index f28a55ec6d..09ffa6ce56 100644 --- a/lib/command.c +++ b/lib/command.c @@ -110,6 +110,7 @@ const char *node_names[] = { "forwarding", // FORWARDING_NODE, "protocol", // PROTOCOL_NODE, "mpls", // MPLS_NODE, + "pw", // PW_NODE, "vty", // VTY_NODE, "link-params", // LINK_PARAMS_NODE, "bgp evpn vni", // BGP_EVPN_VNI_NODE, @@ -1253,6 +1254,7 @@ void cmd_exit(struct vty *vty) vty_config_unlock(vty); break; case INTERFACE_NODE: + case PW_NODE: case NS_NODE: case VRF_NODE: case ZEBRA_NODE: @@ -1338,6 +1340,7 @@ DEFUN (config_end, break; case CONFIG_NODE: case INTERFACE_NODE: + case PW_NODE: case NS_NODE: case VRF_NODE: case ZEBRA_NODE: diff --git a/lib/command.h b/lib/command.h index 533b4b3289..d0c9f0eaf9 100644 --- a/lib/command.h +++ b/lib/command.h @@ -132,6 +132,7 @@ enum node_type { FORWARDING_NODE, /* IP forwarding node. */ PROTOCOL_NODE, /* protocol filtering node */ MPLS_NODE, /* MPLS config node */ + PW_NODE, /* Pseudowire config node */ VTY_NODE, /* Vty node. */ LINK_PARAMS_NODE, /* Link-parameters node */ BGP_EVPN_VNI_NODE, /* BGP EVPN VNI */ @@ -181,6 +182,7 @@ struct cmd_node { #define CMD_ERR_NO_FILE 11 #define CMD_SUSPEND 12 #define CMD_WARNING_CONFIG_FAILED 13 +#define CMD_NOT_MY_INSTANCE 14 /* Argc max counts. */ #define CMD_ARGC_MAX 25 diff --git a/lib/command_graph.c b/lib/command_graph.c index 3efa4d5cfc..dc7233c1fe 100644 --- a/lib/command_graph.c +++ b/lib/command_graph.c @@ -385,7 +385,6 @@ static void cmd_node_names(struct graph_node *gn, struct graph_node *join, break; case START_TKN: - case END_TKN: case JOIN_TKN: /* "<foo|bar> WORD" -> word is not "bar" or "foo" */ prevname = NULL; @@ -405,6 +404,9 @@ static void cmd_node_names(struct graph_node *gn, struct graph_node *join, cmd_token_varname_set(tailtok, jointok->varname); } break; + + case END_TKN: + return; } for (i = 0; i < vector_active(gn->to); i++) { diff --git a/lib/command_lex.l b/lib/command_lex.l index c020d193a1..fddbf7b287 100644 --- a/lib/command_lex.l +++ b/lib/command_lex.l @@ -49,8 +49,8 @@ RANGE \({NUMBER}[ ]?\-[ ]?{NUMBER}\) %option noyywrap %option nounput %option noinput -%option outfile="command_lex.c" -%option header-file="command_lex.h" +%option outfile="lib/command_lex.c" +%option header-file="lib/command_lex.h" %option prefix="cmd_yy" %option reentrant %option bison-bridge diff --git a/lib/command_parse.y b/lib/command_parse.y index ba042c33be..1bc8ea1a44 100644 --- a/lib/command_parse.y +++ b/lib/command_parse.y @@ -33,8 +33,8 @@ /* define api.prefix {cmd_yy} */ /* names for generated header and parser files */ -%defines "command_parse.h" -%output "command_parse.c" +%defines "lib/command_parse.h" +%output "lib/command_parse.c" /* note: code blocks are output in order, to both .c and .h: * 1. %code requires diff --git a/lib/defun_lex.l b/lib/defun_lex.l index 8aa37a62a2..024445be63 100644 --- a/lib/defun_lex.l +++ b/lib/defun_lex.l @@ -85,7 +85,7 @@ SPECIAL [(),] %option noyywrap %option noinput %option nounput -%option outfile="defun_lex.c" +%option outfile="lib/defun_lex.c" %option prefix="def_yy" %option 8bit diff --git a/lib/hash.c b/lib/hash.c index a7714f1569..801871f839 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -94,6 +94,10 @@ static void hash_expand(struct hash *hash) struct hash_backet *hb, *hbnext, **new_index; new_size = hash->size * 2; + + if (hash->max_size && new_size > hash->max_size) + return; + new_index = XCALLOC(MTYPE_HASH_INDEX, sizeof(struct hash_backet *) * new_size); if (new_index == NULL) @@ -354,33 +358,26 @@ DEFUN(show_hash_stats, /* Summary statistics calculated are: * - * - Load factor: This is the number of elements in the table divided by - * the - * number of buckets. Since this hash table implementation uses - * chaining, - * this value can be greater than 1. This number provides information - * on - * how 'full' the table is, but does not provide information on how - * evenly - * distributed the elements are. Notably, a load factor >= 1 does not - * imply - * that every bucket has an element; with a pathological hash - * function, all - * elements could be in a single bucket. + * - Load factor: This is the number of elements in the table divided + * by the number of buckets. Since this hash table implementation + * uses chaining, this value can be greater than 1. + * This number provides information on how 'full' the table is, but + * does not provide information on how evenly distributed the + * elements are. + * Notably, a load factor >= 1 does not imply that every bucket has + * an element; with a pathological hash function, all elements could + * be in a single bucket. * * - Full load factor: this is the number of elements in the table - * divided by - * the number of buckets that have some elements in them. + * divided by the number of buckets that have some elements in them. * * - Std. Dev.: This is the standard deviation calculated from the - * relevant - * load factor. If the load factor is the mean of number of elements - * per - * bucket, the standard deviation measures how much any particular - * bucket - * is likely to deviate from the mean. As a rule of thumb this number - * should be less than 2, and ideally <= 1 for optimal performance. A - * number larger than 3 generally indicates a poor hash function. + * relevant load factor. If the load factor is the mean of number of + * elements per bucket, the standard deviation measures how much any + * particular bucket is likely to deviate from the mean. + * As a rule of thumb this number should be less than 2, and ideally + * <= 1 for optimal performance. A number larger than 3 generally + * indicates a poor hash function. */ double lf; // load factor @@ -407,7 +404,7 @@ DEFUN(show_hash_stats, continue; ssq = (long double)h->stats.ssq; - x2 = powl(h->count, 2.0); + x2 = h->count * h->count; ldc = (long double)h->count; full = h->size - h->stats.empty; lf = h->count / (double)h->size; diff --git a/lib/hash.h b/lib/hash.h index 6ce29f0426..236abbbd6a 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -64,6 +64,9 @@ struct hash { /* Hash table size. Must be power of 2 */ unsigned int size; + /* If max_size is 0 there is no limit */ + unsigned int max_size; + /* Key make function. */ unsigned int (*hash_key)(void *); diff --git a/lib/libospf.h b/lib/libospf.h index c9483a4c65..45aedb6a7d 100644 --- a/lib/libospf.h +++ b/lib/libospf.h @@ -34,7 +34,7 @@ /* Architectual Constants */ #ifdef DEBUG -#define OSPF_LS_REFRESH_TIME 60 +#define OSPF_LS_REFRESH_TIME 120 #else #define OSPF_LS_REFRESH_TIME 1800 #endif @@ -857,6 +857,7 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_INTERFACE_ADDRESS_DELETE), DESC_ENTRY(ZEBRA_INTERFACE_UP), DESC_ENTRY(ZEBRA_INTERFACE_DOWN), + DESC_ENTRY(ZEBRA_INTERFACE_SET_MASTER), DESC_ENTRY(ZEBRA_IPV4_ROUTE_ADD), DESC_ENTRY(ZEBRA_IPV4_ROUTE_DELETE), DESC_ENTRY(ZEBRA_IPV6_ROUTE_ADD), @@ -915,6 +916,11 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_MACIP_DEL), DESC_ENTRY(ZEBRA_REMOTE_MACIP_ADD), DESC_ENTRY(ZEBRA_REMOTE_MACIP_DEL), + DESC_ENTRY(ZEBRA_PW_ADD), + DESC_ENTRY(ZEBRA_PW_DELETE), + DESC_ENTRY(ZEBRA_PW_SET), + DESC_ENTRY(ZEBRA_PW_UNSET), + DESC_ENTRY(ZEBRA_PW_STATUS_UPDATE), }; #undef DESC_ENTRY diff --git a/lib/monotime.h b/lib/monotime.h index 7bd3386498..8e50c1874a 100644 --- a/lib/monotime.h +++ b/lib/monotime.h @@ -49,6 +49,10 @@ static inline time_t monotime(struct timeval *tvo) return ts.tv_sec; } +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND ONE_DAY_SECOND*7 +#define ONE_YEAR_SECOND ONE_DAY_SECOND*365 + /* the following two return microseconds, not time_t! * * also, they're negative forms of each other, but having both makes the diff --git a/lib/prefix.c b/lib/prefix.c index 88b13cd99f..33b6ff1987 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -26,6 +26,7 @@ #include "sockunion.h" #include "memory.h" #include "log.h" +#include "jhash.h" DEFINE_MTYPE_STATIC(LIB, PREFIX, "Prefix") @@ -507,8 +508,9 @@ const char *safi2str(safi_t safi) return "evpn"; case SAFI_LABELED_UNICAST: return "labeled-unicast"; + default: + return "unknown"; } - return NULL; } /* If n includes p prefix then return 1 else return 0. */ @@ -1060,7 +1062,7 @@ int prefix_blen(const struct prefix *p) return IPV6_MAX_BYTELEN; break; case AF_ETHERNET: - return ETHER_ADDR_LEN; + return ETH_ALEN; } return 0; } @@ -1334,3 +1336,15 @@ char *prefix_mac2str(const struct ethaddr *mac, char *buf, int size) (uint8_t)mac->octet[4], (uint8_t)mac->octet[5]); return ptr; } + +unsigned prefix_hash_key(void *pp) +{ + struct prefix copy; + + /* make sure *all* unused bits are zero, particularly including + * alignment / + * padding and unused prefix bytes. */ + memset(©, 0, sizeof(copy)); + prefix_copy(©, (struct prefix *)pp); + return jhash(©, sizeof(copy), 0x55aa5a5a); +} diff --git a/lib/prefix.h b/lib/prefix.h index ce13dcfa0a..5f2b57ccce 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -34,21 +34,39 @@ #include "sockunion.h" #include "ipaddr.h" -#ifndef ETHER_ADDR_LEN -#ifdef ETHERADDRL -#define ETHER_ADDR_LEN ETHERADDRL +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif + +/* for compatibility */ +#if defined(__ICC) +#define CPP_WARN_STR(X) #X +#define CPP_WARN(text) _Pragma(CPP_WARN_STR(message __FILE__ ": " text)) + +#elif (defined(__GNUC__) \ + && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) \ + || (defined(__clang__) \ + && (__clang_major__ >= 4 \ + || (__clang_major__ == 3 && __clang_minor__ >= 5))) +#define CPP_WARN_STR(X) #X +#define CPP_WARN(text) _Pragma(CPP_WARN_STR(GCC warning text)) + #else -#define ETHER_ADDR_LEN 6 +#define CPP_WARN(text) #endif + +#ifdef ETHER_ADDR_LEN +#undef ETHER_ADDR_LEN #endif +#define ETHER_ADDR_LEN 6 CPP_WARN("ETHER_ADDR_LEN is being replaced by ETH_ALEN.\\n") -#define ETHER_ADDR_STRLEN (3*ETHER_ADDR_LEN) +#define ETHER_ADDR_STRLEN (3*ETH_ALEN) /* * there isn't a portable ethernet address type. We define our * own to simplify internal handling */ struct ethaddr { - u_char octet[ETHER_ADDR_LEN]; + u_char octet[ETH_ALEN]; } __attribute__((packed)); @@ -323,6 +341,8 @@ extern const char *inet6_ntoa(struct in6_addr); extern int prefix_str2mac(const char *str, struct ethaddr *mac); extern char *prefix_mac2str(const struct ethaddr *mac, char *buf, int size); +extern unsigned prefix_hash_key(void *pp); + static inline int ipv6_martian(struct in6_addr *addr) { struct in6_addr localhost_addr; diff --git a/lib/pw.h b/lib/pw.h new file mode 100644 index 0000000000..2cfaa47e5d --- /dev/null +++ b/lib/pw.h @@ -0,0 +1,52 @@ +/* Pseudowire definitions + * Copyright (C) 2016 Volta Networks, Inc. + * + * This program 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 of the License, or + * (at your option) any later version. + * + * This program 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 this program; see the file COPYING; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef _FRR_PW_H +#define _FRR_PW_H + +/* L2VPN name length. */ +#define L2VPN_NAME_LEN 32 + +/* Pseudowire type - LDP and BGP use the same values. */ +#define PW_TYPE_ETHERNET_TAGGED 0x0004 /* RFC 4446 */ +#define PW_TYPE_ETHERNET 0x0005 /* RFC 4446 */ +#define PW_TYPE_WILDCARD 0x7FFF /* RFC 4863, RFC 6668 */ + +/* Pseudowire flags. */ +#define F_PSEUDOWIRE_CWORD 0x01 + +/* Pseudowire status. */ +#define PW_STATUS_DOWN 0 +#define PW_STATUS_UP 1 + +/* + * Protocol-specific information about the pseudowire. + */ +union pw_protocol_fields { + struct { + struct in_addr lsr_id; + uint32_t pwid; + char vpn_name[L2VPN_NAME_LEN]; + } ldp; + struct { + /* TODO */ + } bgp; +}; + +#endif /* _FRR_PW_H */ diff --git a/lib/sbuf.c b/lib/sbuf.c new file mode 100644 index 0000000000..37c1e5283d --- /dev/null +++ b/lib/sbuf.c @@ -0,0 +1,107 @@ +/* + * Simple string buffer + * + * Copyright (C) 2017 Christian Franke + * + * This file is part of FRR. + * + * FRR 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. + * + * FRR 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 FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#include <zebra.h> + +#include "sbuf.h" +#include "memory.h" + +void sbuf_init(struct sbuf *dest, char *buf, size_t size) +{ + dest->fixed = (size > 0); + if (dest->fixed) { + dest->buf = buf; + dest->size = size; + } else { + dest->buf = XMALLOC(MTYPE_TMP, 4096); + dest->size = 4096; + } + + dest->pos = 0; + dest->buf[0] = '\0'; +} + +void sbuf_reset(struct sbuf *dest) +{ + dest->pos = 0; + dest->buf[0] = '\0'; +} + +const char *sbuf_buf(struct sbuf *buf) +{ + return buf->buf; +} + +void sbuf_free(struct sbuf *buf) +{ + if (!buf->fixed) + XFREE(MTYPE_TMP, buf->buf); +} + +void sbuf_push(struct sbuf *buf, int indent, const char *format, ...) +{ + va_list args; + int written; + + if (!buf->fixed) { + char dummy; + int written1, written2; + size_t new_size; + + written1 = snprintf(&dummy, 0, "%*s", indent, ""); + va_start(args, format); + written2 = vsnprintf(&dummy, 0, format, args); + va_end(args); + + new_size = buf->size; + if (written1 >= 0 && written2 >= 0) { + while (buf->pos + written1 + written2 >= new_size) + new_size *= 2; + if (new_size > buf->size) { + buf->buf = + XREALLOC(MTYPE_TMP, buf->buf, new_size); + buf->size = new_size; + } + } + } + + written = snprintf(buf->buf + buf->pos, buf->size - buf->pos, "%*s", + indent, ""); + + if (written >= 0) + buf->pos += written; + if (buf->pos > buf->size) + buf->pos = buf->size; + + va_start(args, format); + written = vsnprintf(buf->buf + buf->pos, buf->size - buf->pos, format, + args); + va_end(args); + + if (written >= 0) + buf->pos += written; + if (buf->pos > buf->size) + buf->pos = buf->size; + + if (buf->pos == buf->size) + assert(!"Buffer filled up!"); +} diff --git a/lib/sbuf.h b/lib/sbuf.h new file mode 100644 index 0000000000..3e49ada6c2 --- /dev/null +++ b/lib/sbuf.h @@ -0,0 +1,77 @@ +/* + * Simple string buffer + * + * Copyright (C) 2017 Christian Franke + * + * This file is part of FRR. + * + * FRR 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. + * + * FRR 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 FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ +#ifndef SBUF_H +#define SBUF_H + +/* + * sbuf provides a simple string buffer. One application where this comes + * in handy is the parsing of binary data: If there is an error in the parsing + * process due to invalid input data, printing an error message explaining what + * went wrong is definitely useful. However, just printing the actual error, + * without any information about the previous parsing steps, is usually not very + * helpful. + * Using sbuf, the parser can log the whole parsing process into a buffer using + * a printf like API. When an error ocurrs, all the information about previous + * parsing steps is there in the log, without any need for backtracking, and can + * be used to give a detailed and useful error description. + * When parsing completes successfully without any error, the log can just be + * discarded unless debugging is turned on, to not spam the log. + * + * For the described usecase, the code would look something like this: + * + * int sbuf_example(..., char **parser_log) + * { + * struct sbuf logbuf; + * + * sbuf_init(&logbuf, NULL, 0); + * sbuf_push(&logbuf, 0, "Starting parser\n"); + * + * int rv = do_parse(&logbuf, ...); + * + * *parser_log = sbuf_buf(&logbuf); + * + * return 1; + * } + * + * In this case, sbuf_example uses a string buffer with undefined size, which will + * be allocated on the heap by sbuf. The caller of sbuf_example is expected to free + * the string returned in parser_log. + */ + +struct sbuf { + bool fixed; + char *buf; + size_t size; + size_t pos; + int indent; +}; + +void sbuf_init(struct sbuf *dest, char *buf, size_t size); +void sbuf_reset(struct sbuf *buf); +const char *sbuf_buf(struct sbuf *buf); +void sbuf_free(struct sbuf *buf); +#include "lib/log.h" +void sbuf_push(struct sbuf *buf, int indent, const char *format, ...) + PRINTF_ATTRIBUTE(3, 4); + +#endif diff --git a/lib/sockunion.c b/lib/sockunion.c index af0054d6b2..559ae37ffb 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -354,13 +354,19 @@ int sockopt_ttl(int family, int sock, int ttl) return 0; } +/* + * This function called setsockopt(.., TCP_CORK,...) + * Which on linux is a no-op since it is enabled by + * default and on BSD it uses TCP_NOPUSH to do + * the same thing( which it was not configured to + * use). This cleanup of the api occured on 8/1/17 + * I imagine if after more than 1 year of no-one + * complaining, and a major upgrade release we + * can deprecate and remove this function call + */ int sockopt_cork(int sock, int onoff) { -#ifdef TCP_CORK - return setsockopt(sock, IPPROTO_TCP, TCP_CORK, &onoff, sizeof(onoff)); -#else return 0; -#endif } int sockopt_mark_default(int sock, int mark, struct zebra_privs_t *cap) diff --git a/lib/subdir.am b/lib/subdir.am new file mode 100644 index 0000000000..15ce8ec199 --- /dev/null +++ b/lib/subdir.am @@ -0,0 +1,263 @@ +# +# libfrr +# +lib_LTLIBRARIES += lib/libfrr.la +lib_libfrr_la_LDFLAGS = -version-info 0:0:0 +lib_libfrr_la_LIBADD = @LIBCAP@ + +lib_libfrr_la_SOURCES = \ + lib/bfd.c \ + lib/buffer.c \ + lib/checksum.c \ + lib/command.c \ + lib/command_graph.c \ + lib/command_lex.l \ + lib/command_match.c \ + lib/command_parse.y \ + lib/csv.c \ + lib/distribute.c \ + lib/event_counter.c \ + lib/filter.c \ + lib/frr_pthread.c \ + lib/getopt.c \ + lib/getopt1.c \ + lib/grammar_sandbox.c \ + lib/graph.c \ + lib/hash.c \ + lib/hook.c \ + lib/if.c \ + lib/if_rmap.c \ + lib/imsg-buffer.c \ + lib/imsg.c \ + lib/jhash.c \ + lib/json.c \ + lib/keychain.c \ + lib/libfrr.c \ + lib/linklist.c \ + lib/log.c \ + lib/md5.c \ + lib/memory.c \ + lib/memory_vty.c \ + lib/module.c \ + lib/network.c \ + lib/nexthop.c \ + lib/ns.c \ + lib/openbsd-tree.c \ + lib/pid_output.c \ + lib/plist.c \ + lib/pqueue.c \ + lib/prefix.c \ + lib/privs.c \ + lib/ptm_lib.c \ + lib/qobj.c \ + lib/routemap.c \ + lib/sbuf.c \ + lib/sha256.c \ + lib/sigevent.c \ + lib/skiplist.c \ + lib/sockopt.c \ + lib/sockunion.c \ + lib/spf_backoff.c \ + lib/srcdest_table.c \ + lib/stream.c \ + lib/strlcat.c \ + lib/strlcpy.c \ + lib/systemd.c \ + lib/table.c \ + lib/termtable.c \ + lib/thread.c \ + lib/vector.c \ + lib/vrf.c \ + lib/vty.c \ + lib/wheel.c \ + lib/workqueue.c \ + lib/zclient.c \ + # end + +lib/plist_clippy.c: $(CLIPPY_DEPS) +lib/plist.lo: lib/plist_clippy.c + +pkginclude_HEADERS += \ + lib/bfd.h \ + lib/bitfield.h \ + lib/buffer.h \ + lib/checksum.h \ + lib/command.h \ + lib/command_graph.h \ + lib/command_match.h \ + lib/csv.h \ + lib/distribute.h \ + lib/event_counter.h \ + lib/fifo.h \ + lib/filter.h \ + lib/frr_pthread.h \ + lib/frratomic.h \ + lib/getopt.h \ + lib/graph.h \ + lib/hash.h \ + lib/hook.h \ + lib/if.h \ + lib/if_rmap.h \ + lib/imsg.h \ + lib/ipaddr.h \ + lib/jhash.h \ + lib/json.h \ + lib/keychain.h \ + lib/libfrr.h \ + lib/libospf.h \ + lib/linklist.h \ + lib/log.h \ + lib/md5.h \ + lib/memory.h \ + lib/memory_vty.h \ + lib/module.h \ + lib/monotime.h \ + lib/mpls.h \ + lib/network.h \ + lib/nexthop.h \ + lib/ns.h \ + lib/openbsd-queue.h \ + lib/openbsd-tree.h \ + lib/plist.h \ + lib/pqueue.h \ + lib/prefix.h \ + lib/privs.h \ + lib/ptm_lib.h \ + lib/pw.h \ + lib/qobj.h \ + lib/route_types.h \ + lib/routemap.h \ + lib/sbuf.h \ + lib/sha256.h \ + lib/sigevent.h \ + lib/skiplist.h \ + lib/smux.h \ + lib/sockopt.h \ + lib/sockunion.h \ + lib/spf_backoff.h \ + lib/srcdest_table.h \ + lib/stream.h \ + lib/systemd.h \ + lib/table.h \ + lib/termtable.h \ + lib/thread.h \ + lib/vector.h \ + lib/version.h \ + lib/vlan.h \ + lib/vrf.h \ + lib/vrf_int.h \ + lib/vty.h \ + lib/vxlan.h \ + lib/wheel.h \ + lib/workqueue.h \ + lib/zassert.h \ + lib/zclient.h \ + lib/zebra.h \ + # end + +noinst_HEADERS += \ + lib/clippy.h \ + lib/log_int.h \ + lib/plist_int.h \ + #end + +# +# SNMP support +# +if SNMP +lib_LTLIBRARIES += lib/libfrrsnmp.la +endif + +lib_libfrrsnmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) +lib_libfrrsnmp_la_LDFLAGS = -version-info 0:0:0 +lib_libfrrsnmp_la_LIBADD = lib/libfrr.la $(SNMP_LIBS) +lib_libfrrsnmp_la_SOURCES = \ + lib/agentx.c \ + lib/smux.c \ + lib/snmp.c \ + # end + +# +# CLI utilities +# +noinst_PROGRAMS += \ + lib/clippy \ + lib/grammar_sandbox \ + # end + +lib_grammar_sandbox_SOURCES = \ + lib/grammar_sandbox_main.c +lib_grammar_sandbox_LDADD = \ + lib/libfrr.la + +lib_clippy_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/lib +lib_clippy_CFLAGS = $(PYTHON_CFLAGS) +lib_clippy_LDADD = $(PYTHON_LIBS) +lib_clippy_SOURCES = \ + lib/clippy.c \ + lib/command_graph.c \ + lib/command_lex.l \ + lib/command_parse.y \ + lib/command_py.c \ + lib/defun_lex.l \ + lib/graph.c \ + lib/memory.c \ + lib/vector.c \ + # end + + +# +# generated sources & extra foo +# +EXTRA_DIST += \ + lib/command_lex.h \ + lib/gitversion.pl \ + lib/queue.h \ + lib/route_types.pl \ + lib/route_types.txt \ + # end + +BUILT_SOURCES += \ + lib/command_lex.h \ + lib/command_parse.h \ + lib/gitversion.h \ + lib/route_types.h \ + # end + +## force route_types.h +$(lib_clippy_OBJECTS): lib/route_types.h +$(lib_libfrr_la_OBJECTS): lib/route_types.h + +AM_YFLAGS = -d -Dapi.prefix=@BISON_OPENBRACE@cmd_yy@BISON_CLOSEBRACE@ @BISON_VERBOSE@ + +lib/command_lex.h: lib/command_lex.c + @if test ! -f $@; then rm -f "lib/command_lex.c"; else :; fi + @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) "lib/command_lex.c"; else :; fi +lib/command_lex.lo: lib/command_parse.h +lib/command_parse.lo: lib/command_lex.h +lib/lib_clippy-command_lex.$(OBJEXT): lib/command_parse.h +lib/lib_clippy-command_parse.$(OBJEXT): lib/command_lex.h + +lib/route_types.h: $(top_srcdir)/lib/route_types.txt $(top_srcdir)/lib/route_types.pl + @PERL@ $(top_srcdir)/lib/route_types.pl < $(top_srcdir)/lib/route_types.txt > $@ + +if GIT_VERSION +# bit of a trick here to always have up-to-date git stamps without triggering +# unneccessary rebuilds. .PHONY causes the .tmp file to be rebuilt always, +# but if we use that on gitversion.h it'll ripple through the .c file deps. +# (even if gitversion.h's file timestamp doesn't change, make will think it +# did, because of .PHONY...) + +.PHONY: lib/gitversion.h.tmp +.SILENT: lib/gitversion.h lib/gitversion.h.tmp +GITH=lib/gitversion.h +lib/gitversion.h.tmp: $(top_srcdir)/.git + @PERL@ $(top_srcdir)/lib/gitversion.pl $(top_srcdir) > ${GITH}.tmp +lib/gitversion.h: lib/gitversion.h.tmp + { test -f ${GITH} && diff -s -q ${GITH}.tmp ${GITH}; } || cp ${GITH}.tmp ${GITH} + +else +.PHONY: lib/gitversion.h +lib/gitversion.h: + true +endif diff --git a/lib/table.c b/lib/table.c index 2defa4fb62..833adb9a37 100644 --- a/lib/table.c +++ b/lib/table.c @@ -27,7 +27,6 @@ #include "table.h" #include "memory.h" #include "sockunion.h" -#include "jhash.h" DEFINE_MTYPE(LIB, ROUTE_TABLE, "Route table") DEFINE_MTYPE(LIB, ROUTE_NODE, "Route node") @@ -35,18 +34,6 @@ DEFINE_MTYPE(LIB, ROUTE_NODE, "Route node") static void route_node_delete(struct route_node *); static void route_table_free(struct route_table *); -static unsigned route_table_hash_key(void *pp) -{ - struct prefix copy; - - /* make sure *all* unused bits are zero, particularly including - * alignment / - * padding and unused prefix bytes. */ - memset(©, 0, sizeof(copy)); - prefix_copy(©, (struct prefix *)pp); - return jhash(©, sizeof(copy), 0x55aa5a5a); -} - static int route_table_hash_cmp(const void *a, const void *b) { const struct prefix *pa = a, *pb = b; @@ -63,7 +50,7 @@ route_table_init_with_delegate(route_table_delegate_t *delegate) rt = XCALLOC(MTYPE_ROUTE_TABLE, sizeof(struct route_table)); rt->delegate = delegate; - rt->hash = hash_create(route_table_hash_key, route_table_hash_cmp, + rt->hash = hash_create(prefix_hash_key, route_table_hash_cmp, "route table hash"); return rt; } @@ -88,6 +75,7 @@ static struct route_node *route_node_set(struct route_table *table, node = route_node_new(table); prefix_copy(&node->p, prefix); + apply_mask(&node->p); node->table = table; inserted = hash_get(node->table->hash, node, hash_alloc_intern); diff --git a/lib/thread.c b/lib/thread.c index 5db470ef48..4a5c61d036 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -47,6 +47,9 @@ DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats") write(m->io_pipe[1], &wakebyte, 1); \ } while (0); +/* max # of thread_fetch() calls before we force a poll() */ +#define MAX_TICK_IO 1000 + /* control variable for initializer */ pthread_once_t init_once = PTHREAD_ONCE_INIT; pthread_key_t thread_current; @@ -337,9 +340,6 @@ static void cancelreq_del(void *cr) /* initializer, only ever called once */ static void initializer() { - if (!masters) - masters = list_new(); - pthread_key_create(&thread_current, NULL); } @@ -412,9 +412,12 @@ struct thread_master *thread_master_create(const char *name) rv->handler.copy = XCALLOC(MTYPE_THREAD_MASTER, sizeof(struct pollfd) * rv->handler.pfdsize); - /* add to list */ + /* add to list of threadmasters */ pthread_mutex_lock(&masters_mtx); { + if (!masters) + masters = list_new(); + listnode_add(masters, rv); } pthread_mutex_unlock(&masters_mtx); @@ -548,6 +551,10 @@ void thread_master_free(struct thread_master *m) pthread_mutex_lock(&masters_mtx); { listnode_delete(masters, m); + if (masters->count == 0) { + list_free (masters); + masters = NULL; + } } pthread_mutex_unlock(&masters_mtx); @@ -1312,16 +1319,16 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch) /* Process any pending cancellation requests */ do_thread_cancel(m); - /* Post events to ready queue. This must come before the - * following block - * since events should occur immediately */ + /* + * Post events to ready queue. This must come before the + * following block since events should occur immediately + */ thread_process(&m->event); - /* If there are no tasks on the ready queue, we will poll() - * until a timer - * expires or we receive I/O, whichever comes first. The - * strategy for doing - * this is: + /* + * If there are no tasks on the ready queue, we will poll() + * until a timer expires or we receive I/O, whichever comes + * first. The strategy for doing this is: * * - If there are events pending, set the poll() timeout to zero * - If there are no events pending, but there are timers @@ -1333,9 +1340,8 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch) * - If nothing is pending, it's time for the application to die * * In every case except the last, we need to hit poll() at least - * once per - * loop to avoid starvation by events */ - + * once per loop to avoid starvation by events + */ if (m->ready.count == 0) tw = thread_timer_wait(m->timer, &tv); @@ -1348,37 +1354,53 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch) break; } - /* Copy pollfd array + # active pollfds in it. Not necessary to - * copy - * the array size as this is fixed. */ + /* + * Copy pollfd array + # active pollfds in it. Not necessary to + * copy the array size as this is fixed. + */ m->handler.copycount = m->handler.pfdcount; memcpy(m->handler.copy, m->handler.pfds, m->handler.copycount * sizeof(struct pollfd)); - pthread_mutex_unlock(&m->mtx); - { - num = fd_poll(m, m->handler.copy, m->handler.pfdsize, - m->handler.copycount, tw); - } - pthread_mutex_lock(&m->mtx); + /* + * Attempt to flush ready queue before going into poll(). + * This is performance-critical. Think twice before modifying. + */ + if (m->ready.count == 0 || m->tick_since_io >= MAX_TICK_IO) { + pthread_mutex_unlock(&m->mtx); + { + m->tick_since_io = 0; + num = fd_poll(m, m->handler.copy, + m->handler.pfdsize, + m->handler.copycount, tw); + } + pthread_mutex_lock(&m->mtx); + + /* Handle any errors received in poll() */ + if (num < 0) { + if (errno == EINTR) { + pthread_mutex_unlock(&m->mtx); + /* loop around to signal handler */ + continue; + } - /* Handle any errors received in poll() */ - if (num < 0) { - if (errno == EINTR) { + /* else die */ + zlog_warn("poll() error: %s", + safe_strerror(errno)); pthread_mutex_unlock(&m->mtx); - continue; /* loop around to signal handler */ + fetch = NULL; + break; } - /* else die */ - zlog_warn("poll() error: %s", safe_strerror(errno)); - pthread_mutex_unlock(&m->mtx); - fetch = NULL; - break; - } + /* + * Since we could have received more cancellation + * requests during poll(), process those + */ + do_thread_cancel(m); - /* Since we could have received more cancellation requests - * during poll(), process those */ - do_thread_cancel(m); + } else { + m->tick_since_io++; + } /* Post timers to ready queue. */ monotime(&now); @@ -1388,8 +1410,7 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch) if (num > 0) thread_process_io(m, num); - /* If we have a ready task, break the loop and return it to the - * caller */ + /* have a ready task ==> return it to caller */ if ((thread = thread_trim_head(&m->ready))) { fetch = thread_run(m, thread, fetch); if (fetch->ref) diff --git a/lib/thread.h b/lib/thread.h index c830446e10..86bf4df7c0 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -70,6 +70,7 @@ struct cancel_req { struct thread_master { char *name; + int tick_since_io; struct thread **read; struct thread **write; struct pqueue *timer; @@ -306,6 +306,7 @@ struct vty *vty_new() { struct vty *new = XCALLOC(MTYPE_VTY, sizeof(struct vty)); + new->fd = new->wfd = -1; new->obuf = buffer_new(0); /* Use default buffer size. */ new->buf = XCALLOC(MTYPE_VTY, VTY_BUFSIZ); new->error_buf = XCALLOC(MTYPE_VTY, VTY_BUFSIZ); @@ -683,6 +684,7 @@ static void vty_end_config(struct vty *vty) break; case CONFIG_NODE: case INTERFACE_NODE: + case PW_NODE: case ZEBRA_NODE: case RIP_NODE: case RIPNG_NODE: @@ -1093,6 +1095,7 @@ static void vty_stop_input(struct vty *vty) break; case CONFIG_NODE: case INTERFACE_NODE: + case PW_NODE: case ZEBRA_NODE: case RIP_NODE: case RIPNG_NODE: @@ -2129,16 +2132,21 @@ void vty_close(struct vty *vty) XFREE(MTYPE_VTY_HIST, vty->hist[i]); /* Unset vector. */ - vector_unset(vtyvec, vty->fd); + if (vty->fd != -1) + vector_unset(vtyvec, vty->fd); if (vty->wfd > 0 && vty->type == VTY_FILE) fsync(vty->wfd); - /* Close socket. */ - if (vty->fd > 0) { + /* Close socket. + * note check is for fd > STDERR_FILENO, not fd != -1. + * We never close stdin/stdout/stderr here, because we may be + * running in foreground mode with logging to stdout. Also, + * additionally, we'd need to replace these fds with /dev/null. */ + if (vty->wfd > STDERR_FILENO && vty->wfd != vty->fd) + close(vty->wfd); + if (vty->fd > STDERR_FILENO) { close(vty->fd); - if (vty->wfd > 0 && vty->wfd != vty->fd) - close(vty->wfd); } else was_stdio = true; @@ -2186,13 +2194,14 @@ static void vty_read_file(FILE *confp) unsigned int line_num = 0; vty = vty_new(); - vty->wfd = dup(STDERR_FILENO); /* vty_close() will close this */ - if (vty->wfd < 0) { - /* Fine, we couldn't make a new fd. vty_close doesn't close - * stdout. */ - vty->wfd = STDOUT_FILENO; - } - vty->fd = STDIN_FILENO; + /* vty_close won't close stderr; if some config command prints + * something it'll end up there. (not ideal; it'd be beter if output + * from a file-load went to logging instead. Also note that if this + * function is called after daemonizing, stderr will be /dev/null.) + * + * vty->fd will be -1 from vty_new() + */ + vty->wfd = STDERR_FILENO; vty->type = VTY_FILE; vty->node = CONFIG_NODE; @@ -2200,7 +2209,7 @@ static void vty_read_file(FILE *confp) ret = config_from_file(vty, confp, &line_num); /* Flush any previous errors before printing messages below */ - buffer_flush_all(vty->obuf, vty->fd); + buffer_flush_all(vty->obuf, vty->wfd); if (!((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO))) { const char *message = NULL; @@ -166,6 +166,11 @@ static inline void vty_push_context(struct vty *vty, int node, uint64_t id) #define VTY_DECLVAR_CONTEXT_SUB(structname, ptr) \ struct structname *ptr = VTY_GET_CONTEXT_SUB(structname); \ VTY_CHECK_CONTEXT(ptr); +#define VTY_DECLVAR_INSTANCE_CONTEXT(structname, ptr) \ + if (vty->qobj_index == 0) \ + return CMD_NOT_MY_INSTANCE; \ + struct structname *ptr = VTY_GET_CONTEXT(structname); \ + VTY_CHECK_CONTEXT(ptr); struct vty_arg { const char *name; diff --git a/lib/zclient.c b/lib/zclient.c index a54d8749a3..893d769e3a 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1834,6 +1834,69 @@ int lm_release_label_chunk(struct zclient *zclient, uint32_t start, return 0; } +int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw) +{ + struct stream *s; + + /* Reset stream. */ + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, command, VRF_DEFAULT); + stream_write(s, pw->ifname, IF_NAMESIZE); + stream_putl(s, pw->ifindex); + + /* Put type */ + stream_putl(s, pw->type); + + /* Put nexthop */ + stream_putl(s, pw->af); + switch (pw->af) { + case AF_INET: + stream_put_in_addr(s, &pw->nexthop.ipv4); + break; + case AF_INET6: + stream_write(s, (u_char *)&pw->nexthop.ipv6, 16); + break; + default: + zlog_err("%s: unknown af", __func__); + return -1; + } + + /* Put labels */ + stream_putl(s, pw->local_label); + stream_putl(s, pw->remote_label); + + /* Put flags */ + stream_putc(s, pw->flags); + + /* Protocol specific fields */ + stream_write(s, &pw->data, sizeof(union pw_protocol_fields)); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + +/* + * Receive PW status update from Zebra and send it to LDE process. + */ +void zebra_read_pw_status_update(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id, + struct zapi_pw_status *pw) +{ + struct stream *s; + + memset(pw, 0, sizeof(struct zapi_pw_status)); + s = zclient->ibuf; + + /* Get data. */ + stream_get(pw->ifname, s, IF_NAMESIZE); + pw->ifindex = stream_getl(s); + pw->status = stream_getl(s); +} + /* Zebra client message read function. */ static int zclient_read(struct thread *thread) { @@ -2061,6 +2124,11 @@ static int zclient_read(struct thread *thread) (*zclient->local_macip_del)(command, zclient, length, vrf_id); break; + case ZEBRA_PW_STATUS_UPDATE: + if (zclient->pw_status_update) + (*zclient->pw_status_update)(command, zclient, length, + vrf_id); + break; default: break; } @@ -2184,3 +2252,23 @@ void zclient_serv_path_set(char *path) /* it seems that path is unix socket */ zclient_serv_path = path; } + +void zclient_interface_set_master(struct zclient *client, + struct interface *master, + struct interface *slave) +{ + struct stream *s; + + s = client->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_INTERFACE_SET_MASTER, master->vrf_id); + + stream_putw(s, master->vrf_id); + stream_putl(s, master->ifindex); + stream_putw(s, slave->vrf_id); + stream_putl(s, slave->ifindex); + + stream_putw_at(s, 0, stream_get_endp(s)); + zclient_send_message(client); +} diff --git a/lib/zclient.h b/lib/zclient.h index efa5c32c16..8a2729543f 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -30,6 +30,12 @@ /* For vrf_bitmap_t. */ #include "vrf.h" +/* For union g_addr */ +#include "nexthop.h" + +/* For union pw_protocol_fields */ +#include "pw.h" + /* For input/output buffer to zebra. */ #define ZEBRA_MAX_PACKET_SIZ 4096 @@ -44,6 +50,7 @@ typedef enum { ZEBRA_INTERFACE_ADDRESS_DELETE, ZEBRA_INTERFACE_UP, ZEBRA_INTERFACE_DOWN, + ZEBRA_INTERFACE_SET_MASTER, ZEBRA_IPV4_ROUTE_ADD, ZEBRA_IPV4_ROUTE_DELETE, ZEBRA_IPV6_ROUTE_ADD, @@ -105,6 +112,11 @@ typedef enum { ZEBRA_MACIP_DEL, ZEBRA_REMOTE_MACIP_ADD, ZEBRA_REMOTE_MACIP_DEL, + ZEBRA_PW_ADD, + ZEBRA_PW_DELETE, + ZEBRA_PW_SET, + ZEBRA_PW_UNSET, + ZEBRA_PW_STATUS_UPDATE, } zebra_message_types_t; struct redist_proto { @@ -186,6 +198,7 @@ struct zclient { int (*local_vni_del)(int, struct zclient *, uint16_t, vrf_id_t); int (*local_macip_add)(int, struct zclient *, uint16_t, vrf_id_t); int (*local_macip_del)(int, struct zclient *, uint16_t, vrf_id_t); + int (*pw_status_update)(int, struct zclient *, uint16_t, vrf_id_t); }; /* Zebra API message flag. */ @@ -265,6 +278,25 @@ struct zapi_ipv4 { vrf_id_t vrf_id; }; +struct zapi_pw { + char ifname[IF_NAMESIZE]; + ifindex_t ifindex; + int type; + int af; + union g_addr nexthop; + uint32_t local_label; + uint32_t remote_label; + uint8_t flags; + union pw_protocol_fields data; + uint8_t protocol; +}; + +struct zapi_pw_status { + char ifname[IF_NAMESIZE]; + ifindex_t ifindex; + uint32_t status; +}; + /* Prototypes of zebra client service functions. */ extern struct zclient *zclient_new(struct thread_master *); extern void zclient_init(struct zclient *, int, u_short); @@ -311,6 +343,9 @@ extern int zclient_read_header(struct stream *s, int sock, u_int16_t *size, u_char *marker, u_char *version, vrf_id_t *vrf_id, u_int16_t *cmd); +extern void zclient_interface_set_master(struct zclient *client, + struct interface *master, + struct interface *slave); extern struct interface *zebra_interface_add_read(struct stream *, vrf_id_t); extern struct interface *zebra_interface_state_read(struct stream *s, vrf_id_t); extern struct connected *zebra_interface_address_read(int, struct stream *, @@ -334,6 +369,12 @@ extern int lm_get_label_chunk(struct zclient *zclient, u_char keep, uint32_t *end); extern int lm_release_label_chunk(struct zclient *zclient, uint32_t start, uint32_t end); +extern int zebra_send_pw(struct zclient *zclient, int command, + struct zapi_pw *pw); +extern void zebra_read_pw_status_update(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id, + struct zapi_pw_status *pw); + /* IPv6 prefix add and delete function prototype. */ struct zapi_ipv6 { diff --git a/lib/zebra.h b/lib/zebra.h index 8e1c4db804..6d64bbd670 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -126,6 +126,13 @@ typedef unsigned char u_int8_t; #define __APPLE_USE_RFC_3542 #endif +#ifndef HAVE_LIBCRYPT +# ifdef HAVE_LIBCRYPTO +# include <openssl/des.h> +# define crypt DES_crypt +# endif +#endif + #include "openbsd-tree.h" #include <netinet/in.h> @@ -416,22 +423,15 @@ extern const char *zserv_command_string(unsigned int command); typedef enum { AFI_IP = 1, AFI_IP6 = 2, AFI_L2VPN = 3, AFI_MAX = 4 } afi_t; /* Subsequent Address Family Identifier. */ -#define SAFI_UNICAST 1 -#define SAFI_MULTICAST 2 -#define SAFI_MPLS_VPN 3 -#define SAFI_RESERVED_4 4 -#define SAFI_ENCAP 5 -#define SAFI_RESERVED_5 5 -#define SAFI_EVPN 6 -#define SAFI_LABELED_UNICAST 7 -#define SAFI_MAX 8 - -#define IANA_SAFI_RESERVED 0 -#define IANA_SAFI_UNICAST 1 -#define IANA_SAFI_MULTICAST 2 -#define IANA_SAFI_LABELED_UNICAST 4 -#define IANA_SAFI_ENCAP 7 -#define IANA_SAFI_MPLS_VPN 128 +typedef enum { + SAFI_UNICAST = 1, + SAFI_MULTICAST = 2, + SAFI_MPLS_VPN = 3, + SAFI_ENCAP = 4, + SAFI_EVPN = 5, + SAFI_LABELED_UNICAST = 6, + SAFI_MAX = 7 +} safi_t; /* * The above AFI and SAFI definitions are for internal use. The protocol @@ -451,12 +451,15 @@ typedef enum { IANA_AFI_IP6MR = 129 } iana_afi_t; -#define IANA_SAFI_RESERVED 0 -#define IANA_SAFI_UNICAST 1 -#define IANA_SAFI_MULTICAST 2 -#define IANA_SAFI_ENCAP 7 -#define IANA_SAFI_EVPN 70 -#define IANA_SAFI_MPLS_VPN 128 +typedef enum { + IANA_SAFI_RESERVED = 0, + IANA_SAFI_UNICAST = 1, + IANA_SAFI_MULTICAST = 2, + IANA_SAFI_LABELED_UNICAST = 4, + IANA_SAFI_ENCAP = 7, + IANA_SAFI_EVPN = 70, + IANA_SAFI_MPLS_VPN = 128 +} iana_safi_t; /* Default Administrative Distance of each protocol. */ #define ZEBRA_KERNEL_DISTANCE_DEFAULT 0 @@ -477,8 +480,6 @@ typedef enum { #define UNSET_FLAG(V,F) (V) &= ~(F) #define RESET_FLAG(V) (V) = 0 -typedef u_int8_t safi_t; - /* Zebra types. Used in Zserv message header. */ typedef u_int16_t zebra_size_t; typedef u_int16_t zebra_command_t; @@ -492,58 +493,70 @@ typedef uint32_t route_tag_t; static inline afi_t afi_iana2int(iana_afi_t afi) { - if (afi == IANA_AFI_IPV4) + switch (afi) { + case IANA_AFI_IPV4: return AFI_IP; - if (afi == IANA_AFI_IPV6) + case IANA_AFI_IPV6: return AFI_IP6; - if (afi == IANA_AFI_L2VPN) + case IANA_AFI_L2VPN: return AFI_L2VPN; - return AFI_MAX; + default: + return AFI_MAX; + } } static inline iana_afi_t afi_int2iana(afi_t afi) { - if (afi == AFI_IP) + switch (afi) { + case AFI_IP: return IANA_AFI_IPV4; - if (afi == AFI_IP6) + case AFI_IP6: return IANA_AFI_IPV6; - if (afi == AFI_L2VPN) + case AFI_L2VPN: return IANA_AFI_L2VPN; - return IANA_AFI_RESERVED; + default: + return IANA_AFI_RESERVED; + } } -static inline safi_t safi_iana2int(safi_t safi) +static inline safi_t safi_iana2int(iana_safi_t safi) { - if (safi == IANA_SAFI_UNICAST) + switch (safi) { + case IANA_SAFI_UNICAST: return SAFI_UNICAST; - if (safi == IANA_SAFI_MULTICAST) + case IANA_SAFI_MULTICAST: return SAFI_MULTICAST; - if (safi == IANA_SAFI_MPLS_VPN) + case IANA_SAFI_MPLS_VPN: return SAFI_MPLS_VPN; - if (safi == IANA_SAFI_ENCAP) + case IANA_SAFI_ENCAP: return SAFI_ENCAP; - if (safi == IANA_SAFI_EVPN) + case IANA_SAFI_EVPN: return SAFI_EVPN; - if (safi == IANA_SAFI_LABELED_UNICAST) + case IANA_SAFI_LABELED_UNICAST: return SAFI_LABELED_UNICAST; - return SAFI_MAX; + default: + return SAFI_MAX; + } } -static inline safi_t safi_int2iana(safi_t safi) +static inline iana_safi_t safi_int2iana(safi_t safi) { - if (safi == SAFI_UNICAST) + switch (safi) { + case SAFI_UNICAST: return IANA_SAFI_UNICAST; - if (safi == SAFI_MULTICAST) + case SAFI_MULTICAST: return IANA_SAFI_MULTICAST; - if (safi == SAFI_MPLS_VPN) + case SAFI_MPLS_VPN: return IANA_SAFI_MPLS_VPN; - if (safi == SAFI_ENCAP) + case SAFI_ENCAP: return IANA_SAFI_ENCAP; - if (safi == SAFI_EVPN) + case SAFI_EVPN: return IANA_SAFI_EVPN; - if (safi == SAFI_LABELED_UNICAST) + case SAFI_LABELED_UNICAST: return IANA_SAFI_LABELED_UNICAST; - return IANA_SAFI_RESERVED; + default: + return IANA_SAFI_RESERVED; + } } #endif /* _ZEBRA_H */ diff --git a/m4/Makefile.am b/m4/Makefile.am deleted file mode 100644 index 49a29bdf1f..0000000000 --- a/m4/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -EXTRA_DIST=Makefile.am README.txt diff --git a/nhrpd/nhrp_cache.c b/nhrpd/nhrp_cache.c index bd884bbc51..3ebdbf27ba 100644 --- a/nhrpd/nhrp_cache.c +++ b/nhrpd/nhrp_cache.c @@ -289,7 +289,7 @@ int nhrp_cache_update_binding(struct nhrp_cache *c, enum nhrp_cache_type type, i if (holding_time > 0) c->new.expires = monotime(NULL) + holding_time; else if (holding_time < 0) - c->new.type = NHRP_CACHE_INVALID; + nhrp_cache_reset_new(c); if (c->new.type == NHRP_CACHE_INVALID || c->new.type >= NHRP_CACHE_STATIC || diff --git a/nhrpd/nhrp_main.c b/nhrpd/nhrp_main.c index 7c5d80336c..012d5cd87c 100644 --- a/nhrpd/nhrp_main.c +++ b/nhrpd/nhrp_main.c @@ -128,8 +128,8 @@ int main(int argc, char **argv) /* Library inits. */ master = frr_init(); - nhrp_interface_init(); vrf_init(NULL, NULL, NULL, NULL); + nhrp_interface_init(); resolver_init(); /* Run with elevated capabilities, as for all netlink activity diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c index 89972f8f98..c8a608c657 100644 --- a/nhrpd/nhrp_route.c +++ b/nhrpd/nhrp_route.c @@ -205,17 +205,18 @@ int nhrp_route_read(int cmd, struct zclient *zclient, zebra_size_t length, vrf_i /* Type, flags, message. */ /*type =*/ stream_getc(s); - /*flags =*/ stream_getc(s); + /*instance =*/ stream_getw(s); + /*flags =*/ stream_getl(s); message = stream_getc(s); /* Prefix */ switch (cmd) { - case ZEBRA_IPV4_ROUTE_ADD: - case ZEBRA_IPV4_ROUTE_DELETE: + case ZEBRA_REDISTRIBUTE_IPV4_ADD: + case ZEBRA_REDISTRIBUTE_IPV4_DEL: prefix.family = AF_INET; break; - case ZEBRA_IPV6_ROUTE_ADD: - case ZEBRA_IPV6_ROUTE_DELETE: + case ZEBRA_REDISTRIBUTE_IPV6_ADD: + case ZEBRA_REDISTRIBUTE_IPV6_DEL: prefix.family = AF_INET6; break; default: @@ -244,7 +245,7 @@ int nhrp_route_read(int cmd, struct zclient *zclient, zebra_size_t length, vrf_i if (CHECK_FLAG(message, ZAPI_MESSAGE_METRIC)) /*metric =*/ stream_getl(s); - added = (cmd == ZEBRA_IPV4_ROUTE_ADD || cmd == ZEBRA_IPV6_ROUTE_ADD); + added = (cmd == ZEBRA_REDISTRIBUTE_IPV4_ADD || cmd == ZEBRA_REDISTRIBUTE_IPV6_ADD); debugf(NHRP_DEBUG_ROUTE, "if-route-%s: %s via %s dev %s", added ? "add" : "del", prefix2str(&prefix, buf[0], sizeof buf[0]), @@ -342,12 +343,23 @@ enum nhrp_route_type nhrp_route_address(struct interface *in_ifp, union sockunio return NHRP_ROUTE_BLACKHOLE; } +static void +nhrp_zebra_connected (struct zclient *zclient) +{ + zclient_send_reg_requests(zclient, VRF_DEFAULT); + zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, + ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT); + zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, + ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT); +} + void nhrp_zebra_init(void) { zebra_rib[AFI_IP] = route_table_init(); zebra_rib[AFI_IP6] = route_table_init(); zclient = zclient_new(master); + zclient->zebra_connected = nhrp_zebra_connected; zclient->interface_add = nhrp_interface_add; zclient->interface_delete = nhrp_interface_delete; zclient->interface_up = nhrp_interface_up; @@ -360,20 +372,6 @@ void nhrp_zebra_init(void) zclient->redistribute_route_ipv6_del = nhrp_route_read; zclient_init(zclient, ZEBRA_ROUTE_NHRP, 0); - zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, ZEBRA_ROUTE_KERNEL, 0, VRF_DEFAULT); - zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, ZEBRA_ROUTE_CONNECT, 0, VRF_DEFAULT); - zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, ZEBRA_ROUTE_STATIC, 0, VRF_DEFAULT); - zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, ZEBRA_ROUTE_RIP, 0, VRF_DEFAULT); - zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, ZEBRA_ROUTE_OSPF, 0, VRF_DEFAULT); - zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, ZEBRA_ROUTE_ISIS, 0, VRF_DEFAULT); - zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, ZEBRA_ROUTE_BGP, 0, VRF_DEFAULT); - zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, ZEBRA_ROUTE_KERNEL, 0, VRF_DEFAULT); - zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, ZEBRA_ROUTE_CONNECT, 0, VRF_DEFAULT); - zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, ZEBRA_ROUTE_STATIC, 0, VRF_DEFAULT); - zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, ZEBRA_ROUTE_RIP, 0, VRF_DEFAULT); - zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, ZEBRA_ROUTE_OSPF, 0, VRF_DEFAULT); - zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, ZEBRA_ROUTE_ISIS, 0, VRF_DEFAULT); - zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, ZEBRA_ROUTE_BGP, 0, VRF_DEFAULT); } void nhrp_zebra_terminate(void) diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 7f8341d0e4..dd3630af16 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -622,7 +622,8 @@ void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex, node = route_node_lookup(ospf6->external_id_table, &prefix_id); assert(node); node->info = NULL; - route_unlock_node(node); + route_unlock_node(node); /* to free the lookup lock */ + route_unlock_node(node); /* to free the original lock */ ospf6_route_remove(match, ospf6->external_table); XFREE(MTYPE_OSPF6_EXTERNAL_INFO, info); diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index e1a431ea07..a0dad9344a 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -509,7 +509,8 @@ struct ospf6_lsa *ospf6_lsa_create(struct ospf6_lsa_header *header) /* allocate memory for this LSA */ new_header = - (struct ospf6_lsa_header *)XMALLOC(MTYPE_OSPF6_LSA, lsa_size); + (struct ospf6_lsa_header *)XMALLOC(MTYPE_OSPF6_LSA_HEADER, + lsa_size); /* copy LSA from original header */ memcpy(new_header, header, lsa_size); @@ -537,7 +538,7 @@ struct ospf6_lsa *ospf6_lsa_create_headeronly(struct ospf6_lsa_header *header) /* allocate memory for this LSA */ new_header = (struct ospf6_lsa_header *)XMALLOC( - MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa_header)); + MTYPE_OSPF6_LSA_HEADER, sizeof(struct ospf6_lsa_header)); /* copy LSA from original header */ memcpy(new_header, header, sizeof(struct ospf6_lsa_header)); @@ -568,7 +569,7 @@ void ospf6_lsa_delete(struct ospf6_lsa *lsa) THREAD_OFF(lsa->refresh); /* do free */ - XFREE(MTYPE_OSPF6_LSA, lsa->header); + XFREE(MTYPE_OSPF6_LSA_HEADER, lsa->header); XFREE(MTYPE_OSPF6_LSA, lsa); } diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index 7e08d58791..418f858a32 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -83,8 +83,7 @@ static void _lsdb_count_assert(struct ospf6_lsdb *lsdb) zlog_debug("PANIC !! lsdb[%p]->count = %d, real = %d", lsdb, lsdb->count, num); for (ALL_LSDB(lsdb, debug)) - zlog_debug("%p %p %s lsdb[%p]", debug->prev, debug->next, - debug->name, debug->lsdb); + zlog_debug("%s lsdb[%p]", debug->name, debug->lsdb); zlog_debug("DUMP END"); assert(num == lsdb->count); @@ -139,6 +138,8 @@ void ospf6_lsdb_add(struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) (*lsdb->hook_add)(lsa); } } + /* to free the lookup lock in node get*/ + route_unlock_node(current); ospf6_lsa_unlock(old); } diff --git a/ospf6d/ospf6_memory.c b/ospf6d/ospf6_memory.c index 133dc2cb3c..56c232d6da 100644 --- a/ospf6d/ospf6_memory.c +++ b/ospf6d/ospf6_memory.c @@ -34,6 +34,7 @@ DEFINE_MTYPE(OSPF6D, OSPF6_ROUTE, "OSPF6 route") DEFINE_MTYPE(OSPF6D, OSPF6_PREFIX, "OSPF6 prefix") DEFINE_MTYPE(OSPF6D, OSPF6_MESSAGE, "OSPF6 message") DEFINE_MTYPE(OSPF6D, OSPF6_LSA, "OSPF6 LSA") +DEFINE_MTYPE(OSPF6D, OSPF6_LSA_HEADER, "OSPF6 LSA header") DEFINE_MTYPE(OSPF6D, OSPF6_LSA_SUMMARY, "OSPF6 LSA summary") DEFINE_MTYPE(OSPF6D, OSPF6_LSDB, "OSPF6 LSA database") DEFINE_MTYPE(OSPF6D, OSPF6_VERTEX, "OSPF6 vertex") diff --git a/ospf6d/ospf6_memory.h b/ospf6d/ospf6_memory.h index 324065c3a1..fe72ee3669 100644 --- a/ospf6d/ospf6_memory.h +++ b/ospf6d/ospf6_memory.h @@ -33,6 +33,7 @@ DECLARE_MTYPE(OSPF6_ROUTE) DECLARE_MTYPE(OSPF6_PREFIX) DECLARE_MTYPE(OSPF6_MESSAGE) DECLARE_MTYPE(OSPF6_LSA) +DECLARE_MTYPE(OSPF6_LSA_HEADER) DECLARE_MTYPE(OSPF6_LSA_SUMMARY) DECLARE_MTYPE(OSPF6_LSDB) DECLARE_MTYPE(OSPF6_VERTEX) diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index e0e9fc9449..bfe583a911 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -178,17 +178,6 @@ void ospf6_nexthop_delete(struct ospf6_nexthop *nh) XFREE(MTYPE_OSPF6_NEXTHOP, nh); } -void ospf6_free_nexthops(struct list *nh_list) -{ - struct ospf6_nexthop *nh; - struct listnode *node, *nnode; - - if (nh_list) { - for (ALL_LIST_ELEMENTS(nh_list, node, nnode, nh)) - ospf6_nexthop_delete(nh); - } -} - void ospf6_clear_nexthops(struct list *nh_list) { struct listnode *node; @@ -340,19 +329,29 @@ int ospf6_route_get_first_nh_index(struct ospf6_route *route) return (-1); } +static int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b) +{ + if ((a)->ifindex == (b)->ifindex && + IN6_ARE_ADDR_EQUAL(&(a)->address, &(b)->address)) + return 1; + return 0; +} + struct ospf6_route *ospf6_route_create(void) { struct ospf6_route *route; route = XCALLOC(MTYPE_OSPF6_ROUTE, sizeof(struct ospf6_route)); route->nh_list = list_new(); + route->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp; + route->nh_list->del = (void (*) (void *))ospf6_nexthop_delete; return route; } void ospf6_route_delete(struct ospf6_route *route) { if (route) { - ospf6_free_nexthops(route->nh_list); - list_free(route->nh_list); + if (route->nh_list) + list_delete(route->nh_list); XFREE(MTYPE_OSPF6_ROUTE, route); } } @@ -439,6 +438,7 @@ struct ospf6_route *ospf6_route_lookup(struct prefix *prefix, return NULL; route = (struct ospf6_route *)node->info; + route_unlock_node(node); /* to free the lookup lock */ return route; } @@ -583,6 +583,8 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route, SET_FLAG(old->flag, OSPF6_ROUTE_ADD); ospf6_route_table_assert(table); + /* to free the lookup lock */ + route_unlock_node(node); return old; } @@ -628,9 +630,10 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route, if (prev || next) { if (IS_OSPF6_DEBUG_ROUTE(MEMORY)) zlog_debug( - "%s %p: route add %p: another path: prev %p, next %p", + "%s %p: route add %p: another path: prev %p, next %p node refcount %u", ospf6_route_table_name(table), (void *)table, - (void *)route, (void *)prev, (void *)next); + (void *)route, (void *)prev, (void *)next, + node->lock); else if (IS_OSPF6_DEBUG_ROUTE(TABLE)) zlog_debug("%s: route add: another path found", ospf6_route_table_name(table)); @@ -755,9 +758,9 @@ void ospf6_route_remove(struct ospf6_route *route, prefix2str(&route->prefix, buf, sizeof(buf)); if (IS_OSPF6_DEBUG_ROUTE(MEMORY)) - zlog_debug("%s %p: route remove %p: %s", + zlog_debug("%s %p: route remove %p: %s rnode refcount %u", ospf6_route_table_name(table), (void *)table, - (void *)route, buf); + (void *)route, buf, route->rnode->lock); else if (IS_OSPF6_DEBUG_ROUTE(TABLE)) zlog_debug("%s: route remove: %s", ospf6_route_table_name(table), buf); @@ -768,11 +771,9 @@ void ospf6_route_remove(struct ospf6_route *route, /* find the route to remove, making sure that the route pointer is from the route table. */ current = node->info; - while (current && ospf6_route_is_same(current, route)) { - if (current == route) - break; + while (current && current != route) current = current->next; - } + assert(current == route); /* adjust doubly linked list */ @@ -785,10 +786,14 @@ void ospf6_route_remove(struct ospf6_route *route, if (route->next && route->next->rnode == node) { node->info = route->next; SET_FLAG(route->next->flag, OSPF6_ROUTE_BEST); - } else - node->info = NULL; /* should unlock route_node here ? */ + } else { + node->info = NULL; + route->rnode = NULL; + route_unlock_node(node); /* to free the original lock */ + } } + route_unlock_node(node); /* to free the lookup lock */ table->count--; ospf6_route_table_assert(table); @@ -935,6 +940,7 @@ struct ospf6_route_table *ospf6_route_table_create(int s, int t) void ospf6_route_table_delete(struct ospf6_route_table *table) { ospf6_route_remove_all(table); + bf_free(table->idspace); route_table_finish(table->table); XFREE(MTYPE_OSPF6_ROUTE, table); } @@ -1062,6 +1068,7 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route) vty_out(vty, "Metric: %d (%d)\n", route->path.cost, route->path.u.cost_e2); + vty_out(vty, "Nexthop count: %u\n", route->nh_list->count); /* Nexthops */ vty_out(vty, "Nexthop:\n"); for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) { diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h index 69d275f8b1..166074fb70 100644 --- a/ospf6d/ospf6_route.h +++ b/ospf6d/ospf6_route.h @@ -256,7 +256,6 @@ extern void ospf6_linkstate_prefix2str(struct prefix *prefix, char *buf, extern struct ospf6_nexthop *ospf6_nexthop_create(void); extern void ospf6_nexthop_delete(struct ospf6_nexthop *nh); -extern void ospf6_free_nexthops(struct list *nh_list); extern void ospf6_clear_nexthops(struct list *nh_list); extern int ospf6_num_nexthops(struct list *nh_list); extern void ospf6_copy_nexthops(struct list *dst, struct list *src); diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 86f893bc61..6d589aff8f 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -141,6 +141,7 @@ static struct ospf6_vertex *ospf6_vertex_create(struct ospf6_lsa *lsa) v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END(lsa->header) + 3); v->nh_list = list_new(); + v->nh_list->del = (void (*) (void *))ospf6_nexthop_delete; v->parent = NULL; v->child_list = list_new(); diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index c0670012b8..d3d1ffed5e 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -626,7 +626,7 @@ DEFUN (debug_ospf_packet, if (inst) // user passed instance ID { if (!ospf_lookup_instance(strtoul(argv[2]->arg, NULL, 10))) - return CMD_SUCCESS; + return CMD_NOT_MY_INSTANCE; } int type = 0; @@ -702,7 +702,7 @@ DEFUN (no_debug_ospf_packet, if (inst) // user passed instance ID { if (!ospf_lookup_instance(strtoul(argv[3]->arg, NULL, 10))) - return CMD_SUCCESS; + return CMD_NOT_MY_INSTANCE; } int type = 0; @@ -773,7 +773,7 @@ DEFUN (debug_ospf_ism, if (inst) // user passed instance ID { if (!ospf_lookup_instance(strtoul(argv[2]->arg, NULL, 10))) - return CMD_SUCCESS; + return CMD_NOT_MY_INSTANCE; } if (vty->node == CONFIG_NODE) { @@ -824,7 +824,7 @@ DEFUN (no_debug_ospf_ism, if (inst) // user passed instance ID { if (!ospf_lookup_instance(strtoul(argv[3]->arg, NULL, 10))) - return CMD_SUCCESS; + return CMD_NOT_MY_INSTANCE; } if (vty->node == CONFIG_NODE) { @@ -991,7 +991,7 @@ DEFUN (no_debug_ospf_instance_nsm, instance = strtoul(argv[idx_number]->arg, NULL, 10); if (!ospf_lookup_instance(instance)) - return CMD_SUCCESS; + return CMD_NOT_MY_INSTANCE; return no_debug_ospf_nsm_common(vty, 5, argc, argv); } @@ -1065,7 +1065,7 @@ DEFUN (debug_ospf_instance_lsa, instance = strtoul(argv[idx_number]->arg, NULL, 10); if (!ospf_lookup_instance(instance)) - return CMD_SUCCESS; + return CMD_NOT_MY_INSTANCE; return debug_ospf_lsa_common(vty, 4, argc, argv); } @@ -1141,7 +1141,7 @@ DEFUN (no_debug_ospf_instance_lsa, instance = strtoul(argv[idx_number]->arg, NULL, 10); if (!ospf_lookup_instance(instance)) - return CMD_SUCCESS; + return CMD_NOT_MY_INSTANCE; return no_debug_ospf_lsa_common(vty, 5, argc, argv); } @@ -1203,7 +1203,7 @@ DEFUN (debug_ospf_instance_zebra, instance = strtoul(argv[idx_number]->arg, NULL, 10); if (!ospf_lookup_instance(instance)) - return CMD_SUCCESS; + return CMD_NOT_MY_INSTANCE; return debug_ospf_zebra_common(vty, 4, argc, argv); } diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index a2c40923b1..db523bd2a4 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -750,7 +750,7 @@ DEFUN (capability_opaque, "Enable specific OSPF feature\n" "Opaque LSA\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); /* Turn on the "master switch" of opaque-lsa capability. */ if (!CHECK_FLAG(ospf->config, OSPF_OPAQUE_CAPABLE)) { @@ -779,7 +779,7 @@ DEFUN (no_capability_opaque, "Enable specific OSPF feature\n" "Opaque LSA\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); /* Turn off the "master switch" of opaque-lsa capability. */ if (CHECK_FLAG(ospf->config, OSPF_OPAQUE_CAPABLE)) { diff --git a/ospfd/ospf_opaque.h b/ospfd/ospf_opaque.h index 8bad51e65e..2470cd2e2b 100644 --- a/ospfd/ospf_opaque.h +++ b/ospfd/ospf_opaque.h @@ -77,6 +77,44 @@ ((ntohs((lsahdr)->length) >= sizeof(struct lsa_header)) \ && ((ntohs((lsahdr)->length) % sizeof(u_int32_t)) == 0)) +/* + * Following section defines generic TLV (type, length, value) macros, + * used for various LSA opaque usage e.g. Traffic Engineering. + */ +struct tlv_header { + u_int16_t type; /* Type of Value */ + u_int16_t length; /* Length of Value portion only, in bytes */ +}; + +#define TLV_HDR_SIZE (sizeof(struct tlv_header)) + +#define TLV_BODY_SIZE(tlvh) \ + (ROUNDUP(ntohs((tlvh)->length), sizeof(u_int32_t))) + +#define TLV_SIZE(tlvh) (TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh)) + +#define TLV_HDR_TOP(lsah) \ + (struct tlv_header *)((char *)(lsah) + OSPF_LSA_HEADER_SIZE) + +#define TLV_HDR_NEXT(tlvh) \ + (struct tlv_header *)((char *)(tlvh) + TLV_SIZE(tlvh)) + +#define TLV_HDR_SUBTLV(tlvh) \ + (struct tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE) + +#define TLV_DATA(tlvh) (void *)((char *)(tlvh) + TLV_HDR_SIZE) + +#define TLV_TYPE(tlvh) tlvh.header.type +#define TLV_LEN(tlvh) tlvh.header.length +#define TLV_HDR(tlvh) tlvh.header + +/* Following declaration concerns the Opaque LSA management */ +enum lsa_opcode { + REORIGINATE_THIS_LSA, + REFRESH_THIS_LSA, + FLUSH_THIS_LSA +}; + /* Prototypes. */ extern void ospf_opaque_init(void); @@ -108,7 +146,7 @@ extern int ospf_opaque_new_if(struct interface *ifp); extern int ospf_opaque_del_if(struct interface *ifp); extern void ospf_opaque_ism_change(struct ospf_interface *oi, int old_status); extern void ospf_opaque_nsm_change(struct ospf_neighbor *nbr, int old_status); -extern void ospf_opaque_config_write_router(struct vty *vty, struct ospf *); +extern void ospf_opaque_config_write_router(struct vty *vty, struct ospf *ospf); extern void ospf_opaque_config_write_if(struct vty *vty, struct interface *ifp); extern void ospf_opaque_config_write_debug(struct vty *vty); extern void show_opaque_info_detail(struct vty *vty, struct ospf_lsa *lsa); @@ -116,7 +154,7 @@ extern void ospf_opaque_lsa_dump(struct stream *s, u_int16_t length); extern void ospf_opaque_lsa_originate_schedule(struct ospf_interface *oi, int *init_delay); -extern struct ospf_lsa *ospf_opaque_lsa_install(struct ospf_lsa *, +extern struct ospf_lsa *ospf_opaque_lsa_install(struct ospf_lsa *lsa, int rt_recalc); extern struct ospf_lsa *ospf_opaque_lsa_refresh(struct ospf_lsa *lsa); diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c index 26d2ed7d13..13013bf8ca 100644 --- a/ospfd/ospf_ri.c +++ b/ospfd/ospf_ri.c @@ -58,9 +58,9 @@ #include "ospfd/ospf_ri.h" #include "ospfd/ospf_te.h" +/* Store Router Information PCE TLV and SubTLV in network byte order. */ struct ospf_pce_info { - - /* Store Router Information PCE TLV and SubTLV in network byte order. */ + bool enabled; struct ri_tlv_pce pce_header; struct ri_pce_subtlv_address pce_address; struct ri_pce_subtlv_path_scope pce_scope; @@ -71,15 +71,14 @@ struct ospf_pce_info { /* Following structure are internal use only. */ struct ospf_router_info { - status_t status; + bool enabled; u_int8_t registered; u_int8_t scope; /* Flags to manage this router information. */ -#define RIFLG_LOOKUP_DONE 0x1 -#define RIFLG_LSA_ENGAGED 0x2 -#define RIFLG_LSA_FORCED_REFRESH 0x4 +#define RIFLG_LSA_ENGAGED 0x1 +#define RIFLG_LSA_FORCED_REFRESH 0x2 u_int32_t flags; /* area pointer if flooding is Type 10 Null if flooding is AS scope */ @@ -112,7 +111,7 @@ static void ospf_router_info_config_write_router(struct vty *vty); static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa); static int ospf_router_info_lsa_originate(void *arg); static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa); -static void ospf_router_info_lsa_schedule(opcode_t opcode); +static void ospf_router_info_lsa_schedule(enum lsa_opcode opcode); static void ospf_router_info_register_vty(void); static void del_pce_info(void *val); @@ -120,12 +119,13 @@ int ospf_router_info_init(void) { memset(&OspfRI, 0, sizeof(struct ospf_router_info)); - OspfRI.status = disabled; + OspfRI.enabled = false; OspfRI.registered = 0; OspfRI.scope = OSPF_OPAQUE_AS_LSA; OspfRI.flags = 0; /* Initialize pce domain and neighbor list */ + OspfRI.pce_info.enabled = false; OspfRI.pce_info.pce_domain = list_new(); OspfRI.pce_info.pce_domain->del = del_pce_info; OspfRI.pce_info.pce_neighbor = list_new(); @@ -141,7 +141,7 @@ static int ospf_router_info_register(u_int8_t scope) int rc = 0; if (OspfRI.registered) - return 0; + return rc; zlog_info("Register Router Information with scope %s(%d)", scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS", scope); @@ -165,7 +165,7 @@ static int ospf_router_info_register(u_int8_t scope) OspfRI.registered = 1; OspfRI.scope = scope; - return 0; + return rc; } static int ospf_router_info_unregister() @@ -193,7 +193,7 @@ void ospf_router_info_term(void) OspfRI.pce_info.pce_domain = NULL; OspfRI.pce_info.pce_neighbor = NULL; - OspfRI.status = disabled; + OspfRI.enabled = false; ospf_router_info_unregister(); @@ -229,34 +229,36 @@ static int set_pce_header(struct ospf_pce_info *pce) /* PCE Address */ if (ntohs(pce->pce_address.header.type) != 0) - length += RI_TLV_SIZE(&pce->pce_address.header); + length += TLV_SIZE(&pce->pce_address.header); /* PCE Path Scope */ if (ntohs(pce->pce_scope.header.type) != 0) - length += RI_TLV_SIZE(&pce->pce_scope.header); + length += TLV_SIZE(&pce->pce_scope.header); /* PCE Domain */ for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) { if (ntohs(domain->header.type) != 0) - length += RI_TLV_SIZE(&domain->header); + length += TLV_SIZE(&domain->header); } /* PCE Neighbor */ for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) { if (ntohs(neighbor->header.type) != 0) - length += RI_TLV_SIZE(&neighbor->header); + length += TLV_SIZE(&neighbor->header); } /* PCE Capabilities */ if (ntohs(pce->pce_cap_flag.header.type) != 0) - length += RI_TLV_SIZE(&pce->pce_cap_flag.header); + length += TLV_SIZE(&pce->pce_cap_flag.header); if (length != 0) { pce->pce_header.header.type = htons(RI_TLV_PCE); pce->pce_header.header.length = htons(length); + pce->enabled = true; } else { pce->pce_header.header.type = 0; pce->pce_header.header.length = 0; + pce->enabled = false; } return length; @@ -279,8 +281,6 @@ static void set_pce_address(struct in_addr ipv4, struct ospf_pce_info *pce) static void set_pce_path_scope(u_int32_t scope, struct ospf_pce_info *pce) { - /* Enable PCE Info */ - pce->pce_header.header.type = htons(RI_TLV_PCE); /* Set PCE Scope */ pce->pce_scope.header.type = htons(RI_PCE_SUBTLV_PATH_SCOPE); pce->pce_scope.header.length = htons(RI_TLV_LENGTH); @@ -295,9 +295,6 @@ static void set_pce_domain(u_int16_t type, u_int32_t domain, struct ri_pce_subtlv_domain *new; - /* Enable PCE Info */ - pce->pce_header.header.type = htons(RI_TLV_PCE); - /* Create new domain info */ new = XCALLOC(MTYPE_OSPF_PCE_PARAMS, sizeof(struct ri_pce_subtlv_domain)); @@ -348,9 +345,6 @@ static void set_pce_neighbor(u_int16_t type, u_int32_t domain, struct ri_pce_subtlv_neighbor *new; - /* Enable PCE Info */ - pce->pce_header.header.type = htons(RI_TLV_PCE); - /* Create new neighbor info */ new = XCALLOC(MTYPE_OSPF_PCE_PARAMS, sizeof(struct ri_pce_subtlv_neighbor)); @@ -399,8 +393,6 @@ static void unset_pce_neighbor(u_int16_t type, u_int32_t domain, static void set_pce_cap_flag(u_int32_t cap, struct ospf_pce_info *pce) { - /* Enable PCE Info */ - pce->pce_header.header.type = htons(RI_TLV_PCE); /* Set PCE Capabilities flag */ pce->pce_cap_flag.header.type = htons(RI_PCE_SUBTLV_CAP_FLAG); pce->pce_cap_flag.header.length = htons(RI_TLV_LENGTH); @@ -410,12 +402,12 @@ static void set_pce_cap_flag(u_int32_t cap, struct ospf_pce_info *pce) } -static void unset_param(struct ri_tlv_header *tlv) +static void unset_param(struct tlv_header *tlv) { tlv->type = 0; /* Fill the Value to 0 */ - memset((tlv + RI_TLV_HDR_SIZE), 0, RI_TLV_BODY_SIZE(tlv)); + memset(TLV_DATA(tlv), 0, TLV_BODY_SIZE(tlv)); tlv->length = 0; return; @@ -423,14 +415,13 @@ static void unset_param(struct ri_tlv_header *tlv) static void initialize_params(struct ospf_router_info *ori) { - u_int32_t cap; + u_int32_t cap = 0; struct ospf *top; /* * Initialize default Router Information Capabilities. */ - cap = 0; - cap = cap | RI_TE_SUPPORT; + cap = RI_TE_SUPPORT; set_router_info_capabilities(&ori->router_cap, cap); @@ -462,9 +453,6 @@ static void initialize_params(struct ospf_router_info *ori) | PCE_CAP_ADDITIVE | PCE_CAP_MULTIPLE_REQ; set_pce_cap_flag(cap, &ori->pce_info); - /* Finally compute PCE header */ - set_pce_header(&ori->pce_info); - return; } @@ -473,16 +461,15 @@ static int is_mandated_params_set(struct ospf_router_info ori) int rc = 0; if (ntohs(ori.router_cap.header.type) == 0) - goto out; + return rc; if ((ntohs(ori.pce_info.pce_header.header.type) == RI_TLV_PCE) && (ntohs(ori.pce_info.pce_address.header.type) == 0) && (ntohs(ori.pce_info.pce_cap_flag.header.type) == 0)) - goto out; + return rc; rc = 1; -out: return rc; } @@ -499,7 +486,6 @@ static void ospf_router_info_ism_change(struct ospf_interface *oi, static void ospf_router_info_nsm_change(struct ospf_neighbor *nbr, int old_state) { - /* So far, nothing to do here. */ return; } @@ -508,19 +494,19 @@ static void ospf_router_info_nsm_change(struct ospf_neighbor *nbr, * Followings are OSPF protocol processing functions for ROUTER INFORMATION *------------------------------------------------------------------------*/ -static void build_tlv_header(struct stream *s, struct ri_tlv_header *tlvh) +static void build_tlv_header(struct stream *s, struct tlv_header *tlvh) { - stream_put(s, tlvh, sizeof(struct ri_tlv_header)); + stream_put(s, tlvh, sizeof(struct tlv_header)); return; } -static void build_tlv(struct stream *s, struct ri_tlv_header *tlvh) +static void build_tlv(struct stream *s, struct tlv_header *tlvh) { if (ntohs(tlvh->type) != 0) { build_tlv_header(s, tlvh); - stream_put(s, tlvh + 1, RI_TLV_BODY_SIZE(tlvh)); + stream_put(s, TLV_DATA(tlvh), TLV_BODY_SIZE(tlvh)); } return; } @@ -535,9 +521,11 @@ static void ospf_router_info_lsa_body_set(struct stream *s) /* Build Router Information TLV */ build_tlv(s, &OspfRI.router_cap.header); - /* Add RI PCE TLV if it is set */ /* Compute PCE Info header first */ - if ((set_pce_header(&OspfRI.pce_info)) != 0) { + set_pce_header (&OspfRI.pce_info); + + /* Add RI PCE TLV if it is set */ + if (OspfRI.pce_info.enabled) { /* Build PCE TLV */ build_tlv_header(s, &OspfRI.pce_info.pce_header.header); @@ -580,7 +568,7 @@ static struct ospf_lsa *ospf_router_info_lsa_new() /* Create a stream for LSA. */ if ((s = stream_new(OSPF_MAX_LSA_SIZE)) == NULL) { zlog_warn("ospf_router_info_lsa_new: stream_new() ?"); - goto out; + return NULL; } lsah = (struct lsa_header *)STREAM_DATA(s); @@ -614,14 +602,14 @@ static struct ospf_lsa *ospf_router_info_lsa_new() if ((new = ospf_lsa_new()) == NULL) { zlog_warn("ospf_router_info_lsa_new: ospf_lsa_new() ?"); stream_free(s); - goto out; + return NULL; } if ((new->data = ospf_lsa_data_new(length)) == NULL) { zlog_warn("ospf_router_info_lsa_new: ospf_lsa_data_new() ?"); ospf_lsa_unlock(&new); new = NULL; stream_free(s); - goto out; + return new; } new->area = OspfRI.area; /* Area must be null if the Opaque type is AS @@ -631,7 +619,6 @@ static struct ospf_lsa *ospf_router_info_lsa_new() memcpy(new->data, lsah, length); stream_free(s); -out: return new; } @@ -648,7 +635,7 @@ static int ospf_router_info_lsa_originate1(void *arg) if (area->area_id.s_addr != OspfRI.area_id.s_addr) { zlog_debug( "RI -> This is not the Router Information Area. Stop processing"); - goto out; + return rc; } OspfRI.area = area; } @@ -657,7 +644,7 @@ static int ospf_router_info_lsa_originate1(void *arg) if ((new = ospf_router_info_lsa_new()) == NULL) { zlog_warn( "ospf_router_info_lsa_originate1: ospf_router_info_lsa_new() ?"); - goto out; + return rc; } /* Get ospf info */ @@ -668,7 +655,7 @@ static int ospf_router_info_lsa_originate1(void *arg) zlog_warn( "ospf_router_info_lsa_originate1: ospf_lsa_install() ?"); ospf_lsa_unlock(&new); - goto out; + return rc; } /* Now this Router Info parameter entry has associated LSA. */ @@ -691,7 +678,6 @@ static int ospf_router_info_lsa_originate1(void *arg) } rc = 0; -out: return rc; } @@ -700,17 +686,17 @@ static int ospf_router_info_lsa_originate(void *arg) int rc = -1; - if (OspfRI.status == disabled) { + if (!OspfRI.enabled) { zlog_info( "ospf_router_info_lsa_originate: ROUTER INFORMATION is disabled now."); rc = 0; /* This is not an error case. */ - goto out; + return rc; } /* Check if Router Information LSA is already engaged */ - if (OspfRI.flags & RIFLG_LSA_ENGAGED) { - if (OspfRI.flags & RIFLG_LSA_FORCED_REFRESH) { - OspfRI.flags &= ~RIFLG_LSA_FORCED_REFRESH; + if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) { + if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_FORCED_REFRESH)) { + UNSET_FLAG(OspfRI.flags, RIFLG_LSA_FORCED_REFRESH); ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); } } else { @@ -720,11 +706,10 @@ static int ospf_router_info_lsa_originate(void *arg) /* Ok, let's try to originate an LSA */ if (ospf_router_info_lsa_originate1(arg) != 0) - goto out; + return rc; } rc = 0; -out: return rc; } @@ -733,7 +718,7 @@ static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa) struct ospf_lsa *new = NULL; struct ospf *top; - if (OspfRI.status == disabled) { + if (!OspfRI.enabled) { /* * This LSA must have flushed before due to ROUTER INFORMATION * status change. @@ -749,21 +734,21 @@ static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa) if (GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr)) != 0) { zlog_warn( "ospf_router_info_lsa_refresh: Unsupported Router Information ID"); - goto out; + return NULL; } /* If the lsa's age reached to MaxAge, start flushing procedure. */ if (IS_LSA_MAXAGE(lsa)) { - OspfRI.flags &= ~RIFLG_LSA_ENGAGED; + UNSET_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED); ospf_opaque_lsa_flush_schedule(lsa); - goto out; + return NULL; } /* Create new Opaque-LSA/ROUTER INFORMATION instance. */ if ((new = ospf_router_info_lsa_new()) == NULL) { zlog_warn( "ospf_router_info_lsa_refresh: ospf_router_info_lsa_new() ?"); - goto out; + return NULL; } new->data->ls_seqnum = lsa_seqnum_increment(lsa); @@ -773,7 +758,7 @@ static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa) if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) { zlog_warn("ospf_router_info_lsa_refresh: ospf_lsa_install() ?"); ospf_lsa_unlock(&new); - goto out; + return new; } /* Flood updated LSA through AS or AREA depending of OspfRI.scope. */ @@ -790,11 +775,10 @@ static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa) ospf_lsa_header_dump(new->data); } -out: return new; } -static void ospf_router_info_lsa_schedule(opcode_t opcode) +static void ospf_router_info_lsa_schedule(enum lsa_opcode opcode) { struct ospf_lsa lsa; struct lsa_header lsah; @@ -809,6 +793,13 @@ static void ospf_router_info_lsa_schedule(opcode_t opcode) opcode == REFRESH_THIS_LSA ? "Refresh" : "", opcode == FLUSH_THIS_LSA ? "Flush" : ""); + /* Check LSA flags state coherence */ + if (!CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED) && (opcode != REORIGINATE_THIS_LSA)) + return; + + if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED) && (opcode == REORIGINATE_THIS_LSA)) + opcode = REFRESH_THIS_LSA; + top = ospf_lookup(); if ((OspfRI.scope == OSPF_OPAQUE_AREA_LSA) && (OspfRI.area == NULL)) { zlog_warn( @@ -838,7 +829,7 @@ static void ospf_router_info_lsa_schedule(opcode_t opcode) ospf_opaque_lsa_refresh_schedule(&lsa); break; case FLUSH_THIS_LSA: - OspfRI.flags &= ~RIFLG_LSA_ENGAGED; + UNSET_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED); ospf_opaque_lsa_flush_schedule(&lsa); break; default: @@ -855,7 +846,7 @@ static void ospf_router_info_lsa_schedule(opcode_t opcode) *------------------------------------------------------------------------*/ static u_int16_t show_vty_router_cap(struct vty *vty, - struct ri_tlv_header *tlvh) + struct tlv_header *tlvh) { struct ri_tlv_router_cap *top = (struct ri_tlv_router_cap *)tlvh; @@ -865,11 +856,11 @@ static u_int16_t show_vty_router_cap(struct vty *vty, else zlog_debug(" Router Capabilities: 0x%x", ntohl(top->value)); - return RI_TLV_SIZE(tlvh); + return TLV_SIZE(tlvh); } static u_int16_t show_vty_pce_subtlv_address(struct vty *vty, - struct ri_tlv_header *tlvh) + struct tlv_header *tlvh) { struct ri_pce_subtlv_address *top = (struct ri_pce_subtlv_address *)tlvh; @@ -891,11 +882,11 @@ static u_int16_t show_vty_pce_subtlv_address(struct vty *vty, ntohl(top->address.value.s_addr)); } - return RI_TLV_SIZE(tlvh); + return TLV_SIZE(tlvh); } static u_int16_t show_vty_pce_subtlv_path_scope(struct vty *vty, - struct ri_tlv_header *tlvh) + struct tlv_header *tlvh) { struct ri_pce_subtlv_path_scope *top = (struct ri_pce_subtlv_path_scope *)tlvh; @@ -905,11 +896,11 @@ static u_int16_t show_vty_pce_subtlv_path_scope(struct vty *vty, else zlog_debug(" PCE Path Scope: 0x%x", ntohl(top->value)); - return RI_TLV_SIZE(tlvh); + return TLV_SIZE(tlvh); } static u_int16_t show_vty_pce_subtlv_domain(struct vty *vty, - struct ri_tlv_header *tlvh) + struct tlv_header *tlvh) { struct ri_pce_subtlv_domain *top = (struct ri_pce_subtlv_domain *)tlvh; struct in_addr tmp; @@ -927,11 +918,11 @@ static u_int16_t show_vty_pce_subtlv_domain(struct vty *vty, else zlog_debug(" PCE domain AS: %d", ntohl(top->value)); } - return RI_TLV_SIZE(tlvh); + return TLV_SIZE(tlvh); } static u_int16_t show_vty_pce_subtlv_neighbor(struct vty *vty, - struct ri_tlv_header *tlvh) + struct tlv_header *tlvh) { struct ri_pce_subtlv_neighbor *top = @@ -953,11 +944,11 @@ static u_int16_t show_vty_pce_subtlv_neighbor(struct vty *vty, zlog_debug(" PCE neighbor AS: %d", ntohl(top->value)); } - return RI_TLV_SIZE(tlvh); + return TLV_SIZE(tlvh); } static u_int16_t show_vty_pce_subtlv_cap_flag(struct vty *vty, - struct ri_tlv_header *tlvh) + struct tlv_header *tlvh) { struct ri_pce_subtlv_cap_flag *top = (struct ri_pce_subtlv_cap_flag *)tlvh; @@ -969,11 +960,11 @@ static u_int16_t show_vty_pce_subtlv_cap_flag(struct vty *vty, zlog_debug(" PCE Capabilities Flag: 0x%x", ntohl(top->value)); - return RI_TLV_SIZE(tlvh); + return TLV_SIZE(tlvh); } static u_int16_t show_vty_unknown_tlv(struct vty *vty, - struct ri_tlv_header *tlvh) + struct tlv_header *tlvh) { if (vty != NULL) vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n", @@ -982,16 +973,16 @@ static u_int16_t show_vty_unknown_tlv(struct vty *vty, zlog_debug(" Unknown TLV: [type(0x%x), length(0x%x)]", ntohs(tlvh->type), ntohs(tlvh->length)); - return RI_TLV_SIZE(tlvh); + return TLV_SIZE(tlvh); } -static u_int16_t show_vty_pce_info(struct vty *vty, struct ri_tlv_header *ri, +static u_int16_t show_vty_pce_info(struct vty *vty, struct tlv_header *ri, uint32_t total) { - struct ri_tlv_header *tlvh; + struct tlv_header *tlvh; u_int16_t sum = 0; - for (tlvh = ri; sum < total; tlvh = RI_TLV_HDR_NEXT(tlvh)) { + for (tlvh = ri; sum < total; tlvh = TLV_HDR_NEXT(tlvh)) { switch (ntohs(tlvh->type)) { case RI_PCE_SUBTLV_ADDRESS: sum += show_vty_pce_subtlv_address(vty, tlvh); @@ -1019,21 +1010,21 @@ static u_int16_t show_vty_pce_info(struct vty *vty, struct ri_tlv_header *ri, static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa) { struct lsa_header *lsah = (struct lsa_header *)lsa->data; - struct ri_tlv_header *tlvh; + struct tlv_header *tlvh; u_int16_t length = 0, sum = 0; /* Initialize TLV browsing */ length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE; - for (tlvh = RI_TLV_HDR_TOP(lsah); sum < length; - tlvh = RI_TLV_HDR_NEXT(tlvh)) { + for (tlvh = TLV_HDR_TOP(lsah); sum < length; + tlvh = TLV_HDR_NEXT(tlvh)) { switch (ntohs(tlvh->type)) { case RI_TLV_CAPABILITIES: sum += show_vty_router_cap(vty, tlvh); break; case RI_TLV_PCE: tlvh++; - sum += RI_TLV_HDR_SIZE; + sum += TLV_HDR_SIZE; sum += show_vty_pce_info(vty, tlvh, length - sum); break; default: @@ -1053,50 +1044,53 @@ static void ospf_router_info_config_write_router(struct vty *vty) struct ri_pce_subtlv_neighbor *neighbor; struct in_addr tmp; - if (OspfRI.status == enabled) { + if (OspfRI.enabled) { if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) vty_out(vty, " router-info as\n"); else vty_out(vty, " router-info area %s\n", inet_ntoa(OspfRI.area_id)); - if (pce->pce_address.header.type != 0) - vty_out(vty, " pce address %s\n", - inet_ntoa(pce->pce_address.address.value)); - - if (pce->pce_cap_flag.header.type != 0) - vty_out(vty, " pce flag 0x%x\n", - ntohl(pce->pce_cap_flag.value)); - - for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) { - if (domain->header.type != 0) { - if (domain->type == PCE_DOMAIN_TYPE_AREA) { - tmp.s_addr = domain->value; - vty_out(vty, " pce domain area %s\n", - inet_ntoa(tmp)); - } else { - vty_out(vty, " pce domain as %d\n", - ntohl(domain->value)); + if (OspfRI.pce_info.enabled) { + + if (pce->pce_address.header.type != 0) + vty_out(vty, " pce address %s\n", + inet_ntoa(pce->pce_address.address.value)); + + if (pce->pce_cap_flag.header.type != 0) + vty_out(vty, " pce flag 0x%x\n", + ntohl(pce->pce_cap_flag.value)); + + for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) { + if (domain->header.type != 0) { + if (domain->type == PCE_DOMAIN_TYPE_AREA) { + tmp.s_addr = domain->value; + vty_out(vty, " pce domain area %s\n", + inet_ntoa(tmp)); + } else { + vty_out(vty, " pce domain as %d\n", + ntohl(domain->value)); + } } } - } - for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) { - if (neighbor->header.type != 0) { - if (neighbor->type == PCE_DOMAIN_TYPE_AREA) { - tmp.s_addr = neighbor->value; - vty_out(vty, " pce neighbor area %s\n", - inet_ntoa(tmp)); - } else { - vty_out(vty, " pce neighbor as %d\n", - ntohl(neighbor->value)); + for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) { + if (neighbor->header.type != 0) { + if (neighbor->type == PCE_DOMAIN_TYPE_AREA) { + tmp.s_addr = neighbor->value; + vty_out(vty, " pce neighbor area %s\n", + inet_ntoa(tmp)); + } else { + vty_out(vty, " pce neighbor as %d\n", + ntohl(neighbor->value)); + } } } - } - if (pce->pce_scope.header.type != 0) - vty_out(vty, " pce scope 0x%x\n", - ntohl(OspfRI.pce_info.pce_scope.value)); + if (pce->pce_scope.header.type != 0) + vty_out(vty, " pce scope 0x%x\n", + ntohl(OspfRI.pce_info.pce_scope.value)); + } } return; } @@ -1118,7 +1112,7 @@ DEFUN (router_info, u_int8_t scope; - if (OspfRI.status == enabled) + if (OspfRI.enabled) return CMD_SUCCESS; /* Check and get Area value if present */ @@ -1137,11 +1131,11 @@ DEFUN (router_info, /* First start to register Router Information callbacks */ if ((ospf_router_info_register(scope)) != 0) { zlog_warn( - "Enable to register Router Information callbacks. Abort!"); + "Unable to register Router Information callbacks. Abort!"); return CMD_WARNING_CONFIG_FAILED; } - OspfRI.status = enabled; + OspfRI.enabled = true; if (IS_DEBUG_OSPF_EVENT) zlog_debug("RI-> Router Information (%s flooding): OFF -> ON", @@ -1160,7 +1154,10 @@ DEFUN (router_info, initialize_params(&OspfRI); /* Refresh RI LSA if already engaged */ - if (OspfRI.flags & RIFLG_LSA_ENGAGED) { + if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) { + zlog_debug ("RI-> Refresh LSA following configuration"); + ospf_router_info_lsa_schedule (REFRESH_THIS_LSA); + } else { zlog_debug("RI-> Initial origination following configuration"); ospf_router_info_lsa_schedule(REORIGINATE_THIS_LSA); } @@ -1175,26 +1172,26 @@ DEFUN (no_router_info, "Disable the Router Information functionality\n") { - if (OspfRI.status == disabled) + if (!OspfRI.enabled) return CMD_SUCCESS; if (IS_DEBUG_OSPF_EVENT) zlog_debug("RI-> Router Information: ON -> OFF"); - if (OspfRI.flags & RIFLG_LSA_ENGAGED) + if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule(FLUSH_THIS_LSA); /* Unregister the callbacks */ ospf_router_info_unregister(); - OspfRI.status = disabled; + OspfRI.enabled = false; return CMD_SUCCESS; } static int ospf_ri_enabled(struct vty *vty) { - if (OspfRI.status == enabled) + if (OspfRI.enabled) return 1; if (vty) @@ -1229,7 +1226,7 @@ DEFUN (pce_address, set_pce_address(value, pi); /* Refresh RI LSA if already engaged */ - if (OspfRI.flags & RIFLG_LSA_ENGAGED) + if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); } @@ -1248,7 +1245,7 @@ DEFUN (no_pce_address, unset_param(&OspfRI.pce_info.pce_address.header); /* Refresh RI LSA if already engaged */ - if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); return CMD_SUCCESS; @@ -1279,7 +1276,7 @@ DEFUN (pce_path_scope, set_pce_path_scope(scope, pi); /* Refresh RI LSA if already engaged */ - if (OspfRI.flags & RIFLG_LSA_ENGAGED) + if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); } @@ -1298,7 +1295,7 @@ DEFUN (no_pce_path_scope, unset_param(&OspfRI.pce_info.pce_address.header); /* Refresh RI LSA if already engaged */ - if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); return CMD_SUCCESS; @@ -1337,7 +1334,7 @@ DEFUN (pce_domain, set_pce_domain(PCE_DOMAIN_TYPE_AS, as, pce); /* Refresh RI LSA if already engaged */ - if (OspfRI.flags & RIFLG_LSA_ENGAGED) + if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); return CMD_SUCCESS; @@ -1367,7 +1364,7 @@ DEFUN (no_pce_domain, unset_pce_domain(PCE_DOMAIN_TYPE_AS, as, pce); /* Refresh RI LSA if already engaged */ - if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); return CMD_SUCCESS; @@ -1407,7 +1404,7 @@ DEFUN (pce_neigbhor, set_pce_neighbor(PCE_DOMAIN_TYPE_AS, as, pce); /* Refresh RI LSA if already engaged */ - if (OspfRI.flags & RIFLG_LSA_ENGAGED) + if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); return CMD_SUCCESS; @@ -1437,7 +1434,7 @@ DEFUN (no_pce_neighbor, unset_pce_neighbor(PCE_DOMAIN_TYPE_AS, as, pce); /* Refresh RI LSA if already engaged */ - if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); return CMD_SUCCESS; @@ -1469,7 +1466,7 @@ DEFUN (pce_cap_flag, set_pce_cap_flag(cap, pce); /* Refresh RI LSA if already engaged */ - if (OspfRI.flags & RIFLG_LSA_ENGAGED) + if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); } @@ -1487,7 +1484,7 @@ DEFUN (no_pce_cap_flag, unset_param(&OspfRI.pce_info.pce_cap_flag.header); /* Refresh RI LSA if already engaged */ - if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED)) + if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); return CMD_SUCCESS; @@ -1502,7 +1499,7 @@ DEFUN (show_ip_ospf_router_info, "Router Information\n") { - if (OspfRI.status == enabled) { + if (OspfRI.enabled) { vty_out(vty, "--- Router Information parameters ---\n"); show_vty_router_cap(vty, &OspfRI.router_cap.header); } else { @@ -1528,7 +1525,7 @@ DEFUN (show_ip_opsf_router_info_pce, struct ri_pce_subtlv_domain *domain; struct ri_pce_subtlv_neighbor *neighbor; - if (OspfRI.status == enabled) { + if (OspfRI.enabled) { vty_out(vty, "--- PCE parameters ---\n"); if (pce->pce_address.header.type != 0) diff --git a/ospfd/ospf_ri.h b/ospfd/ospf_ri.h index 50221b25c5..2d90730d93 100644 --- a/ospfd/ospf_ri.h +++ b/ospfd/ospf_ri.h @@ -65,21 +65,6 @@ */ /* - * Following section defines TLV (tag, length, value) structures, - * used for Router Information. - */ -struct ri_tlv_header { - u_int16_t type; /* RI_TLV_XXX (see below) */ - u_int16_t length; /* Value portion only, in byte */ -}; - -#define RI_TLV_HDR_SIZE (sizeof (struct ri_tlv_header)) -#define RI_TLV_BODY_SIZE(tlvh) (ROUNDUP (ntohs ((tlvh)->length), sizeof (u_int32_t))) -#define RI_TLV_SIZE(tlvh) (RI_TLV_HDR_SIZE + RI_TLV_BODY_SIZE(tlvh)) -#define RI_TLV_HDR_TOP(lsah) (struct ri_tlv_header *)((char *)(lsah) + OSPF_LSA_HEADER_SIZE) -#define RI_TLV_HDR_NEXT(tlvh) (struct ri_tlv_header *)((char *)(tlvh) + RI_TLV_SIZE(tlvh)) - -/* * Following section defines TLV body parts. */ @@ -91,7 +76,7 @@ struct ri_tlv_header { #define RI_TLV_CAPABILITIES 1 struct ri_tlv_router_cap { - struct ri_tlv_header header; /* Value length is 4 bytes. */ + struct tlv_header header; /* Value length is 4 bytes. */ u_int32_t value; }; @@ -109,23 +94,19 @@ struct ri_tlv_router_cap { #define RI_TLV_PCE 6 struct ri_tlv_pce { - struct ri_tlv_header header; + struct tlv_header header; /* A set of PCE-sub-TLVs will follow. */ }; /* PCE Address Sub-TLV */ /* Mandatory */ #define RI_PCE_SUBTLV_ADDRESS 1 struct ri_pce_subtlv_address { - struct ri_tlv_header - header; /* Type = 1; Length is 8 (IPv4) or 20 (IPv6) bytes. */ - /* $FRR indent$ */ - /* clang-format off */ + /* Type = 1; Length is 8 (IPv4) or 20 (IPv6) bytes. */ + struct tlv_header header; #define PCE_ADDRESS_LENGTH_IPV4 8 #define PCE_ADDRESS_LENGTH_IPV6 20 struct { u_int16_t type; /* Address type: 1 = IPv4, 2 = IPv6 */ - /* $FRR indent$ */ - /* clang-format off */ #define PCE_ADDRESS_TYPE_IPV4 1 #define PCE_ADDRESS_TYPE_IPV6 2 u_int16_t reserved; @@ -136,9 +117,12 @@ struct ri_pce_subtlv_address { /* PCE Path-Scope Sub-TLV */ /* Mandatory */ #define RI_PCE_SUBTLV_PATH_SCOPE 2 struct ri_pce_subtlv_path_scope { - struct ri_tlv_header header; /* Type = 2; Length = 4 bytes. */ - u_int32_t value; /* L, R, Rd, S, Sd, Y, PrefL, PrefR, PrefS and PrefY - bits see RFC5088 page 9 */ + struct tlv_header header; /* Type = 2; Length = 4 bytes. */ + /* + * L, R, Rd, S, Sd, Y, PrefL, PrefR, PrefS and PrefY bits: + * see RFC5088 page 9 + */ + u_int32_t value; }; /* PCE Domain Sub-TLV */ /* Optional */ @@ -148,7 +132,7 @@ struct ri_pce_subtlv_path_scope { #define PCE_DOMAIN_TYPE_AS 2 struct ri_pce_subtlv_domain { - struct ri_tlv_header header; /* Type = 3; Length = 8 bytes. */ + struct tlv_header header; /* Type = 3; Length = 8 bytes. */ u_int16_t type; /* Domain type: 1 = OSPF Area ID, 2 = AS Number */ u_int16_t reserved; u_int32_t value; @@ -157,7 +141,7 @@ struct ri_pce_subtlv_domain { /* PCE Neighbor Sub-TLV */ /* Mandatory if R or S bit is set */ #define RI_PCE_SUBTLV_NEIGHBOR 4 struct ri_pce_subtlv_neighbor { - struct ri_tlv_header header; /* Type = 4; Length = 8 bytes. */ + struct tlv_header header; /* Type = 4; Length = 8 bytes. */ u_int16_t type; /* Domain type: 1 = OSPF Area ID, 2 = AS Number */ u_int16_t reserved; u_int32_t value; @@ -177,7 +161,7 @@ struct ri_pce_subtlv_neighbor { #define PCE_CAP_MULTIPLE_REQ 0x0100 struct ri_pce_subtlv_cap_flag { - struct ri_tlv_header header; /* Type = 5; Length = n x 4 bytes. */ + struct tlv_header header; /* Type = 5; Length = n x 4 bytes. */ u_int32_t value; }; diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index 4ca6578eae..1c1c76c1af 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -68,9 +68,7 @@ */ struct ospf_mpls_te OspfMplsTE; -const char *mode2text[] = {"Disable", "AS", "Area", "Emulate"}; - -enum oifstate { OI_ANY, OI_DOWN, OI_UP }; +const char *mode2text[] = {"Off", "AS", "Area"}; /*------------------------------------------------------------------------* * Followings are initialize/terminate functions for MPLS-TE handling. @@ -106,29 +104,28 @@ int ospf_mpls_te_init(void) if (rc != 0) { zlog_warn( "ospf_mpls_te_init: Failed to register Traffic Engineering functions"); - goto out; + return rc; } memset(&OspfMplsTE, 0, sizeof(struct ospf_mpls_te)); - OspfMplsTE.status = disabled; - OspfMplsTE.inter_as = Disable; + OspfMplsTE.enabled = false; + OspfMplsTE.inter_as = Off; OspfMplsTE.iflist = list_new(); OspfMplsTE.iflist->del = del_mpls_te_link; ospf_mpls_te_register_vty(); -out: return rc; } /* Additional register for RFC5392 support */ static int ospf_mpls_te_register(enum inter_as_mode mode) { - int rc; + int rc = 0; u_int8_t scope; - if (OspfMplsTE.inter_as != Disable) - return 0; + if (OspfMplsTE.inter_as != Off) + return rc; if (mode == AS) scope = OSPF_OPAQUE_AS_LSA; @@ -147,14 +144,14 @@ static int ospf_mpls_te_register(enum inter_as_mode mode) return rc; } - return 0; + return rc; } static int ospf_mpls_te_unregister() { u_int8_t scope; - if (OspfMplsTE.inter_as == Disable) + if (OspfMplsTE.inter_as == Off) return 0; if (OspfMplsTE.inter_as == AS) @@ -174,10 +171,10 @@ void ospf_mpls_te_term(void) ospf_delete_opaque_functab(OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); - OspfMplsTE.status = disabled; + OspfMplsTE.enabled = false; ospf_mpls_te_unregister(); - OspfMplsTE.inter_as = Disable; + OspfMplsTE.inter_as = Off; return; } @@ -192,7 +189,7 @@ static void del_mpls_te_link(void *val) return; } -u_int32_t get_mpls_te_instance_value(void) +static u_int32_t get_mpls_te_instance_value(void) { static u_int32_t seqno = 0; @@ -204,41 +201,6 @@ u_int32_t get_mpls_te_instance_value(void) return seqno; } -static struct ospf_interface *lookup_oi_by_ifp(struct interface *ifp, - struct ospf_area *area, - enum oifstate oifstate) -{ - struct ospf_interface *oi = NULL; - struct route_node *rn; - - for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) { - if ((oi = rn->info) == NULL) - continue; - - switch (oifstate) { - case OI_ANY: - break; - case OI_DOWN: - if (ospf_if_is_enable(oi)) - continue; - break; - case OI_UP: - if (!ospf_if_is_enable(oi)) - continue; - break; - default: - zlog_warn("lookup_oi_by_ifp: Unknown oifstate: %x", - oifstate); - goto out; - } - - if (area == NULL || oi->area == area) - return oi; - } -out: - return NULL; -} - static struct mpls_te_link *lookup_linkparams_by_ifp(struct interface *ifp) { struct listnode *node, *nnode; @@ -267,8 +229,8 @@ static struct mpls_te_link *lookup_linkparams_by_instance(struct ospf_lsa *lsa) } static void ospf_mpls_te_foreach_area(void (*func)(struct mpls_te_link *lp, - opcode_t sched_opcode), - opcode_t sched_opcode) + enum lsa_opcode sched_opcode), + enum lsa_opcode sched_opcode) { struct listnode *node, *nnode; struct listnode *node2; @@ -281,8 +243,8 @@ static void ospf_mpls_te_foreach_area(void (*func)(struct mpls_te_link *lp, continue; if ((area = lp->area) == NULL) continue; - if - CHECK_FLAG(lp->flags, LPFLG_LOOKUP_DONE) continue; + if (CHECK_FLAG(lp->flags, LPFLG_LOOKUP_DONE)) + continue; if (func != NULL) (*func)(lp, sched_opcode); @@ -793,14 +755,25 @@ static void update_linkparams(struct mpls_te_link *lp) static void initialize_linkparams(struct mpls_te_link *lp) { struct interface *ifp = lp->ifp; - struct ospf_interface *oi; + struct ospf_interface *oi = NULL; + struct route_node *rn; if (IS_DEBUG_OSPF_TE) zlog_debug( "MPLS-TE(initialize_linkparams) Initialize Link Parameters for interface %s", ifp->name); - if ((oi = lookup_oi_by_ifp(ifp, NULL, OI_ANY)) == NULL) { + /* Search OSPF Interface parameters for this interface */ + for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) { + + if ((oi = rn->info) == NULL) + continue; + + if (oi->ifp == ifp) + break; + } + + if ((oi == NULL) || (oi->ifp != ifp)) { if (IS_DEBUG_OSPF_TE) zlog_warn( "MPLS-TE(initialize_linkparams) Could not find corresponding OSPF Interface for %s", @@ -818,7 +791,7 @@ static void initialize_linkparams(struct mpls_te_link *lp) set_linkparams_lclif_ipaddr(lp, oi->address->u.prefix4); /* Set Remote IP addr if Point to Point Interface */ - if (oi->type == LINK_TYPE_SUBTLV_VALUE_PTP) { + if (oi->type == OSPF_IFTYPE_POINTOPOINT) { struct prefix *pref = CONNECTED_PREFIX(oi->connected); if (pref != NULL) set_linkparams_rmtif_ipaddr(lp, pref->u.prefix4); @@ -837,21 +810,20 @@ static int is_mandated_params_set(struct mpls_te_link *lp) if (ntohs(OspfMplsTE.router_addr.header.type) == 0) { zlog_warn( "MPLS-TE(is_mandated_params_set) Missing Router Address"); - goto out; + return rc; } if (ntohs(lp->link_type.header.type) == 0) { zlog_warn("MPLS-TE(is_mandated_params_set) Missing Link Type"); - goto out; + return rc; } if (!IS_INTER_AS(lp->type) && (ntohs(lp->link_id.header.type) == 0)) { zlog_warn("MPLS-TE(is_mandated_params_set) Missing Link ID"); - goto out; + return rc; } rc = 1; -out: return rc; } @@ -873,14 +845,14 @@ static int ospf_mpls_te_new_if(struct interface *ifp) zlog_warn("ospf_mpls_te_new_if: ifp(%p) already in use?", (void *)ifp); rc = 0; /* Do nothing here. */ - goto out; + return rc; } new = XCALLOC(MTYPE_OSPF_MPLS_TE, sizeof(struct mpls_te_link)); if (new == NULL) { zlog_warn("ospf_mpls_te_new_if: XMALLOC: %s", safe_strerror(errno)); - goto out; + return rc; } new->instance = get_mpls_te_instance_value(); @@ -909,7 +881,6 @@ static int ospf_mpls_te_new_if(struct interface *ifp) /* Schedule Opaque-LSA refresh. */ /* XXX */ rc = 0; -out: return rc; } @@ -934,7 +905,6 @@ static int ospf_mpls_te_del_if(struct interface *ifp) /* Schedule Opaque-LSA refresh. */ /* XXX */ rc = 0; - /*out:*/ return rc; } @@ -952,10 +922,9 @@ void ospf_mpls_te_update_if(struct interface *ifp) /* Get Link context from interface */ if ((lp = lookup_linkparams_by_ifp(ifp)) == NULL) { - if (IS_DEBUG_OSPF_TE) - zlog_warn( - "OSPF MPLS-TE Update: Did not find Link Parameters context for interface %s", - ifp->name); + zlog_warn( + "OSPF MPLS-TE Update: Did not find Link Parameters context for interface %s", + ifp->name); return; } @@ -968,20 +937,18 @@ void ospf_mpls_te_update_if(struct interface *ifp) /* Finally Re-Originate or Refresh Opaque LSA if MPLS_TE is * enabled */ - if (OspfMplsTE.status == enabled) + if (OspfMplsTE.enabled) if (lp->area != NULL) { - if - CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED) - ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA); - else ospf_mpls_te_lsa_schedule( - lp, REORIGINATE_THIS_LSA); + if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) + ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA); + else + ospf_mpls_te_lsa_schedule(lp, REORIGINATE_THIS_LSA); } } else { /* If MPLS TE is disable on this interface, flush LSA if it is * already engaged */ - if - CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED) - ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); + if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) + ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); else /* Reset Activity flag */ lp->flags = LPFLG_LSA_INACTIVE; @@ -1000,14 +967,14 @@ static void ospf_mpls_te_ism_change(struct ospf_interface *oi, int old_state) zlog_warn( "ospf_mpls_te_ism_change: Cannot get linkparams from OI(%s)?", IF_NAME(oi)); - goto out; + return; } if (oi->area == NULL || oi->area->ospf == NULL) { zlog_warn( "ospf_mpls_te_ism_change: Cannot refer to OSPF from OI(%s)?", IF_NAME(oi)); - goto out; + return; } #ifdef notyet if ((lp->area != NULL @@ -1059,24 +1026,21 @@ static void ospf_mpls_te_ism_change(struct ospf_interface *oi, int old_state) != ntohs(lp->link_id.header.type) || ntohl(old_id.value.s_addr) != ntohl(lp->link_id.value.s_addr))) { - if - CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED) - ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA); - else ospf_mpls_te_lsa_schedule(lp, - REORIGINATE_THIS_LSA); + if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) + ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA); + else + ospf_mpls_te_lsa_schedule(lp, REORIGINATE_THIS_LSA); } break; default: lp->link_type.header.type = htons(0); lp->link_id.header.type = htons(0); - if - CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED) - ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); + if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) + ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); break; } -out: return; } @@ -1090,28 +1054,28 @@ static void ospf_mpls_te_nsm_change(struct ospf_neighbor *nbr, int old_state) * Followings are OSPF protocol processing functions for MPLS-TE. *------------------------------------------------------------------------*/ -static void build_tlv_header(struct stream *s, struct te_tlv_header *tlvh) +static void build_tlv_header(struct stream *s, struct tlv_header *tlvh) { - stream_put(s, tlvh, sizeof(struct te_tlv_header)); + stream_put(s, tlvh, sizeof(struct tlv_header)); return; } static void build_router_tlv(struct stream *s) { - struct te_tlv_header *tlvh = &OspfMplsTE.router_addr.header; + struct tlv_header *tlvh = &OspfMplsTE.router_addr.header; if (ntohs(tlvh->type) != 0) { build_tlv_header(s, tlvh); - stream_put(s, tlvh + 1, TLV_BODY_SIZE(tlvh)); + stream_put(s, TLV_DATA(tlvh), TLV_BODY_SIZE(tlvh)); } return; } -static void build_link_subtlv(struct stream *s, struct te_tlv_header *tlvh) +static void build_link_subtlv(struct stream *s, struct tlv_header *tlvh) { if ((tlvh != NULL) && (ntohs(tlvh->type) != 0)) { build_tlv_header(s, tlvh); - stream_put(s, tlvh + 1, TLV_BODY_SIZE(tlvh)); + stream_put(s, TLV_DATA(tlvh), TLV_BODY_SIZE(tlvh)); } return; } @@ -1177,7 +1141,7 @@ static struct ospf_lsa *ospf_mpls_te_lsa_new(struct ospf_area *area, /* Create a stream for LSA. */ if ((s = stream_new(OSPF_MAX_LSA_SIZE)) == NULL) { zlog_warn("ospf_mpls_te_lsa_new: stream_new() ?"); - goto out; + return NULL; } lsah = (struct lsa_header *)STREAM_DATA(s); @@ -1233,14 +1197,14 @@ static struct ospf_lsa *ospf_mpls_te_lsa_new(struct ospf_area *area, if ((new = ospf_lsa_new()) == NULL) { zlog_warn("ospf_mpls_te_lsa_new: ospf_lsa_new() ?"); stream_free(s); - goto out; + return NULL; } if ((new->data = ospf_lsa_data_new(length)) == NULL) { zlog_warn("ospf_mpls_te_lsa_new: ospf_lsa_data_new() ?"); ospf_lsa_unlock(&new); new = NULL; stream_free(s); - goto out; + return new; } new->area = area; @@ -1248,7 +1212,6 @@ static struct ospf_lsa *ospf_mpls_te_lsa_new(struct ospf_area *area, memcpy(new->data, lsah, length); stream_free(s); -out: return new; } @@ -1262,14 +1225,14 @@ static int ospf_mpls_te_lsa_originate1(struct ospf_area *area, if ((new = ospf_mpls_te_lsa_new(area, lp)) == NULL) { zlog_warn( "ospf_mpls_te_lsa_originate1: ospf_mpls_te_lsa_new() ?"); - goto out; + return rc; } /* Install this LSA into LSDB. */ if (ospf_lsa_install(area->ospf, NULL /*oi*/, new) == NULL) { zlog_warn("ospf_mpls_te_lsa_originate1: ospf_lsa_install() ?"); ospf_lsa_unlock(&new); - goto out; + return rc; } /* Now this link-parameter entry has associated LSA. */ @@ -1291,7 +1254,6 @@ static int ospf_mpls_te_lsa_originate1(struct ospf_area *area, } rc = 0; -out: return rc; } @@ -1302,11 +1264,11 @@ static int ospf_mpls_te_lsa_originate_area(void *arg) struct mpls_te_link *lp; int rc = -1; - if (OspfMplsTE.status == disabled) { + if (!OspfMplsTE.enabled) { zlog_info( "ospf_mpls_te_lsa_originate_area: MPLS-TE is disabled now."); rc = 0; /* This is not an error case. */ - goto out; + return rc; } for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) { @@ -1321,23 +1283,16 @@ static int ospf_mpls_te_lsa_originate_area(void *arg) if (!IPV4_ADDR_SAME(&lp->area->area_id, &area->area_id)) continue; - if - CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED) - { - if - CHECK_FLAG(lp->flags, - LPFLG_LSA_FORCED_REFRESH) - { - UNSET_FLAG( - lp->flags, - LPFLG_LSA_FORCED_REFRESH); - zlog_warn( - "OSPF MPLS-TE (ospf_mpls_te_lsa_originate_area): Refresh instead of Originate"); - ospf_mpls_te_lsa_schedule( - lp, REFRESH_THIS_LSA); - } - continue; + if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) { + if (CHECK_FLAG(lp->flags, LPFLG_LSA_FORCED_REFRESH)) { + UNSET_FLAG(lp->flags, LPFLG_LSA_FORCED_REFRESH); + zlog_warn( + "OSPF MPLS-TE (ospf_mpls_te_lsa_originate_area): Refresh instead of Originate"); + ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA); } + continue; + } + if (!is_mandated_params_set(lp)) { zlog_warn( "ospf_mpls_te_lsa_originate_area: Link(%s) lacks some mandated MPLS-TE parameters.", @@ -1352,11 +1307,10 @@ static int ospf_mpls_te_lsa_originate_area(void *arg) lp->instance, inet_ntoa(area->area_id), lp->ifp ? lp->ifp->name : "?"); if (ospf_mpls_te_lsa_originate1(area, lp) != 0) - goto out; + return rc; } rc = 0; -out: return rc; } @@ -1370,14 +1324,14 @@ static int ospf_mpls_te_lsa_originate2(struct ospf *top, if ((new = ospf_mpls_te_lsa_new(NULL, lp)) == NULL) { zlog_warn( "ospf_mpls_te_lsa_originate2: ospf_router_info_lsa_new() ?"); - goto out; + return rc; } /* Install this LSA into LSDB. */ if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) { zlog_warn("ospf_mpls_te_lsa_originate2: ospf_lsa_install() ?"); ospf_lsa_unlock(&new); - goto out; + return rc; } /* Now this Router Info parameter entry has associated LSA. */ @@ -1396,7 +1350,6 @@ static int ospf_mpls_te_lsa_originate2(struct ospf *top, } rc = 0; -out: return rc; } @@ -1408,12 +1361,12 @@ static int ospf_mpls_te_lsa_originate_as(void *arg) struct mpls_te_link *lp; int rc = -1; - if ((OspfMplsTE.status == disabled) - || (OspfMplsTE.inter_as == Disable)) { + if ((!OspfMplsTE.enabled) + || (OspfMplsTE.inter_as == Off)) { zlog_info( "ospf_mpls_te_lsa_originate_as: MPLS-TE Inter-AS is disabled for now."); rc = 0; /* This is not an error case. */ - goto out; + return rc; } for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) { @@ -1422,21 +1375,14 @@ static int ospf_mpls_te_lsa_originate_as(void *arg) || !IS_INTER_AS(lp->type)) continue; - if - CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED) - { - if - CHECK_FLAG(lp->flags, - LPFLG_LSA_FORCED_REFRESH) - { - UNSET_FLAG( - lp->flags, - LPFLG_LSA_FORCED_REFRESH); - ospf_mpls_te_lsa_schedule( - lp, REFRESH_THIS_LSA); - } - continue; + if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) { + if (CHECK_FLAG(lp->flags, LPFLG_LSA_FORCED_REFRESH)) { + UNSET_FLAG(lp->flags,LPFLG_LSA_FORCED_REFRESH); + ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA); } + continue; + } + if (!is_mandated_params_set(lp)) { zlog_warn( "ospf_mpls_te_lsa_originate_as: Link(%s) lacks some mandated MPLS-TE parameters.", @@ -1462,7 +1408,6 @@ static int ospf_mpls_te_lsa_originate_as(void *arg) } rc = 0; -out: return rc; } @@ -1473,7 +1418,7 @@ static struct ospf_lsa *ospf_mpls_te_lsa_refresh(struct ospf_lsa *lsa) struct ospf *top; struct ospf_lsa *new = NULL; - if (OspfMplsTE.status == disabled) { + if (!OspfMplsTE.enabled) { /* * This LSA must have flushed before due to MPLS-TE status * change. @@ -1504,13 +1449,13 @@ static struct ospf_lsa *ospf_mpls_te_lsa_refresh(struct ospf_lsa *lsa) if (lp) UNSET_FLAG(lp->flags, LPFLG_LSA_ENGAGED); ospf_opaque_lsa_flush_schedule(lsa); - goto out; + return NULL; } /* Create new Opaque-LSA/MPLS-TE instance. */ if ((new = ospf_mpls_te_lsa_new(area, lp)) == NULL) { zlog_warn("ospf_mpls_te_lsa_refresh: ospf_mpls_te_lsa_new() ?"); - goto out; + return NULL; } new->data->ls_seqnum = lsa_seqnum_increment(lsa); @@ -1526,7 +1471,7 @@ static struct ospf_lsa *ospf_mpls_te_lsa_refresh(struct ospf_lsa *lsa) if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) { zlog_warn("ospf_mpls_te_lsa_refresh: ospf_lsa_install() ?"); ospf_lsa_unlock(&new); - goto out; + return NULL; } /* Flood updated LSA through AS or Area depending of the RFC of the link @@ -1543,11 +1488,10 @@ static struct ospf_lsa *ospf_mpls_te_lsa_refresh(struct ospf_lsa *lsa) ospf_lsa_header_dump(new->data); } -out: return new; } -void ospf_mpls_te_lsa_schedule(struct mpls_te_link *lp, opcode_t opcode) +void ospf_mpls_te_lsa_schedule(struct mpls_te_link *lp, enum lsa_opcode opcode) { struct ospf_lsa lsa; struct lsa_header lsah; @@ -1636,7 +1580,7 @@ void ospf_mpls_te_lsa_schedule(struct mpls_te_link *lp, opcode_t opcode) *------------------------------------------------------------------------*/ static u_int16_t show_vty_router_addr(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_tlv_router_addr *top = (struct te_tlv_router_addr *)tlvh; @@ -1649,7 +1593,7 @@ static u_int16_t show_vty_router_addr(struct vty *vty, } static u_int16_t show_vty_link_header(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_tlv_link *top = (struct te_tlv_link *)tlvh; @@ -1664,7 +1608,7 @@ static u_int16_t show_vty_link_header(struct vty *vty, } static u_int16_t show_vty_link_subtlv_link_type(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_link_subtlv_link_type *top; const char *cp = "Unknown"; @@ -1691,7 +1635,7 @@ static u_int16_t show_vty_link_subtlv_link_type(struct vty *vty, } static u_int16_t show_vty_link_subtlv_link_id(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_link_subtlv_link_id *top; @@ -1705,7 +1649,7 @@ static u_int16_t show_vty_link_subtlv_link_id(struct vty *vty, } static u_int16_t show_vty_link_subtlv_lclif_ipaddr(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_link_subtlv_lclif_ipaddr *top; int i, n; @@ -1730,7 +1674,7 @@ static u_int16_t show_vty_link_subtlv_lclif_ipaddr(struct vty *vty, } static u_int16_t show_vty_link_subtlv_rmtif_ipaddr(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_link_subtlv_rmtif_ipaddr *top; int i, n; @@ -1754,7 +1698,7 @@ static u_int16_t show_vty_link_subtlv_rmtif_ipaddr(struct vty *vty, } static u_int16_t show_vty_link_subtlv_te_metric(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_link_subtlv_te_metric *top; @@ -1770,7 +1714,7 @@ static u_int16_t show_vty_link_subtlv_te_metric(struct vty *vty, } static u_int16_t show_vty_link_subtlv_max_bw(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_link_subtlv_max_bw *top; float fval; @@ -1787,7 +1731,7 @@ static u_int16_t show_vty_link_subtlv_max_bw(struct vty *vty, } static u_int16_t show_vty_link_subtlv_max_rsv_bw(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_link_subtlv_max_rsv_bw *top; float fval; @@ -1806,7 +1750,7 @@ static u_int16_t show_vty_link_subtlv_max_rsv_bw(struct vty *vty, } static u_int16_t show_vty_link_subtlv_unrsv_bw(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_link_subtlv_unrsv_bw *top; float fval1, fval2; @@ -1837,7 +1781,7 @@ static u_int16_t show_vty_link_subtlv_unrsv_bw(struct vty *vty, } static u_int16_t show_vty_link_subtlv_rsc_clsclr(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_link_subtlv_rsc_clsclr *top; @@ -1853,7 +1797,7 @@ static u_int16_t show_vty_link_subtlv_rsc_clsclr(struct vty *vty, } static u_int16_t show_vty_link_subtlv_lrrid(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_link_subtlv_lrrid *top; @@ -1875,7 +1819,7 @@ static u_int16_t show_vty_link_subtlv_lrrid(struct vty *vty, } static u_int16_t show_vty_link_subtlv_llri(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_link_subtlv_llri *top; @@ -1897,7 +1841,7 @@ static u_int16_t show_vty_link_subtlv_llri(struct vty *vty, } static u_int16_t show_vty_link_subtlv_rip(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_link_subtlv_rip *top; @@ -1914,7 +1858,7 @@ static u_int16_t show_vty_link_subtlv_rip(struct vty *vty, } static u_int16_t show_vty_link_subtlv_ras(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_link_subtlv_ras *top; @@ -1931,7 +1875,7 @@ static u_int16_t show_vty_link_subtlv_ras(struct vty *vty, } static u_int16_t show_vty_link_subtlv_av_delay(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_link_subtlv_av_delay *top; u_int32_t delay; @@ -1952,7 +1896,7 @@ static u_int16_t show_vty_link_subtlv_av_delay(struct vty *vty, } static u_int16_t show_vty_link_subtlv_mm_delay(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_link_subtlv_mm_delay *top; u_int32_t low, high; @@ -1974,7 +1918,7 @@ static u_int16_t show_vty_link_subtlv_mm_delay(struct vty *vty, } static u_int16_t show_vty_link_subtlv_delay_var(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_link_subtlv_delay_var *top; u_int32_t jitter; @@ -1991,7 +1935,7 @@ static u_int16_t show_vty_link_subtlv_delay_var(struct vty *vty, } static u_int16_t show_vty_link_subtlv_pkt_loss(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_link_subtlv_pkt_loss *top; u_int32_t loss; @@ -2014,7 +1958,7 @@ static u_int16_t show_vty_link_subtlv_pkt_loss(struct vty *vty, } static u_int16_t show_vty_link_subtlv_res_bw(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_link_subtlv_res_bw *top; float fval; @@ -2035,7 +1979,7 @@ static u_int16_t show_vty_link_subtlv_res_bw(struct vty *vty, } static u_int16_t show_vty_link_subtlv_ava_bw(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_link_subtlv_ava_bw *top; float fval; @@ -2056,7 +2000,7 @@ static u_int16_t show_vty_link_subtlv_ava_bw(struct vty *vty, } static u_int16_t show_vty_link_subtlv_use_bw(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { struct te_link_subtlv_use_bw *top; float fval; @@ -2077,7 +2021,7 @@ static u_int16_t show_vty_link_subtlv_use_bw(struct vty *vty, } static u_int16_t show_vty_unknown_tlv(struct vty *vty, - struct te_tlv_header *tlvh) + struct tlv_header *tlvh) { if (vty != NULL) vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n", @@ -2090,11 +2034,11 @@ static u_int16_t show_vty_unknown_tlv(struct vty *vty, } static u_int16_t ospf_mpls_te_show_link_subtlv(struct vty *vty, - struct te_tlv_header *tlvh0, + struct tlv_header *tlvh0, u_int16_t subtotal, u_int16_t total) { - struct te_tlv_header *tlvh, *next; + struct tlv_header *tlvh, *next; u_int16_t sum = subtotal; for (tlvh = tlvh0; sum < total; @@ -2172,9 +2116,9 @@ static u_int16_t ospf_mpls_te_show_link_subtlv(struct vty *vty, static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa) { struct lsa_header *lsah = (struct lsa_header *)lsa->data; - struct te_tlv_header *tlvh, *next; + struct tlv_header *tlvh, *next; u_int16_t sum, total; - u_int16_t (*subfunc)(struct vty * vty, struct te_tlv_header * tlvh, + u_int16_t (*subfunc)(struct vty * vty, struct tlv_header * tlvh, u_int16_t subtotal, u_int16_t total) = NULL; sum = 0; @@ -2184,7 +2128,7 @@ static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa) tlvh = (next ? next : TLV_HDR_NEXT(tlvh))) { if (subfunc != NULL) { sum = (*subfunc)(vty, tlvh, sum, total); - next = (struct te_tlv_header *)((char *)tlvh + sum); + next = (struct tlv_header *)((char *)tlvh + sum); subfunc = NULL; continue; } @@ -2197,7 +2141,7 @@ static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa) case TE_TLV_LINK: sum += show_vty_link_header(vty, tlvh); subfunc = ospf_mpls_te_show_link_subtlv; - next = tlvh + 1; + next = TLV_DATA(tlvh); break; default: sum += show_vty_unknown_tlv(vty, tlvh); @@ -2210,7 +2154,7 @@ static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa) static void ospf_mpls_te_config_write_router(struct vty *vty) { - if (OspfMplsTE.status == enabled) { + if (OspfMplsTE.enabled) { vty_out(vty, " mpls-te on\n"); vty_out(vty, " mpls-te router-address %s\n", inet_ntoa(OspfMplsTE.router_addr.value)); @@ -2235,24 +2179,24 @@ DEFUN (ospf_mpls_te_on, MPLS_TE_STR "Enable the MPLS-TE functionality\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); struct listnode *node; struct mpls_te_link *lp; - if (OspfMplsTE.status == enabled) + if (OspfMplsTE.enabled) return CMD_SUCCESS; if (IS_DEBUG_OSPF_EVENT) zlog_debug("MPLS-TE: OFF -> ON"); - OspfMplsTE.status = enabled; + OspfMplsTE.enabled = true; /* Reoriginate RFC3630 & RFC6827 Links */ ospf_mpls_te_foreach_area(ospf_mpls_te_lsa_schedule, REORIGINATE_THIS_LSA); /* Reoriginate LSA if INTER-AS is always on */ - if (OspfMplsTE.inter_as != Disable) { + if (OspfMplsTE.inter_as != Off) { for (ALL_LIST_ELEMENTS_RO(OspfMplsTE.iflist, node, lp)) { if (IS_INTER_AS(lp->type)) { ospf_mpls_te_lsa_schedule(lp, @@ -2271,22 +2215,21 @@ DEFUN (no_ospf_mpls_te, MPLS_TE_STR "Disable the MPLS-TE functionality\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); struct listnode *node, *nnode; struct mpls_te_link *lp; - if (OspfMplsTE.status == disabled) + if (!OspfMplsTE.enabled) return CMD_SUCCESS; if (IS_DEBUG_OSPF_EVENT) zlog_debug("MPLS-TE: ON -> OFF"); - OspfMplsTE.status = disabled; + OspfMplsTE.enabled = false; for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) - if - CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED) - ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); + if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) + ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); return CMD_SUCCESS; } @@ -2299,7 +2242,7 @@ DEFUN (ospf_mpls_te_router_addr, "Stable IP address of the advertising router\n" "MPLS-TE router address in IPv4 address format\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4 = 2; struct te_tlv_router_addr *ra = &OspfMplsTE.router_addr; struct in_addr value; @@ -2317,8 +2260,8 @@ DEFUN (ospf_mpls_te_router_addr, set_mpls_te_router_addr(value); - if (OspfMplsTE.status == disabled) - goto out; + if (!OspfMplsTE.enabled) + return CMD_SUCCESS; for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) { if ((lp->area == NULL) || IS_FLOOD_AS(lp->type)) @@ -2344,7 +2287,7 @@ DEFUN (ospf_mpls_te_router_addr, ospf_mpls_te_foreach_area(ospf_mpls_te_lsa_schedule, REORIGINATE_THIS_LSA); } -out: + return CMD_SUCCESS; } @@ -2356,7 +2299,7 @@ static int set_inter_as_mode(struct vty *vty, const char *mode_name, struct mpls_te_link *lp; int format; - if (OspfMplsTE.status == enabled) { + if (OspfMplsTE.enabled) { /* Read and Check inter_as mode */ if (strcmp(mode_name, "as") == 0) @@ -2385,7 +2328,7 @@ static int set_inter_as_mode(struct vty *vty, const char *mode_name, } /* Enable mode and re-originate LSA if needed */ - if ((OspfMplsTE.inter_as == Disable) + if ((OspfMplsTE.inter_as == Off) && (mode != OspfMplsTE.inter_as)) { OspfMplsTE.inter_as = mode; /* Re-originate all InterAS-TEv2 LSA */ @@ -2451,9 +2394,9 @@ DEFUN (no_ospf_mpls_te_inter_as, if (IS_DEBUG_OSPF_EVENT) zlog_debug("MPLS-TE: Inter-AS support OFF"); - if ((OspfMplsTE.status == enabled) - && (OspfMplsTE.inter_as != Disable)) { - OspfMplsTE.inter_as = Disable; + if ((OspfMplsTE.enabled) + && (OspfMplsTE.inter_as != Off)) { + OspfMplsTE.inter_as = Off; /* Flush all Inter-AS LSA */ for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) if (IS_INTER_AS(lp->type) @@ -2476,7 +2419,7 @@ DEFUN (show_ip_ospf_mpls_te_router, "MPLS-TE information\n" "MPLS-TE Router parameters\n") { - if (OspfMplsTE.status == enabled) { + if (OspfMplsTE.enabled) { vty_out(vty, "--- MPLS-TE router parameters ---\n"); if (ntohs(OspfMplsTE.router_addr.header.type) != 0) @@ -2492,7 +2435,7 @@ static void show_mpls_te_link_sub(struct vty *vty, struct interface *ifp) { struct mpls_te_link *lp; - if ((OspfMplsTE.status == enabled) && HAS_LINK_PARAMS(ifp) + if ((OspfMplsTE.enabled) && HAS_LINK_PARAMS(ifp) && !if_is_loopback(ifp) && if_is_up(ifp) && ((lp = lookup_linkparams_by_ifp(ifp)) != NULL)) { /* Continue only if interface is not passive or support Inter-AS diff --git a/ospfd/ospf_te.h b/ospfd/ospf_te.h index 4ee9139a3c..0134214510 100644 --- a/ospfd/ospf_te.h +++ b/ospfd/ospf_te.h @@ -78,7 +78,7 @@ #define FLOOD_AS 0x20 #define EMULATED 0x80 -#define IS_STD_TE(x) (x & STD_TE) +#define IS_STD_TE(x) (x & STD_TE) #define IS_PSEUDO_TE(x) (x & PSEUDO_TE) #define IS_INTER_AS(x) (x & INTER_AS) #define IS_EMULATED(x) (x & EMULATED) @@ -95,57 +95,31 @@ #define LPFLG_LSA_FORCED_REFRESH 0x8 /* - * Following section defines TLV (tag, length, value) structures, - * used for Traffic Engineering. - */ -struct te_tlv_header { - u_int16_t type; /* TE_TLV_XXX (see below) */ - u_int16_t length; /* Value portion only, in octets */ -}; - -#define TLV_HDR_SIZE (sizeof(struct te_tlv_header)) - -#define TLV_BODY_SIZE(tlvh) (ROUNDUP(ntohs((tlvh)->length), sizeof(u_int32_t))) - -#define TLV_SIZE(tlvh) (TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh)) - -#define TLV_HDR_TOP(lsah) \ - (struct te_tlv_header *)((char *)(lsah) + OSPF_LSA_HEADER_SIZE) - -#define TLV_HDR_NEXT(tlvh) \ - (struct te_tlv_header *)((char *)(tlvh) + TLV_SIZE(tlvh)) - -#define TLV_HDR_SUBTLV(tlvh) \ - (struct te_tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE) - -#define TLV_TYPE(tlvh) tlvh.header.type -#define TLV_LEN(tlvh) tlvh.header.length -#define TLV_HDR(tlvh) tlvh.header - -/* * Following section defines TLV body parts. */ + /* Router Address TLV */ /* Mandatory */ #define TE_TLV_ROUTER_ADDR 1 struct te_tlv_router_addr { - struct te_tlv_header header; /* Value length is 4 octets. */ + struct tlv_header header; /* Value length is 4 octets. */ struct in_addr value; }; /* Link TLV */ #define TE_TLV_LINK 2 struct te_tlv_link { - struct te_tlv_header header; + struct tlv_header header; /* A set of link-sub-TLVs will follow. */ }; +/* Default TE TLV size */ #define TE_LINK_SUBTLV_DEF_SIZE 4 /* Link Type Sub-TLV */ /* Mandatory */ #define TE_LINK_SUBTLV_LINK_TYPE 1 #define TE_LINK_SUBTLV_TYPE_SIZE 1 struct te_link_subtlv_link_type { - struct te_tlv_header header; /* Value length is 1 octet. */ + struct tlv_header header; /* Value length is 1 octet. */ struct { #define LINK_TYPE_SUBTLV_VALUE_PTP 1 #define LINK_TYPE_SUBTLV_VALUE_MA 2 @@ -157,42 +131,42 @@ struct te_link_subtlv_link_type { /* Link Sub-TLV: Link ID */ /* Mandatory */ #define TE_LINK_SUBTLV_LINK_ID 2 struct te_link_subtlv_link_id { - struct te_tlv_header header; /* Value length is 4 octets. */ + struct tlv_header header; /* Value length is 4 octets. */ struct in_addr value; /* Same as router-lsa's link-id. */ }; /* Link Sub-TLV: Local Interface IP Address */ /* Optional */ #define TE_LINK_SUBTLV_LCLIF_IPADDR 3 struct te_link_subtlv_lclif_ipaddr { - struct te_tlv_header header; /* Value length is 4 x N octets. */ + struct tlv_header header; /* Value length is 4 x N octets. */ struct in_addr value[1]; /* Local IP address(es). */ }; /* Link Sub-TLV: Remote Interface IP Address */ /* Optional */ #define TE_LINK_SUBTLV_RMTIF_IPADDR 4 struct te_link_subtlv_rmtif_ipaddr { - struct te_tlv_header header; /* Value length is 4 x N octets. */ + struct tlv_header header; /* Value length is 4 x N octets. */ struct in_addr value[1]; /* Neighbor's IP address(es). */ }; /* Link Sub-TLV: Traffic Engineering Metric */ /* Optional */ #define TE_LINK_SUBTLV_TE_METRIC 5 struct te_link_subtlv_te_metric { - struct te_tlv_header header; /* Value length is 4 octets. */ + struct tlv_header header; /* Value length is 4 octets. */ u_int32_t value; /* Link metric for TE purpose. */ }; /* Link Sub-TLV: Maximum Bandwidth */ /* Optional */ #define TE_LINK_SUBTLV_MAX_BW 6 struct te_link_subtlv_max_bw { - struct te_tlv_header header; /* Value length is 4 octets. */ + struct tlv_header header; /* Value length is 4 octets. */ float value; /* bytes/sec */ }; /* Link Sub-TLV: Maximum Reservable Bandwidth */ /* Optional */ #define TE_LINK_SUBTLV_MAX_RSV_BW 7 struct te_link_subtlv_max_rsv_bw { - struct te_tlv_header header; /* Value length is 4 octets. */ + struct tlv_header header; /* Value length is 4 octets. */ float value; /* bytes/sec */ }; @@ -200,14 +174,14 @@ struct te_link_subtlv_max_rsv_bw { #define TE_LINK_SUBTLV_UNRSV_BW 8 #define TE_LINK_SUBTLV_UNRSV_SIZE 32 struct te_link_subtlv_unrsv_bw { - struct te_tlv_header header; /* Value length is 32 octets. */ + struct tlv_header header; /* Value length is 32 octets. */ float value[MAX_CLASS_TYPE]; /* One for each priority level. */ }; /* Link Sub-TLV: Resource Class/Color */ /* Optional */ #define TE_LINK_SUBTLV_RSC_CLSCLR 9 struct te_link_subtlv_rsc_clsclr { - struct te_tlv_header header; /* Value length is 4 octets. */ + struct tlv_header header; /* Value length is 4 octets. */ u_int32_t value; /* Admin. group membership. */ }; @@ -216,7 +190,7 @@ struct te_link_subtlv_rsc_clsclr { #define TE_LINK_SUBTLV_LRRID 10 #define TE_LINK_SUBTLV_LRRID_SIZE 8 struct te_link_subtlv_lrrid { - struct te_tlv_header header; /* Value length is 8 octets. */ + struct tlv_header header; /* Value length is 8 octets. */ struct in_addr local; /* Local TE Router Identifier */ struct in_addr remote; /* Remote TE Router Identifier */ }; @@ -225,7 +199,7 @@ struct te_link_subtlv_lrrid { #define TE_LINK_SUBTLV_LLRI 11 #define TE_LINK_SUBTLV_LLRI_SIZE 8 struct te_link_subtlv_llri { - struct te_tlv_header header; /* Value length is 8 octets. */ + struct tlv_header header; /* Value length is 8 octets. */ u_int32_t local; /* Link Local Identifier */ u_int32_t remote; /* Link Remote Identifier */ }; @@ -240,14 +214,14 @@ struct te_link_subtlv_llri { /* Remote AS Number sub-TLV */ #define TE_LINK_SUBTLV_RAS 21 struct te_link_subtlv_ras { - struct te_tlv_header header; /* Value length is 4 octets. */ + struct tlv_header header; /* Value length is 4 octets. */ u_int32_t value; /* Remote AS number */ }; /* IPv4 Remote ASBR ID Sub-TLV */ #define TE_LINK_SUBTLV_RIP 22 struct te_link_subtlv_rip { - struct te_tlv_header header; /* Value length is 4 octets. */ + struct tlv_header header; /* Value length is 4 octets. */ struct in_addr value; /* Remote ASBR IP address */ }; @@ -261,63 +235,69 @@ struct te_link_subtlv_rip { /* Link Sub-TLV: Average Link Delay */ /* Optional */ #define TE_LINK_SUBTLV_AV_DELAY 27 struct te_link_subtlv_av_delay { - struct te_tlv_header header; /* Value length is 4 bytes. */ - u_int32_t - value; /* delay in micro-seconds only 24 bits => 0 ... 16777215 - with Anomalous Bit as Upper most bit */ + struct tlv_header header; /* Value length is 4 bytes. */ + /* + * delay in micro-seconds only 24 bits => 0 ... 16777215 + * with Anomalous Bit as Upper most bit + */ + u_int32_t value; }; /* Link Sub-TLV: Low/High Link Delay */ #define TE_LINK_SUBTLV_MM_DELAY 28 #define TE_LINK_SUBTLV_MM_DELAY_SIZE 8 struct te_link_subtlv_mm_delay { - struct te_tlv_header header; /* Value length is 8 bytes. */ - u_int32_t low; /* low delay in micro-seconds only 24 bits => 0 ... - 16777215 - with Anomalous Bit (A) as Upper most bit */ - u_int32_t high; /* high delay in micro-seconds only 24 bits => 0 ... - 16777215 */ + struct tlv_header header; /* Value length is 8 bytes. */ + /* + * low delay in micro-seconds only 24 bits => 0 ... 16777215 + * with Anomalous Bit (A) as Upper most bit + */ + u_int32_t low; + /* high delay in micro-seconds only 24 bits => 0 ... 16777215 */ + u_int32_t high; }; /* Link Sub-TLV: Link Delay Variation i.e. Jitter */ #define TE_LINK_SUBTLV_DELAY_VAR 29 struct te_link_subtlv_delay_var { - struct te_tlv_header header; /* Value length is 4 bytes. */ - u_int32_t value; /* interval in micro-seconds only 24 bits => 0 ... - 16777215 */ + struct tlv_header header; /* Value length is 4 bytes. */ + /* interval in micro-seconds only 24 bits => 0 ... 16777215 */ + u_int32_t value; }; /* Link Sub-TLV: Routine Unidirectional Link Packet Loss */ #define TE_LINK_SUBTLV_PKT_LOSS 30 struct te_link_subtlv_pkt_loss { - struct te_tlv_header header; /* Value length is 4 bytes. */ - u_int32_t - value; /* in percentage of total traffic only 24 bits (2^24 - 2) - with Anomalous Bit as Upper most bit */ + struct tlv_header header; /* Value length is 4 bytes. */ + /* + * in percentage of total traffic only 24 bits (2^24 - 2) + * with Anomalous Bit as Upper most bit + */ + u_int32_t value; }; /* Link Sub-TLV: Unidirectional Residual Bandwidth */ /* Optional */ #define TE_LINK_SUBTLV_RES_BW 31 struct te_link_subtlv_res_bw { - struct te_tlv_header header; /* Value length is 4 bytes. */ - float value; /* bandwidth in IEEE floating point format with units in - bytes per second */ + struct tlv_header header; /* Value length is 4 bytes. */ + /* bandwidth in IEEE floating point format with units in bytes/second */ + float value; }; /* Link Sub-TLV: Unidirectional Available Bandwidth */ /* Optional */ #define TE_LINK_SUBTLV_AVA_BW 32 struct te_link_subtlv_ava_bw { - struct te_tlv_header header; /* Value length is 4 octets. */ - float value; /* bandwidth in IEEE floating point format with units in - bytes per second */ + struct tlv_header header; /* Value length is 4 octets. */ + /* bandwidth in IEEE floating point format with units in bytes/second */ + float value; }; /* Link Sub-TLV: Unidirectional Utilized Bandwidth */ /* Optional */ #define TE_LINK_SUBTLV_USE_BW 33 struct te_link_subtlv_use_bw { - struct te_tlv_header header; /* Value length is 4 octets. */ - float value; /* bandwidth in IEEE floating point format with units in - bytes per second */ + struct tlv_header header; /* Value length is 4 octets. */ + /* bandwidth in IEEE floating point format with units in bytes/second */ + float value; }; #define TE_LINK_SUBTLV_MAX 34 /* Last SUBTLV + 1 */ @@ -325,20 +305,11 @@ struct te_link_subtlv_use_bw { /* Here are "non-official" architectural constants. */ #define MPLS_TE_MINIMUM_BANDWIDTH 1.0 /* Reasonable? *//* XXX */ -/* Following declaration concerns the MPLS-TE and LINk-TE management */ -typedef enum _opcode_t { - REORIGINATE_THIS_LSA, - REFRESH_THIS_LSA, - FLUSH_THIS_LSA -} opcode_t; - -typedef enum _status_t { disabled, enabled } status_t; - /* Mode for Inter-AS Opaque-LSA */ -enum inter_as_mode { Disable, AS, Area }; +enum inter_as_mode { Off, AS, Area }; struct te_link_subtlv { - struct te_tlv_header header; + struct tlv_header header; union { u_int32_t link_type; struct in_addr link_id; @@ -366,7 +337,7 @@ struct te_link_subtlv { /* Following structure are internal use only. */ struct ospf_mpls_te { /* Status of MPLS-TE: enable or disbale */ - status_t status; + bool enabled; /* RFC5392 */ enum inter_as_mode inter_as; @@ -437,8 +408,7 @@ extern int ospf_mpls_te_init(void); extern void ospf_mpls_te_term(void); extern struct ospf_mpls_te *get_ospf_mpls_te(void); extern void ospf_mpls_te_update_if(struct interface *); -extern void ospf_mpls_te_lsa_schedule(struct mpls_te_link *, opcode_t); -extern u_int32_t get_mpls_te_instance_value(void); +extern void ospf_mpls_te_lsa_schedule(struct mpls_te_link *, enum lsa_opcode); extern void set_linkparams_llri(struct mpls_te_link *, u_int32_t, u_int32_t); extern void set_linkparams_lrrid(struct mpls_te_link *, struct in_addr, struct in_addr); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index a8bfb669af..13d4780db3 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -135,6 +135,7 @@ DEFUN_NOSH (router_ospf, { struct ospf *ospf; u_short instance = 0; + int ret = CMD_SUCCESS; ospf = ospf_lookup(); if (!ospf) { @@ -147,9 +148,10 @@ DEFUN_NOSH (router_ospf, /* The following logic to set the vty qobj index is in place to be able to ignore the commands which dont belong to this instance. */ - if (ospf->instance != instance) + if (ospf->instance != instance) { VTY_PUSH_CONTEXT_NULL(OSPF_NODE); - else { + ret = CMD_NOT_MY_INSTANCE; + } else { if (IS_DEBUG_OSPF_EVENT) zlog_debug("Config command 'router ospf %d' received", instance); @@ -158,7 +160,7 @@ DEFUN_NOSH (router_ospf, ospf_router_id_update(ospf); } - return CMD_SUCCESS; + return ret; } DEFUN (no_router_ospf, @@ -175,8 +177,9 @@ DEFUN (no_router_ospf, if (argc > 3) instance = strtoul(argv[3]->arg, NULL, 10); - if ((ospf = ospf_lookup_instance(instance)) == NULL) - return CMD_SUCCESS; + ospf = ospf_lookup_instance(instance); + if (ospf == NULL) + return CMD_NOT_MY_INSTANCE; ospf_finish(ospf); @@ -191,7 +194,7 @@ DEFUN (ospf_router_id, "router-id for the OSPF process\n" "OSPF router-id in IP address format\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4 = 2; struct listnode *node; struct ospf_area *area; @@ -225,7 +228,7 @@ DEFUN_HIDDEN (ospf_router_id_old, "router-id for the OSPF process\n" "OSPF router-id in IP address format\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4 = 1; struct listnode *node; struct ospf_area *area; @@ -261,7 +264,7 @@ DEFUN (no_ospf_router_id, "router-id for the OSPF process\n" "OSPF router-id in IP address format\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); struct listnode *node; struct ospf_area *area; @@ -350,7 +353,7 @@ DEFUN (ospf_passive_interface, "IPv4 address\n" "Suppress routing updates on interfaces by default\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4 = 2; struct interface *ifp; struct in_addr addr = {.s_addr = INADDR_ANY}; @@ -417,7 +420,7 @@ DEFUN (no_ospf_passive_interface, "IPv4 address\n" "Allow routing updates on interfaces by default\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4 = 3; struct interface *ifp; struct in_addr addr = {.s_addr = INADDR_ANY}; @@ -478,7 +481,7 @@ DEFUN (ospf_network_area, "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_prefixlen = 1; int idx_ipv4_number = 3; struct prefix_ipv4 p; @@ -520,7 +523,7 @@ DEFUN (no_ospf_network_area, "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_prefixlen = 2; int idx_ipv4_number = 4; struct prefix_ipv4 p; @@ -559,7 +562,7 @@ DEFUN (ospf_area_range, "User specified metric for this range\n" "Advertised metric for this range\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 1; int idx_ipv4_prefixlen = 3; int idx_cost = 6; @@ -591,7 +594,7 @@ DEFUN (ospf_area_range_cost, "User specified metric for this range\n" "Advertised metric for this range\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 1; int idx_ipv4_prefixlen = 3; int idx_cost = 5; @@ -623,7 +626,7 @@ DEFUN (ospf_area_range_not_advertise, "Area range prefix\n" "DoNotAdvertise this range\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 1; int idx_ipv4_prefixlen = 3; struct prefix_ipv4 p; @@ -656,7 +659,7 @@ DEFUN (no_ospf_area_range, "Advertised metric for this range\n" "DoNotAdvertise this range\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 2; int idx_ipv4_prefixlen = 4; struct prefix_ipv4 p; @@ -682,7 +685,7 @@ DEFUN (ospf_area_range_substitute, "Announce area range as another prefix\n" "Network prefix to be announced instead of range\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 1; int idx_ipv4_prefixlen = 3; int idx_ipv4_prefixlen_2 = 5; @@ -713,7 +716,7 @@ DEFUN (no_ospf_area_range_substitute, "Announce area range as another prefix\n" "Network prefix to be announced instead of range\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 2; int idx_ipv4_prefixlen = 4; int idx_ipv4_prefixlen_2 = 6; @@ -981,7 +984,7 @@ DEFUN (ospf_area_vlink, "Use MD5 algorithm\n" \ "The OSPF password (key)") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 1; int idx_ipv4 = 3; struct ospf_vl_config_data vl_config; @@ -1105,7 +1108,7 @@ DEFUN (no_ospf_area_vlink, "Use MD5 algorithm\n" \ "The OSPF password (key)") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 2; int idx_ipv4 = 4; struct ospf_area *area; @@ -1204,7 +1207,7 @@ DEFUN (ospf_area_vlink_intervals, VLINK_HELPSTR_IPADDR VLINK_HELPSTR_TIME_PARAM) { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); struct ospf_vl_config_data vl_config; int ret = 0; @@ -1251,7 +1254,7 @@ DEFUN (no_ospf_area_vlink_intervals, VLINK_HELPSTR_IPADDR VLINK_HELPSTR_TIME_PARAM) { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); struct ospf_vl_config_data vl_config; int ret = 0; @@ -1300,7 +1303,7 @@ DEFUN (ospf_area_shortcut, "Enable shortcutting through the area\n" "Disable shortcutting through the area\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 1; int idx_enable_disable = 3; struct ospf_area *area; @@ -1344,7 +1347,7 @@ DEFUN (no_ospf_area_shortcut, "Deconfigure enabled shortcutting through the area\n" "Deconfigure disabled shortcutting through the area\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 2; struct ospf_area *area; struct in_addr area_id; @@ -1371,7 +1374,7 @@ DEFUN (ospf_area_stub, "OSPF area ID as a decimal value\n" "Configure OSPF area as stub\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 1; struct in_addr area_id; int ret, format; @@ -1402,7 +1405,7 @@ DEFUN (ospf_area_stub_no_summary, "Configure OSPF area as stub\n" "Do not inject inter-area routes into stub\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 1; struct in_addr area_id; int ret, format; @@ -1433,7 +1436,7 @@ DEFUN (no_ospf_area_stub, "OSPF area ID as a decimal value\n" "Configure OSPF area as stub\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 2; struct in_addr area_id; int format; @@ -1457,7 +1460,7 @@ DEFUN (no_ospf_area_stub_no_summary, "Configure OSPF area as stub\n" "Do not inject inter-area routes into area\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 2; struct in_addr area_id; int format; @@ -1472,7 +1475,7 @@ DEFUN (no_ospf_area_stub_no_summary, static int ospf_area_nssa_cmd_handler(struct vty *vty, int argc, struct cmd_token **argv, int nosum) { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); struct in_addr area_id; int ret, format; @@ -1577,7 +1580,7 @@ DEFUN (no_ospf_area_nssa, "Configure NSSA-ABR to always translate\n" "Do not inject inter-area routes into nssa\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 2; struct in_addr area_id; int format; @@ -1603,7 +1606,7 @@ DEFUN (ospf_area_default_cost, "Set the summary-default cost of a NSSA or stub area\n" "Stub's advertised default summary cost\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 1; int idx_number = 3; struct ospf_area *area; @@ -1649,7 +1652,7 @@ DEFUN (no_ospf_area_default_cost, "Set the summary-default cost of a NSSA or stub area\n" "Stub's advertised default summary cost\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 2; struct ospf_area *area; struct in_addr area_id; @@ -1695,7 +1698,7 @@ DEFUN (ospf_area_export_list, "Set the filter for networks announced to other areas\n" "Name of the access-list\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 1; struct ospf_area *area; struct in_addr area_id; @@ -1720,7 +1723,7 @@ DEFUN (no_ospf_area_export_list, "Unset the filter for networks announced to other areas\n" "Name of the access-list\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 2; struct ospf_area *area; struct in_addr area_id; @@ -1747,7 +1750,7 @@ DEFUN (ospf_area_import_list, "Set the filter for networks from other areas announced to the specified one\n" "Name of the access-list\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 1; struct ospf_area *area; struct in_addr area_id; @@ -1772,7 +1775,7 @@ DEFUN (no_ospf_area_import_list, "Unset the filter for networks announced to other areas\n" "Name of the access-list\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 2; struct ospf_area *area; struct in_addr area_id; @@ -1801,7 +1804,7 @@ DEFUN (ospf_area_filter_list, "Filter networks sent to this area\n" "Filter networks sent from this area\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 1; int idx_word = 4; int idx_in_out = 5; @@ -1847,7 +1850,7 @@ DEFUN (no_ospf_area_filter_list, "Filter networks sent to this area\n" "Filter networks sent from this area\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 2; int idx_word = 5; int idx_in_out = 6; @@ -1901,7 +1904,7 @@ DEFUN (ospf_area_authentication_message_digest, "Enable authentication\n" "Use message-digest authentication\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 1; struct ospf_area *area; struct in_addr area_id; @@ -1924,7 +1927,7 @@ DEFUN (ospf_area_authentication, "OSPF area ID as a decimal value\n" "Enable authentication\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 1; struct ospf_area *area; struct in_addr area_id; @@ -1948,7 +1951,7 @@ DEFUN (no_ospf_area_authentication, "OSPF area ID as a decimal value\n" "Enable authentication\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4_number = 2; struct ospf_area *area; struct in_addr area_id; @@ -1978,7 +1981,7 @@ DEFUN (ospf_abr_type, "Shortcut ABR\n" "Standard behavior (RFC2328)\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_vendor = 2; u_char abr_type = OSPF_ABR_UNKNOWN; @@ -2013,7 +2016,7 @@ DEFUN (no_ospf_abr_type, "Shortcut ABR\n" "Standard ABR\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_vendor = 3; u_char abr_type = OSPF_ABR_UNKNOWN; @@ -2042,7 +2045,7 @@ DEFUN (ospf_log_adjacency_changes, "log-adjacency-changes", "Log changes in adjacency state\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); SET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES); UNSET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL); @@ -2055,7 +2058,7 @@ DEFUN (ospf_log_adjacency_changes_detail, "Log changes in adjacency state\n" "Log all state changes\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); SET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES); SET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL); @@ -2068,7 +2071,7 @@ DEFUN (no_ospf_log_adjacency_changes, NO_STR "Log changes in adjacency state\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); UNSET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL); UNSET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES); @@ -2082,7 +2085,7 @@ DEFUN (no_ospf_log_adjacency_changes_detail, "Log changes in adjacency state\n" "Log all state changes\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); UNSET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL); return CMD_SUCCESS; @@ -2094,7 +2097,7 @@ DEFUN (ospf_compatible_rfc1583, "OSPF compatibility list\n" "compatible with RFC 1583\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); if (!CHECK_FLAG(ospf->config, OSPF_RFC1583_COMPATIBLE)) { SET_FLAG(ospf->config, OSPF_RFC1583_COMPATIBLE); @@ -2110,7 +2113,7 @@ DEFUN (no_ospf_compatible_rfc1583, "OSPF compatibility list\n" "compatible with RFC 1583\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); if (CHECK_FLAG(ospf->config, OSPF_RFC1583_COMPATIBLE)) { UNSET_FLAG(ospf->config, OSPF_RFC1583_COMPATIBLE); @@ -2132,7 +2135,7 @@ ALIAS(no_ospf_compatible_rfc1583, no_ospf_rfc1583_flag_cmd, static int ospf_timers_spf_set(struct vty *vty, unsigned int delay, unsigned int hold, unsigned int max) { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); ospf->spf_delay = delay; ospf->spf_holdtime = hold; @@ -2150,7 +2153,7 @@ DEFUN (ospf_timers_min_ls_interval, "All LSA types\n" "Delay (msec) between sending LSAs\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_number = 4; unsigned int interval; @@ -2176,54 +2179,12 @@ DEFUN (no_ospf_timers_min_ls_interval, "All LSA types\n" "Delay (msec) between sending LSAs\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); ospf->min_ls_interval = OSPF_MIN_LS_INTERVAL; return CMD_SUCCESS; } - -DEFUN (ospf_timers_min_ls_arrival, - ospf_timers_min_ls_arrival_cmd, - "timers lsa arrival (0-1000)", - "Adjust routing timers\n" - "Throttling link state advertisement delays\n" - "OSPF minimum arrival interval delay\n" - "Delay (msec) between accepted LSAs\n") -{ - VTY_DECLVAR_CONTEXT(ospf, ospf); - int idx_number = 3; - unsigned int arrival; - - if (argc < 4) { - vty_out(vty, "Insufficient arguments\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - arrival = strtoul(argv[idx_number]->arg, NULL, 10); - - ospf->min_ls_arrival = arrival; - - return CMD_SUCCESS; -} - -DEFUN (no_ospf_timers_min_ls_arrival, - no_ospf_timers_min_ls_arrival_cmd, - "no timers lsa arrival [(0-1000)]", - NO_STR - "Adjust routing timers\n" - "Throttling link state advertisement delays\n" - "OSPF minimum arrival interval delay\n" - "Delay (msec) between accepted LSAs\n") -{ - VTY_DECLVAR_CONTEXT(ospf, ospf); - - ospf->min_ls_arrival = OSPF_MIN_LS_ARRIVAL; - - return CMD_SUCCESS; -} - - DEFUN (ospf_timers_throttle_spf, ospf_timers_throttle_spf_cmd, "timers throttle spf (0-600000) (0-600000) (0-600000)", @@ -2268,32 +2229,21 @@ DEFUN (no_ospf_timers_throttle_spf, } -DEFUN (ospf_timers_lsa, - ospf_timers_lsa_cmd, +DEFUN (ospf_timers_lsa_min_arrival, + ospf_timers_lsa_min_arrival_cmd, "timers lsa min-arrival (0-600000)", "Adjust routing timers\n" "OSPF LSA timers\n" "Minimum delay in receiving new version of a LSA\n" "Delay in milliseconds\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); - int idx_number = 3; - unsigned int minarrival; - - if (argc < 4) { - vty_out(vty, "Insufficient number of arguments\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - minarrival = strtoul(argv[idx_number]->arg, NULL, 10); - - ospf->min_ls_arrival = minarrival; - + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + ospf->min_ls_arrival = strtoul(argv[argc - 1]->arg, NULL, 10); return CMD_SUCCESS; } -DEFUN (no_ospf_timers_lsa, - no_ospf_timers_lsa_cmd, +DEFUN (no_ospf_timers_lsa_min_arrival, + no_ospf_timers_lsa_min_arrival_cmd, "no timers lsa min-arrival [(0-600000)]", NO_STR "Adjust routing timers\n" @@ -2301,11 +2251,11 @@ DEFUN (no_ospf_timers_lsa, "Minimum delay in receiving new version of a LSA\n" "Delay in milliseconds\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); unsigned int minarrival; if (argc > 4) { - minarrival = strtoul(argv[4]->arg, NULL, 10); + minarrival = strtoul(argv[argc - 1]->arg, NULL, 10); if (ospf->min_ls_arrival != minarrival || minarrival == OSPF_MIN_LS_ARRIVAL) @@ -2317,6 +2267,26 @@ DEFUN (no_ospf_timers_lsa, return CMD_SUCCESS; } +/* Deprecated: 08/07/2017 */ +ALIAS_HIDDEN (ospf_timers_lsa_min_arrival, + ospf_timers_lsa_arrival_cmd, + "timers lsa arrival (0-1000)", + "adjust routing timers\n" + "throttling link state advertisement delays\n" + "ospf minimum arrival interval delay\n" + "delay (msec) between accepted lsas\n"); + +/* Deprecated: 08/07/2017 */ +ALIAS_HIDDEN (no_ospf_timers_lsa_min_arrival, + no_ospf_timers_lsa_arrival_cmd, + "no timers lsa arrival (0-1000)", + NO_STR + "adjust routing timers\n" + "throttling link state advertisement delays\n" + "ospf minimum arrival interval delay\n" + "delay (msec) between accepted lsas\n"); + + DEFUN (ospf_neighbor, ospf_neighbor_cmd, "neighbor A.B.C.D [priority (0-255) [poll-interval (1-65535)]]", @@ -2327,7 +2297,7 @@ DEFUN (ospf_neighbor, "Dead Neighbor Polling interval\n" "Seconds\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4 = 1; int idx_pri = 3; int idx_poll = 5; @@ -2364,7 +2334,7 @@ DEFUN (ospf_neighbor_poll_interval, "OSPF priority of non-broadcast neighbor\n" "Priority\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4 = 1; int idx_poll = 3; int idx_pri = 5; @@ -2399,7 +2369,7 @@ DEFUN (no_ospf_neighbor, "Dead Neighbor Polling interval\n" "Seconds\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4 = 2; struct in_addr nbr_addr; @@ -2421,7 +2391,7 @@ DEFUN (no_ospf_neighbor_poll, "Neighbor Priority\n" "Priority\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ipv4 = 2; struct in_addr nbr_addr; @@ -2439,7 +2409,7 @@ DEFUN (ospf_refresh_timer, "Set refresh timer\n" "Timer value in seconds\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_number = 2; unsigned int interval; @@ -2460,7 +2430,7 @@ DEFUN (no_ospf_refresh_timer, "Unset refresh timer\n" "Timer value in seconds\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_number = 3; unsigned int interval; @@ -2485,7 +2455,7 @@ DEFUN (ospf_auto_cost_reference_bandwidth, "Use reference bandwidth method to assign OSPF cost\n" "The reference bandwidth in terms of Mbits per second\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_number = 2; u_int32_t refbw; struct listnode *node; @@ -2516,7 +2486,7 @@ DEFUN (no_ospf_auto_cost_reference_bandwidth, "Use reference bandwidth method to assign OSPF cost\n" "The reference bandwidth in terms of Mbits per second\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); struct listnode *node, *nnode; struct interface *ifp; @@ -2541,7 +2511,7 @@ DEFUN (ospf_write_multiplier, "Write multiplier\n" "Maximum number of interface serviced per write\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_number; u_int32_t write_oi_count; @@ -2572,7 +2542,7 @@ DEFUN (no_ospf_write_multiplier, "Write multiplier\n" "Maximum number of interface serviced per write\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); ospf->write_oi_count = OSPF_WRITE_INTERFACE_COUNT_DEFAULT; return CMD_SUCCESS; @@ -3218,8 +3188,11 @@ DEFUN (show_ip_ospf_instance, u_char uj = use_json(argc, argv); instance = strtoul(argv[idx_number]->arg, NULL, 10); - if ((ospf = ospf_lookup_instance(instance)) == NULL - || !ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (ospf == NULL) + return CMD_NOT_MY_INSTANCE; + + if (!ospf->oi_running) return CMD_SUCCESS; return (show_ip_ospf_common(vty, ospf, uj)); @@ -3654,8 +3627,11 @@ DEFUN (show_ip_ospf_instance_interface, u_char uj = use_json(argc, argv); instance = strtoul(argv[idx_number]->arg, NULL, 10); - if ((ospf = ospf_lookup_instance(instance)) == NULL - || !ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (ospf == NULL) + return CMD_NOT_MY_INSTANCE; + + if (!ospf->oi_running) return CMD_SUCCESS; if (uj) @@ -3861,8 +3837,11 @@ DEFUN (show_ip_ospf_instance_neighbor, u_char uj = use_json(argc, argv); instance = strtoul(argv[idx_number]->arg, NULL, 10); - if ((ospf = ospf_lookup_instance(instance)) == NULL - || !ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (ospf == NULL) + return CMD_NOT_MY_INSTANCE; + + if (!ospf->oi_running) return CMD_SUCCESS; return show_ip_ospf_neighbor_common(vty, ospf, uj); @@ -3982,8 +3961,11 @@ DEFUN (show_ip_ospf_instance_neighbor_all, u_char uj = use_json(argc, argv); instance = strtoul(argv[idx_number]->arg, NULL, 10); - if ((ospf = ospf_lookup_instance(instance)) == NULL - || !ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (ospf == NULL) + return CMD_NOT_MY_INSTANCE; + + if (!ospf->oi_running) return CMD_SUCCESS; return show_ip_ospf_neighbor_all_common(vty, ospf, uj); @@ -4075,8 +4057,11 @@ DEFUN (show_ip_ospf_instance_neighbor_int, u_char uj = use_json(argc, argv); instance = strtoul(argv[idx_number]->arg, NULL, 10); - if ((ospf = ospf_lookup_instance(instance)) == NULL - || !ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (ospf == NULL) + return CMD_NOT_MY_INSTANCE; + + if (!ospf->oi_running) return CMD_SUCCESS; return show_ip_ospf_neighbor_int_common(vty, ospf, 1, argv, uj); @@ -4462,8 +4447,11 @@ DEFUN (show_ip_ospf_instance_neighbor_id, u_char uj = use_json(argc, argv); instance = strtoul(argv[idx_number]->arg, NULL, 10); - if ((ospf = ospf_lookup_instance(instance)) == NULL - || !ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (ospf == NULL) + return CMD_NOT_MY_INSTANCE; + + if (!ospf->oi_running) return CMD_SUCCESS; return show_ip_ospf_neighbor_id_common(vty, ospf, 1, argv, uj); @@ -4551,8 +4539,11 @@ DEFUN (show_ip_ospf_instance_neighbor_detail, u_char uj = use_json(argc, argv); instance = strtoul(argv[idx_number]->arg, NULL, 10); - if ((ospf = ospf_lookup_instance(instance)) == NULL - || !ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (ospf == NULL) + return CMD_NOT_MY_INSTANCE; + + if (!ospf->oi_running) return CMD_SUCCESS; return show_ip_ospf_neighbor_detail_common(vty, ospf, uj); @@ -4652,8 +4643,11 @@ DEFUN (show_ip_ospf_instance_neighbor_detail_all, u_char uj = use_json(argc, argv); instance = strtoul(argv[idx_number]->arg, NULL, 10); - if ((ospf = ospf_lookup_instance(instance)) == NULL - || !ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (ospf == NULL) + return CMD_NOT_MY_INSTANCE; + + if (!ospf->oi_running) return CMD_SUCCESS; return show_ip_ospf_neighbor_detail_all_common(vty, ospf, uj); @@ -4757,8 +4751,11 @@ DEFUN (show_ip_ospf_instance_neighbor_int_detail, u_char uj = use_json(argc, argv); instance = strtoul(argv[idx_number]->arg, NULL, 10); - if ((ospf = ospf_lookup_instance(instance)) == NULL - || !ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (ospf == NULL) + return CMD_NOT_MY_INSTANCE; + + if (!ospf->oi_running) return CMD_SUCCESS; return show_ip_ospf_neighbor_int_detail_common(vty, ospf, 1, argv, uj); @@ -5446,6 +5443,8 @@ DEFUN (show_ip_ospf_instance_database, if (argv_find(argv, argc, "(1-65535)", &idx)) { instance = strtoul(argv[idx]->arg, NULL, 10); ospf = ospf_lookup_instance(instance); + if (ospf == NULL) + return CMD_NOT_MY_INSTANCE; } else { ospf = ospf_lookup(); } @@ -5474,8 +5473,11 @@ DEFUN (show_ip_ospf_instance_database_max, instance = strtoul(argv[idx_number]->arg, NULL, 10); - if ((ospf = ospf_lookup_instance(instance)) == NULL - || !ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (ospf == NULL) + return CMD_NOT_MY_INSTANCE; + + if (!ospf->oi_running) return CMD_SUCCESS; return (show_ip_ospf_database_common(vty, ospf, 1, argc, argv)); @@ -5553,6 +5555,8 @@ DEFUN (show_ip_ospf_instance_database_type_adv_router, if (argv_find(argv, argc, "(1-65535)", &idx)) { instance = strtoul(argv[idx]->arg, NULL, 10); ospf = ospf_lookup_instance(instance); + if (ospf == NULL) + return CMD_NOT_MY_INSTANCE; } else ospf = ospf_lookup(); @@ -6922,7 +6926,7 @@ DEFUN (ip_ospf_area, ospf = ospf_lookup(); ospf->if_ospf_cli_count--; } - return CMD_SUCCESS; + return CMD_NOT_MY_INSTANCE; } ret = str2area_id(areaid, &area_id, &format); @@ -6995,8 +6999,9 @@ DEFUN (no_ip_ospf_area, if (argv_find(argv, argc, "(1-65535)", &idx)) instance = strtol(argv[idx]->arg, NULL, 10); - if ((ospf = ospf_lookup_instance(instance)) == NULL) - return CMD_SUCCESS; + ospf = ospf_lookup_instance(instance); + if (ospf == NULL) + return CMD_NOT_MY_INSTANCE; argv_find(argv, argc, "area", &idx); @@ -7038,7 +7043,7 @@ DEFUN (ospf_redistribute_source, "Route map reference\n" "Pointer to route-map entries\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_protocol = 1; int source; int type = -1; @@ -7088,7 +7093,7 @@ DEFUN (no_ospf_redistribute_source, "Route map reference\n" "Pointer to route-map entries\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_protocol = 2; int source; struct ospf_redist *red; @@ -7119,7 +7124,7 @@ DEFUN (ospf_redistribute_instance_source, "Route map reference\n" "Pointer to route-map entries\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ospf_table = 1; int idx_number = 2; int idx = 3; @@ -7187,7 +7192,7 @@ DEFUN (no_ospf_redistribute_instance_source, "Route map reference\n" "Pointer to route-map entries\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_ospf_table = 2; int idx_number = 3; u_int instance; @@ -7228,7 +7233,7 @@ DEFUN (ospf_distribute_list_out, OUT_STR FRR_REDIST_HELP_STR_OSPFD) { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_word = 1; int source; @@ -7251,7 +7256,7 @@ DEFUN (no_ospf_distribute_list_out, OUT_STR FRR_REDIST_HELP_STR_OSPFD) { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_word = 2; int source; @@ -7278,7 +7283,7 @@ DEFUN (ospf_default_information_originate, "Route map reference\n" "Pointer to route-map entries\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int default_originate = DEFAULT_ORIGINATE_ZEBRA; int type = -1; int metric = -1; @@ -7324,7 +7329,7 @@ DEFUN (no_ospf_default_information_originate, "Route map reference\n" "Pointer to route-map entries\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); struct prefix_ipv4 p; struct ospf_external *ext; struct ospf_redist *red; @@ -7355,7 +7360,7 @@ DEFUN (ospf_default_metric, "Set metric of redistributed routes\n" "Default metric\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_number = 1; int metric = -1; @@ -7374,7 +7379,7 @@ DEFUN (no_ospf_default_metric, "Set metric of redistributed routes\n" "Default metric\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); ospf->default_metric = -1; @@ -7388,7 +7393,7 @@ DEFUN (ospf_distance, "Administrative distance\n" "OSPF Administrative distance\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_number = 1; ospf->distance_all = atoi(argv[idx_number]->arg); @@ -7403,7 +7408,7 @@ DEFUN (no_ospf_distance, "Administrative distance\n" "OSPF Administrative distance\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); ospf->distance_all = 0; @@ -7423,7 +7428,7 @@ DEFUN (no_ospf_distance_ospf, "External routes\n" "Distance for external routes\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx = 0; if (!ospf) @@ -7451,7 +7456,7 @@ DEFUN (ospf_distance_ospf, "External routes\n" "Distance for external routes\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx = 0; if (argv_find(argv, argc, "intra-area", &idx)) @@ -7636,7 +7641,7 @@ DEFUN (ospf_max_metric_router_lsa_admin, "Advertise own Router-LSA with infinite distance (stub router)\n" "Administratively applied, for an indefinite period\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); struct listnode *ln; struct ospf_area *area; @@ -7662,7 +7667,7 @@ DEFUN (no_ospf_max_metric_router_lsa_admin, "Advertise own Router-LSA with infinite distance (stub router)\n" "Administratively applied, for an indefinite period\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); struct listnode *ln; struct ospf_area *area; @@ -7691,7 +7696,7 @@ DEFUN (ospf_max_metric_router_lsa_startup, "Automatically advertise stub Router-LSA on startup of OSPF\n" "Time (seconds) to advertise self as stub-router\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_number = 3; unsigned int seconds; @@ -7716,7 +7721,7 @@ DEFUN (no_ospf_max_metric_router_lsa_startup, "Automatically advertise stub Router-LSA on startup of OSPF\n" "Time (seconds) to advertise self as stub-router\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); struct listnode *ln; struct ospf_area *area; @@ -7747,7 +7752,7 @@ DEFUN (ospf_max_metric_router_lsa_shutdown, "Advertise stub-router prior to full shutdown of OSPF\n" "Time (seconds) to wait till full shutdown\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); int idx_number = 3; unsigned int seconds; @@ -7772,7 +7777,7 @@ DEFUN (no_ospf_max_metric_router_lsa_shutdown, "Advertise stub-router prior to full shutdown of OSPF\n" "Time (seconds) to wait till full shutdown\n") { - VTY_DECLVAR_CONTEXT(ospf, ospf); + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); ospf->stub_router_shutdown_time = OSPF_STUB_ROUTER_UNCONFIGURED; @@ -8034,8 +8039,11 @@ DEFUN (show_ip_ospf_instance_border_routers, u_short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if ((ospf = ospf_lookup_instance(instance)) == NULL - || !ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (ospf == NULL) + return CMD_NOT_MY_INSTANCE; + + if (!ospf->oi_running) return CMD_SUCCESS; return show_ip_ospf_border_routers_common(vty, ospf); @@ -8095,8 +8103,11 @@ DEFUN (show_ip_ospf_instance_route, u_short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if ((ospf = ospf_lookup_instance(instance)) == NULL - || !ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (ospf == NULL) + return CMD_NOT_MY_INSTANCE; + + if (!ospf->oi_running) return CMD_SUCCESS; return show_ip_ospf_route_common(vty, ospf); @@ -9141,10 +9152,10 @@ void ospf_vty_init(void) /* LSA timers commands */ install_element(OSPF_NODE, &ospf_timers_min_ls_interval_cmd); install_element(OSPF_NODE, &no_ospf_timers_min_ls_interval_cmd); - install_element(OSPF_NODE, &ospf_timers_min_ls_arrival_cmd); - install_element(OSPF_NODE, &no_ospf_timers_min_ls_arrival_cmd); - install_element(OSPF_NODE, &ospf_timers_lsa_cmd); - install_element(OSPF_NODE, &no_ospf_timers_lsa_cmd); + install_element(OSPF_NODE, &ospf_timers_lsa_min_arrival_cmd); + install_element(OSPF_NODE, &no_ospf_timers_lsa_min_arrival_cmd); + install_element(OSPF_NODE, &ospf_timers_lsa_arrival_cmd); + install_element(OSPF_NODE, &no_ospf_timers_lsa_arrival_cmd); /* refresh timer commands */ install_element(OSPF_NODE, &ospf_refresh_timer_cmd); diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index c6b0955dab..ec8f1ee852 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -51,6 +51,9 @@ #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_te.h" +DEFINE_MTYPE_STATIC(OSPFD, OSPF_EXTERNAL, "OSPF External route table") +DEFINE_MTYPE_STATIC(OSPFD, OSPF_REDISTRIBUTE, "OSPF Redistriute") + DEFINE_HOOK(ospf_if_update, (struct interface * ifp), (ifp)) DEFINE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp)) @@ -628,7 +631,8 @@ struct ospf_external *ospf_external_add(u_char type, u_short instance) om->external[type] = list_new(); ext_list = om->external[type]; - ext = (struct ospf_external *)calloc(1, sizeof(struct ospf_external)); + ext = (struct ospf_external *)XCALLOC(MTYPE_OSPF_EXTERNAL, + sizeof(struct ospf_external)); ext->instance = instance; EXTERNAL_INFO(ext) = route_table_init(); @@ -652,6 +656,7 @@ void ospf_external_del(u_char type, u_short instance) list_free(om->external[type]); om->external[type] = NULL; } + XFREE(MTYPE_OSPF_EXTERNAL, ext); } } @@ -687,7 +692,8 @@ struct ospf_redist *ospf_redist_add(struct ospf *ospf, u_char type, ospf->redist[type] = list_new(); red_list = ospf->redist[type]; - red = (struct ospf_redist *)calloc(1, sizeof(struct ospf_redist)); + red = (struct ospf_redist *)XCALLOC(MTYPE_OSPF_REDISTRIBUTE, + sizeof(struct ospf_redist)); red->instance = instance; red->dmetric.type = -1; red->dmetric.value = -1; @@ -709,6 +715,7 @@ void ospf_redist_del(struct ospf *ospf, u_char type, u_short instance) list_free(ospf->redist[type]); ospf->redist[type] = NULL; } + XFREE(MTYPE_OSPF_REDISTRIBUTE, red); } } diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index cee2244dd9..b3553238ef 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -590,6 +590,7 @@ static void ospf_finish_final(struct ospf *ospf) route_unlock_node(rn); } } + route_table_finish(ospf->networks); for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) { listnode_delete(ospf->areas, area); @@ -655,6 +656,8 @@ static void ospf_finish_final(struct ospf *ospf) } list_delete(ospf->areas); + list_delete(ospf->oi_write_q); + list_delete(ospf->oiflist); for (i = ZEBRA_ROUTE_SYSTEM; i <= ZEBRA_ROUTE_MAX; i++) { struct list *ext_list; @@ -752,6 +755,7 @@ static void ospf_area_free(struct ospf_area *area) LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa) ospf_discard_from_db(area->ospf, area->lsdb, lsa); + ospf_opaque_type10_lsa_term(area); ospf_lsdb_delete_all(area->lsdb); ospf_lsdb_free(area->lsdb); @@ -976,9 +980,13 @@ int ospf_network_unset(struct ospf *ospf, struct prefix_ipv4 *p, rn->info = NULL; route_unlock_node(rn); /* initial reference */ - /* Find interfaces that not configured already. */ + /* Find interfaces that are not configured already. */ for (ALL_LIST_ELEMENTS(ospf->oiflist, node, nnode, oi)) { - ospf_network_run_subnet(ospf, oi->connected, NULL, NULL); + + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + continue; + + ospf_network_run_subnet(ospf, oi->connected, NULL, NULL); } /* Update connected redistribute. */ diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 4142f1a3e9..b49bbdc17d 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -101,7 +101,7 @@ struct ospf_master { /* Various OSPF global configuration. */ u_char options; -#define OSPF_MASTER_SHUTDOWN (1 << 0) /* deferred-shutdown */ +#define OSPF_MASTER_SHUTDOWN (1 << 0) /* deferred-shutdown */ }; struct ospf_redist { diff --git a/pimd/Makefile.am b/pimd/Makefile.am index 0dd6c569dc..f440221d42 100644 --- a/pimd/Makefile.am +++ b/pimd/Makefile.am @@ -53,7 +53,8 @@ libpim_a_SOURCES = \ pim_ssmpingd.c pim_int.c pim_rp.c \ pim_static.c pim_br.c pim_register.c pim_routemap.c \ pim_msdp.c pim_msdp_socket.c pim_msdp_packet.c \ - pim_jp_agg.c pim_nht.c pim_ssm.c pim_bfd.c + pim_jp_agg.c pim_nht.c pim_ssm.c pim_bfd.c \ + pim_instance.c noinst_HEADERS = \ pim_memory.h \ @@ -66,7 +67,7 @@ noinst_HEADERS = \ pim_igmp_join.h pim_ssmpingd.h pim_int.h pim_rp.h \ pim_static.h pim_br.h pim_register.h \ pim_msdp.h pim_msdp_socket.h pim_msdp_packet.h pim_nht.h \ - pim_jp_agg.h pim_ssm.h pim_bfd.h + pim_jp_agg.h pim_ssm.h pim_bfd.h pim_instance.h pimd_SOURCES = \ pim_main.c $(libpim_a_SOURCES) diff --git a/pimd/WHY_SSM b/pimd/WHY_SSM deleted file mode 100644 index 2e8c966f16..0000000000 --- a/pimd/WHY_SSM +++ /dev/null @@ -1,32 +0,0 @@ -WHY SSM - -Benefis of PIM SSM over PIM SM ------------------------------- - -- SSM consumes minimum link bandwidth -- SSM simplifies multicast address management (specially important for - inter-domain multicast) - - SSM (S,G) channels easily provide unique per-application addressing - - SSM does not require MSDP between PIM domains -- SSM does not suffer instabilities from traffic-driven SPT switchover -- SSM is not suscetible to DoS attack from unwanted sources -- SSM does not use RP. Some RP issues: - - RP is possible point of failure - - RP demands redundancy management - - RP may require PIM dense mode support for RP election - - RP is possible performance bottleneck - - RP may demand lots of extra management -- SSM can be deployed in an existing PIM SM network (only the last hop - routers need to support IGMPv3) -- SSM is easier to deploy and maintain - -PIM-SSM drawbacks ------------------ - -- SSM requires IGMPv3 support on both receivers and last-hop routers -- SSM may be memory intensive when managing (S,G) states for - many-to-many multicast distribution -- SSM will keep (S,G) state as long as there are subscriptions from - receivers, even if the source is not actually sending traffic - ---EOF-- diff --git a/pimd/pim_assert.c b/pimd/pim_assert.c index f68c252a35..934fea5a9e 100644 --- a/pimd/pim_assert.c +++ b/pimd/pim_assert.c @@ -47,6 +47,7 @@ void pim_ifassert_winner_set(struct pim_ifchannel *ch, struct in_addr winner, struct pim_assert_metric winner_metric) { + struct pim_interface *pim_ifp = ch->interface->info; int winner_changed = (ch->ifassert_winner.s_addr != winner.s_addr); int metric_changed = !pim_assert_metric_match( &ch->ifassert_winner_metric, &winner_metric); @@ -81,7 +82,7 @@ void pim_ifassert_winner_set(struct pim_ifchannel *ch, ch->ifassert_creation = pim_time_monotonic_sec(); if (winner_changed || metric_changed) { - pim_upstream_update_join_desired(ch->upstream); + pim_upstream_update_join_desired(pim_ifp->pim, ch->upstream); pim_ifchannel_update_could_assert(ch); pim_ifchannel_update_assert_tracking_desired(ch); } @@ -146,7 +147,7 @@ static int dispatch_assert(struct interface *ifp, struct in_addr source_addr, memset(&sg, 0, sizeof(struct prefix_sg)); sg.src = source_addr; sg.grp = group_addr; - ch = pim_ifchannel_add(ifp, &sg, 0); + ch = pim_ifchannel_add(ifp, &sg, 0, 0); if (!ch) { zlog_warn( "%s: (S,G)=%s failure creating channel on interface %s", @@ -404,9 +405,9 @@ int pim_assert_build_msg(uint8_t *pim_msg, int buf_size, struct interface *ifp, } /* Metric preference */ - pim_write_uint32(pim_msg_curr, - rpt_bit_flag ? metric_preference | 0x80000000 - : metric_preference); + pim_write_uint32(pim_msg_curr, rpt_bit_flag + ? metric_preference | 0x80000000 + : metric_preference); pim_msg_curr += 4; /* Route metric */ diff --git a/pimd/pim_bfd.c b/pimd/pim_bfd.c index e4c50a18be..1dfb558f46 100644 --- a/pimd/pim_bfd.c +++ b/pimd/pim_bfd.c @@ -27,6 +27,7 @@ #include "vty.h" #include "zclient.h" +#include "pim_instance.h" #include "pim_cmd.h" #include "pim_vty.h" #include "pim_iface.h" diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 1c9fe40c29..d7e94d11dd 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -27,6 +27,7 @@ #include "plist.h" #include "hash.h" #include "nexthop.h" +#include "vrf.h" #include "pimd.h" #include "pim_mroute.h" @@ -70,6 +71,23 @@ static struct cmd_node interface_node = { static struct cmd_node debug_node = {DEBUG_NODE, "", 1}; +static struct vrf *pim_cmd_lookup_vrf(struct vty *vty, struct cmd_token *argv[], + const int argc, int *idx) +{ + struct vrf *vrf; + + if (argv_find(argv, argc, "NAME", idx)) + vrf = vrf_lookup_by_name(argv[*idx]->arg); + else + vrf = vrf_lookup_by_id(VRF_DEFAULT); + + if (!vrf) + vty_out(vty, "Specified VRF: %s does not exist\n", + argv[*idx]->arg); + + return vrf; +} + static void pim_if_membership_clear(struct interface *ifp) { struct pim_interface *pim_ifp; @@ -158,12 +176,45 @@ static void pim_if_membership_refresh(struct interface *ifp) pim_ifchannel_delete_on_noinfo(ifp); } -static void pim_show_assert(struct vty *vty) +static void pim_show_assert_helper(struct vty *vty, + struct pim_interface *pim_ifp, + struct pim_ifchannel *ch, + time_t now) +{ + char ch_src_str[INET_ADDRSTRLEN]; + char ch_grp_str[INET_ADDRSTRLEN]; + char winner_str[INET_ADDRSTRLEN]; + struct in_addr ifaddr; + char uptime[10]; + char timer[10]; + + ifaddr = pim_ifp->primary_address; + + pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str, + sizeof(ch_src_str)); + pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, + sizeof(ch_grp_str)); + pim_inet4_dump("<assrt_win?>", ch->ifassert_winner, winner_str, + sizeof(winner_str)); + + pim_time_uptime(uptime, sizeof(uptime), + now - ch->ifassert_creation); + pim_time_timer_to_mmss(timer, sizeof(timer), + ch->t_ifassert_timer); + + vty_out(vty, "%-9s %-15s %-15s %-15s %-6s %-15s %-8s %-5s\n", + ch->interface->name, inet_ntoa(ifaddr), ch_src_str, + ch_grp_str, + pim_ifchannel_ifassert_name(ch->ifassert_state), + winner_str, uptime, timer); +} + +static void pim_show_assert(struct pim_instance *pim, struct vty *vty) { struct pim_interface *pim_ifp; struct pim_ifchannel *ch; - struct listnode *ch_node; - struct in_addr ifaddr; + struct listnode *if_node; + struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); @@ -171,46 +222,49 @@ static void pim_show_assert(struct vty *vty) vty_out(vty, "Interface Address Source Group State Winner Uptime Timer\n"); - for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, ch_node, ch)) { - char ch_src_str[INET_ADDRSTRLEN]; - char ch_grp_str[INET_ADDRSTRLEN]; - char winner_str[INET_ADDRSTRLEN]; - char uptime[10]; - char timer[10]; - - pim_ifp = ch->interface->info; - + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), if_node, ifp)) { + pim_ifp = ifp->info; if (!pim_ifp) continue; - ifaddr = pim_ifp->primary_address; + RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) { + pim_show_assert_helper(vty, pim_ifp, ch, now); + } /* scan interface channels */ + } +} - pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str, - sizeof(ch_src_str)); - pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, - sizeof(ch_grp_str)); - pim_inet4_dump("<assrt_win?>", ch->ifassert_winner, winner_str, - sizeof(winner_str)); +static void pim_show_assert_internal_helper(struct vty *vty, + struct pim_interface *pim_ifp, + struct pim_ifchannel *ch) +{ + char ch_src_str[INET_ADDRSTRLEN]; + char ch_grp_str[INET_ADDRSTRLEN]; + struct in_addr ifaddr; - pim_time_uptime(uptime, sizeof(uptime), - now - ch->ifassert_creation); - pim_time_timer_to_mmss(timer, sizeof(timer), - ch->t_ifassert_timer); + ifaddr = pim_ifp->primary_address; - vty_out(vty, "%-9s %-15s %-15s %-15s %-6s %-15s %-8s %-5s\n", - ch->interface->name, inet_ntoa(ifaddr), ch_src_str, - ch_grp_str, - pim_ifchannel_ifassert_name(ch->ifassert_state), - winner_str, uptime, timer); - } /* scan interface channels */ + pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str, + sizeof(ch_src_str)); + pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, + sizeof(ch_grp_str)); + vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %-3s %-3s %-4s\n", + ch->interface->name, inet_ntoa(ifaddr), ch_src_str, + ch_grp_str, + PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags) ? "yes" : "no", + pim_macro_ch_could_assert_eval(ch) ? "yes" : "no", + PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags) + ? "yes" + : "no", + pim_macro_assert_tracking_desired_eval(ch) ? "yes" + : "no"); } -static void pim_show_assert_internal(struct vty *vty) +static void pim_show_assert_internal(struct pim_instance *pim, struct vty *vty) { struct pim_interface *pim_ifp; - struct listnode *ch_node; + struct listnode *if_node; struct pim_ifchannel *ch; - struct in_addr ifaddr; + struct interface *ifp; vty_out(vty, "CA: CouldAssert\n" @@ -220,126 +274,127 @@ static void pim_show_assert_internal(struct vty *vty) vty_out(vty, "Interface Address Source Group CA eCA ATD eATD\n"); - - for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, ch_node, ch)) { - pim_ifp = ch->interface->info; - + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), if_node, ifp)) { + pim_ifp = ifp->info; if (!pim_ifp) continue; - ifaddr = pim_ifp->primary_address; + RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) { + pim_show_assert_internal_helper(vty, pim_ifp, ch); + } /* scan interface channels */ + } +} + +static void pim_show_assert_metric_helper(struct vty *vty, + struct pim_interface *pim_ifp, + struct pim_ifchannel *ch) +{ + char ch_src_str[INET_ADDRSTRLEN]; + char ch_grp_str[INET_ADDRSTRLEN]; + char addr_str[INET_ADDRSTRLEN]; + struct pim_assert_metric am; + struct in_addr ifaddr; + + ifaddr = pim_ifp->primary_address; + + am = pim_macro_spt_assert_metric(&ch->upstream->rpf, + pim_ifp->primary_address); - char ch_src_str[INET_ADDRSTRLEN]; - char ch_grp_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str, + sizeof(ch_src_str)); + pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, + sizeof(ch_grp_str)); + pim_inet4_dump("<addr?>", am.ip_address, addr_str, + sizeof(addr_str)); - pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str, - sizeof(ch_src_str)); - pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, - sizeof(ch_grp_str)); - vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %-3s %-3s %-4s\n", - ch->interface->name, inet_ntoa(ifaddr), ch_src_str, - ch_grp_str, - PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags) ? "yes" : "no", - pim_macro_ch_could_assert_eval(ch) ? "yes" : "no", - PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags) - ? "yes" - : "no", - pim_macro_assert_tracking_desired_eval(ch) ? "yes" - : "no"); - } /* scan interface channels */ + vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %4u %6u %-15s\n", + ch->interface->name, inet_ntoa(ifaddr), ch_src_str, + ch_grp_str, am.rpt_bit_flag ? "yes" : "no", + am.metric_preference, am.route_metric, addr_str); } -static void pim_show_assert_metric(struct vty *vty) +static void pim_show_assert_metric(struct pim_instance *pim, struct vty *vty) { struct pim_interface *pim_ifp; - struct listnode *ch_node; + struct listnode *if_node; struct pim_ifchannel *ch; - struct in_addr ifaddr; + struct interface *ifp; vty_out(vty, "Interface Address Source Group RPT Pref Metric Address \n"); - for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, ch_node, ch)) { - pim_ifp = ch->interface->info; - + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), if_node, ifp)) { + pim_ifp = ifp->info; if (!pim_ifp) continue; - ifaddr = pim_ifp->primary_address; + RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) { + pim_show_assert_metric_helper(vty, pim_ifp, ch); + } /* scan interface channels */ + } +} + +static void pim_show_assert_winner_metric_helper(struct vty *vty, + struct pim_interface *pim_ifp, + struct pim_ifchannel *ch) +{ + char ch_src_str[INET_ADDRSTRLEN]; + char ch_grp_str[INET_ADDRSTRLEN]; + char addr_str[INET_ADDRSTRLEN]; + struct pim_assert_metric *am; + struct in_addr ifaddr; + char pref_str[5]; + char metr_str[7]; + + ifaddr = pim_ifp->primary_address; + + am = &ch->ifassert_winner_metric; - char ch_src_str[INET_ADDRSTRLEN]; - char ch_grp_str[INET_ADDRSTRLEN]; - char addr_str[INET_ADDRSTRLEN]; - struct pim_assert_metric am; + pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str, + sizeof(ch_src_str)); + pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, + sizeof(ch_grp_str)); + pim_inet4_dump("<addr?>", am->ip_address, addr_str, + sizeof(addr_str)); - am = pim_macro_spt_assert_metric(&ch->upstream->rpf, - pim_ifp->primary_address); + if (am->metric_preference == PIM_ASSERT_METRIC_PREFERENCE_MAX) + snprintf(pref_str, sizeof(pref_str), "INFI"); + else + snprintf(pref_str, sizeof(pref_str), "%4u", + am->metric_preference); - pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str, - sizeof(ch_src_str)); - pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, - sizeof(ch_grp_str)); - pim_inet4_dump("<addr?>", am.ip_address, addr_str, - sizeof(addr_str)); + if (am->route_metric == PIM_ASSERT_ROUTE_METRIC_MAX) + snprintf(metr_str, sizeof(metr_str), "INFI"); + else + snprintf(metr_str, sizeof(metr_str), "%6u", + am->route_metric); - vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %4u %6u %-15s\n", - ch->interface->name, inet_ntoa(ifaddr), ch_src_str, - ch_grp_str, am.rpt_bit_flag ? "yes" : "no", - am.metric_preference, am.route_metric, addr_str); - } /* scan interface channels */ + vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %-4s %-6s %-15s\n", + ch->interface->name, inet_ntoa(ifaddr), ch_src_str, + ch_grp_str, am->rpt_bit_flag ? "yes" : "no", pref_str, + metr_str, addr_str); } -static void pim_show_assert_winner_metric(struct vty *vty) +static void pim_show_assert_winner_metric(struct pim_instance *pim, + struct vty *vty) { + struct listnode *if_node; struct pim_interface *pim_ifp; - struct listnode *ch_node; struct pim_ifchannel *ch; - struct in_addr ifaddr; + struct interface *ifp; vty_out(vty, "Interface Address Source Group RPT Pref Metric Address \n"); - for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, ch_node, ch)) { - pim_ifp = ch->interface->info; - + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), if_node, ifp)) { + pim_ifp = ifp->info; if (!pim_ifp) continue; - ifaddr = pim_ifp->primary_address; - - char ch_src_str[INET_ADDRSTRLEN]; - char ch_grp_str[INET_ADDRSTRLEN]; - char addr_str[INET_ADDRSTRLEN]; - struct pim_assert_metric *am; - char pref_str[5]; - char metr_str[7]; - - am = &ch->ifassert_winner_metric; - - pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str, - sizeof(ch_src_str)); - pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, - sizeof(ch_grp_str)); - pim_inet4_dump("<addr?>", am->ip_address, addr_str, - sizeof(addr_str)); - - if (am->metric_preference == PIM_ASSERT_METRIC_PREFERENCE_MAX) - snprintf(pref_str, sizeof(pref_str), "INFI"); - else - snprintf(pref_str, sizeof(pref_str), "%4u", - am->metric_preference); - - if (am->route_metric == PIM_ASSERT_ROUTE_METRIC_MAX) - snprintf(metr_str, sizeof(metr_str), "INFI"); - else - snprintf(metr_str, sizeof(metr_str), "%6u", - am->route_metric); - - vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %-4s %-6s %-15s\n", - ch->interface->name, inet_ntoa(ifaddr), ch_src_str, - ch_grp_str, am->rpt_bit_flag ? "yes" : "no", pref_str, - metr_str, addr_str); - } /* scan interface channels */ + RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) { + pim_show_assert_winner_metric_helper(vty, pim_ifp, ch); + } /* scan interface channels */ + } } static void json_object_pim_ifp_add(struct json_object *json, @@ -373,54 +428,63 @@ static void json_object_pim_ifp_add(struct json_object *json, json_object_boolean_true_add(json, "lanDelayEnabled"); } -static void pim_show_membership(struct vty *vty, u_char uj) +static void pim_show_membership_helper(struct vty *vty, + struct pim_interface *pim_ifp, + struct pim_ifchannel *ch, + struct json_object *json) { + char ch_src_str[INET_ADDRSTRLEN]; + char ch_grp_str[INET_ADDRSTRLEN]; + json_object *json_iface = NULL; + json_object *json_row = NULL; + + pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str, + sizeof(ch_src_str)); + pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, + sizeof(ch_grp_str)); + + json_object_object_get_ex(json, ch->interface->name, + &json_iface); + if (!json_iface) { + json_iface = json_object_new_object(); + json_object_pim_ifp_add(json_iface, ch->interface); + json_object_object_add(json, ch->interface->name, + json_iface); + } + + json_row = json_object_new_object(); + json_object_string_add(json_row, "source", ch_src_str); + json_object_string_add(json_row, "group", ch_grp_str); + json_object_string_add( + json_row, "localMembership", + ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO + ? "NOINFO" + : "INCLUDE"); + json_object_object_add(json_iface, ch_grp_str, json_row); + +} +static void pim_show_membership(struct pim_instance *pim, struct vty *vty, + u_char uj) +{ + struct listnode *if_node; struct pim_interface *pim_ifp; - struct listnode *ch_node; struct pim_ifchannel *ch; + struct interface *ifp; enum json_type type; json_object *json = NULL; - json_object *json_iface = NULL; - json_object *json_row = NULL; json_object *json_tmp = NULL; json = json_object_new_object(); - for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, ch_node, ch)) { - - pim_ifp = ch->interface->info; - + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), if_node, ifp)) { + pim_ifp = ifp->info; if (!pim_ifp) continue; - char ch_src_str[INET_ADDRSTRLEN]; - char ch_grp_str[INET_ADDRSTRLEN]; - - pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str, - sizeof(ch_src_str)); - pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, - sizeof(ch_grp_str)); - - json_object_object_get_ex(json, ch->interface->name, - &json_iface); - - if (!json_iface) { - json_iface = json_object_new_object(); - json_object_pim_ifp_add(json_iface, ch->interface); - json_object_object_add(json, ch->interface->name, - json_iface); - } - - json_row = json_object_new_object(); - json_object_string_add(json_row, "source", ch_src_str); - json_object_string_add(json_row, "group", ch_grp_str); - json_object_string_add( - json_row, "localMembership", - ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO - ? "NOINFO" - : "INCLUDE"); - json_object_object_add(json_iface, ch_grp_str, json_row); - } /* scan interface channels */ + RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) { + pim_show_membership_helper(vty, pim_ifp, ch, json); + } /* scan interface channels */ + } if (uj) { vty_out(vty, "%s\n", json_object_to_json_string_ext( @@ -517,7 +581,8 @@ static void pim_print_ifp_flags(struct vty *vty, struct interface *ifp, vty_out(vty, "\n"); } -static void igmp_show_interfaces(struct vty *vty, u_char uj) +static void igmp_show_interfaces(struct pim_instance *pim, struct vty *vty, + u_char uj) { struct listnode *node; struct interface *ifp; @@ -533,7 +598,7 @@ static void igmp_show_interfaces(struct vty *vty, u_char uj) vty_out(vty, "Interface State Address V Querier Query Timer Uptime\n"); - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) { struct pim_interface *pim_ifp; struct listnode *sock_node; struct igmp_sock *igmp; @@ -594,7 +659,8 @@ static void igmp_show_interfaces(struct vty *vty, u_char uj) } } -static void igmp_show_interfaces_single(struct vty *vty, const char *ifname, +static void igmp_show_interfaces_single(struct pim_instance *pim, + struct vty *vty, const char *ifname, u_char uj) { struct igmp_sock *igmp; @@ -607,7 +673,7 @@ static void igmp_show_interfaces_single(struct vty *vty, const char *ifname, char other_hhmmss[10]; int found_ifname = 0; int sqi; - int mloop; + int mloop = 0; long gmi_msec; /* Group Membership Interval */ long lmqt_msec; long ohpi_msec; @@ -623,7 +689,7 @@ static void igmp_show_interfaces_single(struct vty *vty, const char *ifname, now = pim_time_monotonic_sec(); - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) @@ -670,7 +736,11 @@ static void igmp_show_interfaces_single(struct vty *vty, const char *ifname, qri_msec = pim_ifp->igmp_query_max_response_time_dsec * 100; - mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd); + if (pim_ifp->pim_sock_fd >= 0) + mloop = pim_socket_mcastloop_get( + pim_ifp->pim_sock_fd); + else + mloop = 0; if (uj) { json_row = json_object_new_object(); @@ -793,7 +863,7 @@ static void igmp_show_interfaces_single(struct vty *vty, const char *ifname, } } -static void igmp_show_interface_join(struct vty *vty) +static void igmp_show_interface_join(struct pim_instance *pim, struct vty *vty) { struct listnode *node; struct interface *ifp; @@ -804,7 +874,7 @@ static void igmp_show_interface_join(struct vty *vty) vty_out(vty, "Interface Address Source Group Socket Uptime \n"); - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) { struct pim_interface *pim_ifp; struct listnode *join_node; struct igmp_join *ij; @@ -844,7 +914,8 @@ static void igmp_show_interface_join(struct vty *vty) } /* for (iflist) */ } -static void pim_show_interfaces_single(struct vty *vty, const char *ifname, +static void pim_show_interfaces_single(struct pim_instance *pim, + struct vty *vty, const char *ifname, u_char uj) { struct in_addr ifaddr; @@ -866,7 +937,7 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, char src_str[INET_ADDRSTRLEN]; char stat_uptime[10]; char uptime[10]; - int mloop; + int mloop = 0; int found_ifname = 0; int print_header; json_object *json = NULL; @@ -884,15 +955,12 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, if (uj) json = json_object_new_object(); - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) continue; - if (pim_ifp->pim_sock_fd < 0) - continue; - if (strcmp(ifname, "detail") && strcmp(ifname, ifp->name)) continue; @@ -908,7 +976,10 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, pim_ifp->pim_hello_period); pim_time_uptime(stat_uptime, sizeof(stat_uptime), now - pim_ifp->pim_ifstat_start); - mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd); + if (pim_ifp->pim_sock_fd >= 0) + mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd); + else + mloop = 0; if (uj) { char pbuf[PREFIX2STR_BUFFER]; @@ -989,7 +1060,7 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, pim_ifp->pim_dr_election_changes); // FHR - for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode, + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) { if (ifp == up->rpf.source_nexthop.interface) { if (up->flags @@ -1163,11 +1234,10 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, // FHR print_header = 1; - for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode, + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) { - if (strcmp(ifp->name, - up->rpf.source_nexthop - .interface->name) + if (strcmp(ifp->name, up->rpf.source_nexthop + .interface->name) == 0) { if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR) { @@ -1263,7 +1333,8 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, } } -static void pim_show_interfaces(struct vty *vty, u_char uj) +static void pim_show_interfaces(struct pim_instance *pim, struct vty *vty, + u_char uj) { struct interface *ifp; struct listnode *node; @@ -1279,20 +1350,17 @@ static void pim_show_interfaces(struct vty *vty, u_char uj) json = json_object_new_object(); - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) continue; - if (pim_ifp->pim_sock_fd < 0) - continue; - pim_nbrs = pim_ifp->pim_neighbor_list->count; - pim_ifchannels = pim_ifp->pim_ifchannel_list->count; + pim_ifchannels = pim_if_ifchannel_count(pim_ifp); fhr = 0; - for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode, up)) + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) if (ifp == up->rpf.source_nexthop.interface) if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR) fhr++; @@ -1359,7 +1427,8 @@ static void pim_show_interfaces(struct vty *vty, u_char uj) json_object_free(json); } -static void pim_show_interface_traffic(struct vty *vty, u_char uj) +static void pim_show_interface_traffic(struct pim_instance *pim, + struct vty *vty, u_char uj) { struct interface *ifp = NULL; struct pim_interface *pim_ifp = NULL; @@ -1381,7 +1450,7 @@ static void pim_show_interface_traffic(struct vty *vty, u_char uj) "---------------------------------------------------------------------------------------------------------------\n"); } - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) @@ -1438,7 +1507,8 @@ static void pim_show_interface_traffic(struct vty *vty, u_char uj) } } -static void pim_show_interface_traffic_single(struct vty *vty, +static void pim_show_interface_traffic_single(struct pim_instance *pim, + struct vty *vty, const char *ifname, u_char uj) { struct interface *ifp = NULL; @@ -1462,7 +1532,7 @@ static void pim_show_interface_traffic_single(struct vty *vty, "---------------------------------------------------------------------------------------------------------------\n"); } - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) { if (strcmp(ifname, ifp->name)) continue; @@ -1527,17 +1597,92 @@ static void pim_show_interface_traffic_single(struct vty *vty, } } -static void pim_show_join(struct vty *vty, u_char uj) +static void pim_show_join_helper(struct vty *vty, + struct pim_interface *pim_ifp, + struct pim_ifchannel *ch, + json_object *json, + time_t now, + u_char uj) { - struct pim_interface *pim_ifp; + char ch_src_str[INET_ADDRSTRLEN]; + char ch_grp_str[INET_ADDRSTRLEN]; + json_object *json_iface = NULL; + json_object *json_row = NULL; + json_object *json_grp = NULL; struct in_addr ifaddr; - struct listnode *ch_node; + char uptime[10]; + char expire[10]; + char prune[10]; + + ifaddr = pim_ifp->primary_address; + + pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str, + sizeof(ch_src_str)); + pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, + sizeof(ch_grp_str)); + + pim_time_uptime_begin(uptime, sizeof(uptime), now, + ch->ifjoin_creation); + pim_time_timer_to_mmss(expire, sizeof(expire), + ch->t_ifjoin_expiry_timer); + pim_time_timer_to_mmss(prune, sizeof(prune), + ch->t_ifjoin_prune_pending_timer); + + if (uj) { + json_object_object_get_ex(json, ch->interface->name, + &json_iface); + + if (!json_iface) { + json_iface = json_object_new_object(); + json_object_pim_ifp_add(json_iface, + ch->interface); + json_object_object_add( + json, ch->interface->name, json_iface); + } + + json_row = json_object_new_object(); + json_object_string_add(json_row, "source", ch_src_str); + json_object_string_add(json_row, "group", ch_grp_str); + json_object_string_add(json_row, "upTime", uptime); + json_object_string_add(json_row, "expire", expire); + json_object_string_add(json_row, "prune", prune); + json_object_string_add( + json_row, "channelJoinName", + pim_ifchannel_ifjoin_name(ch->ifjoin_state, + ch->flags)); + if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)) + json_object_int_add(json_row, "SGRpt", 1); + + json_object_object_get_ex(json_iface, ch_grp_str, + &json_grp); + if (!json_grp) { + json_grp = json_object_new_object(); + json_object_object_add(json_grp, ch_src_str, + json_row); + json_object_object_add(json_iface, ch_grp_str, + json_grp); + } else + json_object_object_add(json_grp, ch_src_str, + json_row); + } else { + vty_out(vty, + "%-9s %-15s %-15s %-15s %-6s %8s %-6s %5s\n", + ch->interface->name, inet_ntoa(ifaddr), + ch_src_str, ch_grp_str, + pim_ifchannel_ifjoin_name(ch->ifjoin_state, + ch->flags), + uptime, expire, prune); + } +} + +static void pim_show_join(struct pim_instance *pim, struct vty *vty, u_char uj) +{ + struct listnode *if_node; + struct pim_interface *pim_ifp; struct pim_ifchannel *ch; + struct interface *ifp; time_t now; json_object *json = NULL; - json_object *json_iface = NULL; - json_object *json_row = NULL; - json_object *json_grp = NULL; now = pim_time_monotonic_sec(); @@ -1547,89 +1692,26 @@ static void pim_show_join(struct vty *vty, u_char uj) vty_out(vty, "Interface Address Source Group State Uptime Expire Prune\n"); - for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, ch_node, ch)) { - - pim_ifp = ch->interface->info; - + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), if_node, ifp)) { + pim_ifp = ifp->info; if (!pim_ifp) continue; - ifaddr = pim_ifp->primary_address; - - char ch_src_str[INET_ADDRSTRLEN]; - char ch_grp_str[INET_ADDRSTRLEN]; - char uptime[10]; - char expire[10]; - char prune[10]; - - pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str, - sizeof(ch_src_str)); - pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, - sizeof(ch_grp_str)); - - pim_time_uptime_begin(uptime, sizeof(uptime), now, - ch->ifjoin_creation); - pim_time_timer_to_mmss(expire, sizeof(expire), - ch->t_ifjoin_expiry_timer); - pim_time_timer_to_mmss(prune, sizeof(prune), - ch->t_ifjoin_prune_pending_timer); - - if (uj) { - json_object_object_get_ex(json, ch->interface->name, - &json_iface); - - if (!json_iface) { - json_iface = json_object_new_object(); - json_object_pim_ifp_add(json_iface, - ch->interface); - json_object_object_add( - json, ch->interface->name, json_iface); - } - - json_row = json_object_new_object(); - json_object_string_add(json_row, "source", ch_src_str); - json_object_string_add(json_row, "group", ch_grp_str); - json_object_string_add(json_row, "upTime", uptime); - json_object_string_add(json_row, "expire", expire); - json_object_string_add(json_row, "prune", prune); - json_object_string_add( - json_row, "channelJoinName", - pim_ifchannel_ifjoin_name(ch->ifjoin_state, - ch->flags)); - if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)) - json_object_int_add(json_row, "SGRpt", 1); - - json_object_object_get_ex(json_iface, ch_grp_str, - &json_grp); - if (!json_grp) { - json_grp = json_object_new_object(); - json_object_object_add(json_grp, ch_src_str, - json_row); - json_object_object_add(json_iface, ch_grp_str, - json_grp); - } else - json_object_object_add(json_grp, ch_src_str, - json_row); - } else { - vty_out(vty, - "%-9s %-15s %-15s %-15s %-6s %8s %-6s %5s\n", - ch->interface->name, inet_ntoa(ifaddr), - ch_src_str, ch_grp_str, - pim_ifchannel_ifjoin_name(ch->ifjoin_state, - ch->flags), - uptime, expire, prune); - } - } /* scan interface channels */ + RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) { + pim_show_join_helper(vty, pim_ifp, + ch, json, now, uj); + } /* scan interface channels */ + } if (uj) { vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); + json, JSON_C_TO_STRING_PRETTY)); json_object_free(json); } } -static void pim_show_neighbors_single(struct vty *vty, const char *neighbor, - u_char uj) +static void pim_show_neighbors_single(struct pim_instance *pim, struct vty *vty, + const char *neighbor, u_char uj) { struct listnode *node; struct listnode *neighnode; @@ -1657,7 +1739,7 @@ static void pim_show_neighbors_single(struct vty *vty, const char *neighbor, if (uj) json = json_object_new_object(); - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) @@ -1838,8 +1920,9 @@ static void pim_show_neighbors_single(struct vty *vty, const char *neighbor, } } -static void pim_show_state(struct vty *vty, const char *src_or_group, - const char *group, u_char uj) +static void pim_show_state(struct pim_instance *pim, struct vty *vty, + const char *src_or_group, const char *group, + u_char uj) { struct channel_oil *c_oil; struct listnode *node; @@ -1861,7 +1944,7 @@ static void pim_show_state(struct vty *vty, const char *src_or_group, "\nInstalled Source Group IIF OIL\n"); } - for (ALL_LIST_ELEMENTS_RO(pim_channel_oil_list, node, c_oil)) { + for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) { char grp_str[INET_ADDRSTRLEN]; char src_str[INET_ADDRSTRLEN]; char in_ifname[INTERFACE_NAMSIZ + 1]; @@ -1874,7 +1957,7 @@ static void pim_show_state(struct vty *vty, const char *src_or_group, sizeof(grp_str)); pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, src_str, sizeof(src_str)); - ifp_in = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent); + ifp_in = pim_if_find_by_vif_index(pim, c_oil->oil.mfcc_parent); if (ifp_in) strcpy(in_ifname, ifp_in->name); @@ -1956,7 +2039,7 @@ static void pim_show_state(struct vty *vty, const char *src_or_group, if (ttl < 1) continue; - ifp_out = pim_if_find_by_vif_index(oif_vif_index); + ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index); pim_time_uptime( oif_uptime, sizeof(oif_uptime), now - c_oil->oif_creation[oif_vif_index]); @@ -2039,7 +2122,8 @@ static void pim_show_state(struct vty *vty, const char *src_or_group, } } -static void pim_show_neighbors(struct vty *vty, u_char uj) +static void pim_show_neighbors(struct pim_instance *pim, struct vty *vty, + u_char uj) { struct listnode *node; struct listnode *neighnode; @@ -2063,7 +2147,7 @@ static void pim_show_neighbors(struct vty *vty, u_char uj) "Interface Neighbor Uptime Holdtime DR Pri\n"); } - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) @@ -2121,7 +2205,8 @@ static void pim_show_neighbors(struct vty *vty, u_char uj) } } -static void pim_show_neighbors_secondary(struct vty *vty) +static void pim_show_neighbors_secondary(struct pim_instance *pim, + struct vty *vty) { struct listnode *node; struct interface *ifp; @@ -2129,7 +2214,7 @@ static void pim_show_neighbors_secondary(struct vty *vty) vty_out(vty, "Interface Address Neighbor Secondary \n"); - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct listnode *neighnode; @@ -2235,7 +2320,8 @@ static const char *pim_reg_state2brief_str(enum pim_reg_state reg_state, return state_str; } -static void pim_show_upstream(struct vty *vty, u_char uj) +static void pim_show_upstream(struct pim_instance *pim, struct vty *vty, + u_char uj) { struct listnode *upnode; struct pim_upstream *up; @@ -2252,7 +2338,7 @@ static void pim_show_upstream(struct vty *vty, u_char uj) vty_out(vty, "Iif Source Group State Uptime JoinTimer RSTimer KATimer RefCnt\n"); - for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode, up)) { + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) { char src_str[INET_ADDRSTRLEN]; char grp_str[INET_ADDRSTRLEN]; char uptime[10]; @@ -2352,81 +2438,100 @@ static void pim_show_upstream(struct vty *vty, u_char uj) } } -static void pim_show_join_desired(struct vty *vty, u_char uj) +static void pim_show_join_desired_helper(struct pim_instance *pim, + struct vty *vty, + struct pim_interface *pim_ifp, + struct pim_ifchannel *ch, + json_object *json, + u_char uj) { - struct listnode *chnode; - struct pim_interface *pim_ifp; - struct pim_ifchannel *ch; + struct pim_upstream *up = ch->upstream; + json_object *json_group = NULL; char src_str[INET_ADDRSTRLEN]; char grp_str[INET_ADDRSTRLEN]; - json_object *json = NULL; - json_object *json_group = NULL; json_object *json_row = NULL; - if (uj) - json = json_object_new_object(); - else - vty_out(vty, - "Interface Source Group LostAssert Joins PimInclude JoinDesired EvalJD\n"); + pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str)); + pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str)); - /* scan per-interface (S,G) state */ - for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, chnode, ch)) { - /* scan all interfaces */ - pim_ifp = ch->interface->info; - if (!pim_ifp) - continue; + if (uj) { + json_object_object_get_ex(json, grp_str, &json_group); - struct pim_upstream *up = ch->upstream; + if (!json_group) { + json_group = json_object_new_object(); + json_object_object_add(json, grp_str, + json_group); + } - pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str)); - pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str)); + json_row = json_object_new_object(); + json_object_pim_upstream_add(json_row, up); + json_object_string_add(json_row, "interface", + ch->interface->name); + json_object_string_add(json_row, "source", src_str); + json_object_string_add(json_row, "group", grp_str); - if (uj) { - json_object_object_get_ex(json, grp_str, &json_group); + if (pim_macro_ch_lost_assert(ch)) + json_object_boolean_true_add(json_row, + "lostAssert"); - if (!json_group) { - json_group = json_object_new_object(); - json_object_object_add(json, grp_str, - json_group); - } + if (pim_macro_chisin_joins(ch)) + json_object_boolean_true_add(json_row, "joins"); - json_row = json_object_new_object(); - json_object_pim_upstream_add(json_row, up); - json_object_string_add(json_row, "interface", - ch->interface->name); - json_object_string_add(json_row, "source", src_str); - json_object_string_add(json_row, "group", grp_str); + if (pim_macro_chisin_pim_include(ch)) + json_object_boolean_true_add(json_row, + "pimInclude"); - if (pim_macro_ch_lost_assert(ch)) - json_object_boolean_true_add(json_row, - "lostAssert"); + if (pim_upstream_evaluate_join_desired(pim, up)) + json_object_boolean_true_add( + json_row, "evaluateJoinDesired"); - if (pim_macro_chisin_joins(ch)) - json_object_boolean_true_add(json_row, "joins"); + json_object_object_add(json_group, src_str, json_row); - if (pim_macro_chisin_pim_include(ch)) - json_object_boolean_true_add(json_row, - "pimInclude"); + } else { + vty_out(vty, + "%-9s %-15s %-15s %-10s %-5s %-10s %-11s %-6s\n", + ch->interface->name, src_str, grp_str, + pim_macro_ch_lost_assert(ch) ? "yes" : "no", + pim_macro_chisin_joins(ch) ? "yes" : "no", + pim_macro_chisin_pim_include(ch) ? "yes" : "no", + PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED( + up->flags) + ? "yes" + : "no", + pim_upstream_evaluate_join_desired(pim, up) + ? "yes" + : "no"); + } +} - if (pim_upstream_evaluate_join_desired(up)) - json_object_boolean_true_add( - json_row, "evaluateJoinDesired"); +static void pim_show_join_desired(struct pim_instance *pim, struct vty *vty, + u_char uj) +{ + struct listnode *if_node; + struct pim_interface *pim_ifp; + struct pim_ifchannel *ch; + struct interface *ifp; - json_object_object_add(json_group, src_str, json_row); + json_object *json = NULL; - } else { - vty_out(vty, - "%-9s %-15s %-15s %-10s %-5s %-10s %-11s %-6s\n", - ch->interface->name, src_str, grp_str, - pim_macro_ch_lost_assert(ch) ? "yes" : "no", - pim_macro_chisin_joins(ch) ? "yes" : "no", - pim_macro_chisin_pim_include(ch) ? "yes" : "no", - PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED( - up->flags) - ? "yes" - : "no", - pim_upstream_evaluate_join_desired(up) ? "yes" - : "no"); + if (uj) + json = json_object_new_object(); + else + vty_out(vty, + "Interface Source Group LostAssert Joins PimInclude JoinDesired EvalJD\n"); + + /* scan per-interface (S,G) state */ + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), if_node, ifp)) { + pim_ifp = ifp->info; + if (!pim_ifp) + continue; + + + RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) { + /* scan all interfaces */ + pim_show_join_desired_helper(pim, vty, + pim_ifp, ch, + json, uj); } } @@ -2437,7 +2542,8 @@ static void pim_show_join_desired(struct vty *vty, u_char uj) } } -static void pim_show_upstream_rpf(struct vty *vty, u_char uj) +static void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty, + u_char uj) { struct listnode *upnode; struct pim_upstream *up; @@ -2451,7 +2557,7 @@ static void pim_show_upstream_rpf(struct vty *vty, u_char uj) vty_out(vty, "Source Group RpfIface RibNextHop RpfAddress \n"); - for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode, up)) { + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) { char src_str[INET_ADDRSTRLEN]; char grp_str[INET_ADDRSTRLEN]; char rpf_nexthop_str[PREFIX_STRLEN]; @@ -2547,7 +2653,8 @@ static void show_rpf_refresh_stats(struct vty *vty, time_t now, } } -static void show_scan_oil_stats(struct vty *vty, time_t now) +static void show_scan_oil_stats(struct pim_instance *pim, struct vty *vty, + time_t now) { char uptime_scan_oil[10]; char uptime_mroute_add[10]; @@ -2556,20 +2663,20 @@ static void show_scan_oil_stats(struct vty *vty, time_t now) pim_time_uptime_begin(uptime_scan_oil, sizeof(uptime_scan_oil), now, qpim_scan_oil_last); pim_time_uptime_begin(uptime_mroute_add, sizeof(uptime_mroute_add), now, - qpim_mroute_add_last); + pim->mroute_add_last); pim_time_uptime_begin(uptime_mroute_del, sizeof(uptime_mroute_del), now, - qpim_mroute_del_last); + pim->mroute_del_last); vty_out(vty, "Scan OIL - Last: %s Events: %lld\n" "MFC Add - Last: %s Events: %lld\n" "MFC Del - Last: %s Events: %lld\n", uptime_scan_oil, (long long)qpim_scan_oil_events, - uptime_mroute_add, (long long)qpim_mroute_add_events, - uptime_mroute_del, (long long)qpim_mroute_del_events); + uptime_mroute_add, (long long)pim->mroute_add_events, + uptime_mroute_del, (long long)pim->mroute_del_events); } -static void pim_show_rpf(struct vty *vty, u_char uj) +static void pim_show_rpf(struct pim_instance *pim, struct vty *vty, u_char uj) { struct listnode *up_node; struct pim_upstream *up; @@ -2588,7 +2695,7 @@ static void pim_show_rpf(struct vty *vty, u_char uj) "Source Group RpfIface RpfAddress RibNextHop Metric Pref\n"); } - for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, up_node, up)) { + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, up_node, up)) { char src_str[INET_ADDRSTRLEN]; char grp_str[INET_ADDRSTRLEN]; char rpf_addr_str[PREFIX_STRLEN]; @@ -2648,10 +2755,17 @@ static void pim_show_rpf(struct vty *vty, u_char uj) } } +struct pnc_cache_walk_data { + struct vty *vty; + struct pim_instance *pim; +}; + static int pim_print_pnc_cache_walkcb(struct hash_backet *backet, void *arg) { struct pim_nexthop_cache *pnc = backet->data; - struct vty *vty = arg; + struct pnc_cache_walk_data *cwd = arg; + struct vty *vty = cwd->vty; + struct pim_instance *pim = cwd->pim; struct nexthop *nh_node = NULL; ifindex_t first_ifindex; struct interface *ifp = NULL; @@ -2661,7 +2775,7 @@ static int pim_print_pnc_cache_walkcb(struct hash_backet *backet, void *arg) for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) { first_ifindex = nh_node->ifindex; - ifp = if_lookup_by_index(first_ifindex, VRF_DEFAULT); + ifp = if_lookup_by_index(first_ifindex, pim->vrf_id); vty_out(vty, "%-15s ", inet_ntoa(pnc->rpf.rpf_addr.u.prefix4)); vty_out(vty, "%-14s ", ifp ? ifp->name : "NULL"); @@ -2671,23 +2785,22 @@ static int pim_print_pnc_cache_walkcb(struct hash_backet *backet, void *arg) return CMD_SUCCESS; } -static void pim_show_nexthop(struct vty *vty) +static void pim_show_nexthop(struct pim_instance *pim, struct vty *vty) { + struct pnc_cache_walk_data cwd; - if (pimg && !pimg->rpf_hash) { - vty_out(vty, "no nexthop cache \n"); - return; - } - - vty_out(vty, "Number of registered addresses: %lu \n", - pimg->rpf_hash->count); + cwd.vty = vty; + cwd.pim = pim; + vty_out(vty, "Number of registered addresses: %lu\n", + pim->rpf_hash->count); vty_out(vty, "Address Interface Nexthop\n"); vty_out(vty, "-------------------------------------------\n"); - hash_walk(pimg->rpf_hash, pim_print_pnc_cache_walkcb, vty); + hash_walk(pim->rpf_hash, pim_print_pnc_cache_walkcb, &cwd); } -static void igmp_show_groups(struct vty *vty, u_char uj) +static void igmp_show_groups(struct pim_instance *pim, struct vty *vty, + u_char uj) { struct listnode *ifnode; struct interface *ifp; @@ -2705,7 +2818,7 @@ static void igmp_show_groups(struct vty *vty, u_char uj) "Interface Address Group Mode Timer Srcs V Uptime \n"); /* scan interfaces */ - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode, ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode, ifp)) { struct pim_interface *pim_ifp = ifp->info; struct listnode *sock_node; struct igmp_sock *igmp; @@ -2808,7 +2921,8 @@ static void igmp_show_groups(struct vty *vty, u_char uj) } } -static void igmp_show_group_retransmission(struct vty *vty) +static void igmp_show_group_retransmission(struct pim_instance *pim, + struct vty *vty) { struct listnode *ifnode; struct interface *ifp; @@ -2817,7 +2931,7 @@ static void igmp_show_group_retransmission(struct vty *vty) "Interface Address Group RetTimer Counter RetSrcs\n"); /* scan interfaces */ - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode, ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode, ifp)) { struct pim_interface *pim_ifp = ifp->info; struct listnode *sock_node; struct igmp_sock *igmp; @@ -2873,7 +2987,7 @@ static void igmp_show_group_retransmission(struct vty *vty) } /* scan interfaces */ } -static void igmp_show_sources(struct vty *vty) +static void igmp_show_sources(struct pim_instance *pim, struct vty *vty) { struct listnode *ifnode; struct interface *ifp; @@ -2885,7 +2999,7 @@ static void igmp_show_sources(struct vty *vty) "Interface Address Group Source Timer Fwd Uptime \n"); /* scan interfaces */ - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode, ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode, ifp)) { struct pim_interface *pim_ifp = ifp->info; struct listnode *sock_node; struct igmp_sock *igmp; @@ -2949,7 +3063,8 @@ static void igmp_show_sources(struct vty *vty) } /* scan interfaces */ } -static void igmp_show_source_retransmission(struct vty *vty) +static void igmp_show_source_retransmission(struct pim_instance *pim, + struct vty *vty) { struct listnode *ifnode; struct interface *ifp; @@ -2958,7 +3073,7 @@ static void igmp_show_source_retransmission(struct vty *vty) "Interface Address Group Source Counter\n"); /* scan interfaces */ - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode, ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode, ifp)) { struct pim_interface *pim_ifp = ifp->info; struct listnode *sock_node; struct igmp_sock *igmp; @@ -3008,30 +3123,30 @@ static void igmp_show_source_retransmission(struct vty *vty) } /* scan interfaces */ } -static void clear_igmp_interfaces() +static void clear_igmp_interfaces(struct pim_instance *pim) { struct listnode *ifnode; struct listnode *ifnextnode; struct interface *ifp; - for (ALL_LIST_ELEMENTS(vrf_iflist(VRF_DEFAULT), ifnode, ifnextnode, + for (ALL_LIST_ELEMENTS(vrf_iflist(pim->vrf_id), ifnode, ifnextnode, ifp)) { pim_if_addr_del_all_igmp(ifp); } - for (ALL_LIST_ELEMENTS(vrf_iflist(VRF_DEFAULT), ifnode, ifnextnode, + for (ALL_LIST_ELEMENTS(vrf_iflist(pim->vrf_id), ifnode, ifnextnode, ifp)) { pim_if_addr_add_all(ifp); } } -static void clear_pim_interfaces() +static void clear_pim_interfaces(struct pim_instance *pim) { struct listnode *ifnode; struct listnode *ifnextnode; struct interface *ifp; - for (ALL_LIST_ELEMENTS(vrf_iflist(VRF_DEFAULT), ifnode, ifnextnode, + for (ALL_LIST_ELEMENTS(vrf_iflist(pim->vrf_id), ifnode, ifnextnode, ifp)) { if (ifp->info) { pim_neighbor_delete_all(ifp, "interface cleared"); @@ -3039,43 +3154,57 @@ static void clear_pim_interfaces() } } -static void clear_interfaces() +static void clear_interfaces(struct pim_instance *pim) { - clear_igmp_interfaces(); - clear_pim_interfaces(); + clear_igmp_interfaces(pim); + clear_pim_interfaces(pim); } DEFUN (clear_ip_interfaces, clear_ip_interfaces_cmd, - "clear ip interfaces", + "clear ip interfaces [vrf NAME]", CLEAR_STR IP_STR - "Reset interfaces\n") + "Reset interfaces\n" + VRF_CMD_HELP_STR) { - clear_interfaces(); + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + clear_interfaces(vrf->info); return CMD_SUCCESS; } DEFUN (clear_ip_igmp_interfaces, clear_ip_igmp_interfaces_cmd, - "clear ip igmp interfaces", + "clear ip igmp [vrf NAME] interfaces", CLEAR_STR IP_STR CLEAR_IP_IGMP_STR + VRF_CMD_HELP_STR "Reset IGMP interfaces\n") { - clear_igmp_interfaces(); + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + clear_igmp_interfaces(vrf->info); return CMD_SUCCESS; } -static void mroute_add_all() +static void mroute_add_all(struct pim_instance *pim) { struct listnode *node; struct channel_oil *c_oil; - for (ALL_LIST_ELEMENTS_RO(pim_channel_oil_list, node, c_oil)) { + for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) { if (pim_mroute_add(c_oil, __PRETTY_FUNCTION__)) { /* just log warning */ char source_str[INET_ADDRSTRLEN]; @@ -3091,12 +3220,12 @@ static void mroute_add_all() } } -static void mroute_del_all() +static void mroute_del_all(struct pim_instance *pim) { struct listnode *node; struct channel_oil *c_oil; - for (ALL_LIST_ELEMENTS_RO(pim_channel_oil_list, node, c_oil)) { + for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) { if (pim_mroute_del(c_oil, __PRETTY_FUNCTION__)) { /* just log warning */ char source_str[INET_ADDRSTRLEN]; @@ -3114,45 +3243,65 @@ static void mroute_del_all() DEFUN (clear_ip_mroute, clear_ip_mroute_cmd, - "clear ip mroute", + "clear ip mroute [vrf NAME]", CLEAR_STR IP_STR - "Reset multicast routes\n") + "Reset multicast routes\n" + VRF_CMD_HELP_STR) { - mroute_del_all(); - mroute_add_all(); + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + mroute_del_all(vrf->info); + mroute_add_all(vrf->info); return CMD_SUCCESS; } DEFUN (clear_ip_pim_interfaces, clear_ip_pim_interfaces_cmd, - "clear ip pim interfaces", + "clear ip pim [vrf NAME] interfaces", CLEAR_STR IP_STR CLEAR_IP_PIM_STR + VRF_CMD_HELP_STR "Reset PIM interfaces\n") { - clear_pim_interfaces(); + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + clear_pim_interfaces(vrf->info); return CMD_SUCCESS; } DEFUN (clear_ip_pim_interface_traffic, clear_ip_pim_interface_traffic_cmd, - "clear ip pim interface traffic", + "clear ip pim [vrf NAME] interface traffic", "Reset functions\n" "IP information\n" "PIM clear commands\n" + VRF_CMD_HELP_STR "Reset PIM interfaces\n" "Reset Protocol Packet counters\n") { + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); struct listnode *ifnode = NULL; struct listnode *ifnextnode = NULL; struct interface *ifp = NULL; struct pim_interface *pim_ifp = NULL; - for (ALL_LIST_ELEMENTS(vrf_iflist(VRF_DEFAULT), ifnode, ifnextnode, + if (!vrf) + return CMD_WARNING; + + for (ALL_LIST_ELEMENTS(vrf_iflist(vrf->vrf_id), ifnode, ifnextnode, ifp)) { pim_ifp = ifp->info; @@ -3178,373 +3327,893 @@ DEFUN (clear_ip_pim_interface_traffic, DEFUN (clear_ip_pim_oil, clear_ip_pim_oil_cmd, - "clear ip pim oil", + "clear ip pim [vrf NAME] oil", CLEAR_STR IP_STR CLEAR_IP_PIM_STR + VRF_CMD_HELP_STR "Rescan PIM OIL (output interface list)\n") { - pim_scan_oil(); + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + pim_scan_oil(vrf->info); return CMD_SUCCESS; } DEFUN (show_ip_igmp_interface, show_ip_igmp_interface_cmd, - "show ip igmp interface [detail|WORD] [json]", + "show ip igmp [vrf NAME] interface [detail|WORD] [json]", SHOW_STR IP_STR IGMP_STR + VRF_CMD_HELP_STR "IGMP interface information\n" "Detailed output\n" "interface name\n" - "JavaScript Object Notation\n") + JSON_STR) { + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); u_char uj = use_json(argc, argv); - int idx = 0; + + if (!vrf) + return CMD_WARNING; if (argv_find(argv, argc, "detail", &idx) || argv_find(argv, argc, "WORD", &idx)) - igmp_show_interfaces_single(vty, argv[idx]->arg, uj); + igmp_show_interfaces_single(vrf->info, vty, argv[idx]->arg, uj); else - igmp_show_interfaces(vty, uj); + igmp_show_interfaces(vrf->info, vty, uj); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_igmp_interface_vrf_all, + show_ip_igmp_interface_vrf_all_cmd, + "show ip igmp vrf all interface [detail|WORD] [json]", + SHOW_STR + IP_STR + IGMP_STR + VRF_CMD_HELP_STR + "IGMP interface information\n" + "Detailed output\n" + "interface name\n" + JSON_STR) +{ + int idx = 2; + u_char uj = use_json(argc, argv); + struct vrf *vrf; + bool first = true; + + if (uj) + vty_out(vty, "{ "); + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + if (uj) { + if (!first) + vty_out(vty, ", "); + vty_out(vty, " \"%s\": ", vrf->name); + first = false; + } else + vty_out(vty, "VRF: %s\n", vrf->name); + if (argv_find(argv, argc, "detail", &idx) + || argv_find(argv, argc, "WORD", &idx)) + igmp_show_interfaces_single(vrf->info, vty, + argv[idx]->arg, uj); + else + igmp_show_interfaces(vrf->info, vty, uj); + } + if (uj) + vty_out(vty, "}\n"); return CMD_SUCCESS; } DEFUN (show_ip_igmp_join, show_ip_igmp_join_cmd, - "show ip igmp join", + "show ip igmp [vrf NAME] join", SHOW_STR IP_STR IGMP_STR + VRF_CMD_HELP_STR "IGMP static join information\n") { - igmp_show_interface_join(vty); + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + igmp_show_interface_join(vrf->info, vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_igmp_join_vrf_all, + show_ip_igmp_join_vrf_all_cmd, + "show ip igmp vrf all join", + SHOW_STR + IP_STR + IGMP_STR + VRF_CMD_HELP_STR + "IGMP static join information\n") +{ + u_char uj = use_json(argc, argv); + struct vrf *vrf; + bool first = true; + + if (uj) + vty_out(vty, "{ "); + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + if (uj) { + if (!first) + vty_out(vty, ", "); + vty_out(vty, " \"%s\": ", vrf->name); + first = false; + } else + vty_out(vty, "VRF: %s\n", vrf->name); + igmp_show_interface_join(vrf->info, vty); + } + if (uj) + vty_out(vty, "}\n"); return CMD_SUCCESS; } DEFUN (show_ip_igmp_groups, show_ip_igmp_groups_cmd, - "show ip igmp groups [json]", + "show ip igmp [vrf NAME] groups [json]", + SHOW_STR + IP_STR + IGMP_STR + VRF_CMD_HELP_STR + IGMP_GROUP_STR + JSON_STR) +{ + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + u_char uj = use_json(argc, argv); + + if (!vrf) + return CMD_WARNING; + + igmp_show_groups(vrf->info, vty, uj); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_igmp_groups_vrf_all, + show_ip_igmp_groups_vrf_all_cmd, + "show ip igmp vrf all groups [json]", SHOW_STR IP_STR IGMP_STR + VRF_CMD_HELP_STR IGMP_GROUP_STR - "JavaScript Object Notation\n") + JSON_STR) { u_char uj = use_json(argc, argv); - igmp_show_groups(vty, uj); + struct vrf *vrf; + bool first = true; + + if (uj) + vty_out(vty, "{ "); + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + if (uj) { + if (!first) + vty_out(vty, ", "); + vty_out(vty, " \"%s\": ", vrf->name); + first = false; + } else + vty_out(vty, "VRF: %s\n", vrf->name); + igmp_show_groups(vrf->info, vty, uj); + } + if (uj) + vty_out(vty, "}\n"); return CMD_SUCCESS; } DEFUN (show_ip_igmp_groups_retransmissions, show_ip_igmp_groups_retransmissions_cmd, - "show ip igmp groups retransmissions", + "show ip igmp [vrf NAME] groups retransmissions", SHOW_STR IP_STR IGMP_STR + VRF_CMD_HELP_STR IGMP_GROUP_STR "IGMP group retransmissions\n") { - igmp_show_group_retransmission(vty); + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + igmp_show_group_retransmission(vrf->info, vty); return CMD_SUCCESS; } DEFUN (show_ip_igmp_sources, show_ip_igmp_sources_cmd, - "show ip igmp sources", + "show ip igmp [vrf NAME] sources", SHOW_STR IP_STR IGMP_STR + VRF_CMD_HELP_STR IGMP_SOURCE_STR) { - igmp_show_sources(vty); + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + igmp_show_sources(vrf->info, vty); return CMD_SUCCESS; } DEFUN (show_ip_igmp_sources_retransmissions, show_ip_igmp_sources_retransmissions_cmd, - "show ip igmp sources retransmissions", + "show ip igmp [vrf NAME] sources retransmissions", SHOW_STR IP_STR IGMP_STR + VRF_CMD_HELP_STR IGMP_SOURCE_STR "IGMP source retransmissions\n") { - igmp_show_source_retransmission(vty); + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + igmp_show_source_retransmission(vrf->info, vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_assert, show_ip_pim_assert_cmd, - "show ip pim assert", + "show ip pim [vrf NAME] assert", SHOW_STR IP_STR PIM_STR + VRF_CMD_HELP_STR "PIM interface assert\n") { - pim_show_assert(vty); + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + pim_show_assert(vrf->info, vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_assert_internal, show_ip_pim_assert_internal_cmd, - "show ip pim assert-internal", + "show ip pim [vrf NAME] assert-internal", SHOW_STR IP_STR PIM_STR + VRF_CMD_HELP_STR "PIM interface internal assert state\n") { - pim_show_assert_internal(vty); + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + pim_show_assert_internal(vrf->info, vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_assert_metric, show_ip_pim_assert_metric_cmd, - "show ip pim assert-metric", + "show ip pim [vrf NAME] assert-metric", SHOW_STR IP_STR PIM_STR + VRF_CMD_HELP_STR "PIM interface assert metric\n") { - pim_show_assert_metric(vty); + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + pim_show_assert_metric(vrf->info, vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_assert_winner_metric, show_ip_pim_assert_winner_metric_cmd, - "show ip pim assert-winner-metric", + "show ip pim [vrf NAME] assert-winner-metric", SHOW_STR IP_STR PIM_STR + VRF_CMD_HELP_STR "PIM interface assert winner metric\n") { - pim_show_assert_winner_metric(vty); + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + pim_show_assert_winner_metric(vrf->info, vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_interface, show_ip_pim_interface_cmd, - "show ip pim interface [detail|WORD] [json]", + "show ip pim [vrf NAME] interface [detail|WORD] [json]", SHOW_STR IP_STR PIM_STR + VRF_CMD_HELP_STR "PIM interface information\n" "Detailed output\n" "interface name\n" - "JavaScript Object Notation\n") + JSON_STR) { + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); u_char uj = use_json(argc, argv); - int idx = 0; + + if (!vrf) + return CMD_WARNING; if (argv_find(argv, argc, "WORD", &idx) || argv_find(argv, argc, "detail", &idx)) - pim_show_interfaces_single(vty, argv[idx]->arg, uj); - + pim_show_interfaces_single(vrf->info, vty, argv[idx]->arg, uj); else - pim_show_interfaces(vty, uj); + pim_show_interfaces(vrf->info, vty, uj); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_interface_vrf_all, + show_ip_pim_interface_vrf_all_cmd, + "show ip pim vrf all interface [detail|WORD] [json]", + SHOW_STR + IP_STR + PIM_STR + VRF_CMD_HELP_STR + "PIM interface information\n" + "Detailed output\n" + "interface name\n" + JSON_STR) +{ + int idx = 6; + u_char uj = use_json(argc, argv); + struct vrf *vrf; + bool first = true; + + if (uj) + vty_out(vty, "{ "); + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + if (uj) { + if (!first) + vty_out(vty, ", "); + vty_out(vty, " \"%s\": ", vrf->name); + first = false; + } else + vty_out(vty, "VRF: %s\n", vrf->name); + if (argv_find(argv, argc, "WORD", &idx) + || argv_find(argv, argc, "detail", &idx)) + pim_show_interfaces_single(vrf->info, vty, + argv[idx]->arg, uj); + else + pim_show_interfaces(vrf->info, vty, uj); + } + if (uj) + vty_out(vty, "}\n"); return CMD_SUCCESS; } DEFUN (show_ip_pim_join, show_ip_pim_join_cmd, - "show ip pim join [json]", + "show ip pim [vrf NAME] join [json]", SHOW_STR IP_STR PIM_STR + VRF_CMD_HELP_STR "PIM interface join information\n" JSON_STR) { + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); u_char uj = use_json(argc, argv); - pim_show_join(vty, uj); + + if (!vrf) + return CMD_WARNING; + + pim_show_join(vrf->info, vty, uj); return CMD_SUCCESS; } +DEFUN (show_ip_pim_join_vrf_all, + show_ip_pim_join_vrf_all_cmd, + "show ip pim vrf all join [json]", + SHOW_STR + IP_STR + PIM_STR + VRF_CMD_HELP_STR + "PIM interface join information\n" + JSON_STR) +{ + u_char uj = use_json(argc, argv); + struct vrf *vrf; + bool first = true; + + if (uj) + vty_out(vty, "{ "); + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + if (uj) { + if (!first) + vty_out(vty, ", "); + vty_out(vty, " \"%s\": ", vrf->name); + first = false; + } else + vty_out(vty, "VRF: %s\n", vrf->name); + pim_show_join(vrf->info, vty, uj); + } + if (uj) + vty_out(vty, "}\n"); + + return CMD_WARNING; +} + DEFUN (show_ip_pim_local_membership, show_ip_pim_local_membership_cmd, - "show ip pim local-membership [json]", + "show ip pim [vrf NAME] local-membership [json]", SHOW_STR IP_STR PIM_STR + VRF_CMD_HELP_STR "PIM interface local-membership\n" JSON_STR) { + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); u_char uj = use_json(argc, argv); - pim_show_membership(vty, uj); + + if (!vrf) + return CMD_WARNING; + + pim_show_membership(vrf->info, vty, uj); return CMD_SUCCESS; } DEFUN (show_ip_pim_neighbor, show_ip_pim_neighbor_cmd, - "show ip pim neighbor [detail|WORD] [json]", + "show ip pim [vrf NAME] neighbor [detail|WORD] [json]", SHOW_STR IP_STR PIM_STR + VRF_CMD_HELP_STR "PIM neighbor information\n" "Detailed output\n" "Name of interface or neighbor\n" - "JavaScript Object Notation\n") + JSON_STR) { + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); u_char uj = use_json(argc, argv); - int idx = 0; + + if (!vrf) + return CMD_WARNING; if (argv_find(argv, argc, "detail", &idx) || argv_find(argv, argc, "WORD", &idx)) - pim_show_neighbors_single(vty, argv[idx]->arg, uj); + pim_show_neighbors_single(vrf->info, vty, argv[idx]->arg, uj); else - pim_show_neighbors(vty, uj); + pim_show_neighbors(vrf->info, vty, uj); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_neighbor_vrf_all, + show_ip_pim_neighbor_vrf_all_cmd, + "show ip pim vrf all neighbor [detail|WORD] [json]", + SHOW_STR + IP_STR + PIM_STR + VRF_CMD_HELP_STR + "PIM neighbor information\n" + "Detailed output\n" + "Name of interface or neighbor\n" + JSON_STR) +{ + int idx = 2; + u_char uj = use_json(argc, argv); + struct vrf *vrf; + bool first = true; + + if (uj) + vty_out(vty, "{ "); + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + if (uj) { + if (!first) + vty_out(vty, ", "); + vty_out(vty, " \"%s\": ", vrf->name); + first = false; + } else + vty_out(vty, "VRF: %s\n", vrf->name); + if (argv_find(argv, argc, "detail", &idx) + || argv_find(argv, argc, "WORD", &idx)) + pim_show_neighbors_single(vrf->info, vty, + argv[idx]->arg, uj); + else + pim_show_neighbors(vrf->info, vty, uj); + } + if (uj) + vty_out(vty, "}\n"); return CMD_SUCCESS; } DEFUN (show_ip_pim_secondary, show_ip_pim_secondary_cmd, - "show ip pim secondary", + "show ip pim [vrf NAME] secondary", SHOW_STR IP_STR PIM_STR + VRF_CMD_HELP_STR "PIM neighbor addresses\n") { - pim_show_neighbors_secondary(vty); + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + pim_show_neighbors_secondary(vrf->info, vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_state, show_ip_pim_state_cmd, - "show ip pim state [A.B.C.D [A.B.C.D]] [json]", + "show ip pim [vrf NAME] state [A.B.C.D [A.B.C.D]] [json]", SHOW_STR IP_STR PIM_STR + VRF_CMD_HELP_STR "PIM state information\n" "Unicast or Multicast address\n" "Multicast address\n" - "JavaScript Object Notation\n") + JSON_STR) { const char *src_or_group = NULL; const char *group = NULL; + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); u_char uj = use_json(argc, argv); + + if (!vrf) + return CMD_WARNING; + if (uj) argc--; - if (argc == 6) { - src_or_group = argv[4]->arg; - group = argv[5]->arg; - } else if (argc == 5) - src_or_group = argv[4]->arg; + if (argv_find(argv, argc, "A.B.C.D", &idx)) { + src_or_group = argv[idx]->arg; + if (idx + 1 < argc) + group = argv[idx + 1]->arg; + } - pim_show_state(vty, src_or_group, group, uj); + pim_show_state(vrf->info, vty, src_or_group, group, uj); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_state_vrf_all, + show_ip_pim_state_vrf_all_cmd, + "show ip pim vrf all state [A.B.C.D [A.B.C.D]] [json]", + SHOW_STR + IP_STR + PIM_STR + VRF_CMD_HELP_STR + "PIM state information\n" + "Unicast or Multicast address\n" + "Multicast address\n" + JSON_STR) +{ + const char *src_or_group = NULL; + const char *group = NULL; + int idx = 2; + u_char uj = use_json(argc, argv); + struct vrf *vrf; + bool first = true; + + if (uj) { + vty_out(vty, "{ "); + argc--; + } + + if (argv_find(argv, argc, "A.B.C.D", &idx)) { + src_or_group = argv[idx]->arg; + if (idx + 1 < argc) + group = argv[idx + 1]->arg; + } + + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + if (uj) { + if (!first) + vty_out(vty, ", "); + vty_out(vty, " \"%s\": ", vrf->name); + first = false; + } else + vty_out(vty, "VRF: %s\n", vrf->name); + pim_show_state(vrf->info, vty, src_or_group, group, uj); + } + if (uj) + vty_out(vty, "}\n"); return CMD_SUCCESS; } DEFUN (show_ip_pim_upstream, show_ip_pim_upstream_cmd, - "show ip pim upstream [json]", + "show ip pim [vrf NAME] upstream [json]", + SHOW_STR + IP_STR + PIM_STR + VRF_CMD_HELP_STR + "PIM upstream information\n" + JSON_STR) +{ + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + u_char uj = use_json(argc, argv); + + if (!vrf) + return CMD_WARNING; + + pim_show_upstream(vrf->info, vty, uj); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_upstream_vrf_all, + show_ip_pim_upstream_vrf_all_cmd, + "show ip pim vrf all upstream [json]", SHOW_STR IP_STR PIM_STR + VRF_CMD_HELP_STR "PIM upstream information\n" - "JavaScript Object Notation\n") + JSON_STR) { u_char uj = use_json(argc, argv); - pim_show_upstream(vty, uj); + struct vrf *vrf; + bool first = true; + + if (uj) + vty_out(vty, "{ "); + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + if (uj) { + if (!first) + vty_out(vty, ", "); + vty_out(vty, " \"%s\": ", vrf->name); + first = false; + } else + vty_out(vty, "VRF: %s\n", vrf->name); + pim_show_upstream(vrf->info, vty, uj); + } return CMD_SUCCESS; } DEFUN (show_ip_pim_upstream_join_desired, show_ip_pim_upstream_join_desired_cmd, - "show ip pim upstream-join-desired [json]", + "show ip pim [vrf NAME] upstream-join-desired [json]", SHOW_STR IP_STR PIM_STR + VRF_CMD_HELP_STR "PIM upstream join-desired\n" - "JavaScript Object Notation\n") + JSON_STR) { + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); u_char uj = use_json(argc, argv); - pim_show_join_desired(vty, uj); + + if (!vrf) + return CMD_WARNING; + + pim_show_join_desired(vrf->info, vty, uj); return CMD_SUCCESS; } DEFUN (show_ip_pim_upstream_rpf, show_ip_pim_upstream_rpf_cmd, - "show ip pim upstream-rpf [json]", + "show ip pim [vrf NAME] upstream-rpf [json]", SHOW_STR IP_STR PIM_STR + VRF_CMD_HELP_STR "PIM upstream source rpf\n" - "JavaScript Object Notation\n") + JSON_STR) { + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); u_char uj = use_json(argc, argv); - pim_show_upstream_rpf(vty, uj); + + if (!vrf) + return CMD_WARNING; + + pim_show_upstream_rpf(vrf->info, vty, uj); return CMD_SUCCESS; } DEFUN (show_ip_pim_rp, show_ip_pim_rp_cmd, - "show ip pim rp-info [json]", + "show ip pim [vrf NAME] rp-info [json]", SHOW_STR IP_STR PIM_STR + VRF_CMD_HELP_STR "PIM RP information\n" - "JavaScript Object Notation\n") + JSON_STR) { + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); u_char uj = use_json(argc, argv); - pim_rp_show_information(vty, uj); + + if (!vrf) + return CMD_WARNING; + + pim_rp_show_information(vrf->info, vty, uj); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_rp_vrf_all, + show_ip_pim_rp_vrf_all_cmd, + "show ip pim vrf all rp-info [json]", + SHOW_STR + IP_STR + PIM_STR + VRF_CMD_HELP_STR + "PIM RP information\n" + JSON_STR) +{ + u_char uj = use_json(argc, argv); + struct vrf *vrf; + bool first = true; + + if (uj) + vty_out(vty, "{ "); + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + if (uj) { + if (!first) + vty_out(vty, ", "); + vty_out(vty, " \"%s\": ", vrf->name); + first = false; + } else + vty_out(vty, "VRF: %s\n", vrf->name); + pim_rp_show_information(vrf->info, vty, uj); + } + if (uj) + vty_out(vty, "}\n"); return CMD_SUCCESS; } DEFUN (show_ip_pim_rpf, show_ip_pim_rpf_cmd, - "show ip pim rpf [json]", + "show ip pim [vrf NAME] rpf [json]", + SHOW_STR + IP_STR + PIM_STR + VRF_CMD_HELP_STR + "PIM cached source rpf information\n" + JSON_STR) +{ + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + u_char uj = use_json(argc, argv); + + if (!vrf) + return CMD_WARNING; + + pim_show_rpf(vrf->info, vty, uj); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_pim_rpf_vrf_all, + show_ip_pim_rpf_vrf_all_cmd, + "show ip pim vrf all rpf [json]", SHOW_STR IP_STR PIM_STR + VRF_CMD_HELP_STR "PIM cached source rpf information\n" - "JavaScript Object Notation\n") + JSON_STR) { u_char uj = use_json(argc, argv); - pim_show_rpf(vty, uj); + struct vrf *vrf; + bool first = true; + + if (uj) + vty_out(vty, "{ "); + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + if (uj) { + if (!first) + vty_out(vty, ", "); + vty_out(vty, " \"%s\": ", vrf->name); + first = false; + } else + vty_out(vty, "VRF: %s\n", vrf->name); + pim_show_rpf(vrf->info, vty, uj); + } + if (uj) + vty_out(vty, "}\n"); return CMD_SUCCESS; } DEFUN (show_ip_pim_nexthop, show_ip_pim_nexthop_cmd, - "show ip pim nexthop", + "show ip pim [vrf NAME] nexthop", SHOW_STR IP_STR PIM_STR + VRF_CMD_HELP_STR "PIM cached nexthop rpf information\n") { - pim_show_nexthop(vty); + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + pim_show_nexthop(vrf->info, vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_nexthop_lookup, show_ip_pim_nexthop_lookup_cmd, - "show ip pim nexthop-lookup A.B.C.D A.B.C.D", + "show ip pim [vrf NAME] nexthop-lookup A.B.C.D A.B.C.D", SHOW_STR IP_STR PIM_STR + VRF_CMD_HELP_STR "PIM cached nexthop rpf lookup\n" "Source/RP address\n" "Multicast Group address\n") @@ -3559,8 +4228,14 @@ DEFUN (show_ip_pim_nexthop_lookup, struct pim_nexthop nexthop; char nexthop_addr_str[PREFIX_STRLEN]; char grp_str[PREFIX_STRLEN]; + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; - addr_str = argv[4]->arg; + argv_find(argv, argc, "A.B.C.D", &idx); + addr_str = argv[idx]->arg; result = inet_pton(AF_INET, addr_str, &src_addr); if (result <= 0) { vty_out(vty, "Bad unicast address %s: errno=%d: %s\n", addr_str, @@ -3574,7 +4249,7 @@ DEFUN (show_ip_pim_nexthop_lookup, return CMD_WARNING; } - addr_str1 = argv[5]->arg; + addr_str1 = argv[idx + 1]->arg; result = inet_pton(AF_INET, addr_str1, &grp_addr); if (result <= 0) { vty_out(vty, "Bad unicast address %s: errno=%d: %s\n", addr_str, @@ -3588,7 +4263,8 @@ DEFUN (show_ip_pim_nexthop_lookup, return CMD_WARNING; } - if (!pim_rp_set_upstream_addr(&vif_source, src_addr, grp_addr)) + if (!pim_rp_set_upstream_addr(vrf->info, &vif_source, src_addr, + grp_addr)) return CMD_SUCCESS; memset(&pnc, 0, sizeof(struct pim_nexthop_cache)); @@ -3600,11 +4276,12 @@ DEFUN (show_ip_pim_nexthop_lookup, grp.u.prefix4 = grp_addr; memset(&nexthop, 0, sizeof(nexthop)); - if ((pim_find_or_track_nexthop(&nht_p, NULL, NULL, &pnc)) == 1) { - // Compute PIM RPF using Cached nexthop - pim_ecmp_nexthop_search(&pnc, &nexthop, &nht_p, &grp, 0); - } else - pim_ecmp_nexthop_lookup(&nexthop, vif_source, &nht_p, &grp, 0); + if (pim_find_or_track_nexthop(vrf->info, &nht_p, NULL, NULL, &pnc)) + pim_ecmp_nexthop_search(vrf->info, &pnc, &nexthop, &nht_p, &grp, + 0); + else + pim_ecmp_nexthop_lookup(vrf->info, &nexthop, vif_source, &nht_p, + &grp, 0); pim_addr_dump("<grp?>", &grp, grp_str, sizeof(grp_str)); pim_addr_dump("<nexthop?>", &nexthop.mrib_nexthop_addr, @@ -3617,27 +4294,33 @@ DEFUN (show_ip_pim_nexthop_lookup, DEFUN (show_ip_pim_interface_traffic, show_ip_pim_interface_traffic_cmd, - "show ip pim interface traffic [WORD] [json]", + "show ip pim [vrf NAME] interface traffic [WORD] [json]", SHOW_STR IP_STR PIM_STR + VRF_CMD_HELP_STR "PIM interface information\n" "Protocol Packet counters\n" "Interface name\n" - "JavaScript Object Notation\n") + JSON_STR) { + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); u_char uj = use_json(argc, argv); - int idx = 0; + + if (!vrf) + return CMD_WARNING; if (argv_find(argv, argc, "WORD", &idx)) - pim_show_interface_traffic_single(vty, argv[idx]->arg, uj); + pim_show_interface_traffic_single(vrf->info, vty, + argv[idx]->arg, uj); else - pim_show_interface_traffic(vty, uj); + pim_show_interface_traffic(vrf->info, vty, uj); return CMD_SUCCESS; } -static void show_multicast_interfaces(struct vty *vty) +static void show_multicast_interfaces(struct pim_instance *pim, struct vty *vty) { struct listnode *node; struct interface *ifp; @@ -3645,9 +4328,9 @@ static void show_multicast_interfaces(struct vty *vty) vty_out(vty, "\n"); vty_out(vty, - "Interface Address ifi Vif PktsIn PktsOut BytesIn BytesOut\n"); + "Interface Address ifi Vif PktsIn PktsOut BytesIn BytesOut\n"); - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct sioc_vif_req vreq; @@ -3660,9 +4343,9 @@ static void show_multicast_interfaces(struct vty *vty) memset(&vreq, 0, sizeof(vreq)); vreq.vifi = pim_ifp->mroute_vif_index; - if (ioctl(qpim_mroute_socket_fd, SIOCGETVIFCNT, &vreq)) { + if (ioctl(pim->mroute_socket, SIOCGETVIFCNT, &vreq)) { zlog_warn( - "ioctl(SIOCGETVIFCNT=%lu) failure for interface %s vif_index=%d: errno=%d: %s\n", + "ioctl(SIOCGETVIFCNT=%lu) failure for interface %s vif_index=%d: errno=%d: %s", (unsigned long)SIOCGETVIFCNT, ifp->name, pim_ifp->mroute_vif_index, errno, safe_strerror(errno)); @@ -3670,7 +4353,7 @@ static void show_multicast_interfaces(struct vty *vty) ifaddr = pim_ifp->primary_address; - vty_out(vty, "%-9s %-15s %3d %3d %7lu %7lu %10lu %10lu\n", + vty_out(vty, "%-12s %-15s %3d %3d %7lu %7lu %10lu %10lu\n", ifp->name, inet_ntoa(ifaddr), ifp->ifindex, pim_ifp->mroute_vif_index, (unsigned long)vreq.icount, (unsigned long)vreq.ocount, (unsigned long)vreq.ibytes, @@ -3678,21 +4361,21 @@ static void show_multicast_interfaces(struct vty *vty) } } -DEFUN (show_ip_multicast, - show_ip_multicast_cmd, - "show ip multicast", - SHOW_STR - IP_STR - "Multicast global information\n") +static void pim_cmd_show_ip_multicast_helper(struct pim_instance *pim, + struct vty *vty) { + struct vrf *vrf = pim->vrf; time_t now = pim_time_monotonic_sec(); - char uptime[10]; - vty_out(vty, "Mroute socket descriptor: %d\n", qpim_mroute_socket_fd); + pim = vrf->info; + + vty_out(vty, "Mroute socket descriptor:"); + + vty_out(vty, " %d(%s)\n", pim->mroute_socket, vrf->name); pim_time_uptime(uptime, sizeof(uptime), - now - qpim_mroute_socket_creation); + now - pim->mroute_socket_creation); vty_out(vty, "Mroute socket uptime: %s\n", uptime); vty_out(vty, "\n"); @@ -3716,14 +4399,62 @@ DEFUN (show_ip_multicast, vty_out(vty, "\n"); - show_scan_oil_stats(vty, now); + show_scan_oil_stats(pim, vty, now); + + show_multicast_interfaces(pim, vty); +} + +DEFUN (show_ip_multicast, + show_ip_multicast_cmd, + "show ip multicast [vrf NAME]", + SHOW_STR + IP_STR + VRF_CMD_HELP_STR + "Multicast global information\n") +{ + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + pim_cmd_show_ip_multicast_helper(vrf->info, vty); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_multicast_vrf_all, + show_ip_multicast_vrf_all_cmd, + "show ip multicast vrf all", + SHOW_STR + IP_STR + VRF_CMD_HELP_STR + "Multicast global information\n") +{ + u_char uj = use_json(argc, argv); + struct vrf *vrf; + bool first = true; - show_multicast_interfaces(vty); + if (uj) + vty_out(vty, "{ "); + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + if (uj) { + if (!first) + vty_out(vty, ", "); + vty_out(vty, " \"%s\": ", vrf->name); + first = false; + } else + vty_out(vty, "VRF: %s\n", vrf->name); + pim_cmd_show_ip_multicast_helper(vrf->info, vty); + } + if (uj) + vty_out(vty, "}\n"); return CMD_SUCCESS; } -static void show_mroute(struct vty *vty, u_char uj) +static void show_mroute(struct pim_instance *pim, struct vty *vty, u_char uj) { struct listnode *node; struct channel_oil *c_oil; @@ -3754,7 +4485,7 @@ static void show_mroute(struct vty *vty, u_char uj) now = pim_time_monotonic_sec(); /* print list of PIM and IGMP routes */ - for (ALL_LIST_ELEMENTS_RO(pim_channel_oil_list, node, c_oil)) { + for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) { found_oif = 0; first = 1; if (!c_oil->installed && !uj) @@ -3764,7 +4495,7 @@ static void show_mroute(struct vty *vty, u_char uj) sizeof(grp_str)); pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, src_str, sizeof(src_str)); - ifp_in = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent); + ifp_in = pim_if_find_by_vif_index(pim, c_oil->oil.mfcc_parent); if (ifp_in) strcpy(in_ifname, ifp_in->name); @@ -3817,7 +4548,7 @@ static void show_mroute(struct vty *vty, u_char uj) if (ttl < 1) continue; - ifp_out = pim_if_find_by_vif_index(oif_vif_index); + ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index); pim_time_uptime( oif_uptime, sizeof(oif_uptime), now - c_oil->oif_creation[oif_vif_index]); @@ -3919,7 +4650,7 @@ static void show_mroute(struct vty *vty, u_char uj) } /* Print list of static routes */ - for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) { + for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) { first = 1; if (!s_route->c_oil.installed) @@ -3929,7 +4660,7 @@ static void show_mroute(struct vty *vty, u_char uj) sizeof(grp_str)); pim_inet4_dump("<source?>", s_route->source, src_str, sizeof(src_str)); - ifp_in = pim_if_find_by_vif_index(s_route->iif); + ifp_in = pim_if_find_by_vif_index(pim, s_route->iif); found_oif = 0; if (ifp_in) @@ -3975,7 +4706,7 @@ static void show_mroute(struct vty *vty, u_char uj) if (ttl < 1) continue; - ifp_out = pim_if_find_by_vif_index(oif_vif_index); + ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index); pim_time_uptime( oif_uptime, sizeof(oif_uptime), now @@ -4019,9 +4750,10 @@ static void show_mroute(struct vty *vty, u_char uj) json_ifp_out); } else { vty_out(vty, - "%-15s %-15s %-6s %-10s %-10s %-3d %8s\n", + "%-15s %-15s %-6s %-10s %-10s %-3d %8s %s\n", src_str, grp_str, proto, in_ifname, - out_ifname, ttl, oif_uptime); + out_ifname, ttl, oif_uptime, + pim->vrf->name); if (first) { src_str[0] = '\0'; grp_str[0] = '\0'; @@ -4032,9 +4764,10 @@ static void show_mroute(struct vty *vty, u_char uj) } if (!uj && !found_oif) { - vty_out(vty, "%-15s %-15s %-6s %-10s %-10s %-3d %8s\n", + vty_out(vty, + "%-15s %-15s %-6s %-10s %-10s %-3d %8s %s\n", src_str, grp_str, proto, in_ifname, "none", 0, - "--:--:--"); + "--:--:--", pim->vrf->name); } } @@ -4047,18 +4780,57 @@ static void show_mroute(struct vty *vty, u_char uj) DEFUN (show_ip_mroute, show_ip_mroute_cmd, - "show ip mroute [json]", + "show ip mroute [vrf NAME] [json]", SHOW_STR IP_STR MROUTE_STR + VRF_CMD_HELP_STR JSON_STR) { u_char uj = use_json(argc, argv); - show_mroute(vty, uj); + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + show_mroute(vrf->info, vty, uj); return CMD_SUCCESS; } -static void show_mroute_count(struct vty *vty) +DEFUN (show_ip_mroute_vrf_all, + show_ip_mroute_vrf_all_cmd, + "show ip mroute vrf all [json]", + SHOW_STR + IP_STR + MROUTE_STR + VRF_CMD_HELP_STR + JSON_STR) +{ + u_char uj = use_json(argc, argv); + struct vrf *vrf; + bool first = true; + + if (uj) + vty_out(vty, "{ "); + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + if (uj) { + if (!first) + vty_out(vty, ", "); + vty_out(vty, " \"%s\": ", vrf->name); + first = false; + } else + vty_out(vty, "VRF: %s\n", vrf->name); + show_mroute(vrf->info, vty, uj); + } + if (uj) + vty_out(vty, "}\n"); + + return CMD_SUCCESS; +} + +static void show_mroute_count(struct pim_instance *pim, struct vty *vty) { struct listnode *node; struct channel_oil *c_oil; @@ -4070,7 +4842,7 @@ static void show_mroute_count(struct vty *vty) "Source Group LastUsed Packets Bytes WrongIf \n"); /* Print PIM and IGMP route counts */ - for (ALL_LIST_ELEMENTS_RO(pim_channel_oil_list, node, c_oil)) { + for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) { char group_str[INET_ADDRSTRLEN]; char source_str[INET_ADDRSTRLEN]; @@ -4090,8 +4862,7 @@ static void show_mroute_count(struct vty *vty) c_oil->cc.wrong_if); } - /* Print static route counts */ - for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) { + for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) { char group_str[INET_ADDRSTRLEN]; char source_str[INET_ADDRSTRLEN]; @@ -4114,33 +4885,75 @@ static void show_mroute_count(struct vty *vty) DEFUN (show_ip_mroute_count, show_ip_mroute_count_cmd, - "show ip mroute count", + "show ip mroute [vrf NAME] count", SHOW_STR IP_STR MROUTE_STR + VRF_CMD_HELP_STR "Route and packet count data\n") { - show_mroute_count(vty); + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + show_mroute_count(vrf->info, vty); + return CMD_SUCCESS; +} + +DEFUN (show_ip_mroute_count_vrf_all, + show_ip_mroute_count_vrf_all_cmd, + "show ip mroute vrf all count", + SHOW_STR + IP_STR + MROUTE_STR + VRF_CMD_HELP_STR + "Route and packet count data\n") +{ + u_char uj = use_json(argc, argv); + struct vrf *vrf; + bool first = true; + + if (uj) + vty_out(vty, "{ "); + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + if (uj) { + if (!first) + vty_out(vty, ", "); + vty_out(vty, " \"%s\": ", vrf->name); + first = false; + } else + vty_out(vty, "VRF: %s\n", vrf->name); + show_mroute_count(vrf->info, vty); + } + if (uj) + vty_out(vty, "}\n"); + return CMD_SUCCESS; } DEFUN (show_ip_rib, show_ip_rib_cmd, - "show ip rib A.B.C.D", + "show ip rib [vrf NAME] A.B.C.D", SHOW_STR IP_STR RIB_STR + VRF_CMD_HELP_STR "Unicast address\n") { - int idx_ipv4 = 3; + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); struct in_addr addr; const char *addr_str; struct pim_nexthop nexthop; char nexthop_addr_str[PREFIX_STRLEN]; int result; + if (!vrf) + return CMD_WARNING; + memset(&nexthop, 0, sizeof(nexthop)); - addr_str = argv[idx_ipv4]->arg; + argv_find(argv, argc, "A.B.C.D", &idx); + addr_str = argv[idx]->arg; result = inet_pton(AF_INET, addr_str, &addr); if (result <= 0) { vty_out(vty, "Bad unicast address %s: errno=%d: %s\n", addr_str, @@ -4148,7 +4961,7 @@ DEFUN (show_ip_rib, return CMD_WARNING; } - if (pim_nexthop_lookup(&nexthop, addr, 0)) { + if (pim_nexthop_lookup(vrf->info, &nexthop, addr, 0)) { vty_out(vty, "Failure querying RIB nexthop for unicast address %s\n", addr_str); @@ -4168,7 +4981,7 @@ DEFUN (show_ip_rib, return CMD_SUCCESS; } -static void show_ssmpingd(struct vty *vty) +static void show_ssmpingd(struct pim_instance *pim, struct vty *vty) { struct listnode *node; struct ssmpingd_sock *ss; @@ -4177,12 +4990,12 @@ static void show_ssmpingd(struct vty *vty) vty_out(vty, "Source Socket Address Port Uptime Requests\n"); - if (!qpim_ssmpingd_list) + if (!pim->ssmpingd_list) return; now = pim_time_monotonic_sec(); - for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) { + for (ALL_LIST_ELEMENTS_RO(pim->ssmpingd_list, node, ss)) { char source_str[INET_ADDRSTRLEN]; char ss_uptime[10]; struct sockaddr_in bind_addr; @@ -4212,21 +5025,29 @@ static void show_ssmpingd(struct vty *vty) DEFUN (show_ip_ssmpingd, show_ip_ssmpingd_cmd, - "show ip ssmpingd", + "show ip ssmpingd [vrf NAME]", SHOW_STR IP_STR - SHOW_SSMPINGD_STR) + SHOW_SSMPINGD_STR + VRF_CMD_HELP_STR) { - show_ssmpingd(vty); + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + show_ssmpingd(vrf->info, vty); return CMD_SUCCESS; } -static int pim_rp_cmd_worker(struct vty *vty, const char *rp, const char *group, +static int pim_rp_cmd_worker(struct pim_instance *pim, struct vty *vty, + const char *rp, const char *group, const char *plist) { int result; - result = pim_rp_new(rp, group, plist); + result = pim_rp_new(pim, rp, group, plist); if (result == PIM_MALLOC_FAIL) { vty_out(vty, "%% Out of memory\n"); @@ -4268,26 +5089,27 @@ static int pim_rp_cmd_worker(struct vty *vty, const char *rp, const char *group, return CMD_SUCCESS; } -static int pim_cmd_spt_switchover(enum pim_spt_switchover spt, +static int pim_cmd_spt_switchover(struct pim_instance *pim, + enum pim_spt_switchover spt, const char *plist) { - pimg->spt.switchover = spt; + pim->spt.switchover = spt; - switch (pimg->spt.switchover) { + switch (pim->spt.switchover) { case PIM_SPT_IMMEDIATE: - if (pimg->spt.plist) - XFREE(MTYPE_PIM_SPT_PLIST_NAME, pimg->spt.plist); + if (pim->spt.plist) + XFREE(MTYPE_PIM_SPT_PLIST_NAME, pim->spt.plist); - pim_upstream_add_lhr_star_pimreg(); + pim_upstream_add_lhr_star_pimreg(pim); break; case PIM_SPT_INFINITY: - pim_upstream_remove_lhr_star_pimreg(plist); + pim_upstream_remove_lhr_star_pimreg(pim, plist); - if (pimg->spt.plist) - XFREE(MTYPE_PIM_SPT_PLIST_NAME, pimg->spt.plist); + if (pim->spt.plist) + XFREE(MTYPE_PIM_SPT_PLIST_NAME, pim->spt.plist); if (plist) - pimg->spt.plist = + pim->spt.plist = XSTRDUP(MTYPE_PIM_SPT_PLIST_NAME, plist); break; } @@ -4303,7 +5125,8 @@ DEFUN (ip_pim_spt_switchover_infinity, "SPT-Switchover\n" "Never switch to SPT Tree\n") { - return pim_cmd_spt_switchover(PIM_SPT_INFINITY, NULL); + PIM_DECLVAR_CONTEXT(vrf, pim); + return pim_cmd_spt_switchover(pim, PIM_SPT_INFINITY, NULL); } DEFUN (ip_pim_spt_switchover_infinity_plist, @@ -4316,7 +5139,8 @@ DEFUN (ip_pim_spt_switchover_infinity_plist, "Prefix-List to control which groups to switch\n" "Prefix-List name\n") { - return pim_cmd_spt_switchover(PIM_SPT_INFINITY, argv[5]->arg); + PIM_DECLVAR_CONTEXT(vrf, pim); + return pim_cmd_spt_switchover(pim, PIM_SPT_INFINITY, argv[5]->arg); } DEFUN (no_ip_pim_spt_switchover_infinity, @@ -4328,7 +5152,8 @@ DEFUN (no_ip_pim_spt_switchover_infinity, "SPT_Switchover\n" "Never switch to SPT Tree\n") { - return pim_cmd_spt_switchover(PIM_SPT_IMMEDIATE, NULL); + PIM_DECLVAR_CONTEXT(vrf, pim); + return pim_cmd_spt_switchover(pim, PIM_SPT_IMMEDIATE, NULL); } DEFUN (no_ip_pim_spt_switchover_infinity_plist, @@ -4342,7 +5167,8 @@ DEFUN (no_ip_pim_spt_switchover_infinity_plist, "Prefix-List to control which groups to switch\n" "Prefix-List name\n") { - return pim_cmd_spt_switchover(PIM_SPT_IMMEDIATE, NULL); + PIM_DECLVAR_CONTEXT(vrf, pim); + return pim_cmd_spt_switchover(pim, PIM_SPT_IMMEDIATE, NULL); } DEFUN (ip_pim_joinprune_time, @@ -4353,6 +5179,7 @@ DEFUN (ip_pim_joinprune_time, "Join Prune Send Interval\n" "Seconds\n") { + PIM_DECLVAR_CONTEXT(vrf, pim); qpim_t_periodic = atoi(argv[3]->arg); return CMD_SUCCESS; } @@ -4366,6 +5193,7 @@ DEFUN (no_ip_pim_joinprune_time, "Join Prune Send Interval\n" "Seconds\n") { + PIM_DECLVAR_CONTEXT(vrf, pim); qpim_t_periodic = PIM_DEFAULT_T_PERIODIC; return CMD_SUCCESS; } @@ -4378,6 +5206,7 @@ DEFUN (ip_pim_register_suppress, "Register Suppress Timer\n" "Seconds\n") { + PIM_DECLVAR_CONTEXT(vrf, pim); qpim_register_suppress_time = atoi(argv[3]->arg); return CMD_SUCCESS; } @@ -4391,10 +5220,40 @@ DEFUN (no_ip_pim_register_suppress, "Register Suppress Timer\n" "Seconds\n") { + PIM_DECLVAR_CONTEXT(vrf, pim); qpim_register_suppress_time = PIM_REGISTER_SUPPRESSION_TIME_DEFAULT; return CMD_SUCCESS; } +DEFUN (ip_pim_rp_keep_alive, + ip_pim_rp_keep_alive_cmd, + "ip pim rp keep-alive-timer (31-60000)", + IP_STR + "pim multicast routing\n" + "Rendevous Point\n" + "Keep alive Timer\n" + "Seconds\n") +{ + PIM_DECLVAR_CONTEXT(vrf, pim); + pim->rp_keep_alive_time = atoi(argv[4]->arg); + return CMD_SUCCESS; +} + +DEFUN (no_ip_pim_rp_keep_alive, + no_ip_pim_rp_keep_alive_cmd, + "no ip pim rp keep-alive-timer (31-60000)", + NO_STR + IP_STR + "pim multicast routing\n" + "Rendevous Point\n" + "Keep alive Timer\n" + "Seconds\n") +{ + PIM_DECLVAR_CONTEXT(vrf, pim); + pim->rp_keep_alive_time = PIM_KEEPALIVE_PERIOD; + return CMD_SUCCESS; +} + DEFUN (ip_pim_keep_alive, ip_pim_keep_alive_cmd, "ip pim keep-alive-timer (31-60000)", @@ -4403,7 +5262,8 @@ DEFUN (ip_pim_keep_alive, "Keep alive Timer\n" "Seconds\n") { - qpim_keep_alive_time = atoi(argv[3]->arg); + PIM_DECLVAR_CONTEXT(vrf, pim); + pim->keep_alive_time = atoi(argv[3]->arg); return CMD_SUCCESS; } @@ -4416,7 +5276,8 @@ DEFUN (no_ip_pim_keep_alive, "Keep alive Timer\n" "Seconds\n") { - qpim_keep_alive_time = PIM_KEEPALIVE_PERIOD; + PIM_DECLVAR_CONTEXT(vrf, pim); + pim->keep_alive_time = PIM_KEEPALIVE_PERIOD; return CMD_SUCCESS; } @@ -4428,6 +5289,7 @@ DEFUN (ip_pim_packets, "packets to process at one time per fd\n" "Number of packets\n") { + PIM_DECLVAR_CONTEXT(vrf, pim); qpim_packet_process = atoi(argv[3]->arg); return CMD_SUCCESS; } @@ -4441,6 +5303,7 @@ DEFUN (no_ip_pim_packets, "packets to process at one time per fd\n" "Number of packets\n") { + PIM_DECLVAR_CONTEXT(vrf, pim); qpim_packet_process = PIM_DEFAULT_PACKET_PROCESS; return CMD_SUCCESS; } @@ -4452,7 +5315,8 @@ DEFUN (ip_pim_v6_secondary, "pim multicast routing\n" "Send v6 secondary addresses\n") { - pimg->send_v6_secondary = 1; + PIM_DECLVAR_CONTEXT(vrf, pim); + pim->send_v6_secondary = 1; return CMD_SUCCESS; } @@ -4465,7 +5329,8 @@ DEFUN (no_ip_pim_v6_secondary, "pim multicast routing\n" "Send v6 secondary addresses\n") { - pimg->send_v6_secondary = 0; + PIM_DECLVAR_CONTEXT(vrf, pim); + pim->send_v6_secondary = 0; return CMD_SUCCESS; } @@ -4479,12 +5344,14 @@ DEFUN (ip_pim_rp, "ip address of RP\n" "Group Address range to cover\n") { + PIM_DECLVAR_CONTEXT(vrf, pim); int idx_ipv4 = 3; if (argc == (idx_ipv4 + 1)) - return pim_rp_cmd_worker(vty, argv[idx_ipv4]->arg, NULL, NULL); + return pim_rp_cmd_worker(pim, vty, argv[idx_ipv4]->arg, NULL, + NULL); else - return pim_rp_cmd_worker(vty, argv[idx_ipv4]->arg, + return pim_rp_cmd_worker(pim, vty, argv[idx_ipv4]->arg, argv[idx_ipv4 + 1]->arg, NULL); } @@ -4498,13 +5365,15 @@ DEFUN (ip_pim_rp_prefix_list, "group prefix-list filter\n" "Name of a prefix-list\n") { - return pim_rp_cmd_worker(vty, argv[3]->arg, NULL, argv[5]->arg); + PIM_DECLVAR_CONTEXT(vrf, pim); + return pim_rp_cmd_worker(pim, vty, argv[3]->arg, NULL, argv[5]->arg); } -static int pim_no_rp_cmd_worker(struct vty *vty, const char *rp, - const char *group, const char *plist) +static int pim_no_rp_cmd_worker(struct pim_instance *pim, struct vty *vty, + const char *rp, const char *group, + const char *plist) { - int result = pim_rp_del(rp, group, plist); + int result = pim_rp_del(pim, rp, group, plist); if (result == PIM_GROUP_BAD_ADDRESS) { vty_out(vty, "%% Bad group address specified: %s\n", group); @@ -4534,13 +5403,14 @@ DEFUN (no_ip_pim_rp, "ip address of RP\n" "Group Address range to cover\n") { + PIM_DECLVAR_CONTEXT(vrf, pim); int idx_ipv4 = 4, idx_group = 0; if (argv_find(argv, argc, "A.B.C.D/M", &idx_group)) - return pim_no_rp_cmd_worker(vty, argv[idx_ipv4]->arg, + return pim_no_rp_cmd_worker(pim, vty, argv[idx_ipv4]->arg, argv[idx_group]->arg, NULL); else - return pim_no_rp_cmd_worker(vty, argv[idx_ipv4]->arg, NULL, + return pim_no_rp_cmd_worker(pim, vty, argv[idx_ipv4]->arg, NULL, NULL); } @@ -4555,12 +5425,14 @@ DEFUN (no_ip_pim_rp_prefix_list, "group prefix-list filter\n" "Name of a prefix-list\n") { - return pim_no_rp_cmd_worker(vty, argv[4]->arg, NULL, argv[6]->arg); + PIM_DECLVAR_CONTEXT(vrf, pim); + return pim_no_rp_cmd_worker(pim, vty, argv[4]->arg, NULL, argv[6]->arg); } -static int pim_ssm_cmd_worker(struct vty *vty, const char *plist) +static int pim_ssm_cmd_worker(struct pim_instance *pim, struct vty *vty, + const char *plist) { - int result = pim_ssm_range_set(VRF_DEFAULT, plist); + int result = pim_ssm_range_set(pim, pim->vrf_id, plist); if (result == PIM_SSM_ERR_NONE) return CMD_SUCCESS; @@ -4588,7 +5460,8 @@ DEFUN (ip_pim_ssm_prefix_list, "group range prefix-list filter\n" "Name of a prefix-list\n") { - return pim_ssm_cmd_worker(vty, argv[0]->arg); + PIM_DECLVAR_CONTEXT(vrf, pim); + return pim_ssm_cmd_worker(pim, vty, argv[4]->arg); } DEFUN (no_ip_pim_ssm_prefix_list, @@ -4600,7 +5473,8 @@ DEFUN (no_ip_pim_ssm_prefix_list, "Source Specific Multicast\n" "group range prefix-list filter\n") { - return pim_ssm_cmd_worker(vty, NULL); + PIM_DECLVAR_CONTEXT(vrf, pim); + return pim_ssm_cmd_worker(pim, vty, NULL); } DEFUN (no_ip_pim_ssm_prefix_list_name, @@ -4613,19 +5487,21 @@ DEFUN (no_ip_pim_ssm_prefix_list_name, "group range prefix-list filter\n" "Name of a prefix-list\n") { - struct pim_ssm *ssm = pimg->ssm_info; + PIM_DECLVAR_CONTEXT(vrf, pim); + struct pim_ssm *ssm = pim->ssm_info; - if (ssm->plist_name && !strcmp(ssm->plist_name, argv[0]->arg)) - return pim_ssm_cmd_worker(vty, NULL); + if (ssm->plist_name && !strcmp(ssm->plist_name, argv[5]->arg)) + return pim_ssm_cmd_worker(pim, vty, NULL); - vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", argv[0]->arg); + vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", argv[5]->arg); return CMD_WARNING_CONFIG_FAILED; } -static void ip_pim_ssm_show_group_range(struct vty *vty, u_char uj) +static void ip_pim_ssm_show_group_range(struct pim_instance *pim, + struct vty *vty, u_char uj) { - struct pim_ssm *ssm = pimg->ssm_info; + struct pim_ssm *ssm = pim->ssm_info; const char *range_str = ssm->plist_name ? ssm->plist_name : PIM_SSM_STANDARD_RANGE; @@ -4642,20 +5518,28 @@ static void ip_pim_ssm_show_group_range(struct vty *vty, u_char uj) DEFUN (show_ip_pim_ssm_range, show_ip_pim_ssm_range_cmd, - "show ip pim group-type [json]", + "show ip pim [vrf NAME] group-type [json]", SHOW_STR IP_STR PIM_STR + VRF_CMD_HELP_STR "PIM group type\n" - "JavaScript Object Notation\n") + JSON_STR) { + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); u_char uj = use_json(argc, argv); - ip_pim_ssm_show_group_range(vty, uj); + + if (!vrf) + return CMD_WARNING; + + ip_pim_ssm_show_group_range(vrf->info, vty, uj); return CMD_SUCCESS; } -static void ip_pim_ssm_show_group_type(struct vty *vty, u_char uj, +static void ip_pim_ssm_show_group_type(struct pim_instance *pim, + struct vty *vty, u_char uj, const char *group) { struct in_addr group_addr; @@ -4667,7 +5551,8 @@ static void ip_pim_ssm_show_group_type(struct vty *vty, u_char uj, type_str = "invalid"; else { if (pim_is_group_224_4(group_addr)) - type_str = pim_is_grp_ssm(group_addr) ? "SSM" : "ASM"; + type_str = + pim_is_grp_ssm(pim, group_addr) ? "SSM" : "ASM"; else type_str = "not-multicast"; } @@ -4685,16 +5570,24 @@ static void ip_pim_ssm_show_group_type(struct vty *vty, u_char uj, DEFUN (show_ip_pim_group_type, show_ip_pim_group_type_cmd, - "show ip pim group-type A.B.C.D [json]", + "show ip pim [vrf NAME] group-type A.B.C.D [json]", SHOW_STR IP_STR PIM_STR + VRF_CMD_HELP_STR "multicast group type\n" "group address\n" - "JavaScript Object Notation\n") + JSON_STR) { + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); u_char uj = use_json(argc, argv); - ip_pim_ssm_show_group_type(vty, uj, argv[0]->arg); + + if (!vrf) + return CMD_WARNING; + + argv_find(argv, argc, "A.B.C.D", &idx); + ip_pim_ssm_show_group_type(vrf->info, vty, uj, argv[idx]->arg); return CMD_SUCCESS; } @@ -4727,6 +5620,7 @@ DEFUN (ip_ssmpingd, CONF_SSMPINGD_STR "Source address\n") { + PIM_DECLVAR_CONTEXT(vrf, pim); int idx_ipv4 = 2; int result; struct in_addr source_addr; @@ -4739,7 +5633,7 @@ DEFUN (ip_ssmpingd, return CMD_WARNING_CONFIG_FAILED; } - result = pim_ssmpingd_start(source_addr); + result = pim_ssmpingd_start(pim, source_addr); if (result) { vty_out(vty, "%% Failure starting ssmpingd for source %s: %d\n", source_str, result); @@ -4757,6 +5651,7 @@ DEFUN (no_ip_ssmpingd, CONF_SSMPINGD_STR "Source address\n") { + PIM_DECLVAR_CONTEXT(vrf, pim); int idx_ipv4 = 3; int result; struct in_addr source_addr; @@ -4769,7 +5664,7 @@ DEFUN (no_ip_ssmpingd, return CMD_WARNING_CONFIG_FAILED; } - result = pim_ssmpingd_stop(source_addr); + result = pim_ssmpingd_stop(pim, source_addr); if (result) { vty_out(vty, "%% Failure stopping ssmpingd for source %s: %d\n", source_str, result); @@ -4786,6 +5681,7 @@ DEFUN (ip_pim_ecmp, "pim multicast routing\n" "Enable PIM ECMP \n") { + PIM_DECLVAR_CONTEXT(vrf, pim); qpim_ecmp_enable = 1; return CMD_SUCCESS; @@ -4799,6 +5695,7 @@ DEFUN (no_ip_pim_ecmp, "pim multicast routing\n" "Disable PIM ECMP \n") { + PIM_DECLVAR_CONTEXT(vrf, pim); qpim_ecmp_enable = 0; return CMD_SUCCESS; @@ -4812,6 +5709,7 @@ DEFUN (ip_pim_ecmp_rebalance, "Enable PIM ECMP \n" "Enable PIM ECMP Rebalance\n") { + PIM_DECLVAR_CONTEXT(vrf, pim); qpim_ecmp_enable = 1; qpim_ecmp_rebalance_enable = 1; @@ -4827,6 +5725,7 @@ DEFUN (no_ip_pim_ecmp_rebalance, "Disable PIM ECMP \n" "Disable PIM ECMP Rebalance\n") { + PIM_DECLVAR_CONTEXT(vrf, pim); qpim_ecmp_rebalance_enable = 0; return CMD_SUCCESS; @@ -5496,13 +6395,17 @@ DEFUN (interface_ip_pim_sm, PIM_STR IFACE_PIM_SM_STR) { + struct pim_interface *pim_ifp; + VTY_DECLVAR_CONTEXT(interface, ifp); if (!pim_cmd_interface_add(ifp)) { vty_out(vty, "Could not enable PIM SM on interface\n"); return CMD_WARNING_CONFIG_FAILED; } - pim_if_create_pimreg(); + pim_ifp = ifp->info; + + pim_if_create_pimreg(pim_ifp->pim); return CMD_SUCCESS; } @@ -5575,6 +6478,8 @@ DEFUN (interface_ip_mroute, "Group address\n") { VTY_DECLVAR_CONTEXT(interface, iif); + struct pim_interface *pim_ifp; + struct pim_instance *pim; int idx_interface = 2; int idx_ipv4 = 3; struct interface *oif; @@ -5584,11 +6489,14 @@ DEFUN (interface_ip_mroute, struct in_addr src_addr; int result; + pim_ifp = iif->info; + pim = pim_ifp->pim; + oifname = argv[idx_interface]->arg; - oif = if_lookup_by_name(oifname, VRF_DEFAULT); + oif = if_lookup_by_name(oifname, pim->vrf_id); if (!oif) { vty_out(vty, "No such interface name %s\n", oifname); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } grp_str = argv[idx_ipv4]->arg; @@ -5596,14 +6504,14 @@ DEFUN (interface_ip_mroute, if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s\n", grp_str, errno, safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } src_addr.s_addr = INADDR_ANY; - if (pim_static_add(iif, oif, grp_addr, src_addr)) { + if (pim_static_add(pim, iif, oif, grp_addr, src_addr)) { vty_out(vty, "Failed to add route\n"); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } return CMD_SUCCESS; @@ -5619,6 +6527,8 @@ DEFUN (interface_ip_mroute_source, "Source address\n") { VTY_DECLVAR_CONTEXT(interface, iif); + struct pim_interface *pim_ifp; + struct pim_instance *pim; int idx_interface = 2; int idx_ipv4 = 3; int idx_ipv4_2 = 4; @@ -5630,11 +6540,14 @@ DEFUN (interface_ip_mroute_source, struct in_addr src_addr; int result; + pim_ifp = iif->info; + pim = pim_ifp->pim; + oifname = argv[idx_interface]->arg; - oif = if_lookup_by_name(oifname, VRF_DEFAULT); + oif = if_lookup_by_name(oifname, pim->vrf_id); if (!oif) { vty_out(vty, "No such interface name %s\n", oifname); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } grp_str = argv[idx_ipv4]->arg; @@ -5642,7 +6555,7 @@ DEFUN (interface_ip_mroute_source, if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s\n", grp_str, errno, safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } src_str = argv[idx_ipv4_2]->arg; @@ -5650,12 +6563,12 @@ DEFUN (interface_ip_mroute_source, if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s\n", src_str, errno, safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } - if (pim_static_add(iif, oif, grp_addr, src_addr)) { + if (pim_static_add(pim, iif, oif, grp_addr, src_addr)) { vty_out(vty, "Failed to add route\n"); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } return CMD_SUCCESS; @@ -5671,6 +6584,8 @@ DEFUN (interface_no_ip_mroute, "Group Address\n") { VTY_DECLVAR_CONTEXT(interface, iif); + struct pim_interface *pim_ifp; + struct pim_instance *pim; int idx_interface = 3; int idx_ipv4 = 4; struct interface *oif; @@ -5680,11 +6595,14 @@ DEFUN (interface_no_ip_mroute, struct in_addr src_addr; int result; + pim_ifp = iif->info; + pim = pim_ifp->pim; + oifname = argv[idx_interface]->arg; - oif = if_lookup_by_name(oifname, VRF_DEFAULT); + oif = if_lookup_by_name(oifname, pim->vrf_id); if (!oif) { vty_out(vty, "No such interface name %s\n", oifname); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } grp_str = argv[idx_ipv4]->arg; @@ -5692,14 +6610,14 @@ DEFUN (interface_no_ip_mroute, if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s\n", grp_str, errno, safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } src_addr.s_addr = INADDR_ANY; - if (pim_static_del(iif, oif, grp_addr, src_addr)) { + if (pim_static_del(pim, iif, oif, grp_addr, src_addr)) { vty_out(vty, "Failed to remove route\n"); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } return CMD_SUCCESS; @@ -5716,6 +6634,8 @@ DEFUN (interface_no_ip_mroute_source, "Source Address\n") { VTY_DECLVAR_CONTEXT(interface, iif); + struct pim_interface *pim_ifp; + struct pim_instance *pim; int idx_interface = 3; int idx_ipv4 = 4; int idx_ipv4_2 = 5; @@ -5727,11 +6647,14 @@ DEFUN (interface_no_ip_mroute_source, struct in_addr src_addr; int result; + pim_ifp = iif->info; + pim = pim_ifp->pim; + oifname = argv[idx_interface]->arg; - oif = if_lookup_by_name(oifname, VRF_DEFAULT); + oif = if_lookup_by_name(oifname, pim->vrf_id); if (!oif) { vty_out(vty, "No such interface name %s\n", oifname); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } grp_str = argv[idx_ipv4]->arg; @@ -5739,7 +6662,7 @@ DEFUN (interface_no_ip_mroute_source, if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s\n", grp_str, errno, safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } src_str = argv[idx_ipv4_2]->arg; @@ -5747,12 +6670,12 @@ DEFUN (interface_no_ip_mroute_source, if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s\n", src_str, errno, safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } - if (pim_static_del(iif, oif, grp_addr, src_addr)) { + if (pim_static_del(pim, iif, oif, grp_addr, src_addr)) { vty_out(vty, "Failed to remove route\n"); - return CMD_WARNING_CONFIG_FAILED; + return CMD_WARNING; } return CMD_SUCCESS; @@ -5789,7 +6712,6 @@ DEFUN (interface_ip_pim_hello, return CMD_SUCCESS; } - DEFUN (interface_no_ip_pim_hello, interface_no_ip_pim_hello_cmd, "no ip pim hello [(1-180) (1-180)]", @@ -6011,6 +6933,28 @@ DEFUN (no_debug_pim, return CMD_SUCCESS; } +DEFUN (debug_pim_nht, + debug_pim_nht_cmd, + "debug pim nht", + DEBUG_STR + DEBUG_PIM_STR + "Nexthop Tracking\n") +{ + PIM_DO_DEBUG_PIM_NHT; + return CMD_SUCCESS; +} + +DEFUN (no_debug_pim_nht, + no_debug_pim_nht_cmd, + "no debug pim nht", + NO_STR + DEBUG_STR + DEBUG_PIM_STR + "Nexthop Tracking\n") +{ + PIM_DONT_DEBUG_PIM_NHT; + return CMD_SUCCESS; +} DEFUN (debug_pim_events, debug_pim_events_cmd, @@ -6115,7 +7059,6 @@ DEFUN (no_debug_pim_packetdump_send, return CMD_SUCCESS; } - DEFUN (debug_pim_packetdump_recv, debug_pim_packetdump_recv_cmd, "debug pim packet-dump receive", @@ -6141,7 +7084,6 @@ DEFUN (no_debug_pim_packetdump_recv, return CMD_SUCCESS; } - DEFUN (debug_pim_trace, debug_pim_trace_cmd, "debug pim trace", @@ -6153,6 +7095,18 @@ DEFUN (debug_pim_trace, return CMD_SUCCESS; } +DEFUN (debug_pim_trace_detail, + debug_pim_trace_detail_cmd, + "debug pim trace detail", + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_TRACE_STR + "Detailed Information\n") +{ + PIM_DO_DEBUG_PIM_TRACE_DETAIL; + return CMD_SUCCESS; +} + DEFUN (no_debug_pim_trace, no_debug_pim_trace_cmd, "no debug pim trace", @@ -6165,6 +7119,18 @@ DEFUN (no_debug_pim_trace, return CMD_SUCCESS; } +DEFUN (no_debug_pim_trace_detail, + no_debug_pim_trace_detail_cmd, + "no debug pim trace detail", + NO_STR + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_TRACE_STR + "Detailed Information\n") +{ + PIM_DONT_DEBUG_PIM_TRACE_DETAIL; + return CMD_SUCCESS; +} DEFUN (debug_ssmpingd, debug_ssmpingd_cmd, @@ -6187,7 +7153,6 @@ DEFUN (no_debug_ssmpingd, return CMD_SUCCESS; } - DEFUN (debug_pim_zebra, debug_pim_zebra_cmd, "debug pim zebra", @@ -6211,7 +7176,6 @@ DEFUN (no_debug_pim_zebra, return CMD_SUCCESS; } - DEFUN (debug_msdp, debug_msdp_cmd, "debug msdp", @@ -6435,8 +7399,8 @@ ALIAS(no_ip_pim_bfd, no_ip_pim_bfd_param_cmd, "Required min receive interval\n" "Desired min transmit interval\n") -static int ip_msdp_peer_cmd_worker(struct vty *vty, const char *peer, - const char *local) +static int ip_msdp_peer_cmd_worker(struct pim_instance *pim, struct vty *vty, + const char *peer, const char *local) { enum pim_msdp_err result; struct in_addr peer_addr; @@ -6456,7 +7420,7 @@ static int ip_msdp_peer_cmd_worker(struct vty *vty, const char *peer, return CMD_WARNING_CONFIG_FAILED; } - result = pim_msdp_peer_add(peer_addr, local_addr, "default", + result = pim_msdp_peer_add(pim, peer_addr, local_addr, "default", NULL /* mp_p */); switch (result) { case PIM_MSDP_ERR_NONE: @@ -6487,10 +7451,12 @@ DEFUN_HIDDEN (ip_msdp_peer, "Source address for TCP connection\n" "local ip address\n") { - return ip_msdp_peer_cmd_worker(vty, argv[3]->arg, argv[5]->arg); + PIM_DECLVAR_CONTEXT(vrf, pim); + return ip_msdp_peer_cmd_worker(pim, vty, argv[3]->arg, argv[5]->arg); } -static int ip_no_msdp_peer_cmd_worker(struct vty *vty, const char *peer) +static int ip_no_msdp_peer_cmd_worker(struct pim_instance *pim, struct vty *vty, + const char *peer) { enum pim_msdp_err result; struct in_addr peer_addr; @@ -6502,7 +7468,7 @@ static int ip_no_msdp_peer_cmd_worker(struct vty *vty, const char *peer) return CMD_WARNING_CONFIG_FAILED; } - result = pim_msdp_peer_del(peer_addr); + result = pim_msdp_peer_del(pim, peer_addr); switch (result) { case PIM_MSDP_ERR_NONE: break; @@ -6525,10 +7491,12 @@ DEFUN_HIDDEN (no_ip_msdp_peer, "Delete MSDP peer\n" "peer ip address\n") { - return ip_no_msdp_peer_cmd_worker(vty, argv[4]->arg); + PIM_DECLVAR_CONTEXT(vrf, pim); + return ip_no_msdp_peer_cmd_worker(pim, vty, argv[4]->arg); } -static int ip_msdp_mesh_group_member_cmd_worker(struct vty *vty, const char *mg, +static int ip_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim, + struct vty *vty, const char *mg, const char *mbr) { enum pim_msdp_err result; @@ -6541,7 +7509,7 @@ static int ip_msdp_mesh_group_member_cmd_worker(struct vty *vty, const char *mg, return CMD_WARNING_CONFIG_FAILED; } - result = pim_msdp_mg_mbr_add(mg, mbr_ip); + result = pim_msdp_mg_mbr_add(pim, mg, mbr_ip); switch (result) { case PIM_MSDP_ERR_NONE: break; @@ -6571,11 +7539,13 @@ DEFUN (ip_msdp_mesh_group_member, "mesh group member\n" "peer ip address\n") { - return ip_msdp_mesh_group_member_cmd_worker(vty, argv[3]->arg, + PIM_DECLVAR_CONTEXT(vrf, pim); + return ip_msdp_mesh_group_member_cmd_worker(pim, vty, argv[3]->arg, argv[5]->arg); } -static int ip_no_msdp_mesh_group_member_cmd_worker(struct vty *vty, +static int ip_no_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim, + struct vty *vty, const char *mg, const char *mbr) { @@ -6589,7 +7559,7 @@ static int ip_no_msdp_mesh_group_member_cmd_worker(struct vty *vty, return CMD_WARNING_CONFIG_FAILED; } - result = pim_msdp_mg_mbr_del(mg, mbr_ip); + result = pim_msdp_mg_mbr_del(pim, mg, mbr_ip); switch (result) { case PIM_MSDP_ERR_NONE: break; @@ -6616,11 +7586,13 @@ DEFUN (no_ip_msdp_mesh_group_member, "mesh group member\n" "peer ip address\n") { - return ip_no_msdp_mesh_group_member_cmd_worker(vty, argv[4]->arg, + PIM_DECLVAR_CONTEXT(vrf, pim); + return ip_no_msdp_mesh_group_member_cmd_worker(pim, vty, argv[4]->arg, argv[6]->arg); } -static int ip_msdp_mesh_group_source_cmd_worker(struct vty *vty, const char *mg, +static int ip_msdp_mesh_group_source_cmd_worker(struct pim_instance *pim, + struct vty *vty, const char *mg, const char *src) { enum pim_msdp_err result; @@ -6633,7 +7605,7 @@ static int ip_msdp_mesh_group_source_cmd_worker(struct vty *vty, const char *mg, return CMD_WARNING_CONFIG_FAILED; } - result = pim_msdp_mg_src_add(mg, src_ip); + result = pim_msdp_mg_src_add(pim, mg, src_ip); switch (result) { case PIM_MSDP_ERR_NONE: break; @@ -6661,16 +7633,18 @@ DEFUN (ip_msdp_mesh_group_source, "mesh group local address\n" "source ip address for the TCP connection\n") { - return ip_msdp_mesh_group_source_cmd_worker(vty, argv[3]->arg, + PIM_DECLVAR_CONTEXT(vrf, pim); + return ip_msdp_mesh_group_source_cmd_worker(pim, vty, argv[3]->arg, argv[5]->arg); } -static int ip_no_msdp_mesh_group_source_cmd_worker(struct vty *vty, +static int ip_no_msdp_mesh_group_source_cmd_worker(struct pim_instance *pim, + struct vty *vty, const char *mg) { enum pim_msdp_err result; - result = pim_msdp_mg_src_del(mg); + result = pim_msdp_mg_src_del(pim, mg); switch (result) { case PIM_MSDP_ERR_NONE: break; @@ -6684,11 +7658,12 @@ static int ip_no_msdp_mesh_group_source_cmd_worker(struct vty *vty, return result ? CMD_WARNING_CONFIG_FAILED : CMD_SUCCESS; } -static int ip_no_msdp_mesh_group_cmd_worker(struct vty *vty, const char *mg) +static int ip_no_msdp_mesh_group_cmd_worker(struct pim_instance *pim, + struct vty *vty, const char *mg) { enum pim_msdp_err result; - result = pim_msdp_mg_del(mg); + result = pim_msdp_mg_del(pim, mg); switch (result) { case PIM_MSDP_ERR_NONE: break; @@ -6713,10 +7688,11 @@ DEFUN (no_ip_msdp_mesh_group_source, "mesh group source\n" "mesh group local address\n") { + PIM_DECLVAR_CONTEXT(vrf, pim); if (argc == 7) - return ip_no_msdp_mesh_group_cmd_worker(vty, argv[6]->arg); + return ip_no_msdp_mesh_group_cmd_worker(pim, vty, argv[6]->arg); else - return ip_no_msdp_mesh_group_source_cmd_worker(vty, + return ip_no_msdp_mesh_group_source_cmd_worker(pim, vty, argv[4]->arg); } @@ -6729,11 +7705,12 @@ static void print_empty_json_obj(struct vty *vty) json_object_free(json); } -static void ip_msdp_show_mesh_group(struct vty *vty, u_char uj) +static void ip_msdp_show_mesh_group(struct pim_instance *pim, struct vty *vty, + u_char uj) { struct listnode *mbrnode; struct pim_msdp_mg_mbr *mbr; - struct pim_msdp_mg *mg = msdp->mg; + struct pim_msdp_mg *mg = pim->msdp.mg; char mbr_str[INET_ADDRSTRLEN]; char src_str[INET_ADDRSTRLEN]; char state_str[PIM_MSDP_STATE_STRLEN]; @@ -6798,20 +7775,61 @@ static void ip_msdp_show_mesh_group(struct vty *vty, u_char uj) DEFUN (show_ip_msdp_mesh_group, show_ip_msdp_mesh_group_cmd, - "show ip msdp mesh-group [json]", + "show ip msdp [vrf NAME] mesh-group [json]", SHOW_STR IP_STR MSDP_STR + VRF_CMD_HELP_STR "MSDP mesh-group information\n" - "JavaScript Object Notation\n") + JSON_STR) { u_char uj = use_json(argc, argv); - ip_msdp_show_mesh_group(vty, uj); + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + ip_msdp_show_mesh_group(vrf->info, vty, uj); return CMD_SUCCESS; } -static void ip_msdp_show_peers(struct vty *vty, u_char uj) +DEFUN (show_ip_msdp_mesh_group_vrf_all, + show_ip_msdp_mesh_group_vrf_all_cmd, + "show ip msdp vrf all mesh-group [json]", + SHOW_STR + IP_STR + MSDP_STR + VRF_CMD_HELP_STR + "MSDP mesh-group information\n" + JSON_STR) +{ + u_char uj = use_json(argc, argv); + struct vrf *vrf; + bool first = true; + + if (uj) + vty_out(vty, "{ "); + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + if (uj) { + if (!first) + vty_out(vty, ", "); + vty_out(vty, " \"%s\": ", vrf->name); + first = false; + } else + vty_out(vty, "VRF: %s\n", vrf->name); + ip_msdp_show_mesh_group(vrf->info, vty, uj); + } + if (uj) + vty_out(vty, "}\n"); + + return CMD_SUCCESS; +} + +static void ip_msdp_show_peers(struct pim_instance *pim, struct vty *vty, + u_char uj) { struct listnode *mpnode; struct pim_msdp_peer *mp; @@ -6831,7 +7849,7 @@ static void ip_msdp_show_peers(struct vty *vty, u_char uj) "Peer Local State Uptime SaCnt\n"); } - for (ALL_LIST_ELEMENTS_RO(msdp->peer_list, mpnode, mp)) { + for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) { if (mp->state == PIM_MSDP_ESTABLISHED) { now = pim_time_monotonic_sec(); pim_time_uptime(timebuf, sizeof(timebuf), @@ -6864,8 +7882,8 @@ static void ip_msdp_show_peers(struct vty *vty, u_char uj) } } -static void ip_msdp_show_peers_detail(struct vty *vty, const char *peer, - u_char uj) +static void ip_msdp_show_peers_detail(struct pim_instance *pim, struct vty *vty, + const char *peer, u_char uj) { struct listnode *mpnode; struct pim_msdp_peer *mp; @@ -6884,7 +7902,7 @@ static void ip_msdp_show_peers_detail(struct vty *vty, const char *peer, json = json_object_new_object(); } - for (ALL_LIST_ELEMENTS_RO(msdp->peer_list, mpnode, mp)) { + for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) { pim_inet4_dump("<peer?>", mp->peer, peer_str, sizeof(peer_str)); if (strcmp(peer, "detail") && strcmp(peer, peer_str)) continue; @@ -6971,28 +7989,81 @@ static void ip_msdp_show_peers_detail(struct vty *vty, const char *peer, DEFUN (show_ip_msdp_peer_detail, show_ip_msdp_peer_detail_cmd, - "show ip msdp peer [detail|A.B.C.D] [json]", + "show ip msdp [vrf NAME] peer [detail|A.B.C.D] [json]", SHOW_STR IP_STR MSDP_STR + VRF_CMD_HELP_STR "MSDP peer information\n" "Detailed output\n" "peer ip address\n" - "JavaScript Object Notation\n") + JSON_STR) { u_char uj = use_json(argc, argv); - if (uj) - argc--; + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + char *arg = NULL; + + if (argv_find(argv, argc, "detail", &idx)) + arg = argv[idx]->text; + else if (argv_find(argv, argc, "A.B.C.D", &idx)) + arg = argv[idx]->arg; - if (argc > 4) - ip_msdp_show_peers_detail(vty, argv[4]->arg, uj); + if (arg) + ip_msdp_show_peers_detail(vrf->info, vty, argv[idx]->arg, uj); else - ip_msdp_show_peers(vty, uj); + ip_msdp_show_peers(vrf->info, vty, uj); return CMD_SUCCESS; } -static void ip_msdp_show_sa(struct vty *vty, u_char uj) +DEFUN (show_ip_msdp_peer_detail_vrf_all, + show_ip_msdp_peer_detail_vrf_all_cmd, + "show ip msdp vrf all peer [detail|A.B.C.D] [json]", + SHOW_STR + IP_STR + MSDP_STR + VRF_CMD_HELP_STR + "MSDP peer information\n" + "Detailed output\n" + "peer ip address\n" + JSON_STR) +{ + int idx = 2; + u_char uj = use_json(argc, argv); + struct vrf *vrf; + bool first = true; + + if (uj) + vty_out(vty, "{ "); + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + if (uj) { + if (!first) + vty_out(vty, ", "); + vty_out(vty, " \"%s\": ", vrf->name); + first = false; + } else + vty_out(vty, "VRF: %s\n", vrf->name); + if (argv_find(argv, argc, "detail", &idx) + || argv_find(argv, argc, "A.B.C.D", &idx)) + ip_msdp_show_peers_detail(vrf->info, vty, + argv[idx]->arg, uj); + else + ip_msdp_show_peers(vrf->info, vty, uj); + } + if (uj) + vty_out(vty, "}\n"); + + return CMD_SUCCESS; +} + +static void ip_msdp_show_sa(struct pim_instance *pim, struct vty *vty, + u_char uj) { struct listnode *sanode; struct pim_msdp_sa *sa; @@ -7014,7 +8085,7 @@ static void ip_msdp_show_sa(struct vty *vty, u_char uj) "Source Group RP Local SPT Uptime\n"); } - for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) { + for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) { now = pim_time_monotonic_sec(); pim_time_uptime(timebuf, sizeof(timebuf), now - sa->uptime); pim_inet4_dump("<src?>", sa->sg.src, src_str, sizeof(src_str)); @@ -7059,7 +8130,6 @@ static void ip_msdp_show_sa(struct vty *vty, u_char uj) } } - if (uj) { vty_out(vty, "%s\n", json_object_to_json_string_ext( json, JSON_C_TO_STRING_PRETTY)); @@ -7133,7 +8203,8 @@ static void ip_msdp_show_sa_entry_detail(struct pim_msdp_sa *sa, } } -static void ip_msdp_show_sa_detail(struct vty *vty, u_char uj) +static void ip_msdp_show_sa_detail(struct pim_instance *pim, struct vty *vty, + u_char uj) { struct listnode *sanode; struct pim_msdp_sa *sa; @@ -7145,7 +8216,7 @@ static void ip_msdp_show_sa_detail(struct vty *vty, u_char uj) json = json_object_new_object(); } - for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) { + for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) { pim_inet4_dump("<src?>", sa->sg.src, src_str, sizeof(src_str)); pim_inet4_dump("<grp?>", sa->sg.grp, grp_str, sizeof(grp_str)); ip_msdp_show_sa_entry_detail(sa, src_str, grp_str, vty, uj, @@ -7161,21 +8232,63 @@ static void ip_msdp_show_sa_detail(struct vty *vty, u_char uj) DEFUN (show_ip_msdp_sa_detail, show_ip_msdp_sa_detail_cmd, - "show ip msdp sa detail [json]", + "show ip msdp [vrf NAME] sa detail [json]", SHOW_STR IP_STR MSDP_STR + VRF_CMD_HELP_STR "MSDP active-source information\n" "Detailed output\n" - "JavaScript Object Notation\n") + JSON_STR) { u_char uj = use_json(argc, argv); - ip_msdp_show_sa_detail(vty, uj); + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; + + ip_msdp_show_sa_detail(vrf->info, vty, uj); return CMD_SUCCESS; } -static void ip_msdp_show_sa_addr(struct vty *vty, const char *addr, u_char uj) +DEFUN (show_ip_msdp_sa_detail_vrf_all, + show_ip_msdp_sa_detail_vrf_all_cmd, + "show ip msdp vrf all sa detail [json]", + SHOW_STR + IP_STR + MSDP_STR + VRF_CMD_HELP_STR + "MSDP active-source information\n" + "Detailed output\n" + JSON_STR) +{ + u_char uj = use_json(argc, argv); + struct vrf *vrf; + bool first = true; + + if (uj) + vty_out(vty, "{ "); + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + if (uj) { + if (!first) + vty_out(vty, ", "); + vty_out(vty, " \"%s\": ", vrf->name); + first = false; + } else + vty_out(vty, "VRF: %s\n", vrf->name); + ip_msdp_show_sa_detail(vrf->info, vty, uj); + } + if (uj) + vty_out(vty, "}\n"); + + return CMD_SUCCESS; +} + +static void ip_msdp_show_sa_addr(struct pim_instance *pim, struct vty *vty, + const char *addr, u_char uj) { struct listnode *sanode; struct pim_msdp_sa *sa; @@ -7187,7 +8300,7 @@ static void ip_msdp_show_sa_addr(struct vty *vty, const char *addr, u_char uj) json = json_object_new_object(); } - for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) { + for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) { pim_inet4_dump("<src?>", sa->sg.src, src_str, sizeof(src_str)); pim_inet4_dump("<grp?>", sa->sg.grp, grp_str, sizeof(grp_str)); if (!strcmp(addr, src_str) || !strcmp(addr, grp_str)) { @@ -7203,8 +8316,8 @@ static void ip_msdp_show_sa_addr(struct vty *vty, const char *addr, u_char uj) } } -static void ip_msdp_show_sa_sg(struct vty *vty, const char *src, - const char *grp, u_char uj) +static void ip_msdp_show_sa_sg(struct pim_instance *pim, struct vty *vty, + const char *src, const char *grp, u_char uj) { struct listnode *sanode; struct pim_msdp_sa *sa; @@ -7216,7 +8329,7 @@ static void ip_msdp_show_sa_sg(struct vty *vty, const char *src, json = json_object_new_object(); } - for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) { + for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) { pim_inet4_dump("<src?>", sa->sg.src, src_str, sizeof(src_str)); pim_inet4_dump("<grp?>", sa->sg.grp, grp_str, sizeof(grp_str)); if (!strcmp(src, src_str) && !strcmp(grp, grp_str)) { @@ -7234,18 +8347,25 @@ static void ip_msdp_show_sa_sg(struct vty *vty, const char *src, DEFUN (show_ip_msdp_sa_sg, show_ip_msdp_sa_sg_cmd, - "show ip msdp sa [A.B.C.D [A.B.C.D]] [json]", + "show ip msdp [vrf NAME] sa [A.B.C.D [A.B.C.D]] [json]", SHOW_STR IP_STR MSDP_STR + VRF_CMD_HELP_STR "MSDP active-source information\n" "source or group ip\n" "group ip\n" - "JavaScript Object Notation\n") + JSON_STR) { u_char uj = use_json(argc, argv); + struct vrf *vrf; + int idx = 2; + + vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + + if (!vrf) + return CMD_WARNING; - int idx = 0; char *src_ip = argv_find(argv, argc, "A.B.C.D", &idx) ? argv[idx++]->arg : NULL; char *grp_ip = idx < argc && argv_find(argv, argc, "A.B.C.D", &idx) @@ -7253,16 +8373,16 @@ DEFUN (show_ip_msdp_sa_sg, : NULL; if (src_ip && grp_ip) - ip_msdp_show_sa_sg(vty, src_ip, grp_ip, uj); + ip_msdp_show_sa_sg(vrf->info, vty, src_ip, grp_ip, uj); else if (src_ip) - ip_msdp_show_sa_addr(vty, src_ip, uj); + ip_msdp_show_sa_addr(vrf->info, vty, src_ip, uj); else - ip_msdp_show_sa(vty, uj); + ip_msdp_show_sa(vrf->info, vty, uj); return CMD_SUCCESS; } -void pim_cmd_init() +void pim_cmd_init(void) { install_node(&pim_global_node, pim_global_config_write); /* PIM_NODE */ install_node(&interface_node, @@ -7274,35 +8394,68 @@ void pim_cmd_init() install_element(CONFIG_NODE, &ip_multicast_routing_cmd); install_element(CONFIG_NODE, &no_ip_multicast_routing_cmd); install_element(CONFIG_NODE, &ip_pim_rp_cmd); + install_element(VRF_NODE, &ip_pim_rp_cmd); install_element(CONFIG_NODE, &no_ip_pim_rp_cmd); + install_element(VRF_NODE, &no_ip_pim_rp_cmd); install_element(CONFIG_NODE, &ip_pim_rp_prefix_list_cmd); + install_element(VRF_NODE, &ip_pim_rp_prefix_list_cmd); install_element(CONFIG_NODE, &no_ip_pim_rp_prefix_list_cmd); + install_element(VRF_NODE, &no_ip_pim_rp_prefix_list_cmd); install_element(CONFIG_NODE, &no_ip_pim_ssm_prefix_list_cmd); + install_element(VRF_NODE, &no_ip_pim_ssm_prefix_list_cmd); install_element(CONFIG_NODE, &no_ip_pim_ssm_prefix_list_name_cmd); + install_element(VRF_NODE, &no_ip_pim_ssm_prefix_list_name_cmd); install_element(CONFIG_NODE, &ip_pim_ssm_prefix_list_cmd); + install_element(VRF_NODE, &ip_pim_ssm_prefix_list_cmd); install_element(CONFIG_NODE, &ip_pim_register_suppress_cmd); + install_element(VRF_NODE, &ip_pim_register_suppress_cmd); install_element(CONFIG_NODE, &no_ip_pim_register_suppress_cmd); + install_element(VRF_NODE, &no_ip_pim_register_suppress_cmd); install_element(CONFIG_NODE, &ip_pim_spt_switchover_infinity_cmd); + install_element(VRF_NODE, &ip_pim_spt_switchover_infinity_cmd); install_element(CONFIG_NODE, &ip_pim_spt_switchover_infinity_plist_cmd); + install_element(VRF_NODE, &ip_pim_spt_switchover_infinity_plist_cmd); install_element(CONFIG_NODE, &no_ip_pim_spt_switchover_infinity_cmd); + install_element(VRF_NODE, &no_ip_pim_spt_switchover_infinity_cmd); install_element(CONFIG_NODE, &no_ip_pim_spt_switchover_infinity_plist_cmd); + install_element(VRF_NODE, &no_ip_pim_spt_switchover_infinity_plist_cmd); install_element(CONFIG_NODE, &ip_pim_joinprune_time_cmd); + install_element(VRF_NODE, &ip_pim_joinprune_time_cmd); install_element(CONFIG_NODE, &no_ip_pim_joinprune_time_cmd); + install_element(VRF_NODE, &no_ip_pim_joinprune_time_cmd); install_element(CONFIG_NODE, &ip_pim_keep_alive_cmd); + install_element(VRF_NODE, &ip_pim_keep_alive_cmd); + install_element(CONFIG_NODE, &ip_pim_rp_keep_alive_cmd); + install_element(VRF_NODE, &ip_pim_rp_keep_alive_cmd); install_element(CONFIG_NODE, &no_ip_pim_keep_alive_cmd); + install_element(VRF_NODE, &no_ip_pim_keep_alive_cmd); + install_element(CONFIG_NODE, &no_ip_pim_rp_keep_alive_cmd); + install_element(VRF_NODE, &no_ip_pim_rp_keep_alive_cmd); install_element(CONFIG_NODE, &ip_pim_packets_cmd); + install_element(VRF_NODE, &ip_pim_packets_cmd); install_element(CONFIG_NODE, &no_ip_pim_packets_cmd); + install_element(VRF_NODE, &no_ip_pim_packets_cmd); install_element(CONFIG_NODE, &ip_pim_v6_secondary_cmd); + install_element(VRF_NODE, &ip_pim_v6_secondary_cmd); install_element(CONFIG_NODE, &no_ip_pim_v6_secondary_cmd); + install_element(VRF_NODE, &no_ip_pim_v6_secondary_cmd); install_element(CONFIG_NODE, &ip_ssmpingd_cmd); + install_element(VRF_NODE, &ip_ssmpingd_cmd); install_element(CONFIG_NODE, &no_ip_ssmpingd_cmd); + install_element(VRF_NODE, &no_ip_ssmpingd_cmd); install_element(CONFIG_NODE, &ip_msdp_peer_cmd); + install_element(VRF_NODE, &ip_msdp_peer_cmd); install_element(CONFIG_NODE, &no_ip_msdp_peer_cmd); + install_element(VRF_NODE, &no_ip_msdp_peer_cmd); install_element(CONFIG_NODE, &ip_pim_ecmp_cmd); + install_element(VRF_NODE, &ip_pim_ecmp_cmd); install_element(CONFIG_NODE, &no_ip_pim_ecmp_cmd); + install_element(VRF_NODE, &no_ip_pim_ecmp_cmd); install_element(CONFIG_NODE, &ip_pim_ecmp_rebalance_cmd); + install_element(VRF_NODE, &ip_pim_ecmp_rebalance_cmd); install_element(CONFIG_NODE, &no_ip_pim_ecmp_rebalance_cmd); + install_element(VRF_NODE, &no_ip_pim_ecmp_rebalance_cmd); install_element(INTERFACE_NODE, &interface_ip_igmp_cmd); install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd); @@ -7337,8 +8490,11 @@ void pim_cmd_init() install_element(INTERFACE_NODE, &interface_no_ip_mroute_source_cmd); install_element(VIEW_NODE, &show_ip_igmp_interface_cmd); + install_element(VIEW_NODE, &show_ip_igmp_interface_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_igmp_join_cmd); + install_element(VIEW_NODE, &show_ip_igmp_join_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_igmp_groups_cmd); + install_element(VIEW_NODE, &show_ip_igmp_groups_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_igmp_groups_retransmissions_cmd); install_element(VIEW_NODE, &show_ip_igmp_sources_cmd); install_element(VIEW_NODE, &show_ip_igmp_sources_retransmissions_cmd); @@ -7348,19 +8504,29 @@ void pim_cmd_init() install_element(VIEW_NODE, &show_ip_pim_assert_winner_metric_cmd); install_element(VIEW_NODE, &show_ip_pim_interface_traffic_cmd); install_element(VIEW_NODE, &show_ip_pim_interface_cmd); + install_element(VIEW_NODE, &show_ip_pim_interface_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_pim_join_cmd); + install_element(VIEW_NODE, &show_ip_pim_join_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_pim_local_membership_cmd); install_element(VIEW_NODE, &show_ip_pim_neighbor_cmd); + install_element(VIEW_NODE, &show_ip_pim_neighbor_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_pim_rpf_cmd); + install_element(VIEW_NODE, &show_ip_pim_rpf_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_pim_secondary_cmd); install_element(VIEW_NODE, &show_ip_pim_state_cmd); + install_element(VIEW_NODE, &show_ip_pim_state_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_pim_upstream_cmd); + install_element(VIEW_NODE, &show_ip_pim_upstream_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_pim_upstream_join_desired_cmd); install_element(VIEW_NODE, &show_ip_pim_upstream_rpf_cmd); install_element(VIEW_NODE, &show_ip_pim_rp_cmd); + install_element(VIEW_NODE, &show_ip_pim_rp_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_multicast_cmd); + install_element(VIEW_NODE, &show_ip_multicast_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_mroute_cmd); + install_element(VIEW_NODE, &show_ip_mroute_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_mroute_count_cmd); + install_element(VIEW_NODE, &show_ip_mroute_count_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_rib_cmd); install_element(VIEW_NODE, &show_ip_ssmpingd_cmd); install_element(VIEW_NODE, &show_debugging_pim_cmd); @@ -7390,6 +8556,8 @@ void pim_cmd_init() install_element(ENABLE_NODE, &no_debug_static_cmd); install_element(ENABLE_NODE, &debug_pim_cmd); install_element(ENABLE_NODE, &no_debug_pim_cmd); + install_element(ENABLE_NODE, &debug_pim_nht_cmd); + install_element(ENABLE_NODE, &no_debug_pim_nht_cmd); install_element(ENABLE_NODE, &debug_pim_events_cmd); install_element(ENABLE_NODE, &no_debug_pim_events_cmd); install_element(ENABLE_NODE, &debug_pim_packets_cmd); @@ -7400,6 +8568,8 @@ void pim_cmd_init() install_element(ENABLE_NODE, &no_debug_pim_packetdump_recv_cmd); install_element(ENABLE_NODE, &debug_pim_trace_cmd); install_element(ENABLE_NODE, &no_debug_pim_trace_cmd); + install_element(ENABLE_NODE, &debug_pim_trace_detail_cmd); + install_element(ENABLE_NODE, &no_debug_pim_trace_detail_cmd); install_element(ENABLE_NODE, &debug_ssmpingd_cmd); install_element(ENABLE_NODE, &no_debug_ssmpingd_cmd); install_element(ENABLE_NODE, &debug_pim_zebra_cmd); @@ -7430,12 +8600,16 @@ void pim_cmd_init() install_element(CONFIG_NODE, &no_debug_static_cmd); install_element(CONFIG_NODE, &debug_pim_cmd); install_element(CONFIG_NODE, &no_debug_pim_cmd); + install_element(CONFIG_NODE, &debug_pim_nht_cmd); + install_element(CONFIG_NODE, &no_debug_pim_nht_cmd); install_element(CONFIG_NODE, &debug_pim_events_cmd); install_element(CONFIG_NODE, &no_debug_pim_events_cmd); install_element(CONFIG_NODE, &debug_pim_packets_cmd); install_element(CONFIG_NODE, &no_debug_pim_packets_cmd); install_element(CONFIG_NODE, &debug_pim_trace_cmd); install_element(CONFIG_NODE, &no_debug_pim_trace_cmd); + install_element(CONFIG_NODE, &debug_pim_trace_detail_cmd); + install_element(CONFIG_NODE, &no_debug_pim_trace_detail_cmd); install_element(CONFIG_NODE, &debug_ssmpingd_cmd); install_element(CONFIG_NODE, &no_debug_ssmpingd_cmd); install_element(CONFIG_NODE, &debug_pim_zebra_cmd); @@ -7449,14 +8623,22 @@ void pim_cmd_init() install_element(CONFIG_NODE, &debug_msdp_packets_cmd); install_element(CONFIG_NODE, &no_debug_msdp_packets_cmd); install_element(CONFIG_NODE, &undebug_msdp_packets_cmd); + install_element(CONFIG_NODE, &ip_msdp_mesh_group_member_cmd); + install_element(VRF_NODE, &ip_msdp_mesh_group_member_cmd); install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_member_cmd); + install_element(VRF_NODE, &no_ip_msdp_mesh_group_member_cmd); install_element(CONFIG_NODE, &ip_msdp_mesh_group_source_cmd); + install_element(VRF_NODE, &ip_msdp_mesh_group_source_cmd); install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_source_cmd); + install_element(VRF_NODE, &no_ip_msdp_mesh_group_source_cmd); install_element(VIEW_NODE, &show_ip_msdp_peer_detail_cmd); + install_element(VIEW_NODE, &show_ip_msdp_peer_detail_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_msdp_sa_detail_cmd); + install_element(VIEW_NODE, &show_ip_msdp_sa_detail_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_msdp_sa_sg_cmd); install_element(VIEW_NODE, &show_ip_msdp_mesh_group_cmd); + install_element(VIEW_NODE, &show_ip_msdp_mesh_group_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_pim_ssm_range_cmd); install_element(VIEW_NODE, &show_ip_pim_group_type_cmd); install_element(INTERFACE_NODE, &interface_pim_use_source_cmd); diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h index 64751d8682..8867514876 100644 --- a/pimd/pim_cmd.h +++ b/pimd/pim_cmd.h @@ -66,4 +66,13 @@ void pim_cmd_init(void); +/* + * Special Macro to allow us to get the correct pim_instance; + */ +#define PIM_DECLVAR_CONTEXT(A, B) \ + struct vrf *A = VTY_GET_CONTEXT(vrf); \ + struct pim_instance *B = \ + (vrf) ? vrf->info : pim_get_pim_instance(VRF_DEFAULT); \ + vrf = (vrf) ? vrf : pim->vrf; + #endif /* PIM_CMD_H */ diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c index 2592514f38..138a110d3a 100644 --- a/pimd/pim_hello.c +++ b/pimd/pim_hello.c @@ -395,7 +395,8 @@ int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, ifp->name); } - pim_upstream_rpf_genid_changed(neigh->source_addr); + pim_upstream_rpf_genid_changed(pim_ifp->pim, + neigh->source_addr); pim_neighbor_delete(ifp, neigh, "GenID mismatch"); neigh = pim_neighbor_add(ifp, src_addr, hello_options, @@ -445,6 +446,8 @@ int pim_hello_build_tlv(struct interface *ifp, uint8_t *tlv_buf, uint8_t *curr = tlv_buf; uint8_t *pastend = tlv_buf + tlv_buf_size; uint8_t *tmp; + struct pim_interface *pim_ifp = ifp->info; + struct pim_instance *pim = pim_ifp->pim; /* * Append options @@ -516,7 +519,7 @@ int pim_hello_build_tlv(struct interface *ifp, uint8_t *tlv_buf, } return -4; } - if (pimg->send_v6_secondary) { + if (pim->send_v6_secondary) { curr = pim_tlv_append_addrlist_ucast( curr, pastend, ifp->connected, AF_INET6); if (!curr) { diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 8201625245..1afcff7cb1 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -29,6 +29,7 @@ #include "hash.h" #include "pimd.h" +#include "pim_instance.h" #include "pim_zebra.h" #include "pim_iface.h" #include "pim_igmp.h" @@ -43,63 +44,87 @@ #include "pim_ssmpingd.h" #include "pim_rp.h" #include "pim_nht.h" - -struct interface *pim_regiface = NULL; -struct list *pim_ifchannel_list = NULL; -static int pim_iface_vif_index[MAXVIFS]; +#include "pim_jp_agg.h" static void pim_if_igmp_join_del_all(struct interface *ifp); static int igmp_join_sock(const char *ifname, ifindex_t ifindex, struct in_addr group_addr, struct in_addr source_addr); -void pim_if_init(void) +void pim_if_init(struct pim_instance *pim) { int i; for (i = 0; i < MAXVIFS; i++) - pim_iface_vif_index[i] = 0; - - pim_ifchannel_list = list_new(); - pim_ifchannel_list->cmp = - (int (*)(void *, void *))pim_ifchannel_compare; + pim->iface_vif_index[i] = 0; } -void pim_if_terminate(void) +void pim_if_terminate(struct pim_instance *pim) { - if (pim_ifchannel_list) - list_free(pim_ifchannel_list); + // Nothing to do at this moment + return; } static void *if_list_clean(struct pim_interface *pim_ifp) { - if (pim_ifp->igmp_join_list) { + struct pim_ifchannel *ch; + + if (pim_ifp->igmp_join_list) list_delete(pim_ifp->igmp_join_list); - } - if (pim_ifp->igmp_socket_list) { + if (pim_ifp->igmp_socket_list) list_delete(pim_ifp->igmp_socket_list); - } - if (pim_ifp->pim_neighbor_list) { + if (pim_ifp->pim_neighbor_list) list_delete(pim_ifp->pim_neighbor_list); - } if (pim_ifp->upstream_switch_list) list_delete(pim_ifp->upstream_switch_list); - if (pim_ifp->pim_ifchannel_list) { - list_delete(pim_ifp->pim_ifchannel_list); - } + if (pim_ifp->sec_addr_list) + list_delete(pim_ifp->sec_addr_list); - if (pim_ifp->pim_ifchannel_hash) - hash_free(pim_ifp->pim_ifchannel_hash); + while ((ch = RB_ROOT(pim_ifchannel_rb, + &pim_ifp->ifchannel_rb)) != NULL) + pim_ifchannel_delete(ch); XFREE(MTYPE_PIM_INTERFACE, pim_ifp); return 0; } +static void pim_sec_addr_free(struct pim_secondary_addr *sec_addr) +{ + XFREE(MTYPE_PIM_SEC_ADDR, sec_addr); +} + +static int pim_sec_addr_comp(const void *p1, const void *p2) +{ + const struct pim_secondary_addr *sec1 = p1; + const struct pim_secondary_addr *sec2 = p2; + + if (sec1->addr.family == AF_INET && sec2->addr.family == AF_INET6) + return -1; + + if (sec1->addr.family == AF_INET6 && sec2->addr.family == AF_INET) + return 1; + + if (sec1->addr.family == AF_INET) { + if (ntohl(sec1->addr.u.prefix4.s_addr) + < ntohl(sec2->addr.u.prefix4.s_addr)) + return -1; + + if (ntohl(sec1->addr.u.prefix4.s_addr) + > ntohl(sec2->addr.u.prefix4.s_addr)) + return 1; + } else { + return memcmp(&sec1->addr.u.prefix6, &sec2->addr.u.prefix6, + sizeof(struct in6_addr)); + } + + return 0; +} + struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim) { struct pim_interface *pim_ifp; @@ -114,6 +139,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim) } pim_ifp->options = 0; + pim_ifp->pim = pim_get_pim_instance(ifp->vrf_id); pim_ifp->mroute_vif_index = -1; pim_ifp->igmp_version = IGMP_DEFAULT_VERSION; @@ -144,15 +170,13 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim) pim_ifp->igmp_socket_list = NULL; pim_ifp->pim_neighbor_list = NULL; pim_ifp->upstream_switch_list = NULL; - pim_ifp->pim_ifchannel_list = NULL; - pim_ifp->pim_ifchannel_hash = NULL; pim_ifp->pim_generation_id = 0; /* list of struct igmp_sock */ pim_ifp->igmp_socket_list = list_new(); if (!pim_ifp->igmp_socket_list) { - zlog_err("%s %s: failure: igmp_socket_list=list_new()", - __FILE__, __PRETTY_FUNCTION__); + zlog_err("%s: failure: igmp_socket_list=list_new()", + __PRETTY_FUNCTION__); return if_list_clean(pim_ifp); } pim_ifp->igmp_socket_list->del = (void (*)(void *))igmp_sock_free; @@ -160,32 +184,32 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim) /* list of struct pim_neighbor */ pim_ifp->pim_neighbor_list = list_new(); if (!pim_ifp->pim_neighbor_list) { - zlog_err("%s %s: failure: pim_neighbor_list=list_new()", - __FILE__, __PRETTY_FUNCTION__); + zlog_err("%s: failure: pim_neighbor_list=list_new()", + __PRETTY_FUNCTION__); return if_list_clean(pim_ifp); } pim_ifp->pim_neighbor_list->del = (void (*)(void *))pim_neighbor_free; pim_ifp->upstream_switch_list = list_new(); if (!pim_ifp->upstream_switch_list) { - zlog_err("%s %s: failure: upstream_switch_list=list_new()", - __FILE__, __PRETTY_FUNCTION__); + zlog_err("%s: failure: upstream_switch_list=list_new()", + __PRETTY_FUNCTION__); return if_list_clean(pim_ifp); } + pim_ifp->upstream_switch_list->del = + (void (*)(void *))pim_jp_agg_group_list_free; + pim_ifp->upstream_switch_list->cmp = pim_jp_agg_group_list_cmp; - /* list of struct pim_ifchannel */ - pim_ifp->pim_ifchannel_list = list_new(); - if (!pim_ifp->pim_ifchannel_list) { - zlog_err("%s %s: failure: pim_ifchannel_list=list_new()", - __FILE__, __PRETTY_FUNCTION__); - return if_list_clean(pim_ifp); + pim_ifp->sec_addr_list = list_new(); + if (!pim_ifp->sec_addr_list) { + zlog_err("%s: failure: secondary addresslist", + __PRETTY_FUNCTION__); } - pim_ifp->pim_ifchannel_list->del = (void (*)(void *))pim_ifchannel_free; - pim_ifp->pim_ifchannel_list->cmp = - (int (*)(void *, void *))pim_ifchannel_compare; + pim_ifp->sec_addr_list->del = (void (*)(void *))pim_sec_addr_free; + pim_ifp->sec_addr_list->cmp = + (int (*)(void *, void *))pim_sec_addr_comp; - pim_ifp->pim_ifchannel_hash = - hash_create(pim_ifchannel_hash_key, pim_ifchannel_equal, NULL); + RB_INIT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb); ifp->info = pim_ifp; @@ -199,6 +223,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim) void pim_if_delete(struct interface *ifp) { struct pim_interface *pim_ifp; + struct pim_ifchannel *ch; zassert(ifp); pim_ifp = ifp->info; @@ -218,9 +243,11 @@ void pim_if_delete(struct interface *ifp) list_delete(pim_ifp->igmp_socket_list); list_delete(pim_ifp->pim_neighbor_list); list_delete(pim_ifp->upstream_switch_list); - list_delete(pim_ifp->pim_ifchannel_list); + list_delete(pim_ifp->sec_addr_list); - hash_free(pim_ifp->pim_ifchannel_hash); + while ((ch = RB_ROOT(pim_ifchannel_rb, + &pim_ifp->ifchannel_rb)) != NULL) + pim_ifchannel_delete(ch); XFREE(MTYPE_PIM_INTERFACE, pim_ifp); @@ -230,15 +257,12 @@ void pim_if_delete(struct interface *ifp) void pim_if_update_could_assert(struct interface *ifp) { struct pim_interface *pim_ifp; - struct listnode *node; - struct listnode *next_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; zassert(pim_ifp); - for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, - ch)) { + RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) { pim_ifchannel_update_could_assert(ch); } } @@ -246,15 +270,12 @@ void pim_if_update_could_assert(struct interface *ifp) static void pim_if_update_my_assert_metric(struct interface *ifp) { struct pim_interface *pim_ifp; - struct listnode *node; - struct listnode *next_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; zassert(pim_ifp); - for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, - ch)) { + RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) { pim_ifchannel_update_my_assert_metric(ch); } } @@ -331,48 +352,12 @@ static int detect_primary_address_change(struct interface *ifp, return changed; } -static int pim_sec_addr_comp(const void *p1, const void *p2) -{ - const struct pim_secondary_addr *sec1 = p1; - const struct pim_secondary_addr *sec2 = p2; - - if (sec1->addr.family == AF_INET && sec2->addr.family == AF_INET6) - return -1; - - if (sec1->addr.family == AF_INET6 && sec2->addr.family == AF_INET) - return 1; - - if (sec1->addr.family == AF_INET) { - if (ntohl(sec1->addr.u.prefix4.s_addr) - < ntohl(sec2->addr.u.prefix4.s_addr)) - return -1; - - if (ntohl(sec1->addr.u.prefix4.s_addr) - > ntohl(sec2->addr.u.prefix4.s_addr)) - return 1; - } else { - return memcmp(&sec1->addr.u.prefix6, &sec2->addr.u.prefix6, - sizeof(struct in6_addr)); - } - - return 0; -} - -static void pim_sec_addr_free(struct pim_secondary_addr *sec_addr) -{ - XFREE(MTYPE_PIM_SEC_ADDR, sec_addr); -} - static struct pim_secondary_addr * pim_sec_addr_find(struct pim_interface *pim_ifp, struct prefix *addr) { struct pim_secondary_addr *sec_addr; struct listnode *node; - if (!pim_ifp->sec_addr_list) { - return NULL; - } - for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) { if (prefix_cmp(&sec_addr->addr, addr)) { return sec_addr; @@ -400,22 +385,9 @@ static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct prefix *addr) return changed; } - if (!pim_ifp->sec_addr_list) { - pim_ifp->sec_addr_list = list_new(); - pim_ifp->sec_addr_list->del = - (void (*)(void *))pim_sec_addr_free; - pim_ifp->sec_addr_list->cmp = - (int (*)(void *, void *))pim_sec_addr_comp; - } - sec_addr = XCALLOC(MTYPE_PIM_SEC_ADDR, sizeof(*sec_addr)); - if (!sec_addr) { - if (list_isempty(pim_ifp->sec_addr_list)) { - list_free(pim_ifp->sec_addr_list); - pim_ifp->sec_addr_list = NULL; - } + if (!sec_addr) return changed; - } changed = 1; sec_addr->addr = *addr; @@ -428,15 +400,10 @@ static int pim_sec_addr_del_all(struct pim_interface *pim_ifp) { int changed = 0; - if (!pim_ifp->sec_addr_list) { - return changed; - } if (!list_isempty(pim_ifp->sec_addr_list)) { changed = 1; /* remove all nodes and free up the list itself */ list_delete_all_node(pim_ifp->sec_addr_list); - list_free(pim_ifp->sec_addr_list); - pim_ifp->sec_addr_list = NULL; } return changed; @@ -451,11 +418,9 @@ static int pim_sec_addr_update(struct interface *ifp) struct pim_secondary_addr *sec_addr; int changed = 0; - if (pim_ifp->sec_addr_list) { - for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, - sec_addr)) { - sec_addr->flags |= PIM_SEC_ADDRF_STALE; - } + for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, + sec_addr)) { + sec_addr->flags |= PIM_SEC_ADDRF_STALE; } for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { @@ -476,20 +441,12 @@ static int pim_sec_addr_update(struct interface *ifp) } } - if (pim_ifp->sec_addr_list) { - /* Drop stale entries */ - for (ALL_LIST_ELEMENTS(pim_ifp->sec_addr_list, node, nextnode, - sec_addr)) { - if (sec_addr->flags & PIM_SEC_ADDRF_STALE) { - pim_sec_addr_del(pim_ifp, sec_addr); - changed = 1; - } - } - - /* If the list went empty free it up */ - if (list_isempty(pim_ifp->sec_addr_list)) { - list_free(pim_ifp->sec_addr_list); - pim_ifp->sec_addr_list = NULL; + /* Drop stale entries */ + for (ALL_LIST_ELEMENTS(pim_ifp->sec_addr_list, node, nextnode, + sec_addr)) { + if (sec_addr->flags & PIM_SEC_ADDRF_STALE) { + pim_sec_addr_del(pim_ifp, sec_addr); + changed = 1; } } @@ -596,8 +553,8 @@ void pim_if_addr_add(struct connected *ifc) detect_address_change(ifp, 0, __PRETTY_FUNCTION__); - if (ifc->address->family != AF_INET) - return; + // if (ifc->address->family != AF_INET) + // return; if (PIM_IF_TEST_IGMP(pim_ifp->options)) { struct igmp_sock *igmp; @@ -607,8 +564,9 @@ void pim_if_addr_add(struct connected *ifc) ifaddr); if (!igmp) { /* if addr new, add IGMP socket */ - pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, - ifp); + if (ifc->address->family == AF_INET) + pim_igmp_sock_add(pim_ifp->igmp_socket_list, + ifaddr, ifp); } /* Replay Static IGMP groups */ @@ -675,9 +633,10 @@ void pim_if_addr_add(struct connected *ifc) rpf.rpf_addr.family = AF_INET; rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN; rpf.rpf_addr.u.prefix4 = ifc->address->u.prefix4; - pnc = pim_nexthop_cache_find(&rpf); + pnc = pim_nexthop_cache_find(pim_ifp->pim, &rpf); if (pnc) - pim_sendmsg_zebra_rnh(zclient, pnc, + pim_sendmsg_zebra_rnh(pim_ifp->pim, zclient, + pnc, ZEBRA_NEXTHOP_REGISTER); } } /* pim */ @@ -758,9 +717,6 @@ void pim_if_addr_del(struct connected *ifc, int force_prim_as_any) ifp = ifc->ifp; zassert(ifp); - if (ifc->address->family != AF_INET) - return; - if (PIM_DEBUG_ZEBRA) { char buf[BUFSIZ]; prefix2str(ifc->address, buf, BUFSIZ); @@ -827,7 +783,7 @@ void pim_if_addr_add_all(struct interface *ifp) } pim_ifchannel_scan_forward_start(ifp); - pim_rp_setup(); + pim_rp_setup(pim_ifp->pim); pim_rp_check_on_if_add(pim_ifp); } @@ -836,6 +792,8 @@ void pim_if_addr_del_all(struct interface *ifp) struct connected *ifc; struct listnode *node; struct listnode *nextnode; + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + struct pim_instance *pim = vrf->info; /* PIM/IGMP enabled ? */ if (!ifp->info) @@ -850,8 +808,8 @@ void pim_if_addr_del_all(struct interface *ifp) pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */); } - pim_rp_setup(); - pim_i_am_rp_re_evaluate(); + pim_rp_setup(pim); + pim_i_am_rp_re_evaluate(pim); } void pim_if_addr_del_all_igmp(struct interface *ifp) @@ -902,6 +860,7 @@ struct in_addr pim_find_primary_addr(struct interface *ifp) int v4_addrs = 0; int v6_addrs = 0; struct pim_interface *pim_ifp = ifp->info; + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); if (pim_ifp && PIM_INADDR_ISNOT_ANY(pim_ifp->update_source)) { return pim_ifp->update_source; @@ -938,7 +897,12 @@ struct in_addr pim_find_primary_addr(struct interface *ifp) */ if (!v4_addrs && v6_addrs && !if_is_loopback(ifp)) { struct interface *lo_ifp; - lo_ifp = if_lookup_by_name("lo", VRF_DEFAULT); + // DBS - Come back and check here + if (ifp->vrf_id == VRF_DEFAULT) + lo_ifp = if_lookup_by_name("lo", vrf->vrf_id); + else + lo_ifp = if_lookup_by_name(vrf->name, vrf->vrf_id); + if (lo_ifp) return pim_find_primary_addr(lo_ifp); } @@ -950,7 +914,10 @@ struct in_addr pim_find_primary_addr(struct interface *ifp) static int pim_iface_next_vif_index(struct interface *ifp) { + struct pim_interface *pim_ifp = ifp->info; + struct pim_instance *pim = pim_ifp->pim; int i; + /* * The pimreg vif is always going to be in index 0 * of the table. @@ -959,7 +926,7 @@ static int pim_iface_next_vif_index(struct interface *ifp) return 0; for (i = 1; i < MAXVIFS; i++) { - if (pim_iface_vif_index[i] == 0) + if (pim->iface_vif_index[i] == 0) return i; } return MAXVIFS; @@ -1021,7 +988,7 @@ int pim_if_add_vif(struct interface *ifp) return -5; } - pim_iface_vif_index[pim_ifp->mroute_vif_index] = 1; + pim_ifp->pim->iface_vif_index[pim_ifp->mroute_vif_index] = 1; return 0; } @@ -1036,57 +1003,26 @@ int pim_if_del_vif(struct interface *ifp) return -1; } - pim_mroute_del_vif(pim_ifp->mroute_vif_index); + pim_mroute_del_vif(ifp); /* Update vif_index */ - pim_iface_vif_index[pim_ifp->mroute_vif_index] = 0; + pim_ifp->pim->iface_vif_index[pim_ifp->mroute_vif_index] = 0; pim_ifp->mroute_vif_index = -1; return 0; } -void pim_if_add_vif_all() -{ - struct listnode *ifnode; - struct listnode *ifnextnode; - struct interface *ifp; - - for (ALL_LIST_ELEMENTS(vrf_iflist(VRF_DEFAULT), ifnode, ifnextnode, - ifp)) { - if (!ifp->info) - continue; - - pim_if_add_vif(ifp); - } -} - -void pim_if_del_vif_all() +// DBS - VRF Revist +struct interface *pim_if_find_by_vif_index(struct pim_instance *pim, + ifindex_t vif_index) { struct listnode *ifnode; - struct listnode *ifnextnode; struct interface *ifp; - for (ALL_LIST_ELEMENTS(vrf_iflist(VRF_DEFAULT), ifnode, ifnextnode, - ifp)) { - if (!ifp->info) - continue; - - pim_if_del_vif(ifp); - } -} - -struct interface *pim_if_find_by_vif_index(ifindex_t vif_index) -{ - struct listnode *ifnode; - struct interface *ifp; - - if (vif_index == 0) - return if_lookup_by_name("pimreg", VRF_DEFAULT); - - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode, ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode, ifp)) { if (ifp->info) { struct pim_interface *pim_ifp; pim_ifp = ifp->info; @@ -1102,12 +1038,12 @@ struct interface *pim_if_find_by_vif_index(ifindex_t vif_index) /* pim_if_add_vif() uses ifindex as vif_index */ -int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex) +int pim_if_find_vifindex_by_ifindex(struct pim_instance *pim, ifindex_t ifindex) { struct pim_interface *pim_ifp; struct interface *ifp; - ifp = if_lookup_by_index(ifindex, VRF_DEFAULT); + ifp = if_lookup_by_index(ifindex, pim->vrf_id); if (!ifp || !ifp->info) return -1; pim_ifp = ifp->info; @@ -1496,15 +1432,12 @@ void pim_if_assert_on_neighbor_down(struct interface *ifp, struct in_addr neigh_addr) { struct pim_interface *pim_ifp; - struct listnode *node; - struct listnode *next_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; zassert(pim_ifp); - for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, - ch)) { + RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) { /* Is (S,G,I) assert loser ? */ if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER) continue; @@ -1518,24 +1451,23 @@ void pim_if_assert_on_neighbor_down(struct interface *ifp, void pim_if_update_join_desired(struct pim_interface *pim_ifp) { - struct listnode *ch_node; struct pim_ifchannel *ch; /* clear off flag from interface's upstreams */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { + RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) { PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED( ch->upstream->flags); } /* scan per-interface (S,G,I) state on this I interface */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { + RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) { struct pim_upstream *up = ch->upstream; if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up->flags)) continue; /* update join_desired for the global (S,G) state */ - pim_upstream_update_join_desired(up); + pim_upstream_update_join_desired(pim_ifp->pim, up); PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up->flags); } } @@ -1543,16 +1475,13 @@ void pim_if_update_join_desired(struct pim_interface *pim_ifp) void pim_if_update_assert_tracking_desired(struct interface *ifp) { struct pim_interface *pim_ifp; - struct listnode *node; - struct listnode *next_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; if (!pim_ifp) return; - for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, - ch)) { + RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) { pim_ifchannel_update_assert_tracking_desired(ch); } } @@ -1562,14 +1491,22 @@ void pim_if_update_assert_tracking_desired(struct interface *ifp) * The pimreg is a special interface that we have that is not * quite an inteface but a VIF is created for it. */ -void pim_if_create_pimreg(void) +void pim_if_create_pimreg(struct pim_instance *pim) { - if (!pim_regiface) { - pim_regiface = - if_create("pimreg", strlen("pimreg"), VRF_DEFAULT); - pim_regiface->ifindex = PIM_OIF_PIM_REGISTER_VIF; + char pimreg_name[100]; + + if (!pim->regiface) { + if (pim->vrf_id == VRF_DEFAULT) + strcpy(pimreg_name, "pimreg"); + else + sprintf(pimreg_name, "pimreg%d", + pim->vrf->data.l.table_id); - pim_if_new(pim_regiface, 0, 0); + pim->regiface = if_create(pimreg_name, strlen(pimreg_name), + pim->vrf_id); + pim->regiface->ifindex = PIM_OIF_PIM_REGISTER_VIF; + + pim_if_new(pim->regiface, 0, 0); } } @@ -1596,14 +1533,38 @@ int pim_if_connected_to_source(struct interface *ifp, struct in_addr src) return 0; } -struct interface *pim_if_lookup_address_vrf(struct in_addr src, vrf_id_t vrf_id) +int pim_if_is_loopback(struct pim_instance *pim, struct interface *ifp) { - struct listnode *ifnode; - struct interface *ifp; + if (if_is_loopback(ifp)) + return 1; - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(vrf_id), ifnode, ifp)) { - if (pim_if_connected_to_source(ifp, src) && ifp->info) - return ifp; + if (strcmp(ifp->name, pim->vrf->name) == 0) + return 1; + + return 0; +} + +int pim_if_is_vrf_device(struct interface *ifp) +{ + struct vrf *vrf; + + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + if (strncmp(ifp->name, vrf->name, strlen(ifp->name)) == 0) + return 1; } - return NULL; + + return 0; +} + +int pim_if_ifchannel_count(struct pim_interface *pim_ifp) +{ + struct pim_ifchannel *ch; + int count = 0; + + RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) { + count++; + } + + return count; } diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index e742e68f67..ed885ff0e3 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -73,6 +73,8 @@ struct pim_secondary_addr { struct pim_interface { uint32_t options; /* bit vector */ ifindex_t mroute_vif_index; + struct pim_instance *pim; + struct in_addr primary_address; /* remember addr to detect change */ struct list *sec_addr_list; /* list of struct pim_secondary_addr */ struct in_addr update_source; /* user can statically set the primary @@ -104,8 +106,7 @@ struct pim_interface { uint16_t pim_override_interval_msec; /* config */ struct list *pim_neighbor_list; /* list of struct pim_neighbor */ struct list *upstream_switch_list; - struct list *pim_ifchannel_list; /* list of struct pim_ifchannel */ - struct hash *pim_ifchannel_hash; + struct pim_ifchannel_rb ifchannel_rb; /* neighbors without lan_delay */ int pim_number_of_nonlandelay_neighbors; @@ -138,8 +139,6 @@ struct pim_interface { struct bfd_info *bfd_info; }; -extern struct interface *pim_regiface; -extern struct list *pim_ifchannel_list; /* if default_holdtime is set (>= 0), use it; otherwise default_holdtime is 3.5 * hello_period @@ -149,8 +148,8 @@ extern struct list *pim_ifchannel_list; ? ((pim_ifp)->pim_hello_period * 7 / 2) \ : ((pim_ifp)->pim_default_holdtime)) -void pim_if_init(void); -void pim_if_terminate(void); +void pim_if_init(struct pim_instance *pim); +void pim_if_terminate(struct pim_instance *pim); struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim); void pim_if_delete(struct interface *ifp); @@ -161,16 +160,15 @@ void pim_if_addr_del_all(struct interface *ifp); void pim_if_addr_del_all_igmp(struct interface *ifp); void pim_if_addr_del_all_pim(struct interface *ifp); -struct interface *pim_if_lookup_address_vrf(struct in_addr src, - vrf_id_t vrf_id); - int pim_if_add_vif(struct interface *ifp); int pim_if_del_vif(struct interface *ifp); -void pim_if_add_vif_all(void); -void pim_if_del_vif_all(void); +void pim_if_add_vif_all(struct pim_instance *pim); +void pim_if_del_vif_all(struct pim_instance *pim); -struct interface *pim_if_find_by_vif_index(ifindex_t vif_index); -int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex); +struct interface *pim_if_find_by_vif_index(struct pim_instance *pim, + ifindex_t vif_index); +int pim_if_find_vifindex_by_ifindex(struct pim_instance *pim, + ifindex_t ifindex); int pim_if_lan_delay_enabled(struct interface *ifp); uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp); @@ -201,9 +199,14 @@ void pim_if_update_join_desired(struct pim_interface *pim_ifp); void pim_if_update_assert_tracking_desired(struct interface *ifp); -void pim_if_create_pimreg(void); +void pim_if_create_pimreg(struct pim_instance *pim); int pim_if_connected_to_source(struct interface *ifp, struct in_addr src); int pim_update_source_set(struct interface *ifp, struct in_addr source); +int pim_if_is_loopback(struct pim_instance *pim, struct interface *ifp); + +int pim_if_is_vrf_device(struct interface *ifp); + +int pim_if_ifchannel_count(struct pim_interface *pim_ifp); #endif /* PIM_IFACE_H */ diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index d4916518e7..c91efbd8b6 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -43,7 +43,11 @@ #include "pim_upstream.h" #include "pim_ssm.h" -int pim_ifchannel_compare(struct pim_ifchannel *ch1, struct pim_ifchannel *ch2) +RB_GENERATE(pim_ifchannel_rb, pim_ifchannel, + pim_ifp_rb, pim_ifchannel_compare); + +int pim_ifchannel_compare(const struct pim_ifchannel *ch1, + const struct pim_ifchannel *ch2) { struct pim_interface *pim_ifp1; struct pim_interface *pim_ifp2; @@ -100,7 +104,6 @@ static void pim_ifchannel_find_new_children(struct pim_ifchannel *ch) { struct pim_interface *pim_ifp = ch->interface->info; struct pim_ifchannel *child; - struct listnode *ch_node; // Basic Sanity that we are not being silly if ((ch->sg.src.s_addr != INADDR_ANY) @@ -111,8 +114,7 @@ static void pim_ifchannel_find_new_children(struct pim_ifchannel *ch) && (ch->sg.grp.s_addr == INADDR_ANY)) return; - for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, - child)) { + RB_FOREACH(child, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) { if ((ch->sg.grp.s_addr != INADDR_ANY) && (child->sg.grp.s_addr == ch->sg.grp.s_addr) && (child != ch)) { @@ -171,14 +173,14 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch) listnode_delete(ch->upstream->ifchannels, ch); if (ch->ifjoin_state != PIM_IFJOIN_NOINFO) { - pim_upstream_update_join_desired(ch->upstream); + pim_upstream_update_join_desired(pim_ifp->pim, ch->upstream); } /* upstream is common across ifchannels, check if upstream's ifchannel list is empty before deleting upstream_del ref count will take care of it. */ - pim_upstream_del(ch->upstream, __PRETTY_FUNCTION__); + pim_upstream_del(pim_ifp->pim, ch->upstream, __PRETTY_FUNCTION__); ch->upstream = NULL; THREAD_OFF(ch->t_ifjoin_expiry_timer); @@ -189,14 +191,8 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch) listnode_delete(ch->parent->sources, ch); ch->parent = NULL; } - /* - notice that listnode_delete() can't be moved - into pim_ifchannel_free() because the later is - called by list_delete_all_node() - */ - listnode_delete(pim_ifp->pim_ifchannel_list, ch); - hash_release(pim_ifp->pim_ifchannel_hash, ch); - listnode_delete(pim_ifchannel_list, ch); + + RB_REMOVE(pim_ifchannel_rb, &pim_ifp->ifchannel_rb, ch); if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: ifchannel entry %s is deleted ", @@ -208,17 +204,15 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch) void pim_ifchannel_delete_all(struct interface *ifp) { struct pim_interface *pim_ifp; - struct listnode *ifchannel_node; - struct listnode *ifchannel_nextnode; - struct pim_ifchannel *ifchannel; + struct pim_ifchannel *ch; pim_ifp = ifp->info; if (!pim_ifp) return; - for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, ifchannel_node, - ifchannel_nextnode, ifchannel)) { - pim_ifchannel_delete(ifchannel); + while ((ch = RB_ROOT(pim_ifchannel_rb, + &pim_ifp->ifchannel_rb)) != NULL) { + pim_ifchannel_delete(ch); } } @@ -234,6 +228,7 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch, enum pim_ifjoin_state new_state) { enum pim_ifjoin_state old_state = ch->ifjoin_state; + struct pim_interface *pim_ifp = ch->interface->info; if (PIM_DEBUG_PIM_EVENTS) zlog_debug( @@ -266,8 +261,6 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch, child)) { struct channel_oil *c_oil = child->channel_oil; - struct pim_interface *pim_ifp = - ch->interface->info; if (PIM_DEBUG_PIM_TRACE) zlog_debug( @@ -280,12 +273,12 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch, continue; if (!pim_upstream_evaluate_join_desired( - child)) { + pim_ifp->pim, child)) { pim_channel_del_oif( c_oil, ch->interface, PIM_OIF_FLAG_PROTO_STAR); pim_upstream_update_join_desired( - child); + pim_ifp->pim, child); } /* @@ -296,9 +289,8 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch, * if channel. So remove it. * I think this is dead code now. is it? */ - if (!ch - && c_oil->oil.mfcc_ttls - [pim_ifp->mroute_vif_index]) + if (c_oil->oil.mfcc_ttls + [pim_ifp->mroute_vif_index]) pim_channel_del_oif( c_oil, ch->interface, PIM_OIF_FLAG_PROTO_STAR); @@ -316,13 +308,13 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch, up->sg_str); if (pim_upstream_evaluate_join_desired( - child)) { + pim_ifp->pim, child)) { pim_channel_add_oif( child->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_STAR); pim_upstream_update_join_desired( - child); + pim_ifp->pim, child); } } } @@ -344,7 +336,7 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch, */ ch->ifjoin_creation = pim_time_monotonic_sec(); - pim_upstream_update_join_desired(ch->upstream); + pim_upstream_update_join_desired(pim_ifp->pim, ch->upstream); pim_ifchannel_update_could_assert(ch); pim_ifchannel_update_assert_tracking_desired(ch); } @@ -426,7 +418,8 @@ struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, } lookup.sg = *sg; - ch = hash_lookup(pim_ifp->pim_ifchannel_hash, &lookup); + lookup.interface = ifp; + ch = RB_FIND(pim_ifchannel_rb, &pim_ifp->ifchannel_rb, &lookup); return ch; } @@ -434,6 +427,8 @@ struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, static void ifmembership_set(struct pim_ifchannel *ch, enum pim_ifmembership membership) { + struct pim_interface *pim_ifp = ch->interface->info; + if (ch->local_ifmembership == membership) return; @@ -447,7 +442,7 @@ static void ifmembership_set(struct pim_ifchannel *ch, ch->local_ifmembership = membership; - pim_upstream_update_join_desired(ch->upstream); + pim_upstream_update_join_desired(pim_ifp->pim, ch->upstream); pim_ifchannel_update_could_assert(ch); pim_ifchannel_update_assert_tracking_desired(ch); } @@ -456,31 +451,25 @@ static void ifmembership_set(struct pim_ifchannel *ch, void pim_ifchannel_membership_clear(struct interface *ifp) { struct pim_interface *pim_ifp; - struct listnode *ch_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; zassert(pim_ifp); - for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { + RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO); - } } void pim_ifchannel_delete_on_noinfo(struct interface *ifp) { struct pim_interface *pim_ifp; - struct listnode *node; - struct listnode *next_node; - struct pim_ifchannel *ch; + struct pim_ifchannel *ch, *ch_tmp; pim_ifp = ifp->info; zassert(pim_ifp); - for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, - ch)) { + RB_FOREACH_SAFE(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb, ch_tmp) delete_on_noinfo(ch); - } } /* @@ -509,7 +498,8 @@ static struct pim_ifchannel *pim_ifchannel_find_parent(struct pim_ifchannel *ch) } struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, - struct prefix_sg *sg, int flags) + struct prefix_sg *sg, + uint8_t source_flags, int up_flags) { struct pim_interface *pim_ifp; struct pim_ifchannel *ch; @@ -521,26 +511,19 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, pim_ifp = ifp->info; - up = pim_upstream_add(sg, NULL, flags, __PRETTY_FUNCTION__); - if (!up) { - zlog_err( - "%s: could not attach upstream (S,G)=%s on interface %s", - __PRETTY_FUNCTION__, pim_str_sg_dump(sg), ifp->name); - return NULL; - } - ch = XCALLOC(MTYPE_PIM_IFCHANNEL, sizeof(*ch)); if (!ch) { zlog_warn( "%s: pim_ifchannel_new() failure for (S,G)=%s on interface %s", - __PRETTY_FUNCTION__, up->sg_str, ifp->name); - - pim_upstream_del(up, __PRETTY_FUNCTION__); + __PRETTY_FUNCTION__, pim_str_sg_dump(sg), ifp->name); return NULL; } ch->flags = 0; - ch->upstream = up; + if ((source_flags & PIM_ENCODE_RPT_BIT) + && !(source_flags & PIM_ENCODE_WC_BIT)) + PIM_IF_FLAG_SET_S_G_RPT(ch->flags); + ch->interface = ifp; ch->sg = *sg; pim_str_sg_set(sg, ch->sg_str); @@ -560,6 +543,32 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, ch->t_ifjoin_prune_pending_timer = NULL; ch->ifjoin_creation = 0; + RB_INSERT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb, ch); + + up = pim_upstream_add(pim_ifp->pim, sg, NULL, up_flags, + __PRETTY_FUNCTION__, ch); + + if (!up) { + zlog_err( + "%s: could not attach upstream (S,G)=%s on interface %s", + __PRETTY_FUNCTION__, pim_str_sg_dump(sg), ifp->name); + + pim_ifchannel_remove_children(ch); + if (ch->sources) + list_delete(ch->sources); + + THREAD_OFF(ch->t_ifjoin_expiry_timer); + THREAD_OFF(ch->t_ifjoin_prune_pending_timer); + THREAD_OFF(ch->t_ifassert_timer); + + RB_REMOVE(pim_ifchannel_rb, &pim_ifp->ifchannel_rb, ch); + XFREE(MTYPE_PIM_IFCHANNEL, ch); + return NULL; + } + ch->upstream = up; + + listnode_add_sort(up->ifchannels, ch); + ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch); ch->ifassert_winner_metric = pim_macro_ch_my_assert_metric_eval(ch); @@ -579,13 +588,6 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, else PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags); - /* Attach to list */ - listnode_add_sort(pim_ifp->pim_ifchannel_list, ch); - ch = hash_get(pim_ifp->pim_ifchannel_hash, ch, hash_alloc_intern); - listnode_add_sort(pim_ifchannel_list, ch); - - listnode_add_sort(up->ifchannels, ch); - if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: ifchannel %s is created ", __PRETTY_FUNCTION__, ch->sg_str); @@ -595,7 +597,7 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, static void ifjoin_to_noinfo(struct pim_ifchannel *ch, bool ch_del) { - pim_forward_stop(ch); + pim_forward_stop(ch, !ch_del); pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_NOINFO); if (ch_del) delete_on_noinfo(ch); @@ -640,7 +642,8 @@ static int on_ifjoin_prune_pending_timer(struct thread *t) */ if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)) { if (ch->upstream) - pim_upstream_update_join_desired(ch->upstream); + pim_upstream_update_join_desired(pim_ifp->pim, + ch->upstream); /* ch->ifjoin_state transition to NOINFO state ch_del is set to 0 for not deleteing from here. @@ -665,9 +668,10 @@ static void check_recv_upstream(int is_join, struct interface *recv_ifp, uint8_t source_flags, int holdtime) { struct pim_upstream *up; + struct pim_interface *pim_ifp = recv_ifp->info; /* Upstream (S,G) in Joined state ? */ - up = pim_upstream_find(sg); + up = pim_upstream_find(pim_ifp->pim, sg); if (!up) return; if (up->join_state != PIM_UPSTREAM_JOINED) @@ -769,7 +773,8 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, return; } - ch = pim_ifchannel_add(ifp, sg, PIM_UPSTREAM_FLAG_MASK_SRC_PIM); + ch = pim_ifchannel_add(ifp, sg, source_flags, + PIM_UPSTREAM_FLAG_MASK_SRC_PIM); if (!ch) return; @@ -808,7 +813,8 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_JOIN); if (pim_macro_chisin_oiflist(ch)) { - pim_upstream_inherited_olist(ch->upstream); + pim_upstream_inherited_olist(pim_ifp->pim, + ch->upstream); pim_forward_start(ch); } /* @@ -822,7 +828,7 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, PIM_UPSTREAM_FLAG_MASK_SRC_LHR, __PRETTY_FUNCTION__); pim_upstream_keep_alive_timer_start( - ch->upstream, qpim_keep_alive_time); + ch->upstream, pim_ifp->pim->keep_alive_time); } break; case PIM_IFJOIN_JOIN: @@ -910,7 +916,8 @@ void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream, return; } - ch = pim_ifchannel_add(ifp, sg, PIM_UPSTREAM_FLAG_MASK_SRC_PIM); + ch = pim_ifchannel_add(ifp, sg, source_flags, + PIM_UPSTREAM_FLAG_MASK_SRC_PIM); if (!ch) return; @@ -942,7 +949,8 @@ void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream, &ch->t_ifjoin_prune_pending_timer); thread_add_timer(master, on_ifjoin_expiry_timer, ch, holdtime, &ch->t_ifjoin_expiry_timer); - pim_upstream_update_join_desired(ch->upstream); + pim_upstream_update_join_desired(pim_ifp->pim, + ch->upstream); } break; case PIM_IFJOIN_PRUNE_PENDING: @@ -999,6 +1007,7 @@ int pim_ifchannel_local_membership_add(struct interface *ifp, { struct pim_ifchannel *ch, *starch; struct pim_interface *pim_ifp; + struct pim_instance *pim; /* PIM enabled on interface? */ pim_ifp = ifp->info; @@ -1007,9 +1016,11 @@ int pim_ifchannel_local_membership_add(struct interface *ifp, if (!PIM_IF_TEST_PIM(pim_ifp->options)) return 0; + pim = pim_ifp->pim; + /* skip (*,G) ch creation if G is of type SSM */ if (sg->src.s_addr == INADDR_ANY) { - if (pim_is_grp_ssm(sg->grp)) { + if (pim_is_grp_ssm(pim, sg->grp)) { if (PIM_DEBUG_PIM_EVENTS) zlog_debug( "%s: local membership (S,G)=%s ignored as group is SSM", @@ -1019,7 +1030,7 @@ int pim_ifchannel_local_membership_add(struct interface *ifp, } } - ch = pim_ifchannel_add(ifp, sg, PIM_UPSTREAM_FLAG_MASK_SRC_IGMP); + ch = pim_ifchannel_add(ifp, sg, 0, PIM_UPSTREAM_FLAG_MASK_SRC_IGMP); if (!ch) { return 0; } @@ -1027,7 +1038,7 @@ int pim_ifchannel_local_membership_add(struct interface *ifp, ifmembership_set(ch, PIM_IFMEMBERSHIP_INCLUDE); if (sg->src.s_addr == INADDR_ANY) { - struct pim_upstream *up = pim_upstream_find(sg); + struct pim_upstream *up = pim_upstream_find(pim, sg); struct pim_upstream *child; struct listnode *up_node; @@ -1045,14 +1056,15 @@ int pim_ifchannel_local_membership_add(struct interface *ifp, child, ch, starch)) { pim_channel_add_oif(child->channel_oil, ifp, PIM_OIF_FLAG_PROTO_STAR); - pim_upstream_switch(child, PIM_UPSTREAM_JOINED); + pim_upstream_switch(pim, child, + PIM_UPSTREAM_JOINED); } } - if (pimg->spt.switchover == PIM_SPT_INFINITY) { - if (pimg->spt.plist) { + if (pim->spt.switchover == PIM_SPT_INFINITY) { + if (pim->spt.plist) { struct prefix_list *plist = prefix_list_lookup( - AFI_IP, pimg->spt.plist); + AFI_IP, pim->spt.plist); struct prefix g; g.family = AF_INET; g.prefixlen = IPV4_MAX_PREFIXLEN; @@ -1061,12 +1073,12 @@ int pim_ifchannel_local_membership_add(struct interface *ifp, if (prefix_list_apply(plist, &g) == PREFIX_DENY) { pim_channel_add_oif( - up->channel_oil, pim_regiface, + up->channel_oil, pim->regiface, PIM_OIF_FLAG_PROTO_IGMP); } } } else - pim_channel_add_oif(up->channel_oil, pim_regiface, + pim_channel_add_oif(up->channel_oil, pim->regiface, PIM_OIF_FLAG_PROTO_IGMP); } @@ -1093,7 +1105,7 @@ void pim_ifchannel_local_membership_del(struct interface *ifp, ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO); if (sg->src.s_addr == INADDR_ANY) { - struct pim_upstream *up = pim_upstream_find(sg); + struct pim_upstream *up = pim_upstream_find(pim_ifp->pim, sg); struct pim_upstream *child; struct listnode *up_node, *up_nnode; @@ -1261,13 +1273,13 @@ void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch) */ void pim_ifchannel_scan_forward_start(struct interface *new_ifp) { + struct pim_interface *new_pim_ifp = new_ifp->info; + struct pim_instance *pim = new_pim_ifp->pim; struct listnode *ifnode; struct interface *ifp; - struct pim_interface *new_pim_ifp = new_ifp->info; - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode, ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode, ifp)) { struct pim_interface *loop_pim_ifp = ifp->info; - struct listnode *ch_node; struct pim_ifchannel *ch; if (!loop_pim_ifp) @@ -1276,8 +1288,7 @@ void pim_ifchannel_scan_forward_start(struct interface *new_ifp) if (new_pim_ifp == loop_pim_ifp) continue; - for (ALL_LIST_ELEMENTS_RO(loop_pim_ifp->pim_ifchannel_list, - ch_node, ch)) { + RB_FOREACH(ch, pim_ifchannel_rb, &loop_pim_ifp->ifchannel_rb) { if (ch->ifjoin_state == PIM_IFJOIN_JOIN) { struct pim_upstream *up = ch->upstream; if ((!up->channel_oil) @@ -1370,15 +1381,3 @@ unsigned int pim_ifchannel_hash_key(void *arg) return jhash_2words(ch->sg.src.s_addr, ch->sg.grp.s_addr, 0); } - -int pim_ifchannel_equal(const void *arg1, const void *arg2) -{ - const struct pim_ifchannel *ch1 = (const struct pim_ifchannel *)arg1; - const struct pim_ifchannel *ch2 = (const struct pim_ifchannel *)arg2; - - if ((ch1->sg.grp.s_addr == ch2->sg.grp.s_addr) - && (ch1->sg.src.s_addr == ch2->sg.src.s_addr)) - return 1; - - return 0; -} diff --git a/pimd/pim_ifchannel.h b/pimd/pim_ifchannel.h index 2260fd451b..cef431c30d 100644 --- a/pimd/pim_ifchannel.h +++ b/pimd/pim_ifchannel.h @@ -80,6 +80,8 @@ struct pim_assert_metric { Per-interface (S,G) state */ struct pim_ifchannel { + RB_ENTRY(rb_ifchannel) pim_ifp_rb; + struct pim_ifchannel *parent; struct list *sources; struct prefix_sg sg; @@ -108,6 +110,10 @@ struct pim_ifchannel { struct pim_upstream *upstream; }; +RB_HEAD(pim_ifchannel_rb, pim_ifchannel); +RB_PROTOTYPE(pim_ifchannel_rb, pim_ifchannel, + pim_ifp_rb, pim_ifchannel_compare); + void pim_ifchannel_free(struct pim_ifchannel *ch); void pim_ifchannel_delete(struct pim_ifchannel *ch); void pim_ifchannel_delete_all(struct interface *ifp); @@ -116,7 +122,8 @@ void pim_ifchannel_delete_on_noinfo(struct interface *ifp); struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, struct prefix_sg *sg); struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, - struct prefix_sg *sg, int flags); + struct prefix_sg *sg, uint8_t ch_flags, + int up_flags); void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, struct in_addr upstream, struct prefix_sg *sg, uint8_t source_flags, uint16_t holdtime); @@ -147,8 +154,8 @@ void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom, uint8_t source_flags, uint8_t join, uint8_t starg_alone); -int pim_ifchannel_compare(struct pim_ifchannel *ch1, struct pim_ifchannel *ch2); +int pim_ifchannel_compare(const struct pim_ifchannel *ch1, + const struct pim_ifchannel *ch2); unsigned int pim_ifchannel_hash_key(void *arg); -int pim_ifchannel_equal(const void *arg1, const void *arg2); #endif /* PIM_IFCHANNEL_H */ diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index c693f30ac2..3a870374c0 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -696,7 +696,7 @@ void igmp_startup_mode_on(struct igmp_sock *igmp) static void igmp_group_free(struct igmp_group *group) { - list_free(group->group_source_list); + list_delete(group->group_source_list); XFREE(MTYPE_PIM_IGMP_GROUP, group); } @@ -748,7 +748,7 @@ void igmp_sock_free(struct igmp_sock *igmp) zassert(igmp->igmp_group_list); zassert(!listcount(igmp->igmp_group_list)); - list_free(igmp->igmp_group_list); + list_delete(igmp->igmp_group_list); hash_free(igmp->igmp_group_hash); XFREE(MTYPE_PIM_IGMP_SOCKET, igmp); @@ -812,6 +812,7 @@ static struct igmp_sock *igmp_sock_new(int fd, struct in_addr ifaddr, { struct pim_interface *pim_ifp; struct igmp_sock *igmp; + char hash_name[64]; pim_ifp = ifp->info; @@ -836,8 +837,10 @@ static struct igmp_sock *igmp_sock_new(int fd, struct in_addr ifaddr, } igmp->igmp_group_list->del = (void (*)(void *))igmp_group_free; - igmp->igmp_group_hash = - hash_create(igmp_group_hash_key, igmp_group_hash_equal, NULL); + snprintf(hash_name, 64, "IGMP %s hash", ifp->name); + igmp->igmp_group_hash = hash_create(igmp_group_hash_key, + igmp_group_hash_equal, + hash_name); igmp->fd = fd; igmp->interface = ifp; diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index 880d840eac..1fc7517e05 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -198,6 +198,7 @@ static void igmp_source_timer_on(struct igmp_group *group, struct igmp_source *source, long interval_msec) { source_timer_off(group, source); + struct pim_interface *pim_ifp = group->group_igmp_sock->interface->info; if (PIM_DEBUG_IGMP_EVENTS) { char group_str[INET_ADDRSTRLEN]; @@ -220,7 +221,7 @@ static void igmp_source_timer_on(struct igmp_group *group, Source timer switched from (T == 0) to (T > 0): enable forwarding. */ - igmp_source_forward_start(source); + igmp_source_forward_start(pim_ifp->pim, source); } void igmp_source_reset_gmi(struct igmp_sock *igmp, struct igmp_group *group, @@ -310,10 +311,12 @@ static void source_clear_send_flag(struct list *source_list) */ static void group_exclude_fwd_anysrc_ifempty(struct igmp_group *group) { + struct pim_interface *pim_ifp = group->group_igmp_sock->interface->info; + zassert(group->group_filtermode_isexcl); if (listcount(group->group_source_list) < 1) { - igmp_anysource_forward_start(group); + igmp_anysource_forward_start(pim_ifp->pim, group); } } diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c new file mode 100644 index 0000000000..7fc77556ec --- /dev/null +++ b/pimd/pim_instance.c @@ -0,0 +1,218 @@ +/* + * PIM for FRR - PIM Instance + * Copyright (C) 2017 Cumulus Networks, Inc. + * Donald Sharp + * + * This program 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 of the License, or + * (at your option) any later version. + * + * This program 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 this program; see the file COPYING; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +#include <zebra.h> + +#include "hash.h" +#include "vrf.h" + +#include "pimd.h" +#include "pim_ssm.h" +#include "pim_rpf.h" +#include "pim_rp.h" +#include "pim_mroute.h" +#include "pim_oil.h" +#include "pim_static.h" +#include "pim_ssmpingd.h" +#include "pim_vty.h" + +static void pim_instance_terminate(struct pim_instance *pim) +{ + /* Traverse and cleanup rpf_hash */ + if (pim->rpf_hash) { + hash_clean(pim->rpf_hash, (void *)pim_rp_list_hash_clean); + hash_free(pim->rpf_hash); + pim->rpf_hash = NULL; + } + + if (pim->ssm_info) { + pim_ssm_terminate(pim->ssm_info); + pim->ssm_info = NULL; + } + + if (pim->static_routes) + list_delete(pim->static_routes); + + pim_rp_free(pim); + + pim_upstream_terminate(pim); + + pim_oil_terminate(pim); + + pim_if_terminate(pim); + + pim_msdp_exit(pim); + + XFREE(MTYPE_PIM_PIM_INSTANCE, pim); +} + +static struct pim_instance *pim_instance_init(struct vrf *vrf) +{ + struct pim_instance *pim; + char hash_name[64]; + + pim = XCALLOC(MTYPE_PIM_PIM_INSTANCE, sizeof(struct pim_instance)); + if (!pim) + return NULL; + + pim_if_init(pim); + + pim->keep_alive_time = PIM_KEEPALIVE_PERIOD; + pim->rp_keep_alive_time = PIM_RP_KEEPALIVE_PERIOD; + + + pim->vrf_id = vrf->vrf_id; + pim->vrf = vrf; + + pim->spt.switchover = PIM_SPT_IMMEDIATE; + pim->spt.plist = NULL; + + pim_msdp_init(pim, master); + + snprintf(hash_name, 64, "PIM %s RPF Hash", vrf->name); + pim->rpf_hash = hash_create_size(256, pim_rpf_hash_key, + pim_rpf_equal, hash_name); + + if (PIM_DEBUG_ZEBRA) + zlog_debug("%s: NHT rpf hash init ", __PRETTY_FUNCTION__); + + pim->ssm_info = pim_ssm_init(); + if (!pim->ssm_info) { + pim_instance_terminate(pim); + return NULL; + } + + pim->static_routes = list_new(); + if (!pim->static_routes) { + zlog_err("%s %s: failure: static_routes=list_new()", __FILE__, + __PRETTY_FUNCTION__); + pim_instance_terminate(pim); + return NULL; + } + pim->static_routes->del = (void (*)(void *))pim_static_route_free; + + pim->send_v6_secondary = 1; + + if (vrf->vrf_id == VRF_DEFAULT) + pimg = pim; + + pim_rp_init(pim); + + pim_oil_init(pim); + + pim_upstream_init(pim); + + return pim; +} + +struct pim_instance *pim_get_pim_instance(vrf_id_t vrf_id) +{ + struct vrf *vrf = vrf_lookup_by_id(vrf_id); + + if (vrf) + return vrf->info; + + return NULL; +} + +static int pim_vrf_new(struct vrf *vrf) +{ + struct pim_instance *pim = pim_instance_init(vrf); + + zlog_debug("VRF Created: %s(%d)", vrf->name, vrf->vrf_id); + if (pim == NULL) { + zlog_err("%s %s: pim class init failure ", __FILE__, + __PRETTY_FUNCTION__); + /* + * We will crash and burn otherwise + */ + exit(1); + } + + vrf->info = (void *)pim; + + if (vrf->vrf_id == VRF_DEFAULT) + pimg = pim; + + pim_ssmpingd_init(pim); + return 0; +} + +static int pim_vrf_delete(struct vrf *vrf) +{ + struct pim_instance *pim = vrf->info; + + zlog_debug("VRF Deletion: %s(%d)", vrf->name, vrf->vrf_id); + + pim_ssmpingd_destroy(pim); + pim_instance_terminate(pim); + return 0; +} + +/* + * Code to turn on the pim instance that + * we have created with new + */ +static int pim_vrf_enable(struct vrf *vrf) +{ + struct pim_instance *pim = (struct pim_instance *)vrf->info; + + zlog_debug("%s: for %s", __PRETTY_FUNCTION__, vrf->name); + + pim_mroute_socket_enable(pim); + + return 0; +} + +static int pim_vrf_disable(struct vrf *vrf) +{ + /* Note: This is a callback, the VRF will be deleted by the caller. */ + return 0; +} + +static int pim_vrf_config_write(struct vty *vty) +{ + struct vrf *vrf; + struct pim_instance *pim; + + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + pim = vrf->info; + if (!pim || vrf->vrf_id != VRF_DEFAULT) { + vty_out(vty, "vrf %s\n", vrf->name); + pim_global_config_write_worker(pim, vty); + vty_out(vty, "!\n"); + } + } + + return 0; +} + +void pim_vrf_init(void) +{ + vrf_init(pim_vrf_new, pim_vrf_enable, pim_vrf_disable, pim_vrf_delete); + + vrf_cmd_init(pim_vrf_config_write); +} + +void pim_vrf_terminate(void) +{ + vrf_terminate(); +} diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h new file mode 100644 index 0000000000..0e91b4ca01 --- /dev/null +++ b/pimd/pim_instance.h @@ -0,0 +1,100 @@ +/* + * PIM for FRR - PIM Instance + * Copyright (C) 2017 Cumulus Networks, Inc. + * Donald Sharp + * + * This program 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 of the License, or + * (at your option) any later version. + * + * This program 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 this program; see the file COPYING; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +#ifndef __PIM_INSTANCE_H__ +#define __PIM_INSTANCE_H__ + +#include "pim_str.h" +#include "pim_msdp.h" + +#if defined(HAVE_LINUX_MROUTE_H) +#include <linux/mroute.h> +#else +/* + Below: from <linux/mroute.h> +*/ + +#ifndef MAXVIFS +#define MAXVIFS (256) +#endif +#endif +extern struct pim_instance *pimg; // Pim Global Instance + +enum pim_spt_switchover { + PIM_SPT_IMMEDIATE, + PIM_SPT_INFINITY, +}; + +/* Per VRF PIM DB */ +struct pim_instance { + vrf_id_t vrf_id; + struct vrf *vrf; + + struct { + enum pim_spt_switchover switchover; + char *plist; + } spt; + + struct hash *rpf_hash; + + void *ssm_info; /* per-vrf SSM configuration */ + + int send_v6_secondary; + + struct thread *thread; + int mroute_socket; + int64_t mroute_socket_creation; + int64_t mroute_add_events; + int64_t mroute_add_last; + int64_t mroute_del_events; + int64_t mroute_del_last; + + struct interface *regiface; + + // List of static routes; + struct list *static_routes; + + // Upstream vrf specific information + struct list *upstream_list; + struct hash *upstream_hash; + struct timer_wheel *upstream_sg_wheel; + + struct list *rp_list; + + int iface_vif_index[MAXVIFS]; + + struct list *channel_oil_list; + struct hash *channel_oil_hash; + + struct pim_msdp msdp; + + struct list *ssmpingd_list; + struct in_addr ssmpingd_group_addr; + + unsigned int keep_alive_time; + unsigned int rp_keep_alive_time; +}; + +void pim_vrf_init(void); +void pim_vrf_terminate(void); + +struct pim_instance *pim_get_pim_instance(vrf_id_t vrf_id); + +#endif diff --git a/pimd/pim_join.c b/pimd/pim_join.c index 9bc5c2d9cc..c60e5a65aa 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -64,9 +64,9 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, zlog_warn( "%s: join (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s", __PRETTY_FUNCTION__, pim_str_sg_dump(sg), - source_flags & PIM_RPT_BIT_MASK, - source_flags & PIM_WILDCARD_BIT_MASK, up_str, holdtime, - neigh_str, ifp->name); + !!(source_flags & PIM_RPT_BIT_MASK), + !!(source_flags & PIM_WILDCARD_BIT_MASK), up_str, + holdtime, neigh_str, ifp->name); } pim_ifp = ifp->info; @@ -80,14 +80,26 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, */ if ((source_flags & PIM_RPT_BIT_MASK) && (source_flags & PIM_WILDCARD_BIT_MASK)) { - struct pim_rpf *rp = RP(sg->grp); + struct pim_rpf *rp = RP(pim_ifp->pim, sg->grp); /* * If the RP sent in the message is not * our RP for the group, drop the message */ - if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr) + if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr) { + char received_rp[INET_ADDRSTRLEN]; + char local_rp[INET_ADDRSTRLEN]; + pim_inet4_dump("<received?>", sg->src, received_rp, + sizeof(received_rp)); + pim_inet4_dump("<local?>", rp->rpf_addr.u.prefix4, + local_rp, sizeof(local_rp)); + if (PIM_DEBUG_PIM_TRACE) + zlog_warn( + "%s: Specified RP(%s) in join is different than our configured RP(%s)", + __PRETTY_FUNCTION__, received_rp, + local_rp); return; + } sg->src.s_addr = INADDR_ANY; } @@ -124,7 +136,7 @@ static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh, if ((source_flags & PIM_RPT_BIT_MASK) && (source_flags & PIM_WILDCARD_BIT_MASK)) { - struct pim_rpf *rp = RP(sg->grp); + struct pim_rpf *rp = RP(pim_ifp->pim, sg->grp); // Ignoring Prune *,G's at the moment. if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr) @@ -294,14 +306,20 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, return -8; } - sg_ch = pim_ifchannel_find(ifp, &sg); - buf += addr_offset; starg_alone = 0; recv_prune(ifp, neigh, msg_holdtime, msg_upstream_addr.u.prefix4, &sg, msg_source_flags); + /* + * So if we are receiving a S,G,RPT prune + * before we have any data for that S,G + * We need to retrieve the sg_ch after + * we parse the prune. + */ + sg_ch = pim_ifchannel_find(ifp, &sg); + /* Received SG-RPT Prune delete oif from specific S,G */ if (starg_ch && sg_ch && (msg_source_flags & PIM_RPT_BIT_MASK) diff --git a/pimd/pim_jp_agg.c b/pimd/pim_jp_agg.c index 16d55d7bf7..8e0b4ab5e8 100644 --- a/pimd/pim_jp_agg.c +++ b/pimd/pim_jp_agg.c @@ -108,6 +108,7 @@ void pim_jp_agg_clear_group(struct list *group) js->up = NULL; XFREE(MTYPE_PIM_JP_AGG_SOURCE, js); } + list_delete(jag->sources); jag->sources = NULL; listnode_delete(group, jag); XFREE(MTYPE_PIM_JP_AGG_GROUP, jag); @@ -215,9 +216,11 @@ void pim_jp_agg_upstream_verification(struct pim_upstream *up, bool ignore) #ifdef PIM_JP_AGG_DEBUG struct listnode *node; struct interface *ifp; + struct pim_interface *pim_ifp = up->rpf.source_nexthop.interface->info; + struct pim_instance *pim = pim_ifp->pim; - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { - struct pim_interface *pim_ifp = ifp->info; + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) { + pim_ifp = ifp->info; struct listnode *nnode; if (ignore && ifp == up->rpf.source_nexthop.interface) diff --git a/pimd/pim_main.c b/pimd/pim_main.c index b8e6d8ad3d..c4cab25ae9 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -40,6 +40,7 @@ #include "libfrr.h" #include "pimd.h" +#include "pim_instance.h" #include "pim_version.h" #include "pim_signals.h" #include "pim_zebra.h" @@ -115,7 +116,6 @@ int main(int argc, char **argv, char **envp) pim_route_map_init(); pim_init(); - pim_msdp_init(master); /* * Initialize zclient "update" and "lookup" sockets diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index a92b01ca00..52d240f54b 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -24,6 +24,7 @@ #include "prefix.h" #include "vty.h" #include "plist.h" +#include "sockopt.h" #include "pimd.h" #include "pim_rpf.h" @@ -39,49 +40,82 @@ #include "pim_ifchannel.h" #include "pim_zlookup.h" #include "pim_ssm.h" +#include "pim_sock.h" -/* GLOBAL VARS */ -static struct thread *qpim_mroute_socket_reader = NULL; +static void mroute_read_on(struct pim_instance *pim); -static void mroute_read_on(void); - -static int pim_mroute_set(int fd, int enable) +static int pim_mroute_set(struct pim_instance *pim, int enable) { int err; - int opt = enable ? MRT_INIT : MRT_DONE; + int opt; socklen_t opt_len = sizeof(opt); - int rcvbuf = 1024 * 1024 * 8; long flags; - err = setsockopt(fd, IPPROTO_IP, opt, &opt, opt_len); + /* + * We need to create the VRF table for the pim mroute_socket + */ + if (pim->vrf_id != VRF_DEFAULT) { + if (pimd_privs.change(ZPRIVS_RAISE)) + zlog_err( + "pim_mroute_socket_enable: could not raise privs, %s", + safe_strerror(errno)); + + opt = pim->vrf->data.l.table_id; + err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_TABLE, + &opt, opt_len); + if (err) { + zlog_warn( + "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP, MRT_TABLE=%d): errno=%d: %s", + __FILE__, __PRETTY_FUNCTION__, + pim->mroute_socket, opt, errno, + safe_strerror(errno)); + return -1; + } + + if (pimd_privs.change(ZPRIVS_LOWER)) + zlog_err( + "pim_mroute_socket_enable: could not lower privs, %s", + safe_strerror(errno)); + } + + opt = enable ? MRT_INIT : MRT_DONE; + err = setsockopt(pim->mroute_socket, IPPROTO_IP, opt, &opt, opt_len); if (err) { zlog_warn( "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s", - __FILE__, __PRETTY_FUNCTION__, fd, + __FILE__, __PRETTY_FUNCTION__, pim->mroute_socket, enable ? "MRT_INIT" : "MRT_DONE", opt, errno, safe_strerror(errno)); return -1; } - err = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)); - if (err) { - zlog_warn( - "%s: failure: setsockopt(fd=%d, SOL_SOCKET, %d): errno=%d: %s", - __PRETTY_FUNCTION__, fd, rcvbuf, errno, - safe_strerror(errno)); +#if defined(HAVE_IP_PKTINFO) + if (enable) { + /* Linux and Solaris IP_PKTINFO */ + opt = 1; + if (setsockopt(pim->mroute_socket, IPPROTO_IP, IP_PKTINFO, &opt, + sizeof(opt))) { + zlog_warn( + "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s", + pim->mroute_socket, errno, + safe_strerror(errno)); + } } +#endif + + setsockopt_so_recvbuf(pim->mroute_socket, 1024 * 1024 * 8); - flags = fcntl(fd, F_GETFL, 0); + flags = fcntl(pim->mroute_socket, F_GETFL, 0); if (flags < 0) { - zlog_warn("Could not get flags on socket fd:%d %d %s", fd, - errno, safe_strerror(errno)); - close(fd); + zlog_warn("Could not get flags on socket fd:%d %d %s", + pim->mroute_socket, errno, safe_strerror(errno)); + close(pim->mroute_socket); return -1; } - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { - zlog_warn("Could not set O_NONBLOCK on socket fd:%d %d %s", fd, - errno, safe_strerror(errno)); - close(fd); + if (fcntl(pim->mroute_socket, F_SETFL, flags | O_NONBLOCK)) { + zlog_warn("Could not set O_NONBLOCK on socket fd:%d %d %s", + pim->mroute_socket, errno, safe_strerror(errno)); + close(pim->mroute_socket); return -1; } @@ -90,7 +124,7 @@ static int pim_mroute_set(int fd, int enable) int upcalls = IGMPMSG_WRVIFWHOLE; opt = MRT_PIM; - err = setsockopt(fd, IPPROTO_IP, opt, &upcalls, + err = setsockopt(pim->mroute_socket, IPPROTO_IP, opt, &upcalls, sizeof(upcalls)); if (err) { zlog_warn( @@ -118,7 +152,7 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, struct pim_rpf *rpg; struct prefix_sg sg; - rpg = RP(msg->im_dst); + rpg = RP(pim_ifp->pim, msg->im_dst); /* * If the incoming interface is unknown OR * the Interface type is SSM we don't need to @@ -170,7 +204,7 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, } PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags); - pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time); + pim_upstream_keep_alive_timer_start(up, pim_ifp->pim->keep_alive_time); up->channel_oil->cc.pktcnt++; PIM_UPSTREAM_FLAG_SET_FHR(up->flags); @@ -178,6 +212,7 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, if (up->channel_oil->oil.mfcc_parent >= MAXVIFS) { int vif_index = 0; vif_index = pim_if_find_vifindex_by_ifindex( + pim_ifp->pim, up->rpf.source_nexthop.interface->ifindex); up->channel_oil->oil.mfcc_parent = vif_index; } @@ -195,23 +230,25 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, const struct ip *ip_hdr; struct pim_upstream *up; + pim_ifp = ifp->info; + ip_hdr = (const struct ip *)buf; memset(&sg, 0, sizeof(struct prefix_sg)); sg.src = ip_hdr->ip_src; sg.grp = ip_hdr->ip_dst; - up = pim_upstream_find(&sg); + up = pim_upstream_find(pim_ifp->pim, &sg); if (!up) { struct prefix_sg star = sg; star.src.s_addr = INADDR_ANY; - up = pim_upstream_find(&star); + up = pim_upstream_find(pim_ifp->pim, &star); if (up && PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags)) { - up = pim_upstream_add(&sg, ifp, + up = pim_upstream_add(pim_ifp->pim, &sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_LHR, - __PRETTY_FUNCTION__); + __PRETTY_FUNCTION__, NULL); if (!up) { if (PIM_DEBUG_MROUTE) zlog_debug( @@ -221,9 +258,10 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, return 0; } pim_upstream_keep_alive_timer_start( - up, qpim_keep_alive_time); - pim_upstream_inherited_olist(up); - pim_upstream_switch(up, PIM_UPSTREAM_JOINED); + up, pim_ifp->pim->keep_alive_time); + pim_upstream_inherited_olist(pim_ifp->pim, up); + pim_upstream_switch(pim_ifp->pim, up, + PIM_UPSTREAM_JOINED); if (PIM_DEBUG_MROUTE) zlog_debug("%s: Creating %s upstream on LHR", @@ -240,7 +278,7 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, pim_ifp = up->rpf.source_nexthop.interface->info; - rpg = RP(sg.grp); + rpg = RP(pim_ifp->pim, sg.grp); if ((pim_rpf_addr_is_inaddr_none(rpg)) || (!pim_ifp) || (!(PIM_I_am_DR(pim_ifp)))) { @@ -255,7 +293,7 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, * If we've received a register suppress */ if (!up->t_rs_timer) { - if (pim_is_grp_ssm(sg.grp)) { + if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) { if (PIM_DEBUG_PIM_REG) zlog_debug( "%s register forward skipped as group is SSM", @@ -386,6 +424,8 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, struct prefix_sg sg; struct channel_oil *oil; + pim_ifp = ifp->info; + memset(&sg, 0, sizeof(struct prefix_sg)); sg.src = ip_hdr->ip_src; sg.grp = ip_hdr->ip_dst; @@ -412,11 +452,11 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, } #endif - up = pim_upstream_find(&sg); + up = pim_upstream_find(pim_ifp->pim, &sg); if (up) { struct pim_upstream *parent; struct pim_nexthop source; - struct pim_rpf *rpf = RP(sg.grp); + struct pim_rpf *rpf = RP(pim_ifp->pim, sg.grp); if (!rpf || !rpf->source_nexthop.interface) return 0; @@ -426,7 +466,7 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, * tree, let's check and if so we can safely drop * it. */ - parent = pim_upstream_find(&star_g); + parent = pim_upstream_find(pim_ifp->pim, &star_g); if (parent && parent->rpf.source_nexthop.interface == ifp) return 0; @@ -439,23 +479,25 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, */ if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) { // No if channel, but upstream we are at the RP. - if (pim_nexthop_lookup(&source, up->upstream_register, - 0) - == 0) + if (pim_nexthop_lookup(pim_ifp->pim, &source, + up->upstream_register, 0) + == 0) { pim_register_stop_send(source.interface, &sg, pim_ifp->primary_address, up->upstream_register); + up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE; + } if (!up->channel_oil) up->channel_oil = pim_channel_oil_add( - &sg, pim_ifp->mroute_vif_index); - pim_upstream_inherited_olist(up); + pim_ifp->pim, &sg, + pim_ifp->mroute_vif_index); + pim_upstream_inherited_olist(pim_ifp->pim, up); if (!up->channel_oil->installed) pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__); - pim_upstream_set_sptbit(up, ifp); } else { - if (I_am_RP(up->sg.grp)) { - if (pim_nexthop_lookup(&source, + if (I_am_RP(pim_ifp->pim, up->sg.grp)) { + if (pim_nexthop_lookup(pim_ifp->pim, &source, up->upstream_register, 0) == 0) pim_register_stop_send( @@ -465,20 +507,21 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE; } pim_upstream_keep_alive_timer_start( - up, qpim_keep_alive_time); - pim_upstream_inherited_olist(up); + up, pim_ifp->pim->keep_alive_time); + pim_upstream_inherited_olist(pim_ifp->pim, up); pim_mroute_msg_wholepkt(fd, ifp, buf); } return 0; } pim_ifp = ifp->info; - oil = pim_channel_oil_add(&sg, pim_ifp->mroute_vif_index); + oil = pim_channel_oil_add(pim_ifp->pim, &sg, pim_ifp->mroute_vif_index); if (!oil->installed) pim_mroute_add(oil, __PRETTY_FUNCTION__); if (pim_if_connected_to_source(ifp, sg.src)) { - up = pim_upstream_add(&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR, - __PRETTY_FUNCTION__); + up = pim_upstream_add(pim_ifp->pim, &sg, ifp, + PIM_UPSTREAM_FLAG_MASK_FHR, + __PRETTY_FUNCTION__, NULL); if (!up) { if (PIM_DEBUG_MROUTE) zlog_debug( @@ -487,11 +530,11 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, return -2; } PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags); - pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time); + pim_upstream_keep_alive_timer_start(up, pim_ifp->pim->keep_alive_time); up->channel_oil = oil; up->channel_oil->cc.pktcnt++; pim_register_join(up); - pim_upstream_inherited_olist(up); + pim_upstream_inherited_olist(pim_ifp->pim, up); // Send the packet to the RP pim_mroute_msg_wholepkt(fd, ifp, buf); @@ -500,7 +543,8 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, return 0; } -int pim_mroute_msg(int fd, const char *buf, int buf_size) +static int pim_mroute_msg(struct pim_instance *pim, const char *buf, + int buf_size, ifindex_t ifindex) { struct interface *ifp; struct pim_interface *pim_ifp; @@ -523,22 +567,11 @@ int pim_mroute_msg(int fd, const char *buf, int buf_size) * the source * of the IP packet. */ - ifp = pim_if_lookup_address_vrf(ip_hdr->ip_src, VRF_DEFAULT); - - if (!ifp) { - if (PIM_DEBUG_MROUTE_DETAIL) { - pim_inet4_dump("<src?>", ip_hdr->ip_src, - ip_src_str, sizeof(ip_src_str)); - pim_inet4_dump("<dst?>", ip_hdr->ip_dst, - ip_dst_str, sizeof(ip_dst_str)); + ifp = if_lookup_by_index(ifindex, pim->vrf_id); - zlog_warn( - "%s: igmp kernel upcall could not find usable interface for %s -> %s", - __PRETTY_FUNCTION__, ip_src_str, - ip_dst_str); - } + if (!ifp || !ifp->info) return 0; - } + pim_ifp = ifp->info; ifaddr = pim_find_primary_addr(ifp); igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list, @@ -551,9 +584,9 @@ int pim_mroute_msg(int fd, const char *buf, int buf_size) sizeof(ip_dst_str)); zlog_warn( - "%s: igmp kernel upcall on %s(%p) for %s -> %s", - __PRETTY_FUNCTION__, ifp->name, igmp, - ip_src_str, ip_dst_str); + "%s(%s): igmp kernel upcall on %s(%p) for %s -> %s", + __PRETTY_FUNCTION__, pim->vrf->name, ifp->name, + igmp, ip_src_str, ip_dst_str); } if (igmp) pim_igmp_packet(igmp, (char *)buf, buf_size); @@ -573,7 +606,7 @@ int pim_mroute_msg(int fd, const char *buf, int buf_size) } else { msg = (const struct igmpmsg *)buf; - ifp = pim_if_find_by_vif_index(msg->im_vif); + ifp = pim_if_find_by_vif_index(pim, msg->im_vif); if (!ifp) return 0; @@ -586,24 +619,27 @@ int pim_mroute_msg(int fd, const char *buf, int buf_size) "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d size=%d", __PRETTY_FUNCTION__, igmpmsgtype2str[msg->im_msgtype], - msg->im_msgtype, ip_hdr->ip_p, fd, src_str, - grp_str, ifp->name, msg->im_vif, buf_size); + msg->im_msgtype, ip_hdr->ip_p, + pim->mroute_socket, src_str, grp_str, ifp->name, + msg->im_vif, buf_size); } switch (msg->im_msgtype) { case IGMPMSG_WRONGVIF: - return pim_mroute_msg_wrongvif(fd, ifp, msg); + return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp, + msg); break; case IGMPMSG_NOCACHE: - return pim_mroute_msg_nocache(fd, ifp, msg); + return pim_mroute_msg_nocache(pim->mroute_socket, ifp, + msg); break; case IGMPMSG_WHOLEPKT: - return pim_mroute_msg_wholepkt(fd, ifp, + return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp, (const char *)msg); break; case IGMPMSG_WRVIFWHOLE: - return pim_mroute_msg_wrvifwhole(fd, ifp, - (const char *)msg); + return pim_mroute_msg_wrvifwhole( + pim->mroute_socket, ifp, (const char *)msg); break; default: break; @@ -615,18 +651,20 @@ int pim_mroute_msg(int fd, const char *buf, int buf_size) static int mroute_read(struct thread *t) { + struct pim_instance *pim; static long long count; char buf[10000]; int result = 0; int cont = 1; - int fd; int rd; - - fd = THREAD_FD(t); + ifindex_t ifindex; + pim = THREAD_ARG(t); while (cont) { - rd = read(fd, buf, sizeof(buf)); - if (rd < 0) { + rd = pim_socket_recvfromto(pim->mroute_socket, (uint8_t *)buf, + sizeof(buf), NULL, NULL, NULL, NULL, + &ifindex); + if (rd <= 0) { if (errno == EINTR) continue; if (errno == EWOULDBLOCK || errno == EAGAIN) @@ -634,13 +672,14 @@ static int mroute_read(struct thread *t) if (PIM_DEBUG_MROUTE) zlog_warn( - "%s: failure reading fd=%d: errno=%d: %s", - __PRETTY_FUNCTION__, fd, errno, + "%s: failure reading rd=%d: fd=%d: errno=%d: %s", + __PRETTY_FUNCTION__, rd, + pim->mroute_socket, errno, safe_strerror(errno)); goto done; } - result = pim_mroute_msg(fd, buf, rd); + result = pim_mroute_msg(pim, buf, rd, ifindex); count++; if (count % qpim_packet_process == 0) @@ -648,23 +687,23 @@ static int mroute_read(struct thread *t) } /* Keep reading */ done: - mroute_read_on(); + mroute_read_on(pim); return result; } -static void mroute_read_on() +static void mroute_read_on(struct pim_instance *pim) { - thread_add_read(master, mroute_read, 0, qpim_mroute_socket_fd, - &qpim_mroute_socket_reader); + thread_add_read(master, mroute_read, pim, pim->mroute_socket, + &pim->thread); } -static void mroute_read_off() +static void mroute_read_off(struct pim_instance *pim) { - THREAD_OFF(qpim_mroute_socket_reader); + THREAD_OFF(pim->thread); } -int pim_mroute_socket_enable() +int pim_mroute_socket_enable(struct pim_instance *pim) { int fd; @@ -674,6 +713,11 @@ int pim_mroute_socket_enable() fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP); +#ifdef SO_BINDTODEVICE + setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, pim->vrf->name, + strlen(pim->vrf->name)); +#endif + if (pimd_privs.change(ZPRIVS_LOWER)) zlog_err("pim_mroute_socket_enable: could not lower privs, %s", safe_strerror(errno)); @@ -684,39 +728,40 @@ int pim_mroute_socket_enable() return -2; } - if (pim_mroute_set(fd, 1)) { + pim->mroute_socket = fd; + if (pim_mroute_set(pim, 1)) { zlog_warn( "Could not enable mroute on socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); close(fd); + pim->mroute_socket = -1; return -3; } - qpim_mroute_socket_fd = fd; + pim->mroute_socket_creation = pim_time_monotonic_sec(); - qpim_mroute_socket_creation = pim_time_monotonic_sec(); - mroute_read_on(); + mroute_read_on(pim); return 0; } -int pim_mroute_socket_disable() +int pim_mroute_socket_disable(struct pim_instance *pim) { - if (pim_mroute_set(qpim_mroute_socket_fd, 0)) { + if (pim_mroute_set(pim, 0)) { zlog_warn( "Could not disable mroute on socket fd=%d: errno=%d: %s", - qpim_mroute_socket_fd, errno, safe_strerror(errno)); + pim->mroute_socket, errno, safe_strerror(errno)); return -2; } - if (close(qpim_mroute_socket_fd)) { + if (close(pim->mroute_socket)) { zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s", - qpim_mroute_socket_fd, errno, safe_strerror(errno)); + pim->mroute_socket, errno, safe_strerror(errno)); return -3; } - mroute_read_off(); - qpim_mroute_socket_fd = -1; + mroute_read_off(pim); + pim->mroute_socket = -1; return 0; } @@ -733,6 +778,11 @@ int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr, struct vifctl vc; int err; + if (PIM_DEBUG_MROUTE) + zlog_debug("%s: Add Vif %d (%s[%s])", __PRETTY_FUNCTION__, + pim_ifp->mroute_vif_index, + ifp->name, pim_ifp->pim->vrf->name); + memset(&vc, 0, sizeof(vc)); vc.vifc_vifi = pim_ifp->mroute_vif_index; #ifdef VIFF_USE_IFINDEX @@ -757,7 +807,7 @@ int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr, } #endif - err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_VIF, + err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_ADD_VIF, (void *)&vc, sizeof(vc)); if (err) { char ifaddr_str[INET_ADDRSTRLEN]; @@ -766,38 +816,38 @@ int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr, sizeof(ifaddr_str)); zlog_warn( - "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s", - __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd, - ifp->ifindex, ifaddr_str, flags, errno, - safe_strerror(errno)); + "%s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s", + __PRETTY_FUNCTION__, + pim_ifp->pim->mroute_socket, ifp->ifindex, ifaddr_str, + flags, errno, safe_strerror(errno)); return -2; } return 0; } -int pim_mroute_del_vif(int vif_index) +int pim_mroute_del_vif(struct interface *ifp) { + struct pim_interface *pim_ifp = ifp->info; struct vifctl vc; int err; - if (PIM_DEBUG_MROUTE) { - struct interface *ifp = pim_if_find_by_vif_index(vif_index); - zlog_debug("%s %s: Del Vif %d (%s) ", __FILE__, - __PRETTY_FUNCTION__, vif_index, - ifp ? ifp->name : "NULL"); - } + if (PIM_DEBUG_MROUTE) + zlog_debug("%s: Del Vif %d (%s[%s])", __PRETTY_FUNCTION__, + pim_ifp->mroute_vif_index, + ifp->name, pim_ifp->pim->vrf->name); memset(&vc, 0, sizeof(vc)); - vc.vifc_vifi = vif_index; + vc.vifc_vifi = pim_ifp->mroute_vif_index; - err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_VIF, + err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_DEL_VIF, (void *)&vc, sizeof(vc)); if (err) { zlog_warn( "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s", - __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd, - vif_index, errno, safe_strerror(errno)); + __FILE__, __PRETTY_FUNCTION__, + pim_ifp->pim->mroute_socket, pim_ifp->mroute_vif_index, + errno, safe_strerror(errno)); return -2; } @@ -806,12 +856,13 @@ int pim_mroute_del_vif(int vif_index) int pim_mroute_add(struct channel_oil *c_oil, const char *name) { + struct pim_instance *pim = c_oil->pim; int err; int orig = 0; int orig_iif_vif = 0; - qpim_mroute_add_last = pim_time_monotonic_sec(); - ++qpim_mroute_add_events; + pim->mroute_add_last = pim_time_monotonic_sec(); + ++pim->mroute_add_events; /* Do not install route if incoming interface is undefined. */ if (c_oil->oil.mfcc_parent >= MAXVIFS) { @@ -846,14 +897,14 @@ int pim_mroute_add(struct channel_oil *c_oil, const char *name) orig_iif_vif = c_oil->oil.mfcc_parent; c_oil->oil.mfcc_parent = 0; } - err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_MFC, + err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC, &c_oil->oil, sizeof(c_oil->oil)); if (!err && !c_oil->installed && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY && orig_iif_vif != 0) { c_oil->oil.mfcc_parent = orig_iif_vif; - err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_MFC, + err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC, &c_oil->oil, sizeof(c_oil->oil)); } @@ -863,14 +914,15 @@ int pim_mroute_add(struct channel_oil *c_oil, const char *name) if (err) { zlog_warn( "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s", - __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd, + __FILE__, __PRETTY_FUNCTION__, pim->mroute_socket, errno, safe_strerror(errno)); return -2; } if (PIM_DEBUG_MROUTE) { char buf[1000]; - zlog_debug("%s(%s), Added Route: %s", __PRETTY_FUNCTION__, name, + zlog_debug("%s(%s), vrf %s Added Route: %s", __PRETTY_FUNCTION__, name, + pim->vrf->name, pim_channel_oil_dump(c_oil, buf, sizeof(buf))); } @@ -880,10 +932,11 @@ int pim_mroute_add(struct channel_oil *c_oil, const char *name) int pim_mroute_del(struct channel_oil *c_oil, const char *name) { + struct pim_instance *pim = c_oil->pim; int err; - qpim_mroute_del_last = pim_time_monotonic_sec(); - ++qpim_mroute_del_events; + pim->mroute_del_last = pim_time_monotonic_sec(); + ++pim->mroute_del_events; if (!c_oil->installed) { if (PIM_DEBUG_MROUTE) { @@ -897,22 +950,23 @@ int pim_mroute_del(struct channel_oil *c_oil, const char *name) return -2; } - err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_MFC, + err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_DEL_MFC, &c_oil->oil, sizeof(c_oil->oil)); if (err) { if (PIM_DEBUG_MROUTE) zlog_warn( "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, - qpim_mroute_socket_fd, errno, + pim->mroute_socket, errno, safe_strerror(errno)); return -2; } if (PIM_DEBUG_MROUTE) { char buf[1000]; - zlog_debug("%s(%s), Deleted Route: %s", __PRETTY_FUNCTION__, - name, pim_channel_oil_dump(c_oil, buf, sizeof(buf))); + zlog_debug("%s(%s), vrf %s Deleted Route: %s", __PRETTY_FUNCTION__, + name, pim->vrf->name, + pim_channel_oil_dump(c_oil, buf, sizeof(buf))); } // Reset kernel installed flag @@ -923,6 +977,7 @@ int pim_mroute_del(struct channel_oil *c_oil, const char *name) void pim_mroute_update_counters(struct channel_oil *c_oil) { + struct pim_instance *pim = c_oil->pim; struct sioc_sg_req sgreq; c_oil->cc.oldpktcnt = c_oil->cc.pktcnt; @@ -930,7 +985,7 @@ void pim_mroute_update_counters(struct channel_oil *c_oil) c_oil->cc.oldwrong_if = c_oil->cc.wrong_if; if (!c_oil->installed) { - c_oil->cc.lastused = 100 * qpim_keep_alive_time; + c_oil->cc.lastused = 100 * pim->keep_alive_time; if (PIM_DEBUG_MROUTE) { struct prefix_sg sg; @@ -949,7 +1004,7 @@ void pim_mroute_update_counters(struct channel_oil *c_oil) sgreq.grp = c_oil->oil.mfcc_mcastgrp; pim_zlookup_sg_statistics(c_oil); - if (ioctl(qpim_mroute_socket_fd, SIOCGETSGCNT, &sgreq)) { + if (ioctl(pim->mroute_socket, SIOCGETSGCNT, &sgreq)) { if (PIM_DEBUG_MROUTE) { struct prefix_sg sg; diff --git a/pimd/pim_mroute.h b/pimd/pim_mroute.h index eb6c40b676..bd71acbf82 100644 --- a/pimd/pim_mroute.h +++ b/pimd/pim_mroute.h @@ -67,6 +67,10 @@ #define MRT_PIM (MRT_BASE+8) /* enable PIM code */ #endif +#ifndef MRT_TABLE +#define MRT_TABLE (209) /* Specify mroute table ID */ +#endif + #ifndef HAVE_VIFI_T typedef unsigned short vifi_t; #endif @@ -163,17 +167,15 @@ struct igmpmsg { Above: from <linux/mroute.h> */ -int pim_mroute_socket_enable(void); -int pim_mroute_socket_disable(void); +int pim_mroute_socket_enable(struct pim_instance *pim); +int pim_mroute_socket_disable(struct pim_instance *pim); int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr, unsigned char flags); -int pim_mroute_del_vif(int vif_index); +int pim_mroute_del_vif(struct interface *ifp); int pim_mroute_add(struct channel_oil *c_oil, const char *name); int pim_mroute_del(struct channel_oil *c_oil, const char *name); -int pim_mroute_msg(int fd, const char *buf, int buf_size); - void pim_mroute_update_counters(struct channel_oil *c_oil); #endif /* PIM_MROUTE_H */ diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index 0f653e70a4..4b049d90ad 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -37,12 +37,13 @@ #include "pim_str.h" #include "pim_time.h" #include "pim_upstream.h" +#include "pim_oil.h" #include "pim_msdp.h" #include "pim_msdp_packet.h" #include "pim_msdp_socket.h" -struct pim_msdp pim_msdp, *msdp = &pim_msdp; +// struct pim_msdp pim_msdp, *msdp = &pim_msdp; static void pim_msdp_peer_listen(struct pim_msdp_peer *mp); static void pim_msdp_peer_cr_timer_setup(struct pim_msdp_peer *mp, bool start); @@ -50,8 +51,8 @@ static void pim_msdp_peer_ka_timer_setup(struct pim_msdp_peer *mp, bool start); static void pim_msdp_peer_hold_timer_setup(struct pim_msdp_peer *mp, bool start); static void pim_msdp_peer_free(struct pim_msdp_peer *mp); -static void pim_msdp_enable(void); -static void pim_msdp_sa_adv_timer_setup(bool start); +static void pim_msdp_enable(struct pim_instance *pim); +static void pim_msdp_sa_adv_timer_setup(struct pim_instance *pim, bool start); static void pim_msdp_sa_deref(struct pim_msdp_sa *sa, enum pim_msdp_sa_flags flags); static int pim_msdp_mg_mbr_comp(const void *p1, const void *p2); @@ -69,21 +70,23 @@ static void pim_msdp_sa_timer_expiry_log(struct pim_msdp_sa *sa, /* RFC-3618:Sec-5.1 - global active source advertisement timer */ static int pim_msdp_sa_adv_timer_cb(struct thread *t) { + struct pim_instance *pim = THREAD_ARG(t); + if (PIM_DEBUG_MSDP_EVENTS) { zlog_debug("MSDP SA advertisment timer expired"); } - pim_msdp_sa_adv_timer_setup(true /* start */); - pim_msdp_pkt_sa_tx(); + pim_msdp_sa_adv_timer_setup(pim, true /* start */); + pim_msdp_pkt_sa_tx(pim); return 0; } -static void pim_msdp_sa_adv_timer_setup(bool start) +static void pim_msdp_sa_adv_timer_setup(struct pim_instance *pim, bool start) { - THREAD_OFF(msdp->sa_adv_timer); + THREAD_OFF(pim->msdp.sa_adv_timer); if (start) { - thread_add_timer(msdp->master, pim_msdp_sa_adv_timer_cb, NULL, - PIM_MSDP_SA_ADVERTISMENT_TIME, - &msdp->sa_adv_timer); + thread_add_timer(pim->msdp.master, pim_msdp_sa_adv_timer_cb, + pim, PIM_MSDP_SA_ADVERTISMENT_TIME, + &pim->msdp.sa_adv_timer); } } @@ -105,7 +108,8 @@ static void pim_msdp_sa_state_timer_setup(struct pim_msdp_sa *sa, bool start) { THREAD_OFF(sa->sa_state_timer); if (start) { - thread_add_timer(msdp->master, pim_msdp_sa_state_timer_cb, sa, + thread_add_timer(sa->pim->msdp.master, + pim_msdp_sa_state_timer_cb, sa, PIM_MSDP_SA_HOLD_TIME, &sa->sa_state_timer); } } @@ -121,7 +125,7 @@ static void pim_msdp_sa_upstream_del(struct pim_msdp_sa *sa) if (PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up->flags)) { PIM_UPSTREAM_FLAG_UNSET_SRC_MSDP(up->flags); sa->flags |= PIM_MSDP_SAF_UP_DEL_IN_PROG; - pim_upstream_del(up, __PRETTY_FUNCTION__); + pim_upstream_del(sa->pim, up, __PRETTY_FUNCTION__); sa->flags &= ~PIM_MSDP_SAF_UP_DEL_IN_PROG; } @@ -138,7 +142,7 @@ static bool pim_msdp_sa_upstream_add_ok(struct pim_msdp_sa *sa, return false; } /* check if we are RP */ - if (!I_am_RP(sa->sg.grp)) { + if (!I_am_RP(sa->pim, sa->sg.grp)) { return false; } @@ -149,7 +153,7 @@ static bool pim_msdp_sa_upstream_add_ok(struct pim_msdp_sa *sa, memset(&sg, 0, sizeof(sg)); sg.grp = sa->sg.grp; - xg_up = pim_upstream_find(&sg); + xg_up = pim_upstream_find(sa->pim, &sg); } if (!xg_up || (xg_up->join_state != PIM_UPSTREAM_JOINED)) { /* join desired will be true for such (*, G) entries so we will @@ -186,7 +190,7 @@ static void pim_msdp_sa_upstream_update(struct pim_msdp_sa *sa, return; } - up = pim_upstream_find(&sa->sg); + up = pim_upstream_find(sa->pim, &sa->sg); if (up && (PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up->flags))) { /* somehow we lost track of the upstream ptr? best log it */ sa->up = up; @@ -199,14 +203,14 @@ static void pim_msdp_sa_upstream_update(struct pim_msdp_sa *sa, /* RFC3618: "RP triggers a (S, G) join event towards the data source * as if a JP message was rxed addressed to the RP itself." */ - up = pim_upstream_add(&sa->sg, NULL /* iif */, + up = pim_upstream_add(sa->pim, &sa->sg, NULL /* iif */, PIM_UPSTREAM_FLAG_MASK_SRC_MSDP, - __PRETTY_FUNCTION__); + __PRETTY_FUNCTION__, NULL); sa->up = up; if (up) { /* update inherited oil */ - pim_upstream_inherited_olist(up); + pim_upstream_inherited_olist(sa->pim, up); /* should we also start the kat in parallel? we will need it * when the * SA ages out */ @@ -227,7 +231,8 @@ static void pim_msdp_sa_free(struct pim_msdp_sa *sa) XFREE(MTYPE_PIM_MSDP_SA, sa); } -static struct pim_msdp_sa *pim_msdp_sa_new(struct prefix_sg *sg, +static struct pim_msdp_sa *pim_msdp_sa_new(struct pim_instance *pim, + struct prefix_sg *sg, struct in_addr rp) { struct pim_msdp_sa *sa; @@ -239,19 +244,20 @@ static struct pim_msdp_sa *pim_msdp_sa_new(struct prefix_sg *sg, return NULL; } + sa->pim = pim; sa->sg = *sg; pim_str_sg_set(sg, sa->sg_str); sa->rp = rp; sa->uptime = pim_time_monotonic_sec(); /* insert into misc tables for easy access */ - sa = hash_get(msdp->sa_hash, sa, hash_alloc_intern); + sa = hash_get(pim->msdp.sa_hash, sa, hash_alloc_intern); if (!sa) { zlog_err("%s: PIM hash get failure", __PRETTY_FUNCTION__); pim_msdp_sa_free(sa); return NULL; } - listnode_add_sort(msdp->sa_list, sa); + listnode_add_sort(pim->msdp.sa_list, sa); if (PIM_DEBUG_MSDP_EVENTS) { zlog_debug("MSDP SA %s created", sa->sg_str); @@ -260,25 +266,27 @@ static struct pim_msdp_sa *pim_msdp_sa_new(struct prefix_sg *sg, return sa; } -static struct pim_msdp_sa *pim_msdp_sa_find(struct prefix_sg *sg) +static struct pim_msdp_sa *pim_msdp_sa_find(struct pim_instance *pim, + struct prefix_sg *sg) { struct pim_msdp_sa lookup; lookup.sg = *sg; - return hash_lookup(msdp->sa_hash, &lookup); + return hash_lookup(pim->msdp.sa_hash, &lookup); } -static struct pim_msdp_sa *pim_msdp_sa_add(struct prefix_sg *sg, +static struct pim_msdp_sa *pim_msdp_sa_add(struct pim_instance *pim, + struct prefix_sg *sg, struct in_addr rp) { struct pim_msdp_sa *sa; - sa = pim_msdp_sa_find(sg); + sa = pim_msdp_sa_find(pim, sg); if (sa) { return sa; } - return pim_msdp_sa_new(sg, rp); + return pim_msdp_sa_new(pim, sg, rp); } static void pim_msdp_sa_del(struct pim_msdp_sa *sa) @@ -291,8 +299,8 @@ static void pim_msdp_sa_del(struct pim_msdp_sa *sa) pim_msdp_sa_state_timer_setup(sa, false /* start */); /* remove the entry from various tables */ - listnode_delete(msdp->sa_list, sa); - hash_release(msdp->sa_hash, sa); + listnode_delete(sa->pim->msdp.sa_list, sa); + hash_release(sa->pim->msdp.sa_hash, sa); if (PIM_DEBUG_MSDP_EVENTS) { zlog_debug("MSDP SA %s deleted", sa->sg_str); @@ -315,7 +323,7 @@ static void pim_msdp_sa_peer_ip_set(struct pim_msdp_sa *sa, /* any time the peer ip changes also update the rp address */ if (PIM_INADDR_ISNOT_ANY(sa->peer)) { - old_mp = pim_msdp_peer_find(sa->peer); + old_mp = pim_msdp_peer_find(sa->pim, sa->peer); if (old_mp && old_mp->sa_cnt) { --old_mp->sa_cnt; } @@ -349,8 +357,8 @@ static void pim_msdp_sa_deref(struct pim_msdp_sa *sa, zlog_debug("MSDP SA %s local reference removed", sa->sg_str); } - if (msdp->local_cnt) - --msdp->local_cnt; + if (sa->pim->msdp.local_cnt) + --sa->pim->msdp.local_cnt; } } @@ -382,12 +390,12 @@ static void pim_msdp_sa_deref(struct pim_msdp_sa *sa, } } -void pim_msdp_sa_ref(struct pim_msdp_peer *mp, struct prefix_sg *sg, - struct in_addr rp) +void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp, + struct prefix_sg *sg, struct in_addr rp) { struct pim_msdp_sa *sa; - sa = pim_msdp_sa_add(sg, rp); + sa = pim_msdp_sa_add(pim, sg, rp); if (!sa) { return; } @@ -412,7 +420,7 @@ void pim_msdp_sa_ref(struct pim_msdp_peer *mp, struct prefix_sg *sg, } else { if (!(sa->flags & PIM_MSDP_SAF_LOCAL)) { sa->flags |= PIM_MSDP_SAF_LOCAL; - ++msdp->local_cnt; + ++sa->pim->msdp.local_cnt; if (PIM_DEBUG_MSDP_EVENTS) { zlog_debug("MSDP SA %s added locally", sa->sg_str); @@ -438,7 +446,9 @@ void pim_msdp_sa_ref(struct pim_msdp_peer *mp, struct prefix_sg *sg, */ static bool pim_msdp_sa_local_add_ok(struct pim_upstream *up) { - if (!(msdp->flags & PIM_MSDPF_ENABLE)) { + struct pim_instance *pim = up->channel_oil->pim; + + if (!(pim->msdp.flags & PIM_MSDPF_ENABLE)) { return false; } @@ -447,7 +457,7 @@ static bool pim_msdp_sa_local_add_ok(struct pim_upstream *up) return false; } - if (!I_am_RP(up->sg.grp)) { + if (!I_am_RP(pim, up->sg.grp)) { /* we are not RP for the group */ return false; } @@ -462,18 +472,19 @@ static bool pim_msdp_sa_local_add_ok(struct pim_upstream *up) return false; } -static void pim_msdp_sa_local_add(struct prefix_sg *sg) +static void pim_msdp_sa_local_add(struct pim_instance *pim, + struct prefix_sg *sg) { struct in_addr rp; rp.s_addr = 0; - pim_msdp_sa_ref(NULL /* mp */, sg, rp); + pim_msdp_sa_ref(pim, NULL /* mp */, sg, rp); } -void pim_msdp_sa_local_del(struct prefix_sg *sg) +void pim_msdp_sa_local_del(struct pim_instance *pim, struct prefix_sg *sg) { struct pim_msdp_sa *sa; - sa = pim_msdp_sa_find(sg); + sa = pim_msdp_sa_find(pim, sg); if (sa) { pim_msdp_sa_deref(sa, PIM_MSDP_SAF_LOCAL); } @@ -481,11 +492,12 @@ void pim_msdp_sa_local_del(struct prefix_sg *sg) /* we need to be very cautious with this API as SA del too can trigger an * upstream del and we will get stuck in a simple loop */ -static void pim_msdp_sa_local_del_on_up_del(struct prefix_sg *sg) +static void pim_msdp_sa_local_del_on_up_del(struct pim_instance *pim, + struct prefix_sg *sg) { struct pim_msdp_sa *sa; - sa = pim_msdp_sa_find(sg); + sa = pim_msdp_sa_find(pim, sg); if (sa) { if (PIM_DEBUG_MSDP_INTERNAL) { zlog_debug("MSDP local sa %s del on up del", @@ -543,32 +555,34 @@ static void pim_msdp_sa_local_del_on_up_del(struct prefix_sg *sg) */ void pim_msdp_sa_local_update(struct pim_upstream *up) { + struct pim_instance *pim = up->channel_oil->pim; + if (pim_msdp_sa_local_add_ok(up)) { - pim_msdp_sa_local_add(&up->sg); + pim_msdp_sa_local_add(pim, &up->sg); } else { - pim_msdp_sa_local_del(&up->sg); + pim_msdp_sa_local_del(pim, &up->sg); } } -static void pim_msdp_sa_local_setup(void) +static void pim_msdp_sa_local_setup(struct pim_instance *pim) { struct pim_upstream *up; struct listnode *up_node; - for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, up_node, up)) { + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, up_node, up)) { pim_msdp_sa_local_update(up); } } /* whenever the RP changes we need to re-evaluate the "local" SA-cache */ /* XXX: needs to be tested */ -void pim_msdp_i_am_rp_changed(void) +void pim_msdp_i_am_rp_changed(struct pim_instance *pim) { struct listnode *sanode; struct listnode *nextnode; struct pim_msdp_sa *sa; - if (!(msdp->flags & PIM_MSDPF_ENABLE)) { + if (!(pim->msdp.flags & PIM_MSDPF_ENABLE)) { /* if the feature is not enabled do nothing */ return; } @@ -578,16 +592,16 @@ void pim_msdp_i_am_rp_changed(void) } /* mark all local entries as stale */ - for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) { + for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) { if (sa->flags & PIM_MSDP_SAF_LOCAL) { sa->flags |= PIM_MSDP_SAF_STALE; } } /* re-setup local SA entries */ - pim_msdp_sa_local_setup(); + pim_msdp_sa_local_setup(pim); - for (ALL_LIST_ELEMENTS(msdp->sa_list, sanode, nextnode, sa)) { + for (ALL_LIST_ELEMENTS(pim->msdp.sa_list, sanode, nextnode, sa)) { /* purge stale SA entries */ if (sa->flags & PIM_MSDP_SAF_STALE) { /* clear the stale flag; the entry may be kept even @@ -609,7 +623,8 @@ void pim_msdp_i_am_rp_changed(void) /* We track the join state of (*, G) entries. If G has sources in the SA-cache * we need to setup or teardown SPT when the JoinDesired status changes for * (*, G) */ -void pim_msdp_up_join_state_changed(struct pim_upstream *xg_up) +void pim_msdp_up_join_state_changed(struct pim_instance *pim, + struct pim_upstream *xg_up) { struct listnode *sanode; struct pim_msdp_sa *sa; @@ -626,7 +641,7 @@ void pim_msdp_up_join_state_changed(struct pim_upstream *xg_up) /* XXX: Need to maintain SAs per-group to avoid all this unnecessary * walking */ - for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) { + for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) { if (sa->sg.grp.s_addr != xg_up->sg.grp.s_addr) { continue; } @@ -634,7 +649,7 @@ void pim_msdp_up_join_state_changed(struct pim_upstream *xg_up) } } -static void pim_msdp_up_xg_del(struct prefix_sg *sg) +static void pim_msdp_up_xg_del(struct pim_instance *pim, struct prefix_sg *sg) { struct listnode *sanode; struct pim_msdp_sa *sa; @@ -650,7 +665,7 @@ static void pim_msdp_up_xg_del(struct prefix_sg *sg) /* XXX: Need to maintain SAs per-group to avoid all this unnecessary * walking */ - for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) { + for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) { if (sa->sg.grp.s_addr != sg->grp.s_addr) { continue; } @@ -658,15 +673,15 @@ static void pim_msdp_up_xg_del(struct prefix_sg *sg) } } -void pim_msdp_up_del(struct prefix_sg *sg) +void pim_msdp_up_del(struct pim_instance *pim, struct prefix_sg *sg) { if (PIM_DEBUG_MSDP_INTERNAL) { zlog_debug("MSDP up %s del", pim_str_sg_dump(sg)); } if (sg->src.s_addr == INADDR_ANY) { - pim_msdp_up_xg_del(sg); + pim_msdp_up_xg_del(pim, sg); } else { - pim_msdp_sa_local_del_on_up_del(sg); + pim_msdp_sa_local_del_on_up_del(pim, sg); } } @@ -797,7 +812,7 @@ static void pim_msdp_peer_listen(struct pim_msdp_peer *mp) * first listening peer is configured; but don't bother tearing it down * when * all the peers go down */ - pim_msdp_sock_listen(); + pim_msdp_sock_listen(mp->pim); } /* 11.2.A4 and 11.2.A5: transition active or passive peer to @@ -913,12 +928,14 @@ static int pim_msdp_peer_hold_timer_cb(struct thread *t) pim_msdp_peer_reset_tcp_conn(mp, "ht-expired"); return 0; } + static void pim_msdp_peer_hold_timer_setup(struct pim_msdp_peer *mp, bool start) { + struct pim_instance *pim = mp->pim; THREAD_OFF(mp->hold_timer); if (start) { - thread_add_timer(msdp->master, pim_msdp_peer_hold_timer_cb, mp, - PIM_MSDP_PEER_HOLD_TIME, &mp->hold_timer); + thread_add_timer(pim->msdp.master, pim_msdp_peer_hold_timer_cb, + mp, PIM_MSDP_PEER_HOLD_TIME, &mp->hold_timer); } } @@ -942,7 +959,8 @@ static void pim_msdp_peer_ka_timer_setup(struct pim_msdp_peer *mp, bool start) { THREAD_OFF(mp->ka_timer); if (start) { - thread_add_timer(msdp->master, pim_msdp_peer_ka_timer_cb, mp, + thread_add_timer(mp->pim->msdp.master, + pim_msdp_peer_ka_timer_cb, mp, PIM_MSDP_PEER_KA_TIME, &mp->ka_timer); } } @@ -1005,9 +1023,9 @@ static void pim_msdp_peer_cr_timer_setup(struct pim_msdp_peer *mp, bool start) { THREAD_OFF(mp->cr_timer); if (start) { - thread_add_timer(msdp->master, pim_msdp_peer_cr_timer_cb, mp, - PIM_MSDP_PEER_CONNECT_RETRY_TIME, - &mp->cr_timer); + thread_add_timer( + mp->pim->msdp.master, pim_msdp_peer_cr_timer_cb, mp, + PIM_MSDP_PEER_CONNECT_RETRY_TIME, &mp->cr_timer); } } @@ -1043,14 +1061,15 @@ static void pim_msdp_addr2su(union sockunion *su, struct in_addr addr) } /* 11.2.A1: create a new peer and transition state to listen or connecting */ -static enum pim_msdp_err pim_msdp_peer_new(struct in_addr peer_addr, +static enum pim_msdp_err pim_msdp_peer_new(struct pim_instance *pim, + struct in_addr peer_addr, struct in_addr local_addr, const char *mesh_group_name, struct pim_msdp_peer **mp_p) { struct pim_msdp_peer *mp; - pim_msdp_enable(); + pim_msdp_enable(pim); mp = XCALLOC(MTYPE_PIM_MSDP_PEER, sizeof(*mp)); if (!mp) { @@ -1059,12 +1078,13 @@ static enum pim_msdp_err pim_msdp_peer_new(struct in_addr peer_addr, return PIM_MSDP_ERR_OOM; } + mp->pim = pim; mp->peer = peer_addr; pim_inet4_dump("<peer?>", mp->peer, mp->key_str, sizeof(mp->key_str)); pim_msdp_addr2su(&mp->su_peer, mp->peer); mp->local = local_addr; /* XXX: originator_id setting needs to move to the mesh group */ - msdp->originator_id = local_addr; + pim->msdp.originator_id = local_addr; pim_msdp_addr2su(&mp->su_local, mp->local); mp->mesh_group_name = XSTRDUP(MTYPE_PIM_MSDP_MG_NAME, mesh_group_name); mp->state = PIM_MSDP_INACTIVE; @@ -1080,8 +1100,8 @@ static enum pim_msdp_err pim_msdp_peer_new(struct in_addr peer_addr, mp->obuf = stream_fifo_new(); /* insert into misc tables for easy access */ - mp = hash_get(msdp->peer_hash, mp, hash_alloc_intern); - listnode_add_sort(msdp->peer_list, mp); + mp = hash_get(pim->msdp.peer_hash, mp, hash_alloc_intern); + listnode_add_sort(pim->msdp.peer_list, mp); if (PIM_DEBUG_MSDP_EVENTS) { zlog_debug("MSDP peer %s created", mp->key_str); @@ -1101,16 +1121,18 @@ static enum pim_msdp_err pim_msdp_peer_new(struct in_addr peer_addr, return PIM_MSDP_ERR_NONE; } -struct pim_msdp_peer *pim_msdp_peer_find(struct in_addr peer_addr) +struct pim_msdp_peer *pim_msdp_peer_find(struct pim_instance *pim, + struct in_addr peer_addr) { struct pim_msdp_peer lookup; lookup.peer = peer_addr; - return hash_lookup(msdp->peer_hash, &lookup); + return hash_lookup(pim->msdp.peer_hash, &lookup); } /* add peer configuration if it doesn't already exist */ -enum pim_msdp_err pim_msdp_peer_add(struct in_addr peer_addr, +enum pim_msdp_err pim_msdp_peer_add(struct pim_instance *pim, + struct in_addr peer_addr, struct in_addr local_addr, const char *mesh_group_name, struct pim_msdp_peer **mp_p) @@ -1133,7 +1155,7 @@ enum pim_msdp_err pim_msdp_peer_add(struct in_addr peer_addr, return PIM_MSDP_ERR_SIP_EQ_DIP; } - mp = pim_msdp_peer_find(peer_addr); + mp = pim_msdp_peer_find(pim, peer_addr); if (mp) { if (mp_p) { *mp_p = mp; @@ -1141,7 +1163,8 @@ enum pim_msdp_err pim_msdp_peer_add(struct in_addr peer_addr, return PIM_MSDP_ERR_PEER_EXISTS; } - return pim_msdp_peer_new(peer_addr, local_addr, mesh_group_name, mp_p); + return pim_msdp_peer_new(pim, peer_addr, local_addr, mesh_group_name, + mp_p); } /* release all mem associated with a peer */ @@ -1168,8 +1191,8 @@ static enum pim_msdp_err pim_msdp_peer_do_del(struct pim_msdp_peer *mp) pim_msdp_peer_stop_tcp_conn(mp, true /* chg_state */); /* remove the session from various tables */ - listnode_delete(msdp->peer_list, mp); - hash_release(msdp->peer_hash, mp); + listnode_delete(mp->pim->msdp.peer_list, mp); + hash_release(mp->pim->msdp.peer_hash, mp); if (PIM_DEBUG_MSDP_EVENTS) { zlog_debug("MSDP peer %s deleted", mp->key_str); @@ -1181,11 +1204,12 @@ static enum pim_msdp_err pim_msdp_peer_do_del(struct pim_msdp_peer *mp) return PIM_MSDP_ERR_NONE; } -enum pim_msdp_err pim_msdp_peer_del(struct in_addr peer_addr) +enum pim_msdp_err pim_msdp_peer_del(struct pim_instance *pim, + struct in_addr peer_addr) { struct pim_msdp_peer *mp; - mp = pim_msdp_peer_find(peer_addr); + mp = pim_msdp_peer_find(pim, peer_addr); if (!mp) { return PIM_MSDP_ERR_NO_PEER; } @@ -1223,7 +1247,7 @@ static int pim_msdp_peer_comp(const void *p1, const void *p2) } /************************** Mesh group management **************************/ -static void pim_msdp_mg_free(struct pim_msdp_mg *mg) +static void pim_msdp_mg_free(struct pim_instance *pim, struct pim_msdp_mg *mg) { /* If the mesh-group has valid member or src_ip don't delete it */ if (!mg || mg->mbr_cnt || (mg->src_ip.s_addr != INADDR_ANY)) { @@ -1237,10 +1261,10 @@ static void pim_msdp_mg_free(struct pim_msdp_mg *mg) XFREE(MTYPE_PIM_MSDP_MG_NAME, mg->mesh_group_name); if (mg->mbr_list) - list_free(mg->mbr_list); + list_delete(mg->mbr_list); XFREE(MTYPE_PIM_MSDP_MG, mg); - msdp->mg = NULL; + pim->msdp.mg = NULL; } static struct pim_msdp_mg *pim_msdp_mg_new(const char *mesh_group_name) @@ -1265,9 +1289,10 @@ static struct pim_msdp_mg *pim_msdp_mg_new(const char *mesh_group_name) return mg; } -enum pim_msdp_err pim_msdp_mg_del(const char *mesh_group_name) +enum pim_msdp_err pim_msdp_mg_del(struct pim_instance *pim, + const char *mesh_group_name) { - struct pim_msdp_mg *mg = msdp->mg; + struct pim_msdp_mg *mg = pim->msdp.mg; struct pim_msdp_mg_mbr *mbr; if (!mg || strcmp(mg->mesh_group_name, mesh_group_name)) { @@ -1284,22 +1309,23 @@ enum pim_msdp_err pim_msdp_mg_del(const char *mesh_group_name) mg->src_ip.s_addr = INADDR_ANY; /* free up the mesh-group */ - pim_msdp_mg_free(mg); + pim_msdp_mg_free(pim, mg); return PIM_MSDP_ERR_NONE; } -static enum pim_msdp_err pim_msdp_mg_add(const char *mesh_group_name) +static enum pim_msdp_err pim_msdp_mg_add(struct pim_instance *pim, + const char *mesh_group_name) { - if (msdp->mg) { - if (!strcmp(msdp->mg->mesh_group_name, mesh_group_name)) { + if (pim->msdp.mg) { + if (!strcmp(pim->msdp.mg->mesh_group_name, mesh_group_name)) { return PIM_MSDP_ERR_NONE; } /* currently only one mesh-group can exist at a time */ return PIM_MSDP_ERR_MAX_MESH_GROUPS; } - msdp->mg = pim_msdp_mg_new(mesh_group_name); - if (!msdp->mg) { + pim->msdp.mg = pim_msdp_mg_new(mesh_group_name); + if (!pim->msdp.mg) { return PIM_MSDP_ERR_OOM; } @@ -1325,17 +1351,18 @@ static void pim_msdp_mg_mbr_free(struct pim_msdp_mg_mbr *mbr) XFREE(MTYPE_PIM_MSDP_MG_MBR, mbr); } -static struct pim_msdp_mg_mbr *pim_msdp_mg_mbr_find(struct in_addr mbr_ip) +static struct pim_msdp_mg_mbr *pim_msdp_mg_mbr_find(struct pim_instance *pim, + struct in_addr mbr_ip) { struct pim_msdp_mg_mbr *mbr; struct listnode *mbr_node; - if (!msdp->mg) { + if (!pim->msdp.mg) { return NULL; } /* we can move this to a hash but considering that number of peers in * a mesh-group that seems like bit of an overkill */ - for (ALL_LIST_ELEMENTS_RO(msdp->mg->mbr_list, mbr_node, mbr)) { + for (ALL_LIST_ELEMENTS_RO(pim->msdp.mg->mbr_list, mbr_node, mbr)) { if (mbr->mbr_ip.s_addr == mbr_ip.s_addr) { return mbr; } @@ -1343,20 +1370,21 @@ static struct pim_msdp_mg_mbr *pim_msdp_mg_mbr_find(struct in_addr mbr_ip) return mbr; } -enum pim_msdp_err pim_msdp_mg_mbr_add(const char *mesh_group_name, +enum pim_msdp_err pim_msdp_mg_mbr_add(struct pim_instance *pim, + const char *mesh_group_name, struct in_addr mbr_ip) { int rc; struct pim_msdp_mg_mbr *mbr; struct pim_msdp_mg *mg; - rc = pim_msdp_mg_add(mesh_group_name); + rc = pim_msdp_mg_add(pim, mesh_group_name); if (rc != PIM_MSDP_ERR_NONE) { return rc; } - mg = msdp->mg; - mbr = pim_msdp_mg_mbr_find(mbr_ip); + mg = pim->msdp.mg; + mbr = pim_msdp_mg_mbr_find(pim, mbr_ip); if (mbr) { return PIM_MSDP_ERR_MG_MBR_EXISTS; } @@ -1366,7 +1394,7 @@ enum pim_msdp_err pim_msdp_mg_mbr_add(const char *mesh_group_name, zlog_err("%s: PIM XCALLOC(%zu) failure", __PRETTY_FUNCTION__, sizeof(*mbr)); /* if there are no references to the mg free it */ - pim_msdp_mg_free(mg); + pim_msdp_mg_free(pim, mg); return PIM_MSDP_ERR_OOM; } mbr->mbr_ip = mbr_ip; @@ -1374,7 +1402,7 @@ enum pim_msdp_err pim_msdp_mg_mbr_add(const char *mesh_group_name, /* if valid SIP has been configured add peer session */ if (mg->src_ip.s_addr != INADDR_ANY) { - pim_msdp_peer_add(mbr_ip, mg->src_ip, mesh_group_name, + pim_msdp_peer_add(pim, mbr_ip, mg->src_ip, mesh_group_name, &mbr->mp); } @@ -1409,33 +1437,34 @@ static void pim_msdp_mg_mbr_do_del(struct pim_msdp_mg *mg, } } -enum pim_msdp_err pim_msdp_mg_mbr_del(const char *mesh_group_name, +enum pim_msdp_err pim_msdp_mg_mbr_del(struct pim_instance *pim, + const char *mesh_group_name, struct in_addr mbr_ip) { struct pim_msdp_mg_mbr *mbr; - struct pim_msdp_mg *mg = msdp->mg; + struct pim_msdp_mg *mg = pim->msdp.mg; if (!mg || strcmp(mg->mesh_group_name, mesh_group_name)) { return PIM_MSDP_ERR_NO_MG; } - mbr = pim_msdp_mg_mbr_find(mbr_ip); + mbr = pim_msdp_mg_mbr_find(pim, mbr_ip); if (!mbr) { return PIM_MSDP_ERR_NO_MG_MBR; } pim_msdp_mg_mbr_do_del(mg, mbr); /* if there are no references to the mg free it */ - pim_msdp_mg_free(mg); + pim_msdp_mg_free(pim, mg); return PIM_MSDP_ERR_NONE; } -static void pim_msdp_mg_src_do_del(void) +static void pim_msdp_mg_src_do_del(struct pim_instance *pim) { struct pim_msdp_mg_mbr *mbr; struct listnode *mbr_node; - struct pim_msdp_mg *mg = msdp->mg; + struct pim_msdp_mg *mg = pim->msdp.mg; /* SIP is being removed - tear down all active peer sessions */ for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbr_node, mbr)) { @@ -1450,9 +1479,10 @@ static void pim_msdp_mg_src_do_del(void) } } -enum pim_msdp_err pim_msdp_mg_src_del(const char *mesh_group_name) +enum pim_msdp_err pim_msdp_mg_src_del(struct pim_instance *pim, + const char *mesh_group_name) { - struct pim_msdp_mg *mg = msdp->mg; + struct pim_msdp_mg *mg = pim->msdp.mg; if (!mg || strcmp(mg->mesh_group_name, mesh_group_name)) { return PIM_MSDP_ERR_NO_MG; @@ -1460,14 +1490,15 @@ enum pim_msdp_err pim_msdp_mg_src_del(const char *mesh_group_name) if (mg->src_ip.s_addr != INADDR_ANY) { mg->src_ip.s_addr = INADDR_ANY; - pim_msdp_mg_src_do_del(); + pim_msdp_mg_src_do_del(pim); /* if there are no references to the mg free it */ - pim_msdp_mg_free(mg); + pim_msdp_mg_free(pim, mg); } return PIM_MSDP_ERR_NONE; } -enum pim_msdp_err pim_msdp_mg_src_add(const char *mesh_group_name, +enum pim_msdp_err pim_msdp_mg_src_add(struct pim_instance *pim, + const char *mesh_group_name, struct in_addr src_ip) { int rc; @@ -1476,23 +1507,23 @@ enum pim_msdp_err pim_msdp_mg_src_add(const char *mesh_group_name, struct pim_msdp_mg *mg; if (src_ip.s_addr == INADDR_ANY) { - pim_msdp_mg_src_del(mesh_group_name); + pim_msdp_mg_src_del(pim, mesh_group_name); return PIM_MSDP_ERR_NONE; } - rc = pim_msdp_mg_add(mesh_group_name); + rc = pim_msdp_mg_add(pim, mesh_group_name); if (rc != PIM_MSDP_ERR_NONE) { return rc; } - mg = msdp->mg; + mg = pim->msdp.mg; if (mg->src_ip.s_addr != INADDR_ANY) { - pim_msdp_mg_src_do_del(); + pim_msdp_mg_src_do_del(pim); } mg->src_ip = src_ip; for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbr_node, mbr)) { - pim_msdp_peer_add(mbr->mbr_ip, mg->src_ip, mesh_group_name, + pim_msdp_peer_add(pim, mbr->mbr_ip, mg->src_ip, mesh_group_name, &mbr->mp); } @@ -1506,11 +1537,12 @@ enum pim_msdp_err pim_msdp_mg_src_add(const char *mesh_group_name, } /*********************** MSDP feature APIs *********************************/ -int pim_msdp_config_write(struct vty *vty) +int pim_msdp_config_write_helper(struct pim_instance *pim, struct vty *vty, + const char *spaces) { struct listnode *mbrnode; struct pim_msdp_mg_mbr *mbr; - struct pim_msdp_mg *mg = msdp->mg; + struct pim_msdp_mg *mg = pim->msdp.mg; char mbr_str[INET_ADDRSTRLEN]; char src_str[INET_ADDRSTRLEN]; int count = 0; @@ -1521,65 +1553,83 @@ int pim_msdp_config_write(struct vty *vty) if (mg->src_ip.s_addr != INADDR_ANY) { pim_inet4_dump("<src?>", mg->src_ip, src_str, sizeof(src_str)); - vty_out(vty, "ip msdp mesh-group %s source %s\n", + vty_out(vty, "%sip msdp mesh-group %s source %s\n", spaces, mg->mesh_group_name, src_str); ++count; } for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbrnode, mbr)) { pim_inet4_dump("<mbr?>", mbr->mbr_ip, mbr_str, sizeof(mbr_str)); - vty_out(vty, "ip msdp mesh-group %s member %s\n", + vty_out(vty, "%sip msdp mesh-group %s member %s\n", spaces, mg->mesh_group_name, mbr_str); ++count; } return count; } +int pim_msdp_config_write(struct vty *vty) +{ + return pim_msdp_config_write_helper(pimg, vty, ""); +} + /* Enable feature including active/periodic timers etc. on the first peer * config. Till then MSDP should just stay quiet. */ -static void pim_msdp_enable(void) +static void pim_msdp_enable(struct pim_instance *pim) { - if (msdp->flags & PIM_MSDPF_ENABLE) { + if (pim->msdp.flags & PIM_MSDPF_ENABLE) { /* feature is already enabled */ return; } - msdp->flags |= PIM_MSDPF_ENABLE; - msdp->work_obuf = stream_new(PIM_MSDP_MAX_PACKET_SIZE); - pim_msdp_sa_adv_timer_setup(true /* start */); + pim->msdp.flags |= PIM_MSDPF_ENABLE; + pim->msdp.work_obuf = stream_new(PIM_MSDP_MAX_PACKET_SIZE); + pim_msdp_sa_adv_timer_setup(pim, true /* start */); /* setup sa cache based on local sources */ - pim_msdp_sa_local_setup(); + pim_msdp_sa_local_setup(pim); } /* MSDP init */ -void pim_msdp_init(struct thread_master *master) +void pim_msdp_init(struct pim_instance *pim, struct thread_master *master) { - msdp->master = master; + pim->msdp.master = master; + char hash_name[64]; - msdp->peer_hash = hash_create(pim_msdp_peer_hash_key_make, - pim_msdp_peer_hash_eq, NULL); - msdp->peer_list = list_new(); - msdp->peer_list->del = (void (*)(void *))pim_msdp_peer_free; - msdp->peer_list->cmp = (int (*)(void *, void *))pim_msdp_peer_comp; + snprintf(hash_name, 64, "PIM %s MSDP Peer Hash", pim->vrf->name); + pim->msdp.peer_hash = hash_create(pim_msdp_peer_hash_key_make, + pim_msdp_peer_hash_eq, hash_name); + pim->msdp.peer_list = list_new(); + pim->msdp.peer_list->del = (void (*)(void *))pim_msdp_peer_free; + pim->msdp.peer_list->cmp = (int (*)(void *, void *))pim_msdp_peer_comp; - msdp->sa_hash = hash_create(pim_msdp_sa_hash_key_make, - pim_msdp_sa_hash_eq, NULL); - msdp->sa_list = list_new(); - msdp->sa_list->del = (void (*)(void *))pim_msdp_sa_free; - msdp->sa_list->cmp = (int (*)(void *, void *))pim_msdp_sa_comp; + snprintf(hash_name, 64, "PIM %s MSDP SA Hash", pim->vrf->name); + pim->msdp.sa_hash = hash_create(pim_msdp_sa_hash_key_make, + pim_msdp_sa_hash_eq, hash_name); + pim->msdp.sa_list = list_new(); + pim->msdp.sa_list->del = (void (*)(void *))pim_msdp_sa_free; + pim->msdp.sa_list->cmp = (int (*)(void *, void *))pim_msdp_sa_comp; } /* counterpart to MSDP init; XXX: unused currently */ -void pim_msdp_exit(void) +void pim_msdp_exit(struct pim_instance *pim) { /* XXX: stop listener and delete all peer sessions */ - if (msdp->peer_hash) { - hash_free(msdp->peer_hash); - msdp->peer_hash = NULL; + if (pim->msdp.peer_hash) { + hash_free(pim->msdp.peer_hash); + pim->msdp.peer_hash = NULL; + } + + if (pim->msdp.peer_list) { + list_delete(pim->msdp.peer_list); + pim->msdp.peer_list = NULL; + } + + if (pim->msdp.sa_hash) { + hash_free(pim->msdp.sa_hash); + pim->msdp.sa_hash = NULL; } - if (msdp->peer_list) { - list_free(msdp->peer_list); - msdp->peer_list = NULL; + if (pim->msdp.sa_list) { + list_delete(pim->msdp.sa_list); + pim->msdp.sa_list = NULL; } } diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h index 66e5457df4..0627ee5f47 100644 --- a/pimd/pim_msdp.h +++ b/pimd/pim_msdp.h @@ -69,11 +69,13 @@ enum pim_msdp_sa_flags { PIM_MSDP_SAF_PEER = (1 << 1), PIM_MSDP_SAF_REF = (PIM_MSDP_SAF_LOCAL | PIM_MSDP_SAF_PEER), PIM_MSDP_SAF_STALE = (1 << 2), /* local entries can get kicked out on - * misc pim events such as RP change */ + * misc pim events such as RP change */ PIM_MSDP_SAF_UP_DEL_IN_PROG = (1 << 3) }; struct pim_msdp_sa { + struct pim_instance *pim; + struct prefix_sg sg; char sg_str[PIM_SG_LEN]; struct in_addr rp; /* Last RP address associated with this SA */ @@ -97,6 +99,8 @@ enum pim_msdp_peer_flags { }; struct pim_msdp_peer { + struct pim_instance *pim; + /* configuration */ struct in_addr local; struct in_addr peer; @@ -203,24 +207,30 @@ struct pim_msdp { }; #define PIM_MSDP_PEER_READ_ON(mp) \ - thread_add_read(msdp->master, pim_msdp_read, mp, mp->fd, &mp->t_read) + thread_add_read(mp->pim->msdp.master, pim_msdp_read, mp, mp->fd, \ + &mp->t_read) #define PIM_MSDP_PEER_WRITE_ON(mp) \ - thread_add_write(msdp->master, pim_msdp_write, mp, mp->fd, &mp->t_write) + thread_add_write(mp->pim->msdp.master, pim_msdp_write, mp, mp->fd, \ + &mp->t_write) #define PIM_MSDP_PEER_READ_OFF(mp) THREAD_READ_OFF(mp->t_read) #define PIM_MSDP_PEER_WRITE_OFF(mp) THREAD_WRITE_OFF(mp->t_write) -extern struct pim_msdp *msdp; -void pim_msdp_init(struct thread_master *master); -void pim_msdp_exit(void); -enum pim_msdp_err pim_msdp_peer_add(struct in_addr peer, struct in_addr local, +// struct pim_msdp *msdp; +struct pim_instance; +void pim_msdp_init(struct pim_instance *pim, struct thread_master *master); +void pim_msdp_exit(struct pim_instance *pim); +enum pim_msdp_err pim_msdp_peer_add(struct pim_instance *pim, + struct in_addr peer, struct in_addr local, const char *mesh_group_name, struct pim_msdp_peer **mp_p); -enum pim_msdp_err pim_msdp_peer_del(struct in_addr peer_addr); +enum pim_msdp_err pim_msdp_peer_del(struct pim_instance *pim, + struct in_addr peer_addr); char *pim_msdp_state_dump(enum pim_msdp_peer_state state, char *buf, int buf_size); -struct pim_msdp_peer *pim_msdp_peer_find(struct in_addr peer_addr); +struct pim_msdp_peer *pim_msdp_peer_find(struct pim_instance *pim, + struct in_addr peer_addr); void pim_msdp_peer_established(struct pim_msdp_peer *mp); void pim_msdp_peer_pkt_rxed(struct pim_msdp_peer *mp); void pim_msdp_peer_stop_tcp_conn(struct pim_msdp_peer *mp, bool chg_state); @@ -229,21 +239,29 @@ int pim_msdp_write(struct thread *thread); char *pim_msdp_peer_key_dump(struct pim_msdp_peer *mp, char *buf, int buf_size, bool long_format); int pim_msdp_config_write(struct vty *vty); +int pim_msdp_config_write_helper(struct pim_instance *pim, struct vty *vty, + const char *spaces); void pim_msdp_peer_pkt_txed(struct pim_msdp_peer *mp); -void pim_msdp_sa_ref(struct pim_msdp_peer *mp, struct prefix_sg *sg, - struct in_addr rp); +void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp, + struct prefix_sg *sg, struct in_addr rp); void pim_msdp_sa_local_update(struct pim_upstream *up); -void pim_msdp_sa_local_del(struct prefix_sg *sg); -void pim_msdp_i_am_rp_changed(void); +void pim_msdp_sa_local_del(struct pim_instance *pim, struct prefix_sg *sg); +void pim_msdp_i_am_rp_changed(struct pim_instance *pim); bool pim_msdp_peer_rpf_check(struct pim_msdp_peer *mp, struct in_addr rp); -void pim_msdp_up_join_state_changed(struct pim_upstream *xg_up); -void pim_msdp_up_del(struct prefix_sg *sg); -enum pim_msdp_err pim_msdp_mg_mbr_add(const char *mesh_group_name, +void pim_msdp_up_join_state_changed(struct pim_instance *pim, + struct pim_upstream *xg_up); +void pim_msdp_up_del(struct pim_instance *pim, struct prefix_sg *sg); +enum pim_msdp_err pim_msdp_mg_mbr_add(struct pim_instance *pim, + const char *mesh_group_name, struct in_addr mbr_ip); -enum pim_msdp_err pim_msdp_mg_mbr_del(const char *mesh_group_name, +enum pim_msdp_err pim_msdp_mg_mbr_del(struct pim_instance *pim, + const char *mesh_group_name, struct in_addr mbr_ip); -enum pim_msdp_err pim_msdp_mg_src_del(const char *mesh_group_name); -enum pim_msdp_err pim_msdp_mg_src_add(const char *mesh_group_name, +enum pim_msdp_err pim_msdp_mg_src_del(struct pim_instance *pim, + const char *mesh_group_name); +enum pim_msdp_err pim_msdp_mg_src_add(struct pim_instance *pim, + const char *mesh_group_name, struct in_addr src_ip); -enum pim_msdp_err pim_msdp_mg_del(const char *mesh_group_name); +enum pim_msdp_err pim_msdp_mg_del(struct pim_instance *pim, + const char *mesh_group_name); #endif diff --git a/pimd/pim_msdp_packet.c b/pimd/pim_msdp_packet.c index 01ce293e36..11efc158e9 100644 --- a/pimd/pim_msdp_packet.c +++ b/pimd/pim_msdp_packet.c @@ -310,7 +310,8 @@ void pim_msdp_pkt_ka_tx(struct pim_msdp_peer *mp) pim_msdp_pkt_send(mp, s); } -static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_msdp_peer *mp) +static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_instance *pim, + struct pim_msdp_peer *mp) { struct stream *s; @@ -318,7 +319,7 @@ static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_msdp_peer *mp) /* don't tx anything unless a session is established */ return; } - s = stream_dup(msdp->work_obuf); + s = stream_dup(pim->msdp.work_obuf); if (s) { pim_msdp_pkt_send(mp, s); mp->flags |= PIM_MSDP_PEERF_SA_JUST_SENT; @@ -326,63 +327,66 @@ static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_msdp_peer *mp) } /* push the stream into the obuf fifo of all the peers */ -static void pim_msdp_pkt_sa_push(struct pim_msdp_peer *mp) +static void pim_msdp_pkt_sa_push(struct pim_instance *pim, + struct pim_msdp_peer *mp) { struct listnode *mpnode; if (mp) { - pim_msdp_pkt_sa_push_to_one_peer(mp); + pim_msdp_pkt_sa_push_to_one_peer(pim, mp); } else { - for (ALL_LIST_ELEMENTS_RO(msdp->peer_list, mpnode, mp)) { + for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) { if (PIM_DEBUG_MSDP_INTERNAL) { zlog_debug("MSDP peer %s pim_msdp_pkt_sa_push", mp->key_str); } - pim_msdp_pkt_sa_push_to_one_peer(mp); + pim_msdp_pkt_sa_push_to_one_peer(pim, mp); } } } -static int pim_msdp_pkt_sa_fill_hdr(int local_cnt) +static int pim_msdp_pkt_sa_fill_hdr(struct pim_instance *pim, int local_cnt) { int curr_tlv_ecnt; - stream_reset(msdp->work_obuf); + stream_reset(pim->msdp.work_obuf); curr_tlv_ecnt = local_cnt > PIM_MSDP_SA_MAX_ENTRY_CNT ? PIM_MSDP_SA_MAX_ENTRY_CNT : local_cnt; local_cnt -= curr_tlv_ecnt; - stream_putc(msdp->work_obuf, PIM_MSDP_V4_SOURCE_ACTIVE); - stream_putw(msdp->work_obuf, PIM_MSDP_SA_ENTRY_CNT2SIZE(curr_tlv_ecnt)); - stream_putc(msdp->work_obuf, curr_tlv_ecnt); - stream_put_ipv4(msdp->work_obuf, msdp->originator_id.s_addr); + stream_putc(pim->msdp.work_obuf, PIM_MSDP_V4_SOURCE_ACTIVE); + stream_putw(pim->msdp.work_obuf, + PIM_MSDP_SA_ENTRY_CNT2SIZE(curr_tlv_ecnt)); + stream_putc(pim->msdp.work_obuf, curr_tlv_ecnt); + stream_put_ipv4(pim->msdp.work_obuf, pim->msdp.originator_id.s_addr); return local_cnt; } static void pim_msdp_pkt_sa_fill_one(struct pim_msdp_sa *sa) { - stream_put3(msdp->work_obuf, 0 /* reserved */); - stream_putc(msdp->work_obuf, 32 /* sprefix len */); - stream_put_ipv4(msdp->work_obuf, sa->sg.grp.s_addr); - stream_put_ipv4(msdp->work_obuf, sa->sg.src.s_addr); + stream_put3(sa->pim->msdp.work_obuf, 0 /* reserved */); + stream_putc(sa->pim->msdp.work_obuf, 32 /* sprefix len */); + stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.grp.s_addr); + stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.src.s_addr); } -static void pim_msdp_pkt_sa_gen(struct pim_msdp_peer *mp) +static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, + struct pim_msdp_peer *mp) { struct listnode *sanode; struct pim_msdp_sa *sa; int sa_count; - int local_cnt = msdp->local_cnt; + int local_cnt = pim->msdp.local_cnt; sa_count = 0; if (PIM_DEBUG_MSDP_INTERNAL) { zlog_debug(" sa gen %d", local_cnt); } - local_cnt = pim_msdp_pkt_sa_fill_hdr(local_cnt); + local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt); - for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) { + for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) { if (!(sa->flags & PIM_MSDP_SAF_LOCAL)) { /* current implementation of MSDP is for anycast i.e. * full mesh. so @@ -394,31 +398,31 @@ static void pim_msdp_pkt_sa_gen(struct pim_msdp_peer *mp) pim_msdp_pkt_sa_fill_one(sa); ++sa_count; if (sa_count >= PIM_MSDP_SA_MAX_ENTRY_CNT) { - pim_msdp_pkt_sa_push(mp); + pim_msdp_pkt_sa_push(pim, mp); /* reset headers */ sa_count = 0; if (PIM_DEBUG_MSDP_INTERNAL) { zlog_debug(" sa gen for remainder %d", local_cnt); } - local_cnt = pim_msdp_pkt_sa_fill_hdr(local_cnt); + local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt); } } if (sa_count) { - pim_msdp_pkt_sa_push(mp); + pim_msdp_pkt_sa_push(pim, mp); } return; } -static void pim_msdp_pkt_sa_tx_done(void) +static void pim_msdp_pkt_sa_tx_done(struct pim_instance *pim) { struct listnode *mpnode; struct pim_msdp_peer *mp; /* if SA were sent to the peers we restart ka timer and avoid * unnecessary ka noise */ - for (ALL_LIST_ELEMENTS_RO(msdp->peer_list, mpnode, mp)) { + for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) { if (mp->flags & PIM_MSDP_PEERF_SA_JUST_SENT) { mp->flags &= ~PIM_MSDP_PEERF_SA_JUST_SENT; pim_msdp_peer_pkt_txed(mp); @@ -426,25 +430,25 @@ static void pim_msdp_pkt_sa_tx_done(void) } } -void pim_msdp_pkt_sa_tx(void) +void pim_msdp_pkt_sa_tx(struct pim_instance *pim) { - pim_msdp_pkt_sa_gen(NULL /* mp */); - pim_msdp_pkt_sa_tx_done(); + pim_msdp_pkt_sa_gen(pim, NULL /* mp */); + pim_msdp_pkt_sa_tx_done(pim); } void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa) { - pim_msdp_pkt_sa_fill_hdr(1 /* cnt */); + pim_msdp_pkt_sa_fill_hdr(sa->pim, 1 /* cnt */); pim_msdp_pkt_sa_fill_one(sa); - pim_msdp_pkt_sa_push(NULL); - pim_msdp_pkt_sa_tx_done(); + pim_msdp_pkt_sa_push(sa->pim, NULL); + pim_msdp_pkt_sa_tx_done(sa->pim); } /* when a connection is first established we push all SAs immediately */ void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp) { - pim_msdp_pkt_sa_gen(mp); - pim_msdp_pkt_sa_tx_done(); + pim_msdp_pkt_sa_gen(mp->pim, mp); + pim_msdp_pkt_sa_tx_done(mp->pim); } static void pim_msdp_pkt_rxed_with_fatal_error(struct pim_msdp_peer *mp) @@ -484,7 +488,7 @@ static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp) if (PIM_DEBUG_MSDP_PACKETS) { zlog_debug(" sg %s", pim_str_sg_dump(&sg)); } - pim_msdp_sa_ref(mp, &sg, rp); + pim_msdp_sa_ref(mp->pim, mp, &sg, rp); } static void pim_msdp_pkt_sa_rx(struct pim_msdp_peer *mp, int len) diff --git a/pimd/pim_msdp_packet.h b/pimd/pim_msdp_packet.h index 986fa3b32a..d922fa50df 100644 --- a/pimd/pim_msdp_packet.h +++ b/pimd/pim_msdp_packet.h @@ -64,7 +64,7 @@ void pim_msdp_pkt_ka_tx(struct pim_msdp_peer *mp); int pim_msdp_read(struct thread *thread); -void pim_msdp_pkt_sa_tx(void); +void pim_msdp_pkt_sa_tx(struct pim_instance *pim); void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa); void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp); diff --git a/pimd/pim_msdp_socket.c b/pimd/pim_msdp_socket.c index 0ce0971012..9473462e63 100644 --- a/pimd/pim_msdp_socket.c +++ b/pimd/pim_msdp_socket.c @@ -24,8 +24,11 @@ #include <lib/sockunion.h> #include <lib/thread.h> #include <lib/vty.h> +#include <lib/if.h> +#include <lib/vrf.h> #include "pimd.h" +#include "pim_sock.h" #include "pim_msdp.h" #include "pim_msdp_socket.h" @@ -56,7 +59,7 @@ static void pim_msdp_update_sock_send_buffer_size(int fd) static int pim_msdp_sock_accept(struct thread *thread) { union sockunion su; - struct pim_msdp_listener *listener = THREAD_ARG(thread); + struct pim_instance *pim = THREAD_ARG(thread); int accept_sock; int msdp_sock; struct pim_msdp_peer *mp; @@ -70,9 +73,9 @@ static int pim_msdp_sock_accept(struct thread *thread) zlog_err("accept_sock is negative value %d", accept_sock); return -1; } - listener->thread = NULL; - thread_add_read(master, pim_msdp_sock_accept, listener, accept_sock, - &listener->thread); + pim->msdp.listener.thread = NULL; + thread_add_read(master, pim_msdp_sock_accept, pim, accept_sock, + &pim->msdp.listener.thread); /* accept client connection. */ msdp_sock = sockunion_accept(accept_sock, &su); @@ -83,9 +86,9 @@ static int pim_msdp_sock_accept(struct thread *thread) } /* see if have peer config for this */ - mp = pim_msdp_peer_find(su.sin.sin_addr); + mp = pim_msdp_peer_find(pim, su.sin.sin_addr); if (!mp || !PIM_MSDP_PEER_IS_LISTENER(mp)) { - ++msdp->rejected_accepts; + ++pim->msdp.rejected_accepts; if (PIM_DEBUG_MSDP_EVENTS) { zlog_err("msdp peer connection refused from %s", sockunion2str(&su, buf, SU_ADDRSTRLEN)); @@ -117,15 +120,15 @@ static int pim_msdp_sock_accept(struct thread *thread) } /* global listener for the MSDP well know TCP port */ -int pim_msdp_sock_listen(void) +int pim_msdp_sock_listen(struct pim_instance *pim) { int sock; int socklen; struct sockaddr_in sin; int rc; - struct pim_msdp_listener *listener = &msdp->listener; + struct pim_msdp_listener *listener = &pim->msdp.listener; - if (msdp->flags & PIM_MSDPF_LISTENER) { + if (pim->msdp.flags & PIM_MSDPF_LISTENER) { /* listener already setup */ return 0; } @@ -147,6 +150,17 @@ int pim_msdp_sock_listen(void) sockopt_reuseaddr(sock); sockopt_reuseport(sock); + if (pim->vrf_id != VRF_DEFAULT) { + struct interface *ifp = + if_lookup_by_name(pim->vrf->name, pim->vrf_id); + if (!ifp) { + zlog_err("%s: Unable to lookup vrf interface: %s", + __PRETTY_FUNCTION__, pim->vrf->name); + return -1; + } + pim_socket_bind(sock, ifp); + } + if (pimd_privs.change(ZPRIVS_RAISE)) { zlog_err("pim_msdp_socket: could not raise privs, %s", safe_strerror(errno)); @@ -178,10 +192,10 @@ int pim_msdp_sock_listen(void) listener->fd = sock; memcpy(&listener->su, &sin, socklen); listener->thread = NULL; - thread_add_read(msdp->master, pim_msdp_sock_accept, listener, sock, + thread_add_read(pim->msdp.master, pim_msdp_sock_accept, pim, sock, &listener->thread); - msdp->flags |= PIM_MSDPF_LISTENER; + pim->msdp.flags |= PIM_MSDPF_LISTENER; return 0; } @@ -214,6 +228,17 @@ int pim_msdp_sock_connect(struct pim_msdp_peer *mp) return -1; } + if (mp->pim->vrf_id != VRF_DEFAULT) { + struct interface *ifp = + if_lookup_by_name(mp->pim->vrf->name, mp->pim->vrf_id); + if (!ifp) { + zlog_err("%s: Unable to lookup vrf interface: %s", + __PRETTY_FUNCTION__, mp->pim->vrf->name); + return -1; + } + pim_socket_bind(mp->fd, ifp); + } + set_nonblocking(mp->fd); /* Set socket send buffer size */ diff --git a/pimd/pim_msdp_socket.h b/pimd/pim_msdp_socket.h index 0abcd57da0..8f46683dff 100644 --- a/pimd/pim_msdp_socket.h +++ b/pimd/pim_msdp_socket.h @@ -19,6 +19,6 @@ #ifndef PIM_MSDP_SOCKET_H #define PIM_MSDP_SOCKET_H -int pim_msdp_sock_listen(void); +int pim_msdp_sock_listen(struct pim_instance *pim); int pim_msdp_sock_connect(struct pim_msdp_peer *mp); #endif diff --git a/pimd/pim_msg.c b/pimd/pim_msg.c index 04f1f4846f..5d4ddf14e8 100644 --- a/pimd/pim_msg.c +++ b/pimd/pim_msg.c @@ -36,6 +36,7 @@ #include "pim_rpf.h" #include "pim_register.h" #include "pim_jp_agg.h" +#include "pim_oil.h" void pim_msg_build_header(uint8_t *pim_msg, size_t pim_msg_size, uint8_t pim_msg_type) @@ -104,6 +105,9 @@ size_t pim_msg_get_jp_group_size(struct list *sources) struct pim_jp_sources *js; size_t size = 0; + if (!sources) + return 0; + size += sizeof(struct pim_encoded_group_ipv4); size += 4; // Joined sources (2) + Pruned Sources (2) @@ -195,7 +199,8 @@ size_t pim_msg_build_jp_groups(struct pim_jp_groups *grp, grp->prunes++; if (source->up->sg.src.s_addr == INADDR_ANY) { - struct pim_rpf *rpf = pim_rp_g(source->up->sg.grp); + struct pim_instance *pim = source->up->channel_oil->pim; + struct pim_rpf *rpf = pim_rp_g(pim, source->up->sg.grp); bits = PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_WC_BIT | PIM_ENCODE_RPT_BIT; stosend = rpf->rpf_addr.u.prefix4; diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index 70341a3754..04e3e10ff3 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -545,7 +545,7 @@ pim_neighbor_add(struct interface *ifp, struct in_addr source_addr, else pim_hello_restart_triggered(neigh->interface); - pim_upstream_find_new_rpf(); + pim_upstream_find_new_rpf(pim_ifp->pim); /* RNH can send nexthop update prior to PIM neibhor UP in that case nexthop cache would not consider this neighbor @@ -553,9 +553,9 @@ pim_neighbor_add(struct interface *ifp, struct in_addr source_addr, Upon PIM neighbor UP, iterate all RPs and update nexthop cache with this neighbor. */ - pim_resolve_rp_nh(); + pim_resolve_rp_nh(pim_ifp->pim); - pim_rp_setup(); + pim_rp_setup(pim_ifp->pim); pim_neighbor_rpf_update(); return neigh; diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index f8bf2ac77c..f7fa9993ad 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -44,7 +44,7 @@ * pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister * command to Zebra. */ -void pim_sendmsg_zebra_rnh(struct zclient *zclient, +void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient, struct pim_nexthop_cache *pnc, int command) { struct stream *s; @@ -58,7 +58,7 @@ void pim_sendmsg_zebra_rnh(struct zclient *zclient, p = &(pnc->rpf.rpf_addr); s = zclient->obuf; stream_reset(s); - zclient_create_header(s, command, VRF_DEFAULT); + zclient_create_header(s, command, pim->vrf_id); /* get update for all routes for a prefix */ stream_putc(s, 0); @@ -81,19 +81,21 @@ void pim_sendmsg_zebra_rnh(struct zclient *zclient, zlog_warn("sendmsg_nexthop: zclient_send_message() failed"); - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_NHT) { char buf[PREFIX2STR_BUFFER]; prefix2str(p, buf, sizeof(buf)); - zlog_debug("%s: NHT %sregistered addr %s with Zebra ret:%d ", - __PRETTY_FUNCTION__, - (command == ZEBRA_NEXTHOP_REGISTER) ? " " : "de", - buf, ret); + zlog_debug( + "%s: NHT %sregistered addr %s(%s) with Zebra ret:%d ", + __PRETTY_FUNCTION__, + (command == ZEBRA_NEXTHOP_REGISTER) ? " " : "de", buf, + pim->vrf->name, ret); } return; } -struct pim_nexthop_cache *pim_nexthop_cache_find(struct pim_rpf *rpf) +struct pim_nexthop_cache *pim_nexthop_cache_find(struct pim_instance *pim, + struct pim_rpf *rpf) { struct pim_nexthop_cache *pnc = NULL; struct pim_nexthop_cache lookup; @@ -102,14 +104,17 @@ struct pim_nexthop_cache *pim_nexthop_cache_find(struct pim_rpf *rpf) lookup.rpf.rpf_addr.prefixlen = rpf->rpf_addr.prefixlen; lookup.rpf.rpf_addr.u.prefix4.s_addr = rpf->rpf_addr.u.prefix4.s_addr; - pnc = hash_lookup(pimg->rpf_hash, &lookup); + pnc = hash_lookup(pim->rpf_hash, &lookup); return pnc; } -struct pim_nexthop_cache *pim_nexthop_cache_add(struct pim_rpf *rpf_addr) +static struct pim_nexthop_cache *pim_nexthop_cache_add(struct pim_instance *pim, + struct pim_rpf *rpf_addr) { struct pim_nexthop_cache *pnc; + char hash_name[64]; + char buf1[64]; pnc = XCALLOC(MTYPE_PIM_NEXTHOP_CACHE, sizeof(struct pim_nexthop_cache)); @@ -122,31 +127,31 @@ struct pim_nexthop_cache *pim_nexthop_cache_add(struct pim_rpf *rpf_addr) pnc->rpf.rpf_addr.u.prefix4.s_addr = rpf_addr->rpf_addr.u.prefix4.s_addr; - pnc = hash_get(pimg->rpf_hash, pnc, hash_alloc_intern); + pnc = hash_get(pim->rpf_hash, pnc, hash_alloc_intern); pnc->rp_list = list_new(); pnc->rp_list->cmp = pim_rp_list_cmp; - pnc->upstream_list = list_new(); - pnc->upstream_list->cmp = pim_upstream_compare; - - if (PIM_DEBUG_ZEBRA) { - char rpf_str[PREFIX_STRLEN]; - pim_addr_dump("<nht?>", &rpf_addr->rpf_addr, rpf_str, - sizeof(rpf_str)); - zlog_debug( - "%s: NHT hash node, RP and UP lists allocated for %s ", - __PRETTY_FUNCTION__, rpf_str); - } + snprintf(hash_name, 64, "PNC %s(%s) Upstream Hash", + prefix2str(&pnc->rpf.rpf_addr, buf1, 64), + pim->vrf->name); + pnc->upstream_hash = hash_create_size(8192, pim_upstream_hash_key, + pim_upstream_equal, + hash_name); return pnc; } -/* This API is used to Register an address with Zebra - ret 1 means nexthop cache is found. -*/ -int pim_find_or_track_nexthop(struct prefix *addr, struct pim_upstream *up, - struct rp_info *rp, +/* + * pim_find_or_track_nexthop + * + * This API is used to Register an address with Zebra + * + * 1 -> Success + * 0 -> Failure + */ +int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr, + struct pim_upstream *up, struct rp_info *rp, struct pim_nexthop_cache *out_pnc) { struct pim_nexthop_cache *pnc = NULL; @@ -160,50 +165,36 @@ int pim_find_or_track_nexthop(struct prefix *addr, struct pim_upstream *up, rpf.rpf_addr.prefixlen = addr->prefixlen; rpf.rpf_addr.u.prefix4 = addr->u.prefix4; - pnc = pim_nexthop_cache_find(&rpf); + pnc = pim_nexthop_cache_find(pim, &rpf); if (!pnc) { - pnc = pim_nexthop_cache_add(&rpf); - if (pnc) - pim_sendmsg_zebra_rnh(zclient, pnc, - ZEBRA_NEXTHOP_REGISTER); - else { + pnc = pim_nexthop_cache_add(pim, &rpf); + if (!pnc) { char rpf_str[PREFIX_STRLEN]; pim_addr_dump("<nht-pnc?>", addr, rpf_str, sizeof(rpf_str)); zlog_warn("%s: pnc node allocation failed. addr %s ", __PRETTY_FUNCTION__, rpf_str); - return -1; + return 0; + } + pim_sendmsg_zebra_rnh(pim, zclient, pnc, + ZEBRA_NEXTHOP_REGISTER); + if (PIM_DEBUG_PIM_NHT) { + char buf[PREFIX2STR_BUFFER]; + prefix2str(addr, buf, sizeof(buf)); + zlog_debug( + "%s: NHT cache and zebra notification added for %s(%s)", + __PRETTY_FUNCTION__, buf, pim->vrf->name); } } if (rp != NULL) { ch_node = listnode_lookup(pnc->rp_list, rp); - if (ch_node == NULL) { - if (PIM_DEBUG_ZEBRA) { - char rp_str[PREFIX_STRLEN]; - pim_addr_dump("<rp?>", &rp->rp.rpf_addr, rp_str, - sizeof(rp_str)); - zlog_debug( - "%s: Add RP %s node to pnc cached list", - __PRETTY_FUNCTION__, rp_str); - } + if (ch_node == NULL) listnode_add_sort(pnc->rp_list, rp); - } } - if (up != NULL) { - ch_node = listnode_lookup(pnc->upstream_list, up); - if (ch_node == NULL) { - if (PIM_DEBUG_ZEBRA) { - char buf[PREFIX2STR_BUFFER]; - prefix2str(addr, buf, sizeof(buf)); - zlog_debug( - "%s: Add upstream %s node to pnc cached list, rpf %s", - __PRETTY_FUNCTION__, up->sg_str, buf); - } - listnode_add_sort(pnc->upstream_list, up); - } - } + if (up != NULL) + up = hash_get(pnc->upstream_hash, up, hash_alloc_intern); if (pnc && CHECK_FLAG(pnc->flags, PIM_NEXTHOP_VALID)) { memcpy(out_pnc, pnc, sizeof(struct pim_nexthop_cache)); @@ -213,8 +204,8 @@ int pim_find_or_track_nexthop(struct prefix *addr, struct pim_upstream *up, return 0; } -void pim_delete_tracked_nexthop(struct prefix *addr, struct pim_upstream *up, - struct rp_info *rp) +void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr, + struct pim_upstream *up, struct rp_info *rp) { struct pim_nexthop_cache *pnc = NULL; struct pim_nexthop_cache lookup; @@ -224,28 +215,31 @@ void pim_delete_tracked_nexthop(struct prefix *addr, struct pim_upstream *up, /* Remove from RPF hash if it is the last entry */ lookup.rpf.rpf_addr = *addr; - pnc = hash_lookup(pimg->rpf_hash, &lookup); + pnc = hash_lookup(pim->rpf_hash, &lookup); if (pnc) { if (rp) listnode_delete(pnc->rp_list, rp); if (up) - listnode_delete(pnc->upstream_list, up); + hash_release(pnc->upstream_hash, up); - if (PIM_DEBUG_ZEBRA) + if (PIM_DEBUG_PIM_NHT) { + char buf[PREFIX_STRLEN]; + prefix2str(addr, buf, sizeof buf); zlog_debug( - "%s: NHT rp_list count:%d upstream_list count:%d ", - __PRETTY_FUNCTION__, pnc->rp_list->count, - pnc->upstream_list->count); + "%s: NHT %s(%s) rp_list count:%d upstream count:%ld", + __PRETTY_FUNCTION__, buf, pim->vrf->name, + pnc->rp_list->count, pnc->upstream_hash->count); + } if (pnc->rp_list->count == 0 - && pnc->upstream_list->count == 0) { - pim_sendmsg_zebra_rnh(zclient, pnc, + && pnc->upstream_hash->count == 0) { + pim_sendmsg_zebra_rnh(pim, zclient, pnc, ZEBRA_NEXTHOP_UNREGISTER); list_delete(pnc->rp_list); - list_delete(pnc->upstream_list); + hash_free(pnc->upstream_hash); - hash_release(pimg->rpf_hash, pnc); + hash_release(pim->rpf_hash, pnc); if (pnc->nexthop) nexthops_free(pnc->nexthop); XFREE(MTYPE_PIM_NEXTHOP_CACHE, pnc); @@ -254,7 +248,8 @@ void pim_delete_tracked_nexthop(struct prefix *addr, struct pim_upstream *up, } /* Update RP nexthop info based on Nexthop update received from Zebra.*/ -int pim_update_rp_nh(struct pim_nexthop_cache *pnc) +static int pim_update_rp_nh(struct pim_instance *pim, + struct pim_nexthop_cache *pnc) { struct listnode *node = NULL; struct rp_info *rp_info = NULL; @@ -266,25 +261,12 @@ int pim_update_rp_nh(struct pim_nexthop_cache *pnc) continue; // Compute PIM RPF using cached nexthop - ret = pim_ecmp_nexthop_search(pnc, &rp_info->rp.source_nexthop, - &rp_info->rp.rpf_addr, - &rp_info->group, 1); - - if (PIM_DEBUG_TRACE) { - char rp_str[PREFIX_STRLEN]; - pim_addr_dump("<rp?>", &rp_info->rp.rpf_addr, rp_str, - sizeof(rp_str)); - zlog_debug( - "%s: NHT update, nexthop for RP %s is interface %s ", - __PRETTY_FUNCTION__, rp_str, - rp_info->rp.source_nexthop.interface->name); - } + ret = pim_ecmp_nexthop_search( + pim, pnc, &rp_info->rp.source_nexthop, + &rp_info->rp.rpf_addr, &rp_info->group, 1); } - if (ret) - return 0; - - return 1; + return !ret; } /* This API is used to traverse nexthop cache of RPF addr @@ -292,152 +274,148 @@ int pim_update_rp_nh(struct pim_nexthop_cache *pnc) unresolved state and due to event like pim neighbor UP event if it can be resolved. */ -void pim_resolve_upstream_nh(struct prefix *nht_p) +void pim_resolve_upstream_nh(struct pim_instance *pim, struct prefix *nht_p) { struct nexthop *nh_node = NULL; struct pim_nexthop_cache pnc; struct pim_neighbor *nbr = NULL; memset(&pnc, 0, sizeof(struct pim_nexthop_cache)); - if ((pim_find_or_track_nexthop(nht_p, NULL, NULL, &pnc)) == 1) { - for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next) { - if (nh_node->gate.ipv4.s_addr == 0) { - struct interface *ifp1 = if_lookup_by_index( - nh_node->ifindex, VRF_DEFAULT); - nbr = pim_neighbor_find_if(ifp1); - if (nbr) { - nh_node->gate.ipv4 = nbr->source_addr; - if (PIM_DEBUG_TRACE) { - char str[PREFIX_STRLEN]; - char str1[INET_ADDRSTRLEN]; - pim_inet4_dump("<nht_nbr?>", - nbr->source_addr, - str1, - sizeof(str1)); - pim_addr_dump("<nht_addr?>", - nht_p, str, - sizeof(str)); - zlog_debug( - "%s: addr %s new nexthop addr %s interface %s", - __PRETTY_FUNCTION__, - str, str1, ifp1->name); - } - } - } + if (!pim_find_or_track_nexthop(pim, nht_p, NULL, NULL, &pnc)) + return; + + for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next) { + if (nh_node->gate.ipv4.s_addr != 0) + continue; + + struct interface *ifp1 = + if_lookup_by_index(nh_node->ifindex, pim->vrf_id); + nbr = pim_neighbor_find_if(ifp1); + if (!nbr) + continue; + + nh_node->gate.ipv4 = nbr->source_addr; + if (PIM_DEBUG_PIM_NHT) { + char str[PREFIX_STRLEN]; + char str1[INET_ADDRSTRLEN]; + pim_inet4_dump("<nht_nbr?>", nbr->source_addr, str1, + sizeof(str1)); + pim_addr_dump("<nht_addr?>", nht_p, str, sizeof(str)); + zlog_debug( + "%s: addr %s new nexthop addr %s interface %s", + __PRETTY_FUNCTION__, str, str1, ifp1->name); } } } /* Update Upstream nexthop info based on Nexthop update received from Zebra.*/ -static int pim_update_upstream_nh(struct pim_nexthop_cache *pnc) +static int pim_update_upstream_nh_helper(struct hash_backet *backet, void *arg) { - struct listnode *up_node; - struct listnode *ifnode; - struct listnode *up_nextnode; - struct listnode *node; - struct pim_upstream *up = NULL; - struct interface *ifp = NULL; + struct pim_instance *pim = (struct pim_instance *)arg; + struct pim_upstream *up = (struct pim_upstream *)backet->data; int vif_index = 0; - for (ALL_LIST_ELEMENTS(pnc->upstream_list, up_node, up_nextnode, up)) { - enum pim_rpf_result rpf_result; - struct pim_rpf old; + enum pim_rpf_result rpf_result; + struct pim_rpf old; - old.source_nexthop.interface = up->rpf.source_nexthop.interface; - rpf_result = pim_rpf_update(up, &old, 0); - if (rpf_result == PIM_RPF_FAILURE) - continue; + old.source_nexthop.interface = up->rpf.source_nexthop.interface; + rpf_result = pim_rpf_update(pim, up, &old, 0); + if (rpf_result == PIM_RPF_FAILURE) + return HASHWALK_CONTINUE; - /* update kernel multicast forwarding cache (MFC) */ - if (up->channel_oil) { - ifindex_t ifindex = - up->rpf.source_nexthop.interface->ifindex; - vif_index = pim_if_find_vifindex_by_ifindex(ifindex); - /* Pass Current selected NH vif index to mroute download - */ - if (vif_index) - pim_scan_individual_oil(up->channel_oil, - vif_index); - else { - if (PIM_DEBUG_ZEBRA) - zlog_debug( - "%s: NHT upstream %s channel_oil IIF %s vif_index is not valid", - __PRETTY_FUNCTION__, up->sg_str, - up->rpf.source_nexthop - .interface->name); - } + /* update kernel multicast forwarding cache (MFC) */ + if (up->channel_oil) { + ifindex_t ifindex = up->rpf.source_nexthop.interface->ifindex; + + vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex); + /* Pass Current selected NH vif index to mroute download + */ + if (vif_index) + pim_scan_individual_oil(up->channel_oil, vif_index); + else { + if (PIM_DEBUG_PIM_NHT) + zlog_debug( + "%s: NHT upstream %s channel_oil IIF %s vif_index is not valid", + __PRETTY_FUNCTION__, up->sg_str, + up->rpf.source_nexthop.interface->name); } + } - if (rpf_result == PIM_RPF_CHANGED) { - struct pim_neighbor *nbr; + if (rpf_result == PIM_RPF_CHANGED) { + struct pim_neighbor *nbr; - nbr = pim_neighbor_find(old.source_nexthop.interface, - old.rpf_addr.u.prefix4); - if (nbr) - pim_jp_agg_remove_group(nbr->upstream_jp_agg, - up); + nbr = pim_neighbor_find(old.source_nexthop.interface, + old.rpf_addr.u.prefix4); + if (nbr) + pim_jp_agg_remove_group(nbr->upstream_jp_agg, up); + /* + * We have detected a case where we might need to rescan + * the inherited o_list so do it. + */ + if (up->channel_oil + && up->channel_oil->oil_inherited_rescan) { + pim_upstream_inherited_olist_decide(pim, up); + up->channel_oil->oil_inherited_rescan = 0; + } + + if (up->join_state == PIM_UPSTREAM_JOINED) { /* - * We have detected a case where we might need to rescan - * the inherited o_list so do it. + * If we come up real fast we can be here + * where the mroute has not been installed + * so install it. */ if (up->channel_oil - && up->channel_oil->oil_inherited_rescan) { - pim_upstream_inherited_olist_decide(up); - up->channel_oil->oil_inherited_rescan = 0; - } + && !up->channel_oil->installed) + pim_mroute_add(up->channel_oil, + __PRETTY_FUNCTION__); - if (up->join_state == PIM_UPSTREAM_JOINED) { - /* - * If we come up real fast we can be here - * where the mroute has not been installed - * so install it. - */ - if (up->channel_oil - && !up->channel_oil->installed) - pim_mroute_add(up->channel_oil, - __PRETTY_FUNCTION__); - - /* - RFC 4601: 4.5.7. Sending (S,G) Join/Prune - Messages - - Transitions from Joined State - - RPF'(S,G) changes not due to an Assert - - The upstream (S,G) state machine remains in - Joined - state. Send Join(S,G) to the new upstream - neighbor, which is - the new value of RPF'(S,G). Send Prune(S,G) - to the old - upstream neighbor, which is the old value of - RPF'(S,G). Set - the Join Timer (JT) to expire after - t_periodic seconds. - */ - pim_jp_agg_switch_interface(&old, &up->rpf, up); - - pim_upstream_join_timer_restart(up, &old); - } /* up->join_state == PIM_UPSTREAM_JOINED */ - - /* FIXME can join_desired actually be changed by - pim_rpf_update() - returning PIM_RPF_CHANGED ? */ - pim_upstream_update_join_desired(up); - - } /* PIM_RPF_CHANGED */ - - if (PIM_DEBUG_TRACE) { - zlog_debug("%s: NHT upstream %s old ifp %s new ifp %s", - __PRETTY_FUNCTION__, up->sg_str, - old.source_nexthop.interface->name, - up->rpf.source_nexthop.interface->name); - } - } /* for (pnc->upstream_list) */ + /* + * RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages + * + * Transitions from Joined State + * + * RPF'(S,G) changes not due to an Assert + * + * The upstream (S,G) state machine remains in Joined + * state. Send Join(S,G) to the new upstream + * neighbor, which is the new value of RPF'(S,G). + * Send Prune(S,G) to the old upstream neighbor, which + * is the old value of RPF'(S,G). Set the Join + * Timer (JT) to expire after t_periodic seconds. + */ + pim_jp_agg_switch_interface(&old, &up->rpf, up); + + pim_upstream_join_timer_restart(up, &old); + } /* up->join_state == PIM_UPSTREAM_JOINED */ + + /* + * FIXME can join_desired actually be changed by + * pim_rpf_update() returning PIM_RPF_CHANGED ? + */ + pim_upstream_update_join_desired(pim, up); + + } /* PIM_RPF_CHANGED */ + + if (PIM_DEBUG_PIM_NHT) { + zlog_debug("%s: NHT upstream %s(%s) old ifp %s new ifp %s", + __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name, + old.source_nexthop.interface->name, + up->rpf.source_nexthop.interface->name); + } - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode, ifp)) + return HASHWALK_CONTINUE; +} + +static int pim_update_upstream_nh(struct pim_instance *pim, + struct pim_nexthop_cache *pnc) +{ + struct listnode *node, *ifnode; + struct interface *ifp; + + hash_walk(pnc->upstream_hash, pim_update_upstream_nh_helper, pim); + + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode, ifp)) if (ifp->info) { struct pim_interface *pim_ifp = ifp->info; struct pim_iface_upstream_switch *us; @@ -475,19 +453,11 @@ uint32_t pim_compute_ecmp_hash(struct prefix *src, struct prefix *grp) } hash_val = jhash_2words(g, s, 101); - if (PIM_DEBUG_PIM_TRACE_DETAIL) { - char buf[PREFIX2STR_BUFFER]; - char bufg[PREFIX2STR_BUFFER]; - prefix2str(src, buf, sizeof(buf)); - if (grp) - prefix2str(grp, bufg, sizeof(bufg)); - zlog_debug("%s: addr %s %s hash_val %u", __PRETTY_FUNCTION__, - buf, grp ? bufg : "", hash_val); - } return hash_val; } -int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc, +int pim_ecmp_nexthop_search(struct pim_instance *pim, + struct pim_nexthop_cache *pnc, struct pim_nexthop *nexthop, struct prefix *src, struct prefix *grp, int neighbor_needed) { @@ -499,7 +469,7 @@ int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc, uint8_t nh_iter = 0, found = 0; if (!pnc || !pnc->nexthop_num || !nexthop) - return -1; + return 0; // Current Nexthop is VALID, check to stay on the current path. if (nexthop->interface && nexthop->interface->info @@ -517,9 +487,12 @@ int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc, // If the current nexthop is not valid, candidate to // choose new Nexthop. for (nh_node = pnc->nexthop; nh_node; - nh_node = nh_node->next) + nh_node = nh_node->next) { curr_route_valid = (nexthop->interface->ifindex == nh_node->ifindex); + if (curr_route_valid) + break; + } if (curr_route_valid && !pim_if_connected_to_source(nexthop->interface, @@ -529,12 +502,12 @@ int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc, nexthop->mrib_nexthop_addr.u.prefix4); if (!nbr && !if_is_loopback(nexthop->interface)) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_NHT) zlog_debug( "%s: current nexthop does not have nbr ", __PRETTY_FUNCTION__); } else { - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_NHT) { char src_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", src->u.prefix4, @@ -546,9 +519,10 @@ int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc, grp_str, sizeof(grp_str)); zlog_debug( - "%s: (%s, %s) current nexthop %s is valid, skipping new path selection", + "%s: (%s,%s)(%s) current nexthop %s is valid, skipping new path selection", __PRETTY_FUNCTION__, src_str, grp_str, + pim->vrf->name, nexthop->interface->name); } return 0; @@ -560,24 +534,22 @@ int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc, // PIM ECMP flag is enable then choose ECMP path. hash_val = pim_compute_ecmp_hash(src, grp); mod_val = hash_val % pnc->nexthop_num; - if (PIM_DEBUG_PIM_TRACE_DETAIL) - zlog_debug("%s: hash_val %u mod_val %u ", - __PRETTY_FUNCTION__, hash_val, mod_val); } for (nh_node = pnc->nexthop; nh_node && (found == 0); nh_node = nh_node->next) { first_ifindex = nh_node->ifindex; - ifp = if_lookup_by_index(first_ifindex, VRF_DEFAULT); + ifp = if_lookup_by_index(first_ifindex, pim->vrf_id); if (!ifp) { - if (PIM_DEBUG_ZEBRA) { + if (PIM_DEBUG_PIM_NHT) { char addr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", src->u.prefix4, addr_str, sizeof(addr_str)); zlog_debug( - "%s %s: could not find interface for ifindex %d (address %s)", + "%s %s: could not find interface for ifindex %d (address %s(%s))", __FILE__, __PRETTY_FUNCTION__, - first_ifindex, addr_str); + first_ifindex, addr_str, + pim->vrf->name); } if (nh_iter == mod_val) mod_val++; // Select nexthpath @@ -585,14 +557,15 @@ int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc, continue; } if (!ifp->info) { - if (PIM_DEBUG_ZEBRA) { + if (PIM_DEBUG_PIM_NHT) { char addr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", src->u.prefix4, addr_str, sizeof(addr_str)); zlog_debug( - "%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)", + "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)", __PRETTY_FUNCTION__, ifp->name, - first_ifindex, addr_str); + pim->vrf->name, first_ifindex, + addr_str); } if (nh_iter == mod_val) mod_val++; // Select nexthpath @@ -603,14 +576,12 @@ int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc, if (neighbor_needed && !pim_if_connected_to_source(ifp, src->u.prefix4)) { nbr = pim_neighbor_find(ifp, nh_node->gate.ipv4); - if (PIM_DEBUG_PIM_TRACE_DETAIL) - zlog_debug("ifp name: %s, pim nbr: %p", - ifp->name, nbr); if (!nbr && !if_is_loopback(ifp)) { - if (PIM_DEBUG_ZEBRA) + if (PIM_DEBUG_PIM_NHT) zlog_debug( - "%s: pim nbr not found on input interface %s", - __PRETTY_FUNCTION__, ifp->name); + "%s: pim nbr not found on input interface %s(%s)", + __PRETTY_FUNCTION__, ifp->name, + pim->vrf->name); if (nh_iter == mod_val) mod_val++; // Select nexthpath nh_iter++; @@ -630,7 +601,7 @@ int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc, nexthop->last_lookup_time = pim_time_monotonic_usec(); nexthop->nbr = nbr; found = 1; - if (PIM_DEBUG_ZEBRA) { + if (PIM_DEBUG_PIM_NHT) { char buf[INET_ADDRSTRLEN]; char buf2[INET_ADDRSTRLEN]; char buf3[INET_ADDRSTRLEN]; @@ -643,19 +614,19 @@ int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc, nexthop->mrib_nexthop_addr.u.prefix4, buf, sizeof(buf)); zlog_debug( - "%s: (%s, %s) selected nhop interface %s addr %s mod_val %u iter %d ecmp %d", + "%s: (%s,%s)(%s) selected nhop interface %s addr %s mod_val %u iter %d ecmp %d", __PRETTY_FUNCTION__, buf2, buf3, - ifp->name, buf, mod_val, nh_iter, - qpim_ecmp_enable); + pim->vrf->name, ifp->name, buf, mod_val, + nh_iter, qpim_ecmp_enable); } } nh_iter++; } if (found) - return 0; + return 1; else - return -1; + return 0; } /* This API is used to parse Registered address nexthop update coming from Zebra @@ -676,8 +647,8 @@ int pim_parse_nexthop_update(int command, struct zclient *zclient, struct pim_neighbor *nbr = NULL; struct interface *ifp = NULL; struct interface *ifp1 = NULL; - struct pim_interface *pim_ifp = NULL; - char str[INET_ADDRSTRLEN]; + struct vrf *vrf = vrf_lookup_by_id(vrf_id); + struct pim_instance *pim = vrf->info; s = zclient->ibuf; memset(&p, 0, sizeof(struct prefix)); @@ -698,9 +669,9 @@ int pim_parse_nexthop_update(int command, struct zclient *zclient, rpf.rpf_addr.family = p.family; rpf.rpf_addr.prefixlen = p.prefixlen; rpf.rpf_addr.u.prefix4.s_addr = p.u.prefix4.s_addr; - pnc = pim_nexthop_cache_find(&rpf); + pnc = pim_nexthop_cache_find(pim, &rpf); if (!pnc) { - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_NHT) { char buf[PREFIX2STR_BUFFER]; prefix2str(&rpf.rpf_addr, buf, sizeof(buf)); zlog_debug( @@ -746,31 +717,12 @@ int pim_parse_nexthop_update(int command, struct zclient *zclient, stream_get(&nexthop->gate.ipv6, s, 16); nexthop->ifindex = stream_getl(s); ifp1 = if_lookup_by_index(nexthop->ifindex, - VRF_DEFAULT); + pim->vrf_id); nbr = pim_neighbor_find_if(ifp1); /* Overwrite with Nbr address as NH addr */ - if (nbr) { + if (nbr) nexthop->gate.ipv4 = nbr->source_addr; - if (PIM_DEBUG_TRACE) { - pim_inet4_dump("<nht_nbr?>", - nbr->source_addr, - str, - sizeof(str)); - zlog_debug( - "%s: NHT using pim nbr addr %s interface %s as rpf", - __PRETTY_FUNCTION__, - str, ifp1->name); - } - } else { - if (PIM_DEBUG_TRACE) { - pim_ifp = ifp1->info; - zlog_debug( - "%s: NHT pim nbr not found on interface %s nbr count:%d ", - __PRETTY_FUNCTION__, - ifp1->name, - pim_ifp->pim_neighbor_list - ->count); - } + else { // Mark nexthop address to 0 until PIM // Nbr is resolved. nexthop->gate.ipv4.s_addr = @@ -783,24 +735,15 @@ int pim_parse_nexthop_update(int command, struct zclient *zclient, break; } - if (PIM_DEBUG_TRACE) { - char p_str[PREFIX2STR_BUFFER]; - prefix2str(&p, p_str, sizeof(p_str)); - zlog_debug( - "%s: NHT addr %s %d-nhop via %s type %d distance:%u metric:%u ", - __PRETTY_FUNCTION__, p_str, i + 1, - inet_ntoa(nexthop->gate.ipv4), - nexthop->type, distance, metric); - } - - ifp = if_lookup_by_index(nexthop->ifindex, VRF_DEFAULT); + ifp = if_lookup_by_index(nexthop->ifindex, pim->vrf_id); if (!ifp) { - if (PIM_DEBUG_ZEBRA) { + if (PIM_DEBUG_PIM_NHT) { char buf[NEXTHOP_STRLEN]; zlog_debug( - "%s: could not find interface for ifindex %d (addr %s)", + "%s: could not find interface for ifindex %d(%s) (addr %s)", __PRETTY_FUNCTION__, nexthop->ifindex, + pim->vrf->name, nexthop2str(nexthop, buf, sizeof(buf))); } @@ -808,12 +751,25 @@ int pim_parse_nexthop_update(int command, struct zclient *zclient, continue; } + if (PIM_DEBUG_PIM_NHT) { + char p_str[PREFIX2STR_BUFFER]; + prefix2str(&p, p_str, sizeof(p_str)); + zlog_debug( + "%s: NHT addr %s(%s) %d-nhop via %s(%s) type %d distance:%u metric:%u ", + __PRETTY_FUNCTION__, p_str, + pim->vrf->name, i + 1, + inet_ntoa(nexthop->gate.ipv4), + ifp->name, nexthop->type, distance, + metric); + } + if (!ifp->info) { - if (PIM_DEBUG_ZEBRA) { + if (PIM_DEBUG_PIM_NHT) { char buf[NEXTHOP_STRLEN]; zlog_debug( - "%s: multicast not enabled on input interface %s (ifindex=%d, addr %s)", + "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, addr %s)", __PRETTY_FUNCTION__, ifp->name, + pim->vrf->name, nexthop->ifindex, nexthop2str(nexthop, buf, sizeof(buf))); @@ -847,27 +803,28 @@ int pim_parse_nexthop_update(int command, struct zclient *zclient, pnc->nexthop = NULL; } - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_NHT) { char buf[PREFIX2STR_BUFFER]; prefix2str(&p, buf, sizeof(buf)); zlog_debug( - "%s: NHT Update for %s num_nh %d num_pim_nh %d vrf:%d up %d rp %d", - __PRETTY_FUNCTION__, buf, nexthop_num, pnc->nexthop_num, - vrf_id, listcount(pnc->upstream_list), + "%s: NHT Update for %s(%s) num_nh %d num_pim_nh %d vrf:%d up %ld rp %d", + __PRETTY_FUNCTION__, buf, pim->vrf->name, nexthop_num, + pnc->nexthop_num, vrf_id, pnc->upstream_hash->count, listcount(pnc->rp_list)); } pim_rpf_set_refresh_time(); if (listcount(pnc->rp_list)) - pim_update_rp_nh(pnc); - if (listcount(pnc->upstream_list)) - pim_update_upstream_nh(pnc); + pim_update_rp_nh(pim, pnc); + if (pnc->upstream_hash->count) + pim_update_upstream_nh(pim, pnc); return 0; } -int pim_ecmp_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, +int pim_ecmp_nexthop_lookup(struct pim_instance *pim, + struct pim_nexthop *nexthop, struct in_addr addr, struct prefix *src, struct prefix *grp, int neighbor_needed) { @@ -880,32 +837,35 @@ int pim_ecmp_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, uint8_t i = 0; uint32_t hash_val = 0, mod_val = 0; - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_NHT) { char addr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); - zlog_debug("%s: Looking up: %s, last lookup time: %lld", - __PRETTY_FUNCTION__, addr_str, + zlog_debug("%s: Looking up: %s(%s), last lookup time: %lld", + __PRETTY_FUNCTION__, addr_str, pim->vrf->name, nexthop->last_lookup_time); } memset(nexthop_tab, 0, sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM); - num_ifindex = zclient_lookup_nexthop(nexthop_tab, MULTIPATH_NUM, addr, - PIM_NEXTHOP_LOOKUP_MAX); + num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM, + addr, PIM_NEXTHOP_LOOKUP_MAX); if (num_ifindex < 1) { - char addr_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); - zlog_warn( - "%s %s: could not find nexthop ifindex for address %s", - __FILE__, __PRETTY_FUNCTION__, addr_str); - return -1; + if (PIM_DEBUG_PIM_NHT) { + char addr_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); + zlog_warn( + "%s: could not find nexthop ifindex for address %s(%s)", + __PRETTY_FUNCTION__, addr_str, + pim->vrf->name); + } + return 0; } // If PIM ECMP enable then choose ECMP path. if (qpim_ecmp_enable) { hash_val = pim_compute_ecmp_hash(src, grp); mod_val = hash_val % num_ifindex; - if (PIM_DEBUG_PIM_TRACE_DETAIL) + if (PIM_DEBUG_PIM_NHT_DETAIL) zlog_debug("%s: hash_val %u mod_val %u", __PRETTY_FUNCTION__, hash_val, mod_val); } @@ -913,16 +873,17 @@ int pim_ecmp_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, while (!found && (i < num_ifindex)) { first_ifindex = nexthop_tab[i].ifindex; - ifp = if_lookup_by_index(first_ifindex, VRF_DEFAULT); + ifp = if_lookup_by_index(first_ifindex, pim->vrf_id); if (!ifp) { - if (PIM_DEBUG_ZEBRA) { + if (PIM_DEBUG_PIM_NHT) { char addr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); zlog_debug( - "%s %s: could not find interface for ifindex %d (address %s)", + "%s %s: could not find interface for ifindex %d (address %s(%s))", __FILE__, __PRETTY_FUNCTION__, - first_ifindex, addr_str); + first_ifindex, addr_str, + pim->vrf->name); } if (i == mod_val) mod_val++; @@ -931,14 +892,15 @@ int pim_ecmp_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, } if (!ifp->info) { - if (PIM_DEBUG_ZEBRA) { + if (PIM_DEBUG_PIM_NHT) { char addr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); zlog_debug( - "%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)", + "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)", __PRETTY_FUNCTION__, ifp->name, - first_ifindex, addr_str); + pim->vrf->name, first_ifindex, + addr_str); } if (i == mod_val) mod_val++; @@ -948,29 +910,29 @@ int pim_ecmp_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, if (neighbor_needed && !pim_if_connected_to_source(ifp, addr)) { nbr = pim_neighbor_find( ifp, nexthop_tab[i].nexthop_addr.u.prefix4); - if (PIM_DEBUG_PIM_TRACE_DETAIL) - zlog_debug("ifp name: %s, pim nbr: %p", - ifp->name, nbr); + if (PIM_DEBUG_PIM_NHT_DETAIL) + zlog_debug("ifp name: %s(%s), pim nbr: %p", + ifp->name, pim->vrf->name, nbr); if (!nbr && !if_is_loopback(ifp)) { if (i == mod_val) mod_val++; i++; - if (PIM_DEBUG_ZEBRA) { + if (PIM_DEBUG_PIM_NHT) { char addr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); zlog_debug( - "%s: NBR not found on input interface %s (RPF for source %s)", + "%s: NBR not found on input interface %s(%s) (RPF for source %s)", __PRETTY_FUNCTION__, ifp->name, - addr_str); + pim->vrf->name, addr_str); } continue; } } if (i == mod_val) { - if (PIM_DEBUG_ZEBRA) { + if (PIM_DEBUG_PIM_NHT) { char nexthop_str[PREFIX_STRLEN]; char addr_str[INET_ADDRSTRLEN]; pim_addr_dump("<nexthop?>", @@ -979,9 +941,9 @@ int pim_ecmp_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); zlog_debug( - "%s %s: found nhop %s for addr %s interface %s metric %d dist %d", - __FILE__, __PRETTY_FUNCTION__, - nexthop_str, addr_str, ifp->name, + "%s: found nhop %s for addr %s interface %s(%s) metric %d dist %d", + __PRETTY_FUNCTION__, nexthop_str, + addr_str, ifp->name, pim->vrf->name, nexthop_tab[i].route_metric, nexthop_tab[i].protocol_distance); } @@ -1000,13 +962,15 @@ int pim_ecmp_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, } i++; } + if (found) - return 0; + return 1; else - return -1; + return 0; } -int pim_ecmp_fib_lookup_if_vif_index(struct in_addr addr, struct prefix *src, +int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim, + struct in_addr addr, struct prefix *src, struct prefix *grp) { struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM]; @@ -1017,16 +981,16 @@ int pim_ecmp_fib_lookup_if_vif_index(struct in_addr addr, struct prefix *src, memset(nexthop_tab, 0, sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM); - num_ifindex = zclient_lookup_nexthop(nexthop_tab, MULTIPATH_NUM, addr, - PIM_NEXTHOP_LOOKUP_MAX); + num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM, + addr, PIM_NEXTHOP_LOOKUP_MAX); if (num_ifindex < 1) { - if (PIM_DEBUG_ZEBRA) { + if (PIM_DEBUG_PIM_NHT) { char addr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); zlog_debug( - "%s %s: could not find nexthop ifindex for address %s", - __FILE__, __PRETTY_FUNCTION__, addr_str); + "%s: could not find nexthop ifindex for address %s(%s)", + __PRETTY_FUNCTION__, addr_str, pim->vrf->name); } return -1; } @@ -1035,32 +999,33 @@ int pim_ecmp_fib_lookup_if_vif_index(struct in_addr addr, struct prefix *src, if (qpim_ecmp_enable) { hash_val = pim_compute_ecmp_hash(src, grp); mod_val = hash_val % num_ifindex; - if (PIM_DEBUG_PIM_TRACE_DETAIL) + if (PIM_DEBUG_PIM_NHT_DETAIL) zlog_debug("%s: hash_val %u mod_val %u", __PRETTY_FUNCTION__, hash_val, mod_val); } first_ifindex = nexthop_tab[mod_val].ifindex; - if (PIM_DEBUG_ZEBRA) { + if (PIM_DEBUG_PIM_NHT) { char addr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str)); zlog_debug( - "%s %s: found nexthop ifindex=%d (interface %s) for address %s", - __FILE__, __PRETTY_FUNCTION__, first_ifindex, - ifindex2ifname(first_ifindex, VRF_DEFAULT), addr_str); + "%s: found nexthop ifindex=%d (interface %s(%s)) for address %s", + __PRETTY_FUNCTION__, first_ifindex, + ifindex2ifname(first_ifindex, pim->vrf_id), + pim->vrf->name, addr_str); } - vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex); + vif_index = pim_if_find_vifindex_by_ifindex(pim, first_ifindex); if (vif_index < 0) { - if (PIM_DEBUG_ZEBRA) { + if (PIM_DEBUG_PIM_NHT) { char addr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); zlog_debug( - "%s %s: low vif_index=%d < 1 nexthop for address %s", - __FILE__, __PRETTY_FUNCTION__, vif_index, + "%s: low vif_index=%d(%s) < 1 nexthop for address %s", + __PRETTY_FUNCTION__, vif_index, pim->vrf->name, addr_str); } return -2; diff --git a/pimd/pim_nht.h b/pimd/pim_nht.h index fb8d836235..72ed777bf7 100644 --- a/pimd/pim_nht.h +++ b/pimd/pim_nht.h @@ -43,29 +43,31 @@ struct pim_nexthop_cache { #define PIM_NEXTHOP_VALID (1 << 0) struct list *rp_list; - struct list *upstream_list; + struct hash *upstream_hash; }; int pim_parse_nexthop_update(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id); -int pim_find_or_track_nexthop(struct prefix *addr, struct pim_upstream *up, - struct rp_info *rp, +int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr, + struct pim_upstream *up, struct rp_info *rp, struct pim_nexthop_cache *out_pnc); -void pim_delete_tracked_nexthop(struct prefix *addr, struct pim_upstream *up, - struct rp_info *rp); -struct pim_nexthop_cache *pim_nexthop_cache_add(struct pim_rpf *rpf_addr); -struct pim_nexthop_cache *pim_nexthop_cache_find(struct pim_rpf *rpf); +void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr, + struct pim_upstream *up, struct rp_info *rp); +struct pim_nexthop_cache *pim_nexthop_cache_find(struct pim_instance *pim, + struct pim_rpf *rpf); uint32_t pim_compute_ecmp_hash(struct prefix *src, struct prefix *grp); -int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc, +int pim_ecmp_nexthop_search(struct pim_instance *pim, + struct pim_nexthop_cache *pnc, struct pim_nexthop *nexthop, struct prefix *src, struct prefix *grp, int neighbor_needed); -int pim_ecmp_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, +int pim_ecmp_nexthop_lookup(struct pim_instance *pim, + struct pim_nexthop *nexthop, struct in_addr addr, struct prefix *src, struct prefix *grp, int neighbor_needed); -void pim_sendmsg_zebra_rnh(struct zclient *zclient, +void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient, struct pim_nexthop_cache *pnc, int command); -int pim_update_rp_nh(struct pim_nexthop_cache *pnc); -void pim_resolve_upstream_nh(struct prefix *nht_p); -int pim_ecmp_fib_lookup_if_vif_index(struct in_addr addr, struct prefix *src, +void pim_resolve_upstream_nh(struct pim_instance *pim, struct prefix *nht_p); +int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim, + struct in_addr addr, struct prefix *src, struct prefix *grp); #endif diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index aeef0ff4ec..9ab0709d3e 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -32,8 +32,8 @@ #include "pim_iface.h" #include "pim_time.h" -struct list *pim_channel_oil_list = NULL; -struct hash *pim_channel_oil_hash = NULL; +// struct list *pim_channel_oil_list = NULL; +// struct hash *pim_channel_oil_hash = NULL; char *pim_channel_oil_dump(struct channel_oil *c_oil, char *buf, size_t size) { @@ -99,31 +99,36 @@ static unsigned int pim_oil_hash_key(void *arg) oil->oil.mfcc_origin.s_addr, 0); } -void pim_oil_init(void) +void pim_oil_init(struct pim_instance *pim) { - pim_channel_oil_hash = - hash_create_size(8192, pim_oil_hash_key, pim_oil_equal, NULL); + char hash_name[64]; - pim_channel_oil_list = list_new(); - if (!pim_channel_oil_list) { + snprintf(hash_name, 64, "PIM %s Oil Hash", pim->vrf->name); + pim->channel_oil_hash = hash_create_size(8192, + pim_oil_hash_key, + pim_oil_equal, + hash_name); + + pim->channel_oil_list = list_new(); + if (!pim->channel_oil_list) { zlog_err("%s %s: failure: channel_oil_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return; } - pim_channel_oil_list->del = (void (*)(void *))pim_channel_oil_free; - pim_channel_oil_list->cmp = + pim->channel_oil_list->del = (void (*)(void *))pim_channel_oil_free; + pim->channel_oil_list->cmp = (int (*)(void *, void *))pim_channel_oil_compare; } -void pim_oil_terminate(void) +void pim_oil_terminate(struct pim_instance *pim) { - if (pim_channel_oil_list) - list_free(pim_channel_oil_list); - pim_channel_oil_list = NULL; + if (pim->channel_oil_list) + list_delete(pim->channel_oil_list); + pim->channel_oil_list = NULL; - if (pim_channel_oil_hash) - hash_free(pim_channel_oil_hash); - pim_channel_oil_hash = NULL; + if (pim->channel_oil_hash) + hash_free(pim->channel_oil_hash); + pim->channel_oil_hash = NULL; } void pim_channel_oil_free(struct channel_oil *c_oil) @@ -131,7 +136,8 @@ void pim_channel_oil_free(struct channel_oil *c_oil) XFREE(MTYPE_PIM_CHANNEL_OIL, c_oil); } -static struct channel_oil *pim_find_channel_oil(struct prefix_sg *sg) +static struct channel_oil *pim_find_channel_oil(struct pim_instance *pim, + struct prefix_sg *sg) { struct channel_oil *c_oil = NULL; struct channel_oil lookup; @@ -139,18 +145,19 @@ static struct channel_oil *pim_find_channel_oil(struct prefix_sg *sg) lookup.oil.mfcc_mcastgrp = sg->grp; lookup.oil.mfcc_origin = sg->src; - c_oil = hash_lookup(pim_channel_oil_hash, &lookup); + c_oil = hash_lookup(pim->channel_oil_hash, &lookup); return c_oil; } -struct channel_oil *pim_channel_oil_add(struct prefix_sg *sg, +struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, + struct prefix_sg *sg, int input_vif_index) { struct channel_oil *c_oil; struct interface *ifp; - c_oil = pim_find_channel_oil(sg); + c_oil = pim_find_channel_oil(pim, sg); if (c_oil) { if (c_oil->oil.mfcc_parent != input_vif_index) { c_oil->oil_inherited_rescan = 1; @@ -165,11 +172,11 @@ struct channel_oil *pim_channel_oil_add(struct prefix_sg *sg, c_oil->oil.mfcc_parent = input_vif_index; ++c_oil->oil_ref_count; c_oil->up = pim_upstream_find( - sg); // channel might be present prior to upstream + pim, sg); // channel might be present prior to upstream return c_oil; } - ifp = pim_if_find_by_vif_index(input_vif_index); + ifp = pim_if_find_by_vif_index(pim, input_vif_index); if (!ifp) { /* warning only */ zlog_warn( @@ -186,14 +193,15 @@ struct channel_oil *pim_channel_oil_add(struct prefix_sg *sg, c_oil->oil.mfcc_mcastgrp = sg->grp; c_oil->oil.mfcc_origin = sg->src; - c_oil = hash_get(pim_channel_oil_hash, c_oil, hash_alloc_intern); + c_oil = hash_get(pim->channel_oil_hash, c_oil, hash_alloc_intern); c_oil->oil.mfcc_parent = input_vif_index; c_oil->oil_ref_count = 1; c_oil->installed = 0; - c_oil->up = pim_upstream_find(sg); + c_oil->up = pim_upstream_find(pim, sg); + c_oil->pim = pim; - listnode_add_sort(pim_channel_oil_list, c_oil); + listnode_add_sort(pim->channel_oil_list, c_oil); return c_oil; } @@ -209,8 +217,8 @@ void pim_channel_oil_del(struct channel_oil *c_oil) * called by list_delete_all_node() */ c_oil->up = NULL; - listnode_delete(pim_channel_oil_list, c_oil); - hash_release(pim_channel_oil_hash, c_oil); + listnode_delete(c_oil->pim->channel_oil_list, c_oil); + hash_release(c_oil->pim->channel_oil_hash, c_oil); pim_channel_oil_free(c_oil); } diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h index f537062c7a..1168ba0a8f 100644 --- a/pimd/pim_oil.h +++ b/pimd/pim_oil.h @@ -67,6 +67,8 @@ struct channel_counts { */ struct channel_oil { + struct pim_instance *pim; + struct mfcctl oil; int installed; int oil_inherited_rescan; @@ -80,11 +82,12 @@ struct channel_oil { extern struct list *pim_channel_oil_list; -void pim_oil_init(void); -void pim_oil_terminate(void); +void pim_oil_init(struct pim_instance *pim); +void pim_oil_terminate(struct pim_instance *pim); void pim_channel_oil_free(struct channel_oil *c_oil); -struct channel_oil *pim_channel_oil_add(struct prefix_sg *sg, +struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, + struct prefix_sg *sg, int input_vif_index); void pim_channel_oil_del(struct channel_oil *c_oil); diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 21892f3477..ffe5d52a15 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -238,7 +238,7 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len) pim_msg_len - PIM_MSG_HEADER_LEN); break; case PIM_MSG_TYPE_REG_STOP: - return pim_register_stop_recv(pim_msg + PIM_MSG_HEADER_LEN, + return pim_register_stop_recv(ifp, pim_msg + PIM_MSG_HEADER_LEN, pim_msg_len - PIM_MSG_HEADER_LEN); break; case PIM_MSG_TYPE_JOIN_PRUNE: @@ -286,7 +286,7 @@ static void pim_sock_read_on(struct interface *ifp); static int pim_sock_read(struct thread *t) { - struct interface *ifp; + struct interface *ifp, *orig_ifp; struct pim_interface *pim_ifp; int fd; struct sockaddr_in from; @@ -300,7 +300,7 @@ static int pim_sock_read(struct thread *t) static long long count = 0; int cont = 1; - ifp = THREAD_ARG(t); + orig_ifp = ifp = THREAD_ARG(t); fd = THREAD_FD(t); pim_ifp = ifp->info; @@ -320,36 +320,20 @@ static int pim_sock_read(struct thread *t) goto done; } -#ifdef PIM_CHECK_RECV_IFINDEX_SANITY - /* ifindex sanity check */ - if (ifindex != (int)ifp->ifindex) { - char from_str[INET_ADDRSTRLEN]; - char to_str[INET_ADDRSTRLEN]; - struct interface *recv_ifp; - - if (!inet_ntop(AF_INET, &from.sin_addr, from_str, - sizeof(from_str))) - sprintf(from_str, "<from?>"); - if (!inet_ntop(AF_INET, &to.sin_addr, to_str, - sizeof(to_str))) - sprintf(to_str, "<to?>"); - - recv_ifp = if_lookup_by_index(ifindex, VRF_DEFAULT); - if (recv_ifp) { - zassert(ifindex == (int)recv_ifp->ifindex); - } - -#ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH - zlog_warn( - "Interface mismatch: recv PIM pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)", - from_str, to_str, fd, ifindex, - recv_ifp ? recv_ifp->name : "<if-notfound>", - ifp->ifindex, ifp->name); -#endif + /* + * What? So with vrf's the incoming packet is received + * on the vrf interface but recvfromto above returns + * the right ifindex, so just use it. We know + * it's the right interface because we bind to it + */ + ifp = if_lookup_by_index(ifindex, pim_ifp->pim->vrf_id); + if (!ifp || !ifp->info) { + if (PIM_DEBUG_PIM_PACKETS) + zlog_debug( + "%s: Received incoming pim packet on interface not yet configured for pim", + __PRETTY_FUNCTION__); goto done; } -#endif - int fail = pim_pim_packet(ifp, buf, len); if (fail) { if (PIM_DEBUG_PIM_PACKETS) @@ -366,7 +350,7 @@ static int pim_sock_read(struct thread *t) result = 0; /* good */ done: - pim_sock_read_on(ifp); + pim_sock_read_on(orig_ifp); if (result) { ++pim_ifp->pim_ifstat_hello_recvfail; @@ -667,13 +651,9 @@ static int hello_send(struct interface *ifp, uint16_t holdtime) static int pim_hello_send(struct interface *ifp, uint16_t holdtime) { - struct pim_interface *pim_ifp; - - zassert(ifp); - pim_ifp = ifp->info; - zassert(pim_ifp); + struct pim_interface *pim_ifp = ifp->info; - if (if_is_loopback(ifp)) + if (pim_if_is_loopback(pim_ifp->pim, ifp)) return 0; if (hello_send(ifp, holdtime)) { @@ -695,9 +675,7 @@ static void hello_resched(struct interface *ifp) { struct pim_interface *pim_ifp; - zassert(ifp); pim_ifp = ifp->info; - zassert(pim_ifp); if (PIM_DEBUG_PIM_HELLO) { zlog_debug("Rescheduling %d sec hello on interface %s", @@ -718,7 +696,6 @@ static int on_pim_hello_send(struct thread *t) struct interface *ifp; ifp = THREAD_ARG(t); - pim_ifp = ifp->info; /* @@ -745,9 +722,7 @@ void pim_hello_restart_now(struct interface *ifp) { struct pim_interface *pim_ifp; - zassert(ifp); pim_ifp = ifp->info; - zassert(pim_ifp); /* * Reset next hello timer @@ -775,9 +750,13 @@ void pim_hello_restart_triggered(struct interface *ifp) int triggered_hello_delay_msec; int random_msec; - zassert(ifp); pim_ifp = ifp->info; - zassert(pim_ifp); + + /* + * No need to ever start loopback or vrf device hello's + */ + if (pim_if_is_loopback(pim_ifp->pim, ifp)) + return; /* * There exists situations where we have the a RPF out this diff --git a/pimd/pim_register.c b/pimd/pim_register.c index 1cbe1dcf7f..a393d0bbda 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -48,14 +48,16 @@ struct thread *send_test_packet_timer = NULL; void pim_register_join(struct pim_upstream *up) { - if (pim_is_grp_ssm(up->sg.grp)) { + struct pim_instance *pim = up->channel_oil->pim; + + if (pim_is_grp_ssm(pim, up->sg.grp)) { if (PIM_DEBUG_PIM_EVENTS) zlog_debug("%s register setup skipped as group is SSM", up->sg_str); return; } - pim_channel_add_oif(up->channel_oil, pim_regiface, + pim_channel_add_oif(up->channel_oil, pim->regiface, PIM_OIF_FLAG_PROTO_PIM); up->reg_state = PIM_REG_JOIN; } @@ -109,8 +111,10 @@ void pim_register_stop_send(struct interface *ifp, struct prefix_sg *sg, ++pinfo->pim_ifstat_reg_stop_send; } -int pim_register_stop_recv(uint8_t *buf, int buf_size) +int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size) { + struct pim_interface *pim_ifp = ifp->info; + struct pim_instance *pim = pim_ifp->pim; struct pim_upstream *upstream = NULL; struct prefix source; struct prefix_sg sg; @@ -123,7 +127,7 @@ int pim_register_stop_recv(uint8_t *buf, int buf_size) pim_parse_addr_ucast(&source, buf, buf_size); sg.src = source.u.prefix4; - upstream = pim_upstream_find(&sg); + upstream = pim_upstream_find(pim, &sg); if (!upstream) { return 0; } @@ -138,7 +142,7 @@ int pim_register_stop_recv(uint8_t *buf, int buf_size) break; case PIM_REG_JOIN: upstream->reg_state = PIM_REG_PRUNE; - pim_channel_del_oif(upstream->channel_oil, pim_regiface, + pim_channel_del_oif(upstream->channel_oil, pim->regiface, PIM_OIF_FLAG_PROTO_PIM); pim_upstream_start_register_stop_timer(upstream, 0); break; @@ -270,10 +274,13 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, int i_am_rp = 0; struct pim_interface *pim_ifp = NULL; + pim_ifp = ifp->info; + #define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4 ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN); - if (!pim_rp_check_is_my_ip_address(ip_hdr->ip_dst, dest_addr)) { + if (!pim_rp_check_is_my_ip_address(pim_ifp->pim, ip_hdr->ip_dst, + dest_addr)) { if (PIM_DEBUG_PIM_REG) { char dest[INET_ADDRSTRLEN]; @@ -285,8 +292,6 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, return 0; } - pim_ifp = ifp->info; - zassert(pim_ifp); ++pim_ifp->pim_ifstat_reg_recv; /* @@ -319,7 +324,7 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, sg.src = ip_hdr->ip_src; sg.grp = ip_hdr->ip_dst; - i_am_rp = I_am_RP(sg.grp); + i_am_rp = I_am_RP(pim_ifp->pim, sg.grp); if (PIM_DEBUG_PIM_REG) { char src_str[INET_ADDRSTRLEN]; @@ -330,8 +335,9 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, pim_str_sg_dump(&sg), src_str, ifp->name, i_am_rp); } - if (i_am_rp && (dest_addr.s_addr - == ((RP(sg.grp))->rpf_addr.u.prefix4.s_addr))) { + if (i_am_rp + && (dest_addr.s_addr + == ((RP(pim_ifp->pim, sg.grp))->rpf_addr.u.prefix4.s_addr))) { sentRegisterStop = 0; if (*bits & PIM_REGISTER_BORDER_BIT) { @@ -355,25 +361,50 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, } } - struct pim_upstream *upstream = pim_upstream_find(&sg); + struct pim_upstream *upstream = + pim_upstream_find(pim_ifp->pim, &sg); /* * If we don't have a place to send ignore the packet */ if (!upstream) { upstream = pim_upstream_add( - &sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM, - __PRETTY_FUNCTION__); + pim_ifp->pim, &sg, ifp, + PIM_UPSTREAM_FLAG_MASK_SRC_STREAM, + __PRETTY_FUNCTION__, NULL); if (!upstream) { zlog_warn("Failure to create upstream state"); return 1; } upstream->upstream_register = src_addr; + } else { + /* + * If the FHR has set a very very fast register timer + * there exists a possibility that the incoming NULL + * register + * is happening before we set the spt bit. If so + * Do a quick check to update the counters and + * then set the spt bit as appropriate + */ + if (upstream->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) { + pim_mroute_update_counters( + upstream->channel_oil); + /* + * Have we seen packets? + */ + if (upstream->channel_oil->cc.oldpktcnt + < upstream->channel_oil->cc.pktcnt) + pim_upstream_set_sptbit( + upstream, + upstream->rpf.source_nexthop + .interface); + } } if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) - || ((SwitchToSptDesired(&sg)) - && pim_upstream_inherited_olist(upstream) == 0)) { + || ((SwitchToSptDesired(pim_ifp->pim, &sg)) + && pim_upstream_inherited_olist(pim_ifp->pim, upstream) + == 0)) { // pim_scan_individual_oil (upstream->channel_oil); pim_register_stop_send(ifp, &sg, dest_addr, src_addr); sentRegisterStop = 1; @@ -383,13 +414,13 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, upstream->sptbit); } if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) - || (SwitchToSptDesired(&sg))) { + || (SwitchToSptDesired(pim_ifp->pim, &sg))) { if (sentRegisterStop) { pim_upstream_keep_alive_timer_start( - upstream, qpim_rp_keep_alive_time); + upstream, pim_ifp->pim->rp_keep_alive_time); } else { pim_upstream_keep_alive_timer_start( - upstream, qpim_keep_alive_time); + upstream, pim_ifp->pim->keep_alive_time); } } diff --git a/pimd/pim_register.h b/pimd/pim_register.h index ad3deb2b24..906d093bb7 100644 --- a/pimd/pim_register.h +++ b/pimd/pim_register.h @@ -30,7 +30,7 @@ #define PIM_MSG_REGISTER_LEN (8) #define PIM_MSG_REGISTER_STOP_LEN (4) -int pim_register_stop_recv(uint8_t *buf, int buf_size); +int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size); int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, struct in_addr src_addr, uint8_t *tlv_buf, diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 2fe0143a87..05592992a9 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -45,8 +45,20 @@ #include "pim_nht.h" -static struct list *qpim_rp_list = NULL; -static struct rp_info *tail = NULL; +/* Cleanup pim->rpf_hash each node data */ +void pim_rp_list_hash_clean(void *data) +{ + struct pim_nexthop_cache *pnc = (struct pim_nexthop_cache *)data; + + list_delete(pnc->rp_list); + pnc->rp_list = NULL; + + hash_clean(pnc->upstream_hash, NULL); + hash_free(pnc->upstream_hash); + pnc->upstream_hash = NULL; + + XFREE(MTYPE_PIM_NEXTHOP_CACHE, pnc); +} static void pim_rp_info_free(struct rp_info *rp_info) { @@ -81,46 +93,49 @@ int pim_rp_list_cmp(void *v1, void *v2) return 0; } -void pim_rp_init(void) +void pim_rp_init(struct pim_instance *pim) { struct rp_info *rp_info; - qpim_rp_list = list_new(); - qpim_rp_list->del = (void (*)(void *))pim_rp_info_free; - qpim_rp_list->cmp = pim_rp_list_cmp; + pim->rp_list = list_new(); + pim->rp_list->del = (void (*)(void *))pim_rp_info_free; + pim->rp_list->cmp = pim_rp_list_cmp; rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info)); if (!rp_info) return; - str2prefix("224.0.0.0/4", &rp_info->group); + if (!str2prefix("224.0.0.0/4", &rp_info->group)) { + XFREE(MTYPE_PIM_RP, rp_info); + return; + } rp_info->group.family = AF_INET; rp_info->rp.rpf_addr.family = AF_INET; rp_info->rp.rpf_addr.prefixlen = IPV4_MAX_PREFIXLEN; rp_info->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE; - tail = rp_info; - listnode_add(qpim_rp_list, rp_info); + listnode_add(pim->rp_list, rp_info); } -void pim_rp_free(void) +void pim_rp_free(struct pim_instance *pim) { - if (qpim_rp_list) - list_delete(qpim_rp_list); - qpim_rp_list = NULL; + if (pim->rp_list) + list_delete(pim->rp_list); + pim->rp_list = NULL; } /* * Given an RP's prefix-list, return the RP's rp_info for that prefix-list */ -static struct rp_info *pim_rp_find_prefix_list(struct in_addr rp, +static struct rp_info *pim_rp_find_prefix_list(struct pim_instance *pim, + struct in_addr rp, const char *plist) { struct listnode *node; struct rp_info *rp_info; - for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) { + for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { if (rp.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr && rp_info->plist && strcmp(rp_info->plist, plist) == 0) { return rp_info; @@ -133,12 +148,12 @@ static struct rp_info *pim_rp_find_prefix_list(struct in_addr rp, /* * Return true if plist is used by any rp_info */ -static int pim_rp_prefix_list_used(const char *plist) +static int pim_rp_prefix_list_used(struct pim_instance *pim, const char *plist) { struct listnode *node; struct rp_info *rp_info; - for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) { + for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { if (rp_info->plist && strcmp(rp_info->plist, plist) == 0) { return 1; } @@ -151,13 +166,14 @@ static int pim_rp_prefix_list_used(const char *plist) * Given an RP's address, return the RP's rp_info that is an exact match for * 'group' */ -static struct rp_info *pim_rp_find_exact(struct in_addr rp, +static struct rp_info *pim_rp_find_exact(struct pim_instance *pim, + struct in_addr rp, struct prefix *group) { struct listnode *node; struct rp_info *rp_info; - for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) { + for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { if (rp.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr && prefix_same(&rp_info->group, group)) return rp_info; @@ -169,13 +185,14 @@ static struct rp_info *pim_rp_find_exact(struct in_addr rp, /* * Given a group, return the rp_info for that group */ -static struct rp_info *pim_rp_find_match_group(struct prefix *group) +static struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, + struct prefix *group) { struct listnode *node; struct rp_info *rp_info; struct prefix_list *plist; - for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) { + for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { if (rp_info->plist) { plist = prefix_list_lookup(AFI_IP, rp_info->plist); @@ -198,18 +215,19 @@ static struct rp_info *pim_rp_find_match_group(struct prefix *group) * * This is a placeholder function for now. */ -static void pim_rp_refresh_group_to_rp_mapping() +static void pim_rp_refresh_group_to_rp_mapping(struct pim_instance *pim) { - pim_msdp_i_am_rp_changed(); + pim_msdp_i_am_rp_changed(pim); } -void pim_rp_prefix_list_update(struct prefix_list *plist) +void pim_rp_prefix_list_update(struct pim_instance *pim, + struct prefix_list *plist) { struct listnode *node; struct rp_info *rp_info; int refresh_needed = 0; - for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) { + for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { if (rp_info->plist && strcmp(rp_info->plist, prefix_list_name(plist)) == 0) { refresh_needed = 1; @@ -218,7 +236,7 @@ void pim_rp_prefix_list_update(struct prefix_list *plist) } if (refresh_needed) - pim_rp_refresh_group_to_rp_mapping(); + pim_rp_refresh_group_to_rp_mapping(pim); } static int pim_rp_check_interface_addrs(struct rp_info *rp_info, @@ -244,13 +262,14 @@ static int pim_rp_check_interface_addrs(struct rp_info *rp_info, return 0; } -static void pim_rp_check_interfaces(struct rp_info *rp_info) +static void pim_rp_check_interfaces(struct pim_instance *pim, + struct rp_info *rp_info) { struct listnode *node; struct interface *ifp; rp_info->i_am_rp = 0; - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) { struct pim_interface *pim_ifp = ifp->info; if (!pim_ifp) @@ -262,7 +281,8 @@ static void pim_rp_check_interfaces(struct rp_info *rp_info) } } -int pim_rp_new(const char *rp, const char *group_range, const char *plist) +int pim_rp_new(struct pim_instance *pim, const char *rp, + const char *group_range, const char *plist) { int result = 0; struct rp_info *rp_info; @@ -302,7 +322,7 @@ int pim_rp_new(const char *rp, const char *group_range, const char *plist) /* * Return if the prefix-list is already configured for this RP */ - if (pim_rp_find_prefix_list(rp_info->rp.rpf_addr.u.prefix4, + if (pim_rp_find_prefix_list(pim, rp_info->rp.rpf_addr.u.prefix4, plist)) { XFREE(MTYPE_PIM_RP, rp_info); return PIM_SUCCESS; @@ -311,7 +331,7 @@ int pim_rp_new(const char *rp, const char *group_range, const char *plist) /* * Barf if the prefix-list is already configured for an RP */ - if (pim_rp_prefix_list_used(plist)) { + if (pim_rp_prefix_list_used(pim, plist)) { XFREE(MTYPE_PIM_RP, rp_info); return PIM_RP_PFXLIST_IN_USE; } @@ -319,16 +339,16 @@ int pim_rp_new(const char *rp, const char *group_range, const char *plist) /* * Free any existing rp_info entries for this RP */ - for (ALL_LIST_ELEMENTS(qpim_rp_list, node, nnode, + for (ALL_LIST_ELEMENTS(pim->rp_list, node, nnode, tmp_rp_info)) { if (rp_info->rp.rpf_addr.u.prefix4.s_addr == tmp_rp_info->rp.rpf_addr.u.prefix4.s_addr) { if (tmp_rp_info->plist) - pim_rp_del(rp, NULL, + pim_rp_del(pim, rp, NULL, tmp_rp_info->plist); else pim_rp_del( - rp, + pim, rp, prefix2str(&tmp_rp_info->group, buffer, BUFSIZ), NULL); @@ -337,8 +357,11 @@ int pim_rp_new(const char *rp, const char *group_range, const char *plist) rp_info->plist = XSTRDUP(MTYPE_PIM_FILTER_NAME, plist); } else { - str2prefix("224.0.0.0/4", &group_all); - rp_all = pim_rp_find_match_group(&group_all); + if (!str2prefix("224.0.0.0/4", &group_all)) { + XFREE(MTYPE_PIM_RP, rp_info); + return PIM_GROUP_BAD_ADDRESS; + } + rp_all = pim_rp_find_match_group(pim, &group_all); /* * Barf if group is a non-multicast subnet @@ -351,13 +374,13 @@ int pim_rp_new(const char *rp, const char *group_range, const char *plist) /* * Remove any prefix-list rp_info entries for this RP */ - for (ALL_LIST_ELEMENTS(qpim_rp_list, node, nnode, + for (ALL_LIST_ELEMENTS(pim->rp_list, node, nnode, tmp_rp_info)) { if (tmp_rp_info->plist && rp_info->rp.rpf_addr.u.prefix4.s_addr == tmp_rp_info->rp.rpf_addr.u.prefix4 .s_addr) { - pim_rp_del(rp, NULL, tmp_rp_info->plist); + pim_rp_del(pim, rp, NULL, tmp_rp_info->plist); } } @@ -384,31 +407,29 @@ int pim_rp_new(const char *rp, const char *group_range, const char *plist) __PRETTY_FUNCTION__, buf, buf1); } memset(&pnc, 0, sizeof(struct pim_nexthop_cache)); - if ((pim_find_or_track_nexthop(&nht_p, NULL, rp_all, - &pnc)) - == 1) { - // Compute PIM RPF using Cached nexthop - if ((pim_ecmp_nexthop_search( - &pnc, &rp_all->rp.source_nexthop, - &nht_p, &rp_all->group, 1)) - != 0) + if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_all, + &pnc)) { + if (!pim_ecmp_nexthop_search( + pim, &pnc, + &rp_all->rp.source_nexthop, &nht_p, + &rp_all->group, 1)) return PIM_RP_NO_PATH; } else { if (pim_nexthop_lookup( - &rp_all->rp.source_nexthop, + pim, &rp_all->rp.source_nexthop, rp_all->rp.rpf_addr.u.prefix4, 1) != 0) return PIM_RP_NO_PATH; } - pim_rp_check_interfaces(rp_all); - pim_rp_refresh_group_to_rp_mapping(); + pim_rp_check_interfaces(pim, rp_all); + pim_rp_refresh_group_to_rp_mapping(pim); return PIM_SUCCESS; } /* * Return if the group is already configured for this RP */ - if (pim_rp_find_exact(rp_info->rp.rpf_addr.u.prefix4, + if (pim_rp_find_exact(pim, rp_info->rp.rpf_addr.u.prefix4, &rp_info->group)) { XFREE(MTYPE_PIM_RP, rp_info); return PIM_SUCCESS; @@ -417,7 +438,7 @@ int pim_rp_new(const char *rp, const char *group_range, const char *plist) /* * Barf if this group is already covered by some other RP */ - tmp_rp_info = pim_rp_find_match_group(&rp_info->group); + tmp_rp_info = pim_rp_find_match_group(pim, &rp_info->group); if (tmp_rp_info) { if (tmp_rp_info->plist) { @@ -440,7 +461,7 @@ int pim_rp_new(const char *rp, const char *group_range, const char *plist) } } - listnode_add_sort(qpim_rp_list, rp_info); + listnode_add_sort(pim->rp_list, rp_info); /* Register addr with Zebra NHT */ nht_p.family = AF_INET; @@ -456,25 +477,25 @@ int pim_rp_new(const char *rp, const char *group_range, const char *plist) } memset(&pnc, 0, sizeof(struct pim_nexthop_cache)); - if ((pim_find_or_track_nexthop(&nht_p, NULL, rp_info, &pnc)) == 1) { - // Compute PIM RPF using Cached nexthop - if (pim_ecmp_nexthop_search(&pnc, &rp_info->rp.source_nexthop, - &nht_p, &rp_info->group, 1) - != 0) + if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, &pnc)) { + if (!pim_ecmp_nexthop_search(pim, &pnc, + &rp_info->rp.source_nexthop, + &nht_p, &rp_info->group, 1)) return PIM_RP_NO_PATH; } else { - if (pim_nexthop_lookup(&rp_info->rp.source_nexthop, + if (pim_nexthop_lookup(pim, &rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1) != 0) return PIM_RP_NO_PATH; } - pim_rp_check_interfaces(rp_info); - pim_rp_refresh_group_to_rp_mapping(); + pim_rp_check_interfaces(pim, rp_info); + pim_rp_refresh_group_to_rp_mapping(pim); return PIM_SUCCESS; } -int pim_rp_del(const char *rp, const char *group_range, const char *plist) +int pim_rp_del(struct pim_instance *pim, const char *rp, + const char *group_range, const char *plist) { struct prefix group; struct in_addr rp_addr; @@ -497,9 +518,9 @@ int pim_rp_del(const char *rp, const char *group_range, const char *plist) return PIM_RP_BAD_ADDRESS; if (plist) - rp_info = pim_rp_find_prefix_list(rp_addr, plist); + rp_info = pim_rp_find_prefix_list(pim, rp_addr, plist); else - rp_info = pim_rp_find_exact(rp_addr, &group); + rp_info = pim_rp_find_exact(pim, rp_addr, &group); if (!rp_info) return PIM_RP_NOT_FOUND; @@ -519,10 +540,10 @@ int pim_rp_del(const char *rp, const char *group_range, const char *plist) zlog_debug("%s: Deregister RP addr %s with Zebra ", __PRETTY_FUNCTION__, buf); } - pim_delete_tracked_nexthop(&nht_p, NULL, rp_info); + pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info); str2prefix("224.0.0.0/4", &g_all); - rp_all = pim_rp_find_match_group(&g_all); + rp_all = pim_rp_find_match_group(pim, &g_all); if (rp_all == rp_info) { rp_all->rp.rpf_addr.family = AF_INET; @@ -531,20 +552,19 @@ int pim_rp_del(const char *rp, const char *group_range, const char *plist) return PIM_SUCCESS; } - listnode_delete(qpim_rp_list, rp_info); - pim_rp_refresh_group_to_rp_mapping(); + listnode_delete(pim->rp_list, rp_info); + pim_rp_refresh_group_to_rp_mapping(pim); return PIM_SUCCESS; } -int pim_rp_setup(void) +void pim_rp_setup(struct pim_instance *pim) { struct listnode *node; struct rp_info *rp_info; - int ret = 0; struct prefix nht_p; struct pim_nexthop_cache pnc; - for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) { + for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE) continue; @@ -552,15 +572,11 @@ int pim_rp_setup(void) nht_p.prefixlen = IPV4_MAX_BITLEN; nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; memset(&pnc, 0, sizeof(struct pim_nexthop_cache)); - if ((pim_find_or_track_nexthop(&nht_p, NULL, rp_info, &pnc)) - == 1) { - // Compute PIM RPF using Cached nexthop - if ((pim_ecmp_nexthop_search( - &pnc, &rp_info->rp.source_nexthop, &nht_p, - &rp_info->group, 1)) - != 0) - ret++; - } else { + if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, &pnc)) + pim_ecmp_nexthop_search(pim, &pnc, + &rp_info->rp.source_nexthop, + &nht_p, &rp_info->group, 1); + else { if (PIM_DEBUG_ZEBRA) { char buf[PREFIX2STR_BUFFER]; prefix2str(&nht_p, buf, sizeof(buf)); @@ -568,22 +584,14 @@ int pim_rp_setup(void) "%s: NHT Local Nexthop not found for RP %s ", __PRETTY_FUNCTION__, buf); } - if (pim_nexthop_lookup(&rp_info->rp.source_nexthop, - rp_info->rp.rpf_addr.u.prefix4, - 1) - != 0) { + if (!pim_nexthop_lookup( + pim, &rp_info->rp.source_nexthop, + rp_info->rp.rpf_addr.u.prefix4, 1)) if (PIM_DEBUG_PIM_TRACE) zlog_debug( "Unable to lookup nexthop for rp specified"); - ret++; - } } } - - if (ret) - return 0; - - return 1; } /* @@ -595,11 +603,12 @@ void pim_rp_check_on_if_add(struct pim_interface *pim_ifp) struct listnode *node; struct rp_info *rp_info; bool i_am_rp_changed = false; + struct pim_instance *pim = pim_ifp->pim; - if (qpim_rp_list == NULL) + if (pim->rp_list == NULL) return; - for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) { + for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { if (pim_rpf_addr_is_inaddr_none(&rp_info->rp)) continue; @@ -623,29 +632,29 @@ void pim_rp_check_on_if_add(struct pim_interface *pim_ifp) } if (i_am_rp_changed) { - pim_msdp_i_am_rp_changed(); + pim_msdp_i_am_rp_changed(pim); } } /* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses * are removed. Removing numbers is an uncommon event in an active network * so I have made no attempt to optimize it. */ -void pim_i_am_rp_re_evaluate(void) +void pim_i_am_rp_re_evaluate(struct pim_instance *pim) { struct listnode *node; struct rp_info *rp_info; bool i_am_rp_changed = false; int old_i_am_rp; - if (qpim_rp_list == NULL) + if (pim->rp_list == NULL) return; - for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) { + for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { if (pim_rpf_addr_is_inaddr_none(&rp_info->rp)) continue; old_i_am_rp = rp_info->i_am_rp; - pim_rp_check_interfaces(rp_info); + pim_rp_check_interfaces(pim, rp_info); if (old_i_am_rp != rp_info->i_am_rp) { i_am_rp_changed = true; @@ -665,7 +674,7 @@ void pim_i_am_rp_re_evaluate(void) } if (i_am_rp_changed) { - pim_msdp_i_am_rp_changed(); + pim_msdp_i_am_rp_changed(pim); } } @@ -675,7 +684,7 @@ void pim_i_am_rp_re_evaluate(void) * * Since we only have static RP, all groups are part of this RP */ -int pim_rp_i_am_rp(struct in_addr group) +int pim_rp_i_am_rp(struct pim_instance *pim, struct in_addr group) { struct prefix g; struct rp_info *rp_info; @@ -685,7 +694,7 @@ int pim_rp_i_am_rp(struct in_addr group) g.prefixlen = 32; g.u.prefix4 = group; - rp_info = pim_rp_find_match_group(&g); + rp_info = pim_rp_find_match_group(pim, &g); if (rp_info) return rp_info->i_am_rp; @@ -698,7 +707,7 @@ int pim_rp_i_am_rp(struct in_addr group) * * Return the RP that the Group belongs too. */ -struct pim_rpf *pim_rp_g(struct in_addr group) +struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group) { struct prefix g; struct rp_info *rp_info; @@ -708,7 +717,7 @@ struct pim_rpf *pim_rp_g(struct in_addr group) g.prefixlen = 32; g.u.prefix4 = group; - rp_info = pim_rp_find_match_group(&g); + rp_info = pim_rp_find_match_group(pim, &g); if (rp_info) { struct prefix nht_p; @@ -727,13 +736,11 @@ struct pim_rpf *pim_rp_g(struct in_addr group) __PRETTY_FUNCTION__, buf, buf1); } memset(&pnc, 0, sizeof(struct pim_nexthop_cache)); - if ((pim_find_or_track_nexthop(&nht_p, NULL, rp_info, &pnc)) - == 1) { - // Compute PIM RPF using Cached nexthop - pim_ecmp_nexthop_search(&pnc, + if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, &pnc)) + pim_ecmp_nexthop_search(pim, &pnc, &rp_info->rp.source_nexthop, &nht_p, &rp_info->group, 1); - } else { + else { if (PIM_DEBUG_ZEBRA) { char buf[PREFIX2STR_BUFFER]; char buf1[PREFIX2STR_BUFFER]; @@ -744,7 +751,7 @@ struct pim_rpf *pim_rp_g(struct in_addr group) __PRETTY_FUNCTION__, buf, buf1); } pim_rpf_set_refresh_time(); - pim_nexthop_lookup(&rp_info->rp.source_nexthop, + pim_nexthop_lookup(pim, &rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1); } return (&rp_info->rp); @@ -762,8 +769,8 @@ struct pim_rpf *pim_rp_g(struct in_addr group) * then return failure. * */ -int pim_rp_set_upstream_addr(struct in_addr *up, struct in_addr source, - struct in_addr group) +int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up, + struct in_addr source, struct in_addr group) { struct rp_info *rp_info; struct prefix g; @@ -773,7 +780,7 @@ int pim_rp_set_upstream_addr(struct in_addr *up, struct in_addr source, g.prefixlen = 32; g.u.prefix4 = group; - rp_info = pim_rp_find_match_group(&g); + rp_info = pim_rp_find_match_group(pim, &g); if ((pim_rpf_addr_is_inaddr_none(&rp_info->rp)) && (source.s_addr == INADDR_ANY)) { @@ -789,7 +796,8 @@ int pim_rp_set_upstream_addr(struct in_addr *up, struct in_addr source, return 1; } -int pim_rp_config_write(struct vty *vty) +int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, + const char *spaces) { struct listnode *node; struct rp_info *rp_info; @@ -797,18 +805,18 @@ int pim_rp_config_write(struct vty *vty) char group_buffer[32]; int count = 0; - for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) { + for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { if (pim_rpf_addr_is_inaddr_none(&rp_info->rp)) continue; if (rp_info->plist) - vty_out(vty, "ip pim rp %s prefix-list %s\n", + vty_out(vty, "%sip pim rp %s prefix-list %s\n", spaces, inet_ntop(AF_INET, &rp_info->rp.rpf_addr.u.prefix4, rp_buffer, 32), rp_info->plist); else - vty_out(vty, "ip pim rp %s %s\n", + vty_out(vty, "%sip pim rp %s %s\n", spaces, inet_ntop(AF_INET, &rp_info->rp.rpf_addr.u.prefix4, rp_buffer, 32), @@ -819,7 +827,8 @@ int pim_rp_config_write(struct vty *vty) return count; } -int pim_rp_check_is_my_ip_address(struct in_addr group, +int pim_rp_check_is_my_ip_address(struct pim_instance *pim, + struct in_addr group, struct in_addr dest_addr) { struct rp_info *rp_info; @@ -830,25 +839,26 @@ int pim_rp_check_is_my_ip_address(struct in_addr group, g.prefixlen = 32; g.u.prefix4 = group; - rp_info = pim_rp_find_match_group(&g); + rp_info = pim_rp_find_match_group(pim, &g); /* * See if we can short-cut some? * This might not make sense if we ever leave a static RP * type of configuration. * Note - Premature optimization might bite our patooeys' here. */ - if (I_am_RP(group)) { + if (I_am_RP(pim, group)) { if (dest_addr.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr) return 1; } - if (if_lookup_exact_address(&dest_addr, AF_INET, VRF_DEFAULT)) + if (if_lookup_exact_address(&dest_addr, AF_INET, pim->vrf_id)) return 1; return 0; } -void pim_rp_show_information(struct vty *vty, u_char uj) +void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, + u_char uj) { struct rp_info *rp_info; struct rp_info *prev_rp_info = NULL; @@ -864,7 +874,7 @@ void pim_rp_show_information(struct vty *vty, u_char uj) vty_out(vty, "RP address group/prefix-list OIF I am RP\n"); - for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) { + for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { if (!pim_rpf_addr_is_inaddr_none(&rp_info->rp)) { char buf[48]; @@ -954,7 +964,7 @@ void pim_rp_show_information(struct vty *vty, u_char uj) } } -void pim_resolve_rp_nh(void) +void pim_resolve_rp_nh(struct pim_instance *pim) { struct listnode *node = NULL; struct rp_info *rp_info = NULL; @@ -963,7 +973,7 @@ void pim_resolve_rp_nh(void) struct pim_nexthop_cache pnc; struct pim_neighbor *nbr = NULL; - for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) { + for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE) continue; @@ -971,43 +981,32 @@ void pim_resolve_rp_nh(void) nht_p.prefixlen = IPV4_MAX_BITLEN; nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; memset(&pnc, 0, sizeof(struct pim_nexthop_cache)); - if ((pim_find_or_track_nexthop(&nht_p, NULL, rp_info, &pnc)) - == 1) { - for (nh_node = pnc.nexthop; nh_node; - nh_node = nh_node->next) { - if (nh_node->gate.ipv4.s_addr == 0) { - nbr = pim_neighbor_find_if( - if_lookup_by_index( - nh_node->ifindex, - VRF_DEFAULT)); - if (nbr) { - nh_node->gate.ipv4 = - nbr->source_addr; - if (PIM_DEBUG_TRACE) { - char str[PREFIX_STRLEN]; - char str1 - [INET_ADDRSTRLEN]; - struct interface *ifp1 = - if_lookup_by_index( - nh_node->ifindex, - VRF_DEFAULT); - pim_inet4_dump( - "<nht_nbr?>", - nbr->source_addr, - str1, - sizeof(str1)); - pim_addr_dump( - "<nht_addr?>", - &nht_p, str, - sizeof(str)); - zlog_debug( - "%s: addr %s new nexthop addr %s interface %s", - __PRETTY_FUNCTION__, - str, str1, - ifp1->name); - } - } - } + if (!pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, + &pnc)) + continue; + + for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next) { + if (nh_node->gate.ipv4.s_addr != 0) + continue; + + struct interface *ifp1 = if_lookup_by_index( + nh_node->ifindex, pim->vrf_id); + nbr = pim_neighbor_find_if(ifp1); + if (!nbr) + continue; + + nh_node->gate.ipv4 = nbr->source_addr; + if (PIM_DEBUG_TRACE) { + char str[PREFIX_STRLEN]; + char str1[INET_ADDRSTRLEN]; + pim_inet4_dump("<nht_nbr?>", nbr->source_addr, + str1, sizeof(str1)); + pim_addr_dump("<nht_addr?>", &nht_p, str, + sizeof(str)); + zlog_debug( + "%s: addr %s new nexthop addr %s interface %s", + __PRETTY_FUNCTION__, str, str1, + ifp1->name); } } } diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h index 7a7c26593e..e07d65137f 100644 --- a/pimd/pim_rp.h +++ b/pimd/pim_rp.h @@ -34,33 +34,41 @@ struct rp_info { char *plist; }; -void pim_rp_init(void); -void pim_rp_free(void); +void pim_rp_init(struct pim_instance *pim); +void pim_rp_free(struct pim_instance *pim); -int pim_rp_new(const char *rp, const char *group, const char *plist); -int pim_rp_del(const char *rp, const char *group, const char *plist); -void pim_rp_prefix_list_update(struct prefix_list *plist); +void pim_rp_list_hash_clean(void *data); -int pim_rp_config_write(struct vty *vty); +int pim_rp_new(struct pim_instance *pim, const char *rp, const char *group, + const char *plist); +int pim_rp_del(struct pim_instance *pim, const char *rp, const char *group, + const char *plist); +void pim_rp_prefix_list_update(struct pim_instance *pim, + struct prefix_list *plist); -int pim_rp_setup(void); +int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, + const char *spaces); -int pim_rp_i_am_rp(struct in_addr group); +void pim_rp_setup(struct pim_instance *pim); + +int pim_rp_i_am_rp(struct pim_instance *pim, struct in_addr group); void pim_rp_check_on_if_add(struct pim_interface *pim_ifp); -void pim_i_am_rp_re_evaluate(void); +void pim_i_am_rp_re_evaluate(struct pim_instance *pim); -int pim_rp_check_is_my_ip_address(struct in_addr group, +int pim_rp_check_is_my_ip_address(struct pim_instance *pim, + struct in_addr group, struct in_addr dest_addr); -int pim_rp_set_upstream_addr(struct in_addr *up, struct in_addr source, - struct in_addr group); +int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up, + struct in_addr source, struct in_addr group); -struct pim_rpf *pim_rp_g(struct in_addr group); +struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group); -#define I_am_RP(G) pim_rp_i_am_rp ((G)) -#define RP(G) pim_rp_g ((G)) +#define I_am_RP(P, G) pim_rp_i_am_rp ((P), (G)) +#define RP(P, G) pim_rp_g ((P), (G)) -void pim_rp_show_information(struct vty *vty, u_char uj); -void pim_resolve_rp_nh(void); +void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, + u_char uj); +void pim_resolve_rp_nh(struct pim_instance *pim); int pim_rp_list_cmp(void *v1, void *v2); #endif diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index 4d0652c27e..36c6c894ef 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -24,6 +24,7 @@ #include "log.h" #include "prefix.h" #include "memory.h" +#include "jhash.h" #include "pimd.h" #include "pim_rpf.h" @@ -34,6 +35,7 @@ #include "pim_ifchannel.h" #include "pim_time.h" #include "pim_nht.h" +#include "pim_oil.h" static long long last_route_change_time = -1; long long nexthop_lookups_avoided = 0; @@ -48,8 +50,8 @@ void pim_rpf_set_refresh_time(void) __PRETTY_FUNCTION__, last_route_change_time); } -int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, - int neighbor_needed) +int pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, + struct in_addr addr, int neighbor_needed) { struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM]; struct pim_neighbor *nbr = NULL; @@ -91,8 +93,8 @@ int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, memset(nexthop_tab, 0, sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM); - num_ifindex = zclient_lookup_nexthop(nexthop_tab, MULTIPATH_NUM, addr, - PIM_NEXTHOP_LOOKUP_MAX); + num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM, + addr, PIM_NEXTHOP_LOOKUP_MAX); if (num_ifindex < 1) { char addr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); @@ -105,7 +107,7 @@ int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, while (!found && (i < num_ifindex)) { first_ifindex = nexthop_tab[i].ifindex; - ifp = if_lookup_by_index(first_ifindex, VRF_DEFAULT); + ifp = if_lookup_by_index(first_ifindex, pim->vrf_id); if (!ifp) { if (PIM_DEBUG_ZEBRA) { char addr_str[INET_ADDRSTRLEN]; @@ -186,14 +188,14 @@ static int nexthop_mismatch(const struct pim_nexthop *nh1, || (nh1->mrib_route_metric != nh2->mrib_route_metric); } -enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old, +enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, + struct pim_upstream *up, struct pim_rpf *old, uint8_t is_new) { struct pim_rpf *rpf = &up->rpf; struct pim_rpf saved; struct prefix nht_p; struct pim_nexthop_cache pnc; - int ret = 0; struct prefix src, grp; saved.source_nexthop = rpf->source_nexthop; @@ -218,27 +220,23 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old, grp.prefixlen = IPV4_MAX_BITLEN; grp.u.prefix4 = up->sg.grp; memset(&pnc, 0, sizeof(struct pim_nexthop_cache)); - if ((ret = pim_find_or_track_nexthop(&nht_p, up, NULL, &pnc)) == 1) { + if (pim_find_or_track_nexthop(pim, &nht_p, up, NULL, &pnc)) { if (pnc.nexthop_num) { - // Compute PIM RPF using Cached nexthop - if (pim_ecmp_nexthop_search( - &pnc, &up->rpf.source_nexthop, &src, &grp, + if (!pim_ecmp_nexthop_search( + pim, &pnc, &up->rpf.source_nexthop, &src, + &grp, !PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) && !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP( up->flags))) - - { return PIM_RPF_FAILURE; - } } } else { - if (pim_ecmp_nexthop_lookup( - &rpf->source_nexthop, up->upstream_addr, &src, &grp, - !PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) - && !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP( - up->flags))) { + if (!pim_ecmp_nexthop_lookup( + pim, &rpf->source_nexthop, up->upstream_addr, &src, + &grp, !PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) + && !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP( + up->flags))) return PIM_RPF_FAILURE; - } } rpf->rpf_addr.family = AF_INET; @@ -267,7 +265,7 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old, rpf->source_nexthop.mrib_route_metric); } - pim_upstream_update_join_desired(up); + pim_upstream_update_join_desired(pim, up); pim_upstream_update_could_assert(up); pim_upstream_update_my_assert_metric(up); } @@ -396,3 +394,20 @@ int pim_rpf_is_same(struct pim_rpf *rpf1, struct pim_rpf *rpf2) return 0; } + +unsigned int pim_rpf_hash_key(void *arg) +{ + struct pim_nexthop_cache *r = (struct pim_nexthop_cache *)arg; + + return jhash_1word(r->rpf.rpf_addr.u.prefix4.s_addr, 0); +} + +int pim_rpf_equal(const void *arg1, const void *arg2) +{ + const struct pim_nexthop_cache *r1 = + (const struct pim_nexthop_cache *)arg1; + const struct pim_nexthop_cache *r2 = + (const struct pim_nexthop_cache *)arg2; + + return prefix_same(&r1->rpf.rpf_addr, &r2->rpf.rpf_addr); +} diff --git a/pimd/pim_rpf.h b/pimd/pim_rpf.h index 0833143563..86032f1c29 100644 --- a/pimd/pim_rpf.h +++ b/pimd/pim_rpf.h @@ -58,9 +58,13 @@ struct pim_upstream; extern long long nexthop_lookups_avoided; -int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, - int neighbor_needed); -enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old, +unsigned int pim_rpf_hash_key(void *arg); +int pim_rpf_equal(const void *arg1, const void *arg2); + +int pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, + struct in_addr addr, int neighbor_needed); +enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, + struct pim_upstream *up, struct pim_rpf *old, uint8_t is_new); int pim_rpf_addr_is_inaddr_none(struct pim_rpf *rpf); diff --git a/pimd/pim_ssm.c b/pimd/pim_ssm.c index 3046e94299..8d270e6205 100644 --- a/pimd/pim_ssm.c +++ b/pimd/pim_ssm.c @@ -29,7 +29,7 @@ #include "pim_ssm.h" #include "pim_zebra.h" -static void pim_ssm_range_reevaluate(void) +static void pim_ssm_range_reevaluate(struct pim_instance *pim) { /* 1. Setup register state for (S,G) entries if G has changed from SSM * to @@ -47,13 +47,14 @@ static void pim_ssm_range_reevaluate(void) * will * disappear in time for SSM groups. */ - pim_upstream_register_reevaluate(); + pim_upstream_register_reevaluate(pim); igmp_source_forward_reevaluate_all(); } -void pim_ssm_prefix_list_update(struct prefix_list *plist) +void pim_ssm_prefix_list_update(struct pim_instance *pim, + struct prefix_list *plist) { - struct pim_ssm *ssm = pimg->ssm_info; + struct pim_ssm *ssm = pim->ssm_info; if (!ssm->plist_name || strcmp(ssm->plist_name, prefix_list_name(plist))) { @@ -61,7 +62,7 @@ void pim_ssm_prefix_list_update(struct prefix_list *plist) return; } - pim_ssm_range_reevaluate(); + pim_ssm_range_reevaluate(pim); } static int pim_is_grp_standard_ssm(struct prefix *group) @@ -77,7 +78,7 @@ static int pim_is_grp_standard_ssm(struct prefix *group) return prefix_match(&group_ssm, group); } -int pim_is_grp_ssm(struct in_addr group_addr) +int pim_is_grp_ssm(struct pim_instance *pim, struct in_addr group_addr) { struct pim_ssm *ssm; struct prefix group; @@ -88,7 +89,7 @@ int pim_is_grp_ssm(struct in_addr group_addr) group.u.prefix4 = group_addr; group.prefixlen = 32; - ssm = pimg->ssm_info; + ssm = pim->ssm_info; if (!ssm->plist_name) { return pim_is_grp_standard_ssm(&group); } @@ -100,15 +101,16 @@ int pim_is_grp_ssm(struct in_addr group_addr) return (prefix_list_apply(plist, &group) == PREFIX_PERMIT); } -int pim_ssm_range_set(vrf_id_t vrf_id, const char *plist_name) +int pim_ssm_range_set(struct pim_instance *pim, vrf_id_t vrf_id, + const char *plist_name) { struct pim_ssm *ssm; int change = 0; - if (vrf_id != VRF_DEFAULT) + if (vrf_id != pim->vrf_id) return PIM_SSM_ERR_NO_VRF; - ssm = pimg->ssm_info; + ssm = pim->ssm_info; if (plist_name) { if (ssm->plist_name) { if (!strcmp(ssm->plist_name, plist_name)) @@ -125,17 +127,16 @@ int pim_ssm_range_set(vrf_id_t vrf_id, const char *plist_name) } if (change) - pim_ssm_range_reevaluate(); + pim_ssm_range_reevaluate(pim); return PIM_SSM_ERR_NONE; } -void *pim_ssm_init(vrf_id_t vrf_id) +void *pim_ssm_init(void) { struct pim_ssm *ssm; ssm = XCALLOC(MTYPE_PIM_SSM_INFO, sizeof(*ssm)); - ssm->vrf_id = vrf_id; return ssm; } diff --git a/pimd/pim_ssm.h b/pimd/pim_ssm.h index 9e89d0c80c..7235ade8dc 100644 --- a/pimd/pim_ssm.h +++ b/pimd/pim_ssm.h @@ -29,13 +29,14 @@ enum pim_ssm_err { }; struct pim_ssm { - vrf_id_t vrf_id; char *plist_name; /* prefix list of group ranges */ }; -void pim_ssm_prefix_list_update(struct prefix_list *plist); -int pim_is_grp_ssm(struct in_addr group_addr); -int pim_ssm_range_set(vrf_id_t vrf_id, const char *plist_name); -void *pim_ssm_init(vrf_id_t vrf_id); +void pim_ssm_prefix_list_update(struct pim_instance *pim, + struct prefix_list *plist); +int pim_is_grp_ssm(struct pim_instance *pim, struct in_addr group_addr); +int pim_ssm_range_set(struct pim_instance *pim, vrf_id_t vrf_id, + const char *plist_name); +void *pim_ssm_init(void); void pim_ssm_terminate(struct pim_ssm *ssm); #endif diff --git a/pimd/pim_ssmpingd.c b/pimd/pim_ssmpingd.c index 406183db86..9e90a34687 100644 --- a/pimd/pim_ssmpingd.c +++ b/pimd/pim_ssmpingd.c @@ -36,35 +36,36 @@ enum { PIM_SSMPINGD_REQUEST = 'Q', PIM_SSMPINGD_REPLY = 'A' }; static void ssmpingd_read_on(struct ssmpingd_sock *ss); -void pim_ssmpingd_init() +void pim_ssmpingd_init(struct pim_instance *pim) { int result; - zassert(!qpim_ssmpingd_list); + zassert(!pim->ssmpingd_list); result = inet_pton(AF_INET, PIM_SSMPINGD_REPLY_GROUP, - &qpim_ssmpingd_group_addr); + &pim->ssmpingd_group_addr); zassert(result > 0); } -void pim_ssmpingd_destroy() +void pim_ssmpingd_destroy(struct pim_instance *pim) { - if (qpim_ssmpingd_list) { - list_free(qpim_ssmpingd_list); - qpim_ssmpingd_list = 0; + if (pim->ssmpingd_list) { + list_delete(pim->ssmpingd_list); + pim->ssmpingd_list = 0; } } -static struct ssmpingd_sock *ssmpingd_find(struct in_addr source_addr) +static struct ssmpingd_sock *ssmpingd_find(struct pim_instance *pim, + struct in_addr source_addr) { struct listnode *node; struct ssmpingd_sock *ss; - if (!qpim_ssmpingd_list) + if (!pim->ssmpingd_list) return 0; - for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) + for (ALL_LIST_ELEMENTS_RO(pim->ssmpingd_list, node, ss)) if (source_addr.s_addr == ss->source_addr.s_addr) return ss; @@ -202,7 +203,6 @@ static int ssmpingd_socket(struct in_addr addr, int port, int mttl) static void ssmpingd_delete(struct ssmpingd_sock *ss) { zassert(ss); - zassert(qpim_ssmpingd_list); THREAD_OFF(ss->t_sock_read); @@ -217,7 +217,7 @@ static void ssmpingd_delete(struct ssmpingd_sock *ss) /* warning only */ } - listnode_delete(qpim_ssmpingd_list, ss); + listnode_delete(ss->pim->ssmpingd_list, ss); ssmpingd_free(ss); } @@ -272,7 +272,7 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss) return -1; } - ifp = if_lookup_by_index(ifindex, VRF_DEFAULT); + ifp = if_lookup_by_index(ifindex, ss->pim->vrf_id); if (buf[0] != PIM_SSMPINGD_REQUEST) { char source_str[INET_ADDRSTRLEN]; @@ -315,7 +315,7 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss) ssmpingd_sendto(ss, buf, len, from); /* multicast reply */ - from.sin_addr = qpim_ssmpingd_group_addr; + from.sin_addr = ss->pim->ssmpingd_group_addr; ssmpingd_sendto(ss, buf, len, from); return 0; @@ -342,20 +342,21 @@ static void ssmpingd_read_on(struct ssmpingd_sock *ss) &ss->t_sock_read); } -static struct ssmpingd_sock *ssmpingd_new(struct in_addr source_addr) +static struct ssmpingd_sock *ssmpingd_new(struct pim_instance *pim, + struct in_addr source_addr) { struct ssmpingd_sock *ss; int sock_fd; - if (!qpim_ssmpingd_list) { - qpim_ssmpingd_list = list_new(); - if (!qpim_ssmpingd_list) { + if (!pim->ssmpingd_list) { + pim->ssmpingd_list = list_new(); + if (!pim->ssmpingd_list) { zlog_err( "%s %s: failure: qpim_ssmpingd_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return 0; } - qpim_ssmpingd_list->del = (void (*)(void *))ssmpingd_free; + pim->ssmpingd_list->del = (void (*)(void *))ssmpingd_free; } sock_fd = @@ -380,24 +381,25 @@ static struct ssmpingd_sock *ssmpingd_new(struct in_addr source_addr) return 0; } + ss->pim = pim; ss->sock_fd = sock_fd; ss->t_sock_read = NULL; ss->source_addr = source_addr; ss->creation = pim_time_monotonic_sec(); ss->requests = 0; - listnode_add(qpim_ssmpingd_list, ss); + listnode_add(pim->ssmpingd_list, ss); ssmpingd_read_on(ss); return ss; } -int pim_ssmpingd_start(struct in_addr source_addr) +int pim_ssmpingd_start(struct pim_instance *pim, struct in_addr source_addr) { struct ssmpingd_sock *ss; - ss = ssmpingd_find(source_addr); + ss = ssmpingd_find(pim, source_addr); if (ss) { /* silently ignore request to recreate entry */ return 0; @@ -411,7 +413,7 @@ int pim_ssmpingd_start(struct in_addr source_addr) __PRETTY_FUNCTION__, source_str); } - ss = ssmpingd_new(source_addr); + ss = ssmpingd_new(pim, source_addr); if (!ss) { char source_str[INET_ADDRSTRLEN]; pim_inet4_dump("<src?>", source_addr, source_str, @@ -424,11 +426,11 @@ int pim_ssmpingd_start(struct in_addr source_addr) return 0; } -int pim_ssmpingd_stop(struct in_addr source_addr) +int pim_ssmpingd_stop(struct pim_instance *pim, struct in_addr source_addr) { struct ssmpingd_sock *ss; - ss = ssmpingd_find(source_addr); + ss = ssmpingd_find(pim, source_addr); if (!ss) { char source_str[INET_ADDRSTRLEN]; pim_inet4_dump("<src?>", source_addr, source_str, diff --git a/pimd/pim_ssmpingd.h b/pimd/pim_ssmpingd.h index 89fb320a76..fafdd7ade1 100644 --- a/pimd/pim_ssmpingd.h +++ b/pimd/pim_ssmpingd.h @@ -27,6 +27,8 @@ #include "pim_iface.h" struct ssmpingd_sock { + struct pim_instance *pim; + int sock_fd; /* socket */ struct thread *t_sock_read; /* thread for reading socket */ struct in_addr source_addr; /* source address */ @@ -34,9 +36,9 @@ struct ssmpingd_sock { int64_t requests; /* counter */ }; -void pim_ssmpingd_init(void); -void pim_ssmpingd_destroy(void); -int pim_ssmpingd_start(struct in_addr source_addr); -int pim_ssmpingd_stop(struct in_addr source_addr); +void pim_ssmpingd_init(struct pim_instance *pim); +void pim_ssmpingd_destroy(struct pim_instance *pim); +int pim_ssmpingd_start(struct pim_instance *pim, struct in_addr source_addr); +int pim_ssmpingd_stop(struct pim_instance *pim, struct in_addr source_addr); #endif /* PIM_SSMPINGD_H */ diff --git a/pimd/pim_static.c b/pimd/pim_static.c index 7c9aca47a7..3d44a01c78 100644 --- a/pimd/pim_static.c +++ b/pimd/pim_static.c @@ -74,8 +74,9 @@ static struct static_route *static_route_new(unsigned int iif, unsigned int oif, } -int pim_static_add(struct interface *iif, struct interface *oif, - struct in_addr group, struct in_addr source) +int pim_static_add(struct pim_instance *pim, struct interface *iif, + struct interface *oif, struct in_addr group, + struct in_addr source) { struct listnode *node = NULL; struct static_route *s_route = NULL; @@ -101,8 +102,11 @@ int pim_static_add(struct interface *iif, struct interface *oif, return -4; } #endif + if (iif->vrf_id != oif->vrf_id) { + return -3; + } - for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) { + for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) { if (s_route->group.s_addr == group.s_addr && s_route->source.s_addr == source.s_addr) { if (s_route->iif == iif_index @@ -181,9 +185,11 @@ int pim_static_add(struct interface *iif, struct interface *oif, * match */ if (!node) { s_route = static_route_new(iif_index, oif_index, group, source); - listnode_add(qpim_static_route_list, s_route); + listnode_add(pim->static_routes, s_route); } + s_route->c_oil.pim = pim; + if (pim_mroute_add(&s_route->c_oil, __PRETTY_FUNCTION__)) { char gifaddr_str[INET_ADDRSTRLEN]; char sifaddr_str[INET_ADDRSTRLEN]; @@ -203,7 +209,7 @@ int pim_static_add(struct interface *iif, struct interface *oif, } else { /* we never stored off a copy, so it must have been a * fresh new route */ - listnode_delete(qpim_static_route_list, s_route); + listnode_delete(pim->static_routes, s_route); pim_static_route_free(s_route); } @@ -235,8 +241,9 @@ int pim_static_add(struct interface *iif, struct interface *oif, return 0; } -int pim_static_del(struct interface *iif, struct interface *oif, - struct in_addr group, struct in_addr source) +int pim_static_del(struct pim_instance *pim, struct interface *iif, + struct interface *oif, struct in_addr group, + struct in_addr source) { struct listnode *node = NULL; struct listnode *nextnode = NULL; @@ -253,8 +260,7 @@ int pim_static_del(struct interface *iif, struct interface *oif, return -2; } - for (ALL_LIST_ELEMENTS(qpim_static_route_list, node, nextnode, - s_route)) { + for (ALL_LIST_ELEMENTS(pim->static_routes, node, nextnode, s_route)) { if (s_route->iif == iif_index && s_route->group.s_addr == group.s_addr && s_route->source.s_addr == source.s_addr @@ -293,8 +299,7 @@ int pim_static_del(struct interface *iif, struct interface *oif, s_route->c_oil.oif_creation[oif_index] = 0; if (s_route->c_oil.oil_ref_count <= 0) { - listnode_delete(qpim_static_route_list, - s_route); + listnode_delete(pim->static_routes, s_route); pim_static_route_free(s_route); } @@ -332,7 +337,8 @@ int pim_static_del(struct interface *iif, struct interface *oif, return 0; } -int pim_static_write_mroute(struct vty *vty, struct interface *ifp) +int pim_static_write_mroute(struct pim_instance *pim, struct vty *vty, + struct interface *ifp) { struct pim_interface *pim_ifp = ifp->info; struct listnode *node; @@ -344,7 +350,7 @@ int pim_static_write_mroute(struct vty *vty, struct interface *ifp) if (!pim_ifp) return 0; - for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, sroute)) { + for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, sroute)) { pim_inet4_dump("<ifaddr?>", sroute->group, gbuf, sizeof(gbuf)); pim_inet4_dump("<ifaddr?>", sroute->source, sbuf, sizeof(sbuf)); if (sroute->iif == pim_ifp->mroute_vif_index) { @@ -352,7 +358,8 @@ int pim_static_write_mroute(struct vty *vty, struct interface *ifp) for (i = 0; i < MAXVIFS; i++) if (sroute->oif_ttls[i]) { struct interface *oifp = - pim_if_find_by_vif_index(i); + pim_if_find_by_vif_index(pim, + i); if (sroute->source.s_addr == 0) vty_out(vty, " ip mroute %s %s\n", diff --git a/pimd/pim_static.h b/pimd/pim_static.h index 1114f4b67b..953ec0a70a 100644 --- a/pimd/pim_static.h +++ b/pimd/pim_static.h @@ -36,10 +36,13 @@ struct static_route { void pim_static_route_free(struct static_route *s_route); -int pim_static_add(struct interface *iif, struct interface *oif, - struct in_addr group, struct in_addr source); -int pim_static_del(struct interface *iif, struct interface *oif, - struct in_addr group, struct in_addr source); -int pim_static_write_mroute(struct vty *vty, struct interface *ifp); +int pim_static_add(struct pim_instance *pim, struct interface *iif, + struct interface *oif, struct in_addr group, + struct in_addr source); +int pim_static_del(struct pim_instance *pim, struct interface *iif, + struct interface *oif, struct in_addr group, + struct in_addr source); +int pim_static_write_mroute(struct pim_instance *pim, struct vty *vty, + struct interface *ifp); #endif /* PIM_STATIC_H_ */ diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 0ddd04c38c..95d1a840ff 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -54,10 +54,6 @@ #include "pim_nht.h" #include "pim_ssm.h" -struct hash *pim_upstream_hash = NULL; -struct list *pim_upstream_list = NULL; -struct timer_wheel *pim_upstream_sg_wheel = NULL; - static void join_timer_stop(struct pim_upstream *up); static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up); @@ -67,7 +63,8 @@ pim_upstream_update_assert_tracking_desired(struct pim_upstream *up); * remove the parent pointer from * those pointing at us */ -static void pim_upstream_remove_children(struct pim_upstream *up) +static void pim_upstream_remove_children(struct pim_instance *pim, + struct pim_upstream *up) { struct pim_upstream *child; @@ -79,7 +76,8 @@ static void pim_upstream_remove_children(struct pim_upstream *up) listnode_delete(up->sources, child); if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(child->flags)) { PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(child->flags); - child = pim_upstream_del(child, __PRETTY_FUNCTION__); + child = pim_upstream_del(pim, child, + __PRETTY_FUNCTION__); } if (child) child->parent = NULL; @@ -93,7 +91,8 @@ static void pim_upstream_remove_children(struct pim_upstream *up) * Find the children that would point * at us. */ -static void pim_upstream_find_new_children(struct pim_upstream *up) +static void pim_upstream_find_new_children(struct pim_instance *pim, + struct pim_upstream *up) { struct pim_upstream *child; struct listnode *ch_node; @@ -106,7 +105,7 @@ static void pim_upstream_find_new_children(struct pim_upstream *up) && (up->sg.grp.s_addr == INADDR_ANY)) return; - for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, ch_node, child)) { + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, ch_node, child)) { if ((up->sg.grp.s_addr != INADDR_ANY) && (child->sg.grp.s_addr == up->sg.grp.s_addr) && (child != up)) { @@ -121,7 +120,8 @@ static void pim_upstream_find_new_children(struct pim_upstream *up) * If we have a (S,G), find the (*,G) * If we have a (*,G), find the (*,*) */ -static struct pim_upstream *pim_upstream_find_parent(struct pim_upstream *child) +static struct pim_upstream *pim_upstream_find_parent(struct pim_instance *pim, + struct pim_upstream *child) { struct prefix_sg any = child->sg; struct pim_upstream *up = NULL; @@ -130,7 +130,7 @@ static struct pim_upstream *pim_upstream_find_parent(struct pim_upstream *child) if ((child->sg.src.s_addr != INADDR_ANY) && (child->sg.grp.s_addr != INADDR_ANY)) { any.src.s_addr = INADDR_ANY; - up = pim_upstream_find(&any); + up = pim_upstream_find(pim, &any); if (up) listnode_add(up->sources, child); @@ -153,12 +153,14 @@ static void upstream_channel_oil_detach(struct pim_upstream *up) /* Detaching from channel_oil, channel_oil may exist post del, but upstream would not keep reference of it */ + up->channel_oil->up = NULL; pim_channel_oil_del(up->channel_oil); up->channel_oil = NULL; } } -struct pim_upstream *pim_upstream_del(struct pim_upstream *up, const char *name) +struct pim_upstream *pim_upstream_del(struct pim_instance *pim, + struct pim_upstream *up, const char *name) { bool notify_msdp = false; struct prefix nht_p; @@ -194,11 +196,11 @@ struct pim_upstream *pim_upstream_del(struct pim_upstream *up, const char *name) up->rpf.source_nexthop.interface = NULL; if (up->sg.src.s_addr != INADDR_ANY) { - wheel_remove_item(pim_upstream_sg_wheel, up); + wheel_remove_item(pim->upstream_sg_wheel, up); notify_msdp = true; } - pim_upstream_remove_children(up); + pim_upstream_remove_children(pim, up); if (up->sources) list_delete(up->sources); up->sources = NULL; @@ -217,11 +219,11 @@ struct pim_upstream *pim_upstream_del(struct pim_upstream *up, const char *name) listnode_delete(up->parent->sources, up); up->parent = NULL; - listnode_delete(pim_upstream_list, up); - hash_release(pim_upstream_hash, up); + listnode_delete(pim->upstream_list, up); + hash_release(pim->upstream_hash, up); if (notify_msdp) { - pim_msdp_up_del(&up->sg); + pim_msdp_up_del(pim, &up->sg); } /* Deregister addr with Zebra NHT */ @@ -234,7 +236,7 @@ struct pim_upstream *pim_upstream_del(struct pim_upstream *up, const char *name) zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT", __PRETTY_FUNCTION__, up->sg_str, buf); } - pim_delete_tracked_nexthop(&nht_p, up, NULL); + pim_delete_tracked_nexthop(pim, &nht_p, up, NULL); pim_upstream_free(up); @@ -442,7 +444,7 @@ static void forward_off(struct pim_upstream *up) /* scan per-interface (S,G) state */ for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) { - pim_forward_stop(ch); + pim_forward_stop(ch, false); } /* scan iface channel list */ } @@ -469,12 +471,12 @@ static int pim_upstream_could_register(struct pim_upstream *up) /* Source registration is supressed for SSM groups. When the SSM range changes * we re-revaluate register setup for existing upstream entries */ -void pim_upstream_register_reevaluate(void) +void pim_upstream_register_reevaluate(struct pim_instance *pim) { struct listnode *upnode; struct pim_upstream *up; - for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode, up)) { + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) { /* If FHR is set CouldRegister is True. Also check if the flow * is actually active; if it is not kat setup will trigger * source @@ -482,7 +484,7 @@ void pim_upstream_register_reevaluate(void) if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) || !up->t_ka_timer) continue; - if (pim_is_grp_ssm(up->sg.grp)) { + if (pim_is_grp_ssm(pim, up->sg.grp)) { /* clear the register state for SSM groups */ if (up->reg_state != PIM_REG_NOINFO) { if (PIM_DEBUG_PIM_EVENTS) @@ -491,7 +493,7 @@ void pim_upstream_register_reevaluate(void) up->sg_str); /* remove regiface from the OIL if it is there*/ pim_channel_del_oif(up->channel_oil, - pim_regiface, + pim->regiface, PIM_OIF_FLAG_PROTO_PIM); up->reg_state = PIM_REG_NOINFO; } @@ -503,7 +505,7 @@ void pim_upstream_register_reevaluate(void) "Register %s as G is now ASM", up->sg_str); pim_channel_add_oif(up->channel_oil, - pim_regiface, + pim->regiface, PIM_OIF_FLAG_PROTO_PIM); up->reg_state = PIM_REG_JOIN; } @@ -511,7 +513,7 @@ void pim_upstream_register_reevaluate(void) } } -void pim_upstream_switch(struct pim_upstream *up, +void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up, enum pim_upstream_state new_state) { enum pim_upstream_state old_state = up->join_state; @@ -533,14 +535,14 @@ void pim_upstream_switch(struct pim_upstream *up, if (old_state != PIM_UPSTREAM_JOINED) { int old_fhr = PIM_UPSTREAM_FLAG_TEST_FHR(up->flags); forward_on(up); - pim_msdp_up_join_state_changed(up); + pim_msdp_up_join_state_changed(pim, up); if (pim_upstream_could_register(up)) { PIM_UPSTREAM_FLAG_SET_FHR(up->flags); if (!old_fhr && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM( up->flags)) { pim_upstream_keep_alive_timer_start( - up, qpim_keep_alive_time); + up, pim->keep_alive_time); pim_register_join(up); } } else { @@ -554,13 +556,13 @@ void pim_upstream_switch(struct pim_upstream *up, forward_off(up); if (old_state == PIM_UPSTREAM_JOINED) - pim_msdp_up_join_state_changed(up); + pim_msdp_up_join_state_changed(pim, up); /* IHR, Trigger SGRpt on *,G IIF to prune S,G from RPT towards RP. If I am RP for G then send S,G prune to its IIF. */ if (pim_upstream_is_sg_rpt(up) && up->parent - && !I_am_RP(up->sg.grp)) { + && !I_am_RP(pim, up->sg.grp)) { if (PIM_DEBUG_PIM_TRACE_DETAIL) zlog_debug( "%s: *,G IIF %s S,G IIF %s ", @@ -598,8 +600,11 @@ int pim_upstream_compare(void *arg1, void *arg2) return 0; } -static struct pim_upstream * -pim_upstream_new(struct prefix_sg *sg, struct interface *incoming, int flags) +static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, + struct prefix_sg *sg, + struct interface *incoming, + int flags, + struct pim_ifchannel *ch) { enum pim_rpf_result rpf_result; struct pim_interface *pim_ifp; @@ -614,25 +619,29 @@ pim_upstream_new(struct prefix_sg *sg, struct interface *incoming, int flags) up->sg = *sg; pim_str_sg_set(sg, up->sg_str); - up = hash_get(pim_upstream_hash, up, hash_alloc_intern); - if (!pim_rp_set_upstream_addr(&up->upstream_addr, sg->src, sg->grp)) { + if (ch) + ch->upstream = up; + + up = hash_get(pim->upstream_hash, up, hash_alloc_intern); + if (!pim_rp_set_upstream_addr(pim, &up->upstream_addr, sg->src, + sg->grp)) { if (PIM_DEBUG_TRACE) zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__); - hash_release(pim_upstream_hash, up); + hash_release(pim->upstream_hash, up); XFREE(MTYPE_PIM_UPSTREAM, up); return NULL; } - up->parent = pim_upstream_find_parent(up); + up->parent = pim_upstream_find_parent(pim, up); if (up->sg.src.s_addr == INADDR_ANY) { up->sources = list_new(); up->sources->cmp = pim_upstream_compare; } else up->sources = NULL; - pim_upstream_find_new_children(up); + pim_upstream_find_new_children(pim, up); up->flags = flags; up->ref_count = 1; up->t_join_timer = NULL; @@ -660,9 +669,9 @@ pim_upstream_new(struct prefix_sg *sg, struct interface *incoming, int flags) up->ifchannels->cmp = (int (*)(void *, void *))pim_ifchannel_compare; if (up->sg.src.s_addr != INADDR_ANY) - wheel_add_item(pim_upstream_sg_wheel, up); + wheel_add_item(pim->upstream_sg_wheel, up); - rpf_result = pim_rpf_update(up, NULL, 1); + rpf_result = pim_rpf_update(pim, up, NULL, 1); if (rpf_result == PIM_RPF_FAILURE) { struct prefix nht_p; @@ -674,7 +683,7 @@ pim_upstream_new(struct prefix_sg *sg, struct interface *incoming, int flags) nht_p.family = AF_INET; nht_p.prefixlen = IPV4_MAX_BITLEN; nht_p.u.prefix4 = up->upstream_addr; - pim_delete_tracked_nexthop(&nht_p, up, NULL); + pim_delete_tracked_nexthop(pim, &nht_p, up, NULL); if (up->parent) { listnode_delete(up->parent->sources, up); @@ -682,13 +691,13 @@ pim_upstream_new(struct prefix_sg *sg, struct interface *incoming, int flags) } if (up->sg.src.s_addr != INADDR_ANY) - wheel_remove_item(pim_upstream_sg_wheel, up); + wheel_remove_item(pim->upstream_sg_wheel, up); - pim_upstream_remove_children(up); + pim_upstream_remove_children(pim, up); if (up->sources) list_delete(up->sources); - hash_release(pim_upstream_hash, up); + hash_release(pim->upstream_hash, up); XFREE(MTYPE_PIM_UPSTREAM, up); return NULL; } @@ -697,9 +706,9 @@ pim_upstream_new(struct prefix_sg *sg, struct interface *incoming, int flags) pim_ifp = up->rpf.source_nexthop.interface->info; if (pim_ifp) up->channel_oil = pim_channel_oil_add( - &up->sg, pim_ifp->mroute_vif_index); + pim, &up->sg, pim_ifp->mroute_vif_index); } - listnode_add_sort(pim_upstream_list, up); + listnode_add_sort(pim->upstream_list, up); if (PIM_DEBUG_TRACE) { zlog_debug( @@ -711,13 +720,14 @@ pim_upstream_new(struct prefix_sg *sg, struct interface *incoming, int flags) return up; } -struct pim_upstream *pim_upstream_find(struct prefix_sg *sg) +struct pim_upstream *pim_upstream_find(struct pim_instance *pim, + struct prefix_sg *sg) { struct pim_upstream lookup; struct pim_upstream *up = NULL; lookup.sg = *sg; - up = hash_lookup(pim_upstream_hash, &lookup); + up = hash_lookup(pim->upstream_hash, &lookup); return up; } @@ -726,8 +736,11 @@ struct pim_upstream *pim_upstream_find_or_add(struct prefix_sg *sg, int flags, const char *name) { struct pim_upstream *up; + struct pim_interface *pim_ifp; + + pim_ifp = incoming->info; - up = pim_upstream_find(sg); + up = pim_upstream_find(pim_ifp->pim, sg); if (up) { if (!(up->flags & flags)) { @@ -740,7 +753,8 @@ struct pim_upstream *pim_upstream_find_or_add(struct prefix_sg *sg, up->ref_count); } } else - up = pim_upstream_add(sg, incoming, flags, name); + up = pim_upstream_add(pim_ifp->pim, sg, incoming, flags, name, + NULL); return up; } @@ -755,18 +769,21 @@ void pim_upstream_ref(struct pim_upstream *up, int flags, const char *name) up->ref_count); } -struct pim_upstream *pim_upstream_add(struct prefix_sg *sg, +struct pim_upstream *pim_upstream_add(struct pim_instance *pim, + struct prefix_sg *sg, struct interface *incoming, int flags, - const char *name) + const char *name, + struct pim_ifchannel *ch) { struct pim_upstream *up = NULL; int found = 0; - up = pim_upstream_find(sg); + + up = pim_upstream_find(pim, sg); if (up) { pim_upstream_ref(up, flags, name); found = 1; } else { - up = pim_upstream_new(sg, incoming, flags); + up = pim_upstream_new(pim, sg, incoming, flags, ch); } if (PIM_DEBUG_TRACE) { @@ -842,7 +859,8 @@ int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up, See also pim_upstream_update_join_desired() below. */ -int pim_upstream_evaluate_join_desired(struct pim_upstream *up) +int pim_upstream_evaluate_join_desired(struct pim_instance *pim, + struct pim_upstream *up) { struct interface *ifp; struct listnode *node; @@ -850,7 +868,7 @@ int pim_upstream_evaluate_join_desired(struct pim_upstream *up) struct pim_upstream *starup = up->parent; int ret = 0; - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) { if (!ifp->info) continue; @@ -874,14 +892,15 @@ int pim_upstream_evaluate_join_desired(struct pim_upstream *up) /* See also pim_upstream_evaluate_join_desired() above. */ -void pim_upstream_update_join_desired(struct pim_upstream *up) +void pim_upstream_update_join_desired(struct pim_instance *pim, + struct pim_upstream *up) { int was_join_desired; /* boolean */ int is_join_desired; /* boolean */ was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags); - is_join_desired = pim_upstream_evaluate_join_desired(up); + is_join_desired = pim_upstream_evaluate_join_desired(pim, up); if (is_join_desired) PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags); else @@ -889,13 +908,13 @@ void pim_upstream_update_join_desired(struct pim_upstream *up) /* switched from false to true */ if (is_join_desired && !was_join_desired) { - pim_upstream_switch(up, PIM_UPSTREAM_JOINED); + pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED); return; } /* switched from true to false */ if (!is_join_desired && was_join_desired) { - pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED); + pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED); return; } } @@ -909,7 +928,8 @@ void pim_upstream_update_join_desired(struct pim_upstream *up) Join Timer is set to expire in more than t_override seconds, reset it so that it expires after t_override seconds. */ -void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr) +void pim_upstream_rpf_genid_changed(struct pim_instance *pim, + struct in_addr neigh_addr) { struct listnode *up_node; struct listnode *up_nextnode; @@ -918,7 +938,7 @@ void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr) /* * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr */ - for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) { + for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) { if (PIM_DEBUG_TRACE) { char neigh_str[INET_ADDRSTRLEN]; @@ -1020,7 +1040,8 @@ static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up) /* When kat is stopped CouldRegister goes to false so we need to * transition the (S, G) on FHR to NI state and remove reg tunnel * from the OIL */ -static void pim_upstream_fhr_kat_expiry(struct pim_upstream *up) +static void pim_upstream_fhr_kat_expiry(struct pim_instance *pim, + struct pim_upstream *up) { if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) return; @@ -1032,7 +1053,7 @@ static void pim_upstream_fhr_kat_expiry(struct pim_upstream *up) /* stop reg-stop timer */ THREAD_OFF(up->t_rs_timer); /* remove regiface from the OIL if it is there*/ - pim_channel_del_oif(up->channel_oil, pim_regiface, + pim_channel_del_oif(up->channel_oil, pim->regiface, PIM_OIF_FLAG_PROTO_PIM); /* clear the register state */ up->reg_state = PIM_REG_NOINFO; @@ -1065,10 +1086,12 @@ static void pim_upstream_fhr_kat_start(struct pim_upstream *up) static int pim_upstream_keep_alive_timer(struct thread *t) { struct pim_upstream *up; + struct pim_instance *pim; up = THREAD_ARG(t); + pim = up->channel_oil->pim; - if (I_am_RP(up->sg.grp)) { + if (I_am_RP(pim, up->sg.grp)) { pim_br_clear_pmbr(&up->sg); /* * We need to do more here :) @@ -1077,19 +1100,19 @@ static int pim_upstream_keep_alive_timer(struct thread *t) } /* source is no longer active - pull the SA from MSDP's cache */ - pim_msdp_sa_local_del(&up->sg); + pim_msdp_sa_local_del(pim, &up->sg); /* if entry was created because of activity we need to deref it */ if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) { - pim_upstream_fhr_kat_expiry(up); + pim_upstream_fhr_kat_expiry(pim, up); if (PIM_DEBUG_TRACE) zlog_debug("kat expired on %s; remove stream reference", up->sg_str); PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags); - pim_upstream_del(up, __PRETTY_FUNCTION__); + pim_upstream_del(pim, up, __PRETTY_FUNCTION__); } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) { PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up->flags); - pim_upstream_del(up, __PRETTY_FUNCTION__); + pim_upstream_del(pim, up, __PRETTY_FUNCTION__); } return 0; @@ -1114,12 +1137,11 @@ void pim_upstream_keep_alive_timer_start(struct pim_upstream *up, uint32_t time) /* MSDP on RP needs to know if a source is registerable to this RP */ static int pim_upstream_msdp_reg_timer(struct thread *t) { - struct pim_upstream *up; - - up = THREAD_ARG(t); + struct pim_upstream *up = THREAD_ARG(t); + struct pim_instance *pim = up->channel_oil->pim; /* source is no longer active - pull the SA from MSDP's cache */ - pim_msdp_sa_local_del(&up->sg); + pim_msdp_sa_local_del(pim, &up->sg); return 1; } void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up) @@ -1159,9 +1181,10 @@ void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up) * SwitchToSptDesired(S,G) return true once a single packet has been * received for the source and group. */ -int pim_upstream_switch_to_spt_desired(struct prefix_sg *sg) +int pim_upstream_switch_to_spt_desired(struct pim_instance *pim, + struct prefix_sg *sg) { - if (I_am_RP(sg->grp)) + if (I_am_RP(pim, sg->grp)) return 1; return 0; @@ -1295,10 +1318,12 @@ const char *pim_reg_state2str(enum pim_reg_state reg_state, char *state_str) static int pim_upstream_register_stop_timer(struct thread *t) { struct pim_interface *pim_ifp; + struct pim_instance *pim; struct pim_upstream *up; struct pim_rpf *rpg; struct ip ip_hdr; up = THREAD_ARG(t); + pim = up->channel_oil->pim; if (PIM_DEBUG_TRACE) { char state_str[PIM_REG_STATE_STR_LEN]; @@ -1310,7 +1335,7 @@ static int pim_upstream_register_stop_timer(struct thread *t) switch (up->reg_state) { case PIM_REG_JOIN_PENDING: up->reg_state = PIM_REG_JOIN; - pim_channel_add_oif(up->channel_oil, pim_regiface, + pim_channel_add_oif(up->channel_oil, pim->regiface, PIM_OIF_FLAG_PROTO_PIM); break; case PIM_REG_JOIN: @@ -1330,14 +1355,21 @@ static int pim_upstream_register_stop_timer(struct thread *t) if (((up->channel_oil->cc.lastused / 100) > PIM_KEEPALIVE_PERIOD) - && (I_am_RP(up->sg.grp))) { + && (I_am_RP(pim_ifp->pim, up->sg.grp))) { if (PIM_DEBUG_TRACE) zlog_debug( "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while", __PRETTY_FUNCTION__); return 0; } - rpg = RP(up->sg.grp); + rpg = RP(pim_ifp->pim, up->sg.grp); + if (!rpg) { + if (PIM_DEBUG_TRACE) + zlog_debug( + "%s: Cannot send register for %s no RPF to the RP", + __PRETTY_FUNCTION__, up->sg_str); + return 0; + } memset(&ip_hdr, 0, sizeof(struct ip)); ip_hdr.ip_p = PIM_IP_PROTO_PIM; ip_hdr.ip_hl = 5; @@ -1380,7 +1412,8 @@ void pim_upstream_start_register_stop_timer(struct pim_upstream *up, &up->t_rs_timer); } -int pim_upstream_inherited_olist_decide(struct pim_upstream *up) +int pim_upstream_inherited_olist_decide(struct pim_instance *pim, + struct pim_upstream *up) { struct interface *ifp; struct pim_interface *pim_ifp = NULL; @@ -1397,10 +1430,10 @@ int pim_upstream_inherited_olist_decide(struct pim_upstream *up) __PRETTY_FUNCTION__, up->sg_str); } if (pim_ifp && !up->channel_oil) - up->channel_oil = - pim_channel_oil_add(&up->sg, pim_ifp->mroute_vif_index); + up->channel_oil = pim_channel_oil_add( + pim, &up->sg, pim_ifp->mroute_vif_index); - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) { if (!ifp->info) continue; @@ -1445,9 +1478,10 @@ int pim_upstream_inherited_olist_decide(struct pim_upstream *up) * return 1 if there are any output interfaces * return 0 if there are not any output interfaces */ -int pim_upstream_inherited_olist(struct pim_upstream *up) +int pim_upstream_inherited_olist(struct pim_instance *pim, + struct pim_upstream *up) { - int output_intf = pim_upstream_inherited_olist_decide(up); + int output_intf = pim_upstream_inherited_olist_decide(pim, up); /* * If we have output_intf switch state to Join and work like normal @@ -1456,7 +1490,7 @@ int pim_upstream_inherited_olist(struct pim_upstream *up) * incoming packets so we don't bother the other stuff! */ if (output_intf) - pim_upstream_switch(up, PIM_UPSTREAM_JOINED); + pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED); else forward_on(up); @@ -1474,7 +1508,7 @@ int pim_upstream_empty_inherited_olist(struct pim_upstream *up) * set and see if the new neighbor allows * the join to be sent */ -void pim_upstream_find_new_rpf(void) +void pim_upstream_find_new_rpf(struct pim_instance *pim) { struct listnode *up_node; struct listnode *up_nextnode; @@ -1483,36 +1517,36 @@ void pim_upstream_find_new_rpf(void) /* * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr */ - for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) { + for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) { if (pim_rpf_addr_is_inaddr_any(&up->rpf)) { if (PIM_DEBUG_TRACE) zlog_debug( "Upstream %s without a path to send join, checking", up->sg_str); - pim_rpf_update(up, NULL, 1); + pim_rpf_update(pim, up, NULL, 1); } } } -static unsigned int pim_upstream_hash_key(void *arg) +unsigned int pim_upstream_hash_key(void *arg) { struct pim_upstream *up = (struct pim_upstream *)arg; return jhash_2words(up->sg.src.s_addr, up->sg.grp.s_addr, 0); } -void pim_upstream_terminate(void) +void pim_upstream_terminate(struct pim_instance *pim) { - if (pim_upstream_list) - list_delete(pim_upstream_list); - pim_upstream_list = NULL; + if (pim->upstream_list) + list_delete(pim->upstream_list); + pim->upstream_list = NULL; - if (pim_upstream_hash) - hash_free(pim_upstream_hash); - pim_upstream_hash = NULL; + if (pim->upstream_hash) + hash_free(pim->upstream_hash); + pim->upstream_hash = NULL; } -static int pim_upstream_equal(const void *arg1, const void *arg2) +int pim_upstream_equal(const void *arg1, const void *arg2) { const struct pim_upstream *up1 = (const struct pim_upstream *)arg1; const struct pim_upstream *up2 = (const struct pim_upstream *)arg2; @@ -1540,6 +1574,8 @@ static int pim_upstream_equal(const void *arg1, const void *arg2) */ static bool pim_upstream_kat_start_ok(struct pim_upstream *up) { + struct pim_instance *pim = up->channel_oil->pim; + /* "iif == RPF_interface(S)" check has to be done by the kernel or hw * so we will skip that here */ if (pim_if_connected_to_source(up->rpf.source_nexthop.interface, @@ -1559,7 +1595,7 @@ static bool pim_upstream_kat_start_ok(struct pim_upstream *up) * MUST be * removed to handle spt turn-arounds correctly in a 3-tier clos */ - if (I_am_RP(up->sg.grp)) + if (I_am_RP(pim, up->sg.grp)) return true; } @@ -1573,9 +1609,10 @@ static bool pim_upstream_kat_start_ok(struct pim_upstream *up) static void pim_upstream_sg_running(void *arg) { struct pim_upstream *up = (struct pim_upstream *)arg; + struct pim_instance *pim = up->channel_oil->pim; // No packet can have arrived here if this is the case - if (!up->channel_oil || !up->channel_oil->installed) { + if (!up->channel_oil->installed) { if (PIM_DEBUG_TRACE) zlog_debug("%s: %s is not installed in mroute", __PRETTY_FUNCTION__, up->sg_str); @@ -1595,7 +1632,7 @@ static void pim_upstream_sg_running(void *arg) zlog_debug( "%s: Handling unscanned inherited_olist for %s", __PRETTY_FUNCTION__, up->sg_str); - pim_upstream_inherited_olist_decide(up); + pim_upstream_inherited_olist_decide(pim, up); up->channel_oil->oil_inherited_rescan = 0; } pim_mroute_update_counters(up->channel_oil); @@ -1628,9 +1665,9 @@ static void pim_upstream_sg_running(void *arg) PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags); pim_upstream_fhr_kat_start(up); } - pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time); + pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time); } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) - pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time); + pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time); if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) { pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface); @@ -1638,29 +1675,30 @@ static void pim_upstream_sg_running(void *arg) return; } -void pim_upstream_add_lhr_star_pimreg(void) +void pim_upstream_add_lhr_star_pimreg(struct pim_instance *pim) { struct pim_upstream *up; struct listnode *node; - for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, node, up)) { + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) { if (up->sg.src.s_addr != INADDR_ANY) continue; if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags)) continue; - pim_channel_add_oif(up->channel_oil, pim_regiface, + pim_channel_add_oif(up->channel_oil, pim->regiface, PIM_OIF_FLAG_PROTO_IGMP); } } -void pim_upstream_spt_prefix_list_update(struct prefix_list *pl) +void pim_upstream_spt_prefix_list_update(struct pim_instance *pim, + struct prefix_list *pl) { const char *pname = prefix_list_name(pl); - if (pimg->spt.plist && strcmp(pimg->spt.plist, pname) == 0) { - pim_upstream_remove_lhr_star_pimreg(pname); + if (pim->spt.plist && strcmp(pim->spt.plist, pname) == 0) { + pim_upstream_remove_lhr_star_pimreg(pim, pname); } } @@ -1676,7 +1714,8 @@ void pim_upstream_spt_prefix_list_update(struct prefix_list *pl) * the interface * */ -void pim_upstream_remove_lhr_star_pimreg(const char *nlist) +void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim, + const char *nlist) { struct pim_upstream *up; struct listnode *node; @@ -1689,7 +1728,7 @@ void pim_upstream_remove_lhr_star_pimreg(const char *nlist) g.family = AF_INET; g.prefixlen = IPV4_MAX_PREFIXLEN; - for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, node, up)) { + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) { if (up->sg.src.s_addr != INADDR_ANY) continue; @@ -1697,30 +1736,35 @@ void pim_upstream_remove_lhr_star_pimreg(const char *nlist) continue; if (!nlist) { - pim_channel_del_oif(up->channel_oil, pim_regiface, + pim_channel_del_oif(up->channel_oil, pim->regiface, PIM_OIF_FLAG_PROTO_IGMP); continue; } g.u.prefix4 = up->sg.grp; apply_new = prefix_list_apply(np, &g); if (apply_new == PREFIX_DENY) - pim_channel_add_oif(up->channel_oil, pim_regiface, + pim_channel_add_oif(up->channel_oil, pim->regiface, PIM_OIF_FLAG_PROTO_IGMP); else - pim_channel_del_oif(up->channel_oil, pim_regiface, + pim_channel_del_oif(up->channel_oil, pim->regiface, PIM_OIF_FLAG_PROTO_IGMP); } } -void pim_upstream_init(void) +void pim_upstream_init(struct pim_instance *pim) { - pim_upstream_sg_wheel = + char hash_name[64]; + + pim->upstream_sg_wheel = wheel_init(master, 31000, 100, pim_upstream_hash_key, pim_upstream_sg_running); - pim_upstream_hash = hash_create_size(8192, pim_upstream_hash_key, - pim_upstream_equal, NULL); - pim_upstream_list = list_new(); - pim_upstream_list->del = (void (*)(void *))pim_upstream_free; - pim_upstream_list->cmp = pim_upstream_compare; + snprintf(hash_name, 64, "PIM %s Upstream Hash", + pim->vrf->name); + pim->upstream_hash = hash_create_size(8192, pim_upstream_hash_key, + pim_upstream_equal, hash_name); + + pim->upstream_list = list_new(); + pim->upstream_list->del = (void (*)(void *))pim_upstream_free; + pim->upstream_list->cmp = pim_upstream_compare; } diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index b6a9729f0f..b75a5b9df3 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -119,7 +119,7 @@ struct pim_upstream { */ struct thread *t_rs_timer; #define PIM_REGISTER_SUPPRESSION_PERIOD (60) -#define PIM_REGISTER_PROBE_PERIOD (15) +#define PIM_REGISTER_PROBE_PERIOD (5) /* * KAT(S,G) @@ -137,26 +137,29 @@ struct pim_upstream { int64_t state_transition; /* Record current state uptime */ }; -struct list *pim_upstream_list; -struct hash *pim_upstream_hash; - void pim_upstream_free(struct pim_upstream *up); -struct pim_upstream *pim_upstream_find(struct prefix_sg *sg); +struct pim_upstream *pim_upstream_find(struct pim_instance *pim, + struct prefix_sg *sg); struct pim_upstream *pim_upstream_find_or_add(struct prefix_sg *sg, struct interface *ifp, int flags, const char *name); -struct pim_upstream *pim_upstream_add(struct prefix_sg *sg, +struct pim_upstream *pim_upstream_add(struct pim_instance *pim, + struct prefix_sg *sg, struct interface *ifp, int flags, - const char *name); + const char *name, + struct pim_ifchannel *ch); void pim_upstream_ref(struct pim_upstream *up, int flags, const char *name); -struct pim_upstream *pim_upstream_del(struct pim_upstream *up, +struct pim_upstream *pim_upstream_del(struct pim_instance *pim, + struct pim_upstream *up, const char *name); -int pim_upstream_evaluate_join_desired(struct pim_upstream *up); +int pim_upstream_evaluate_join_desired(struct pim_instance *pim, + struct pim_upstream *up); int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up, struct pim_ifchannel *ch, struct pim_ifchannel *starch); -void pim_upstream_update_join_desired(struct pim_upstream *up); +void pim_upstream_update_join_desired(struct pim_instance *pim, + struct pim_upstream *up); void pim_upstream_join_suppress(struct pim_upstream *up, struct in_addr rpf_addr, int holdtime); @@ -166,7 +169,8 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, void pim_upstream_join_timer_restart(struct pim_upstream *up, struct pim_rpf *old); -void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr); +void pim_upstream_rpf_genid_changed(struct pim_instance *pim, + struct in_addr neigh_addr); void pim_upstream_rpf_interface_changed(struct pim_upstream *up, struct interface *old_rpf_ifp); @@ -176,8 +180,9 @@ void pim_upstream_update_my_assert_metric(struct pim_upstream *up); void pim_upstream_keep_alive_timer_start(struct pim_upstream *up, uint32_t time); -int pim_upstream_switch_to_spt_desired(struct prefix_sg *sg); -#define SwitchToSptDesired(sg) pim_upstream_switch_to_spt_desired (sg) +int pim_upstream_switch_to_spt_desired(struct pim_instance *pim, + struct prefix_sg *sg); +#define SwitchToSptDesired(pim, sg) pim_upstream_switch_to_spt_desired (pim, sg) int pim_upstream_is_sg_rpt(struct pim_upstream *up); void pim_upstream_set_sptbit(struct pim_upstream *up, @@ -188,29 +193,36 @@ void pim_upstream_start_register_stop_timer(struct pim_upstream *up, void pim_upstream_send_join(struct pim_upstream *up); -void pim_upstream_switch(struct pim_upstream *up, +void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up, enum pim_upstream_state new_state); const char *pim_upstream_state2str(enum pim_upstream_state join_state); #define PIM_REG_STATE_STR_LEN 12 const char *pim_reg_state2str(enum pim_reg_state state, char *state_str); -int pim_upstream_inherited_olist_decide(struct pim_upstream *up); -int pim_upstream_inherited_olist(struct pim_upstream *up); +int pim_upstream_inherited_olist_decide(struct pim_instance *pim, + struct pim_upstream *up); +int pim_upstream_inherited_olist(struct pim_instance *pim, + struct pim_upstream *up); int pim_upstream_empty_inherited_olist(struct pim_upstream *up); -void pim_upstream_find_new_rpf(void); +void pim_upstream_find_new_rpf(struct pim_instance *pim); void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up); -void pim_upstream_init(void); -void pim_upstream_terminate(void); +void pim_upstream_init(struct pim_instance *pim); +void pim_upstream_terminate(struct pim_instance *pim); void join_timer_start(struct pim_upstream *up); int pim_upstream_compare(void *arg1, void *arg2); -void pim_upstream_register_reevaluate(void); +void pim_upstream_register_reevaluate(struct pim_instance *pim); + +void pim_upstream_add_lhr_star_pimreg(struct pim_instance *pim); +void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim, + const char *nlist); -void pim_upstream_add_lhr_star_pimreg(void); -void pim_upstream_remove_lhr_star_pimreg(const char *nlist); +void pim_upstream_spt_prefix_list_update(struct pim_instance *pim, + struct prefix_list *pl); -void pim_upstream_spt_prefix_list_update(struct prefix_list *pl); +unsigned int pim_upstream_hash_key(void *arg); +int pim_upstream_equal(const void *arg1, const void *arg2); #endif /* PIM_UPSTREAM_H */ diff --git a/pimd/pim_util.c b/pimd/pim_util.c index c2e4b2a462..820117a03a 100644 --- a/pimd/pim_util.c +++ b/pimd/pim_util.c @@ -107,7 +107,8 @@ int pim_is_group_224_0_0_0_24(struct in_addr group_addr) struct prefix group; if (first) { - str2prefix("224.0.0.0/24", &group_224); + if (!str2prefix("224.0.0.0/24", &group_224)) + return 0; first = 0; } @@ -125,7 +126,8 @@ int pim_is_group_224_4(struct in_addr group_addr) struct prefix group; if (first) { - str2prefix("224.0.0.0/4", &group_all); + if (!str2prefix("224.0.0.0/4", &group_all)) + return 0; first = 0; } diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index a787767911..8914f6eb00 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -139,74 +139,92 @@ int pim_debug_config_write(struct vty *vty) ++writes; } + if (PIM_DEBUG_PIM_NHT) { + vty_out(vty, "debug pim nht\n"); + ++writes; + } + return writes; } -int pim_global_config_write(struct vty *vty) +int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) { int writes = 0; - struct pim_ssm *ssm = pimg->ssm_info; + struct pim_ssm *ssm = pim->ssm_info; + char spaces[10]; + + if (pim->vrf_id == VRF_DEFAULT) + sprintf(spaces, "%s", ""); + else + sprintf(spaces, "%s", " "); - writes += pim_msdp_config_write(vty); + writes += pim_msdp_config_write_helper(pim, vty, spaces); - if (!pimg->send_v6_secondary) { - vty_out(vty, "no ip pim send-v6-secondary\n"); + if (!pim->send_v6_secondary) { + vty_out(vty, "%sno ip pim send-v6-secondary\n", spaces); ++writes; } - writes += pim_rp_config_write(vty); + writes += pim_rp_config_write(pim, vty, spaces); if (qpim_register_suppress_time != PIM_REGISTER_SUPPRESSION_TIME_DEFAULT) { - vty_out(vty, "ip pim register-suppress-time %d\n", + vty_out(vty, "%sip pim register-suppress-time %d\n", spaces, qpim_register_suppress_time); ++writes; } if (qpim_t_periodic != PIM_DEFAULT_T_PERIODIC) { - vty_out(vty, "ip pim join-prune-interval %d\n", + vty_out(vty, "%sip pim join-prune-interval %d\n", spaces, qpim_t_periodic); ++writes; } - if (qpim_keep_alive_time != PIM_KEEPALIVE_PERIOD) { - vty_out(vty, "ip pim keep-alive-timer %d\n", - qpim_keep_alive_time); + if (pim->keep_alive_time != PIM_KEEPALIVE_PERIOD) { + vty_out(vty, "%sip pim keep-alive-timer %d\n", spaces, + pim->keep_alive_time); + ++writes; + } + if (pim->rp_keep_alive_time != (unsigned int)PIM_RP_KEEPALIVE_PERIOD) { + vty_out(vty, "%sip pim rp keep-alive-timer %d\n", spaces, + pim->rp_keep_alive_time); ++writes; } if (qpim_packet_process != PIM_DEFAULT_PACKET_PROCESS) { - vty_out(vty, "ip pim packets %d\n", qpim_packet_process); + vty_out(vty, "%sip pim packets %d\n", spaces, + qpim_packet_process); ++writes; } if (ssm->plist_name) { - vty_out(vty, "ip pim ssm prefix-list %s\n", ssm->plist_name); + vty_out(vty, "%sip pim ssm prefix-list %s\n", spaces, + ssm->plist_name); ++writes; } - if (pimg->spt.switchover == PIM_SPT_INFINITY) { - if (pimg->spt.plist) + if (pim->spt.switchover == PIM_SPT_INFINITY) { + if (pim->spt.plist) vty_out(vty, - "ip pim spt-switchover infinity-and-beyond prefix-list %s\n", - pimg->spt.plist); + "%sip pim spt-switchover infinity-and-beyond prefix-list %s\n", + spaces, pim->spt.plist); else vty_out(vty, - "ip pim spt-switchover infinity-and-beyond\n"); + "%sip pim spt-switchover infinity-and-beyond\n", + spaces); ++writes; } if (qpim_ecmp_rebalance_enable) { - vty_out(vty, "ip pim ecmp rebalance\n"); + vty_out(vty, "%sip pim ecmp rebalance\n", spaces); ++writes; } else if (qpim_ecmp_enable) { - vty_out(vty, "ip pim ecmp\n"); + vty_out(vty, "%sip pim ecmp\n", spaces); ++writes; } - if (qpim_ssmpingd_list) { + if (pim->ssmpingd_list) { struct listnode *node; struct ssmpingd_sock *ss; - vty_out(vty, "!\n"); ++writes; - for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) { + for (ALL_LIST_ELEMENTS_RO(pim->ssmpingd_list, node, ss)) { char source_str[INET_ADDRSTRLEN]; pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str)); - vty_out(vty, "ip ssmpingd %s\n", source_str); + vty_out(vty, "%sip ssmpingd %s\n", spaces, source_str); ++writes; } } @@ -214,112 +232,140 @@ int pim_global_config_write(struct vty *vty) return writes; } +int pim_global_config_write(struct vty *vty) +{ + return pim_global_config_write_worker(pimg, vty); +} + int pim_interface_config_write(struct vty *vty) { - int writes = 0; + struct pim_instance *pim; struct listnode *node; struct interface *ifp; + struct vrf *vrf; + int writes = 0; - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + pim = vrf->info; + if (!pim) + continue; - /* IF name */ - vty_out(vty, "interface %s\n", ifp->name); - ++writes; + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) { - if (ifp->info) { - struct pim_interface *pim_ifp = ifp->info; + /* IF name */ + if (vrf->vrf_id == VRF_DEFAULT) + vty_out(vty, "interface %s\n", ifp->name); + else + vty_out(vty, "interface %s vrf %s\n", ifp->name, + vrf->name); + ++writes; - if (PIM_IF_TEST_PIM(pim_ifp->options)) { - vty_out(vty, " ip pim sm\n"); - ++writes; - } + if (ifp->info) { + struct pim_interface *pim_ifp = ifp->info; - /* IF ip pim drpriority */ - if (pim_ifp->pim_dr_priority - != PIM_DEFAULT_DR_PRIORITY) { - vty_out(vty, " ip pim drpriority %u\n", - pim_ifp->pim_dr_priority); - ++writes; - } + if (PIM_IF_TEST_PIM(pim_ifp->options)) { + vty_out(vty, " ip pim sm\n"); + ++writes; + } - /* IF ip pim hello */ - if (pim_ifp->pim_hello_period - != PIM_DEFAULT_HELLO_PERIOD) { - vty_out(vty, " ip pim hello %d", - pim_ifp->pim_hello_period); - if (pim_ifp->pim_default_holdtime != -1) - vty_out(vty, " %d", - pim_ifp->pim_default_holdtime); - vty_out(vty, "\n"); - } + /* IF ip pim drpriority */ + if (pim_ifp->pim_dr_priority + != PIM_DEFAULT_DR_PRIORITY) { + vty_out(vty, " ip pim drpriority %u\n", + pim_ifp->pim_dr_priority); + ++writes; + } - /* update source */ - if (PIM_INADDR_ISNOT_ANY(pim_ifp->update_source)) { - char src_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<src?>", pim_ifp->update_source, - src_str, sizeof(src_str)); - vty_out(vty, " ip pim use-source %s\n", - src_str); - ++writes; - } + /* IF ip pim hello */ + if (pim_ifp->pim_hello_period + != PIM_DEFAULT_HELLO_PERIOD) { + vty_out(vty, " ip pim hello %d", + pim_ifp->pim_hello_period); + if (pim_ifp->pim_default_holdtime != -1) + vty_out(vty, " %d", + pim_ifp->pim_default_holdtime); + vty_out(vty, "\n"); + } - /* IF ip igmp */ - if (PIM_IF_TEST_IGMP(pim_ifp->options)) { - vty_out(vty, " ip igmp\n"); - ++writes; - } + /* update source */ + if (PIM_INADDR_ISNOT_ANY( + pim_ifp->update_source)) { + char src_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<src?>", + pim_ifp->update_source, + src_str, + sizeof(src_str)); + vty_out(vty, " ip pim use-source %s\n", + src_str); + ++writes; + } - /* ip igmp version */ - if (pim_ifp->igmp_version != IGMP_DEFAULT_VERSION) { - vty_out(vty, " ip igmp version %d\n", - pim_ifp->igmp_version); - ++writes; - } + /* IF ip igmp */ + if (PIM_IF_TEST_IGMP(pim_ifp->options)) { + vty_out(vty, " ip igmp\n"); + ++writes; + } - /* IF ip igmp query-interval */ - if (pim_ifp->igmp_default_query_interval - != IGMP_GENERAL_QUERY_INTERVAL) { - vty_out(vty, " ip igmp query-interval %d\n", - pim_ifp->igmp_default_query_interval); - ++writes; - } + /* ip igmp version */ + if (pim_ifp->igmp_version + != IGMP_DEFAULT_VERSION) { + vty_out(vty, " ip igmp version %d\n", + pim_ifp->igmp_version); + ++writes; + } - /* IF ip igmp query-max-response-time */ - if (pim_ifp->igmp_query_max_response_time_dsec - != IGMP_QUERY_MAX_RESPONSE_TIME_DSEC) { - vty_out(vty, - " ip igmp query-max-response-time %d\n", - pim_ifp->igmp_query_max_response_time_dsec); - ++writes; - } + /* IF ip igmp query-interval */ + if (pim_ifp->igmp_default_query_interval + != IGMP_GENERAL_QUERY_INTERVAL) { + vty_out(vty, + " ip igmp query-interval %d\n", + pim_ifp->igmp_default_query_interval); + ++writes; + } - /* IF ip igmp join */ - if (pim_ifp->igmp_join_list) { - struct listnode *node; - struct igmp_join *ij; - for (ALL_LIST_ELEMENTS_RO( - pim_ifp->igmp_join_list, node, - ij)) { - char group_str[INET_ADDRSTRLEN]; - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<grp?>", ij->group_addr, - group_str, - sizeof(group_str)); - inet_ntop(AF_INET, &ij->source_addr, - source_str, - sizeof(source_str)); - vty_out(vty, " ip igmp join %s %s\n", - group_str, source_str); + /* IF ip igmp query-max-response-time */ + if (pim_ifp->igmp_query_max_response_time_dsec + != IGMP_QUERY_MAX_RESPONSE_TIME_DSEC) { + vty_out(vty, + " ip igmp query-max-response-time %d\n", + pim_ifp->igmp_query_max_response_time_dsec); ++writes; } - } - writes += pim_static_write_mroute(vty, ifp); + /* IF ip igmp join */ + if (pim_ifp->igmp_join_list) { + struct listnode *node; + struct igmp_join *ij; + for (ALL_LIST_ELEMENTS_RO( + pim_ifp->igmp_join_list, + node, ij)) { + char group_str[INET_ADDRSTRLEN]; + char source_str + [INET_ADDRSTRLEN]; + pim_inet4_dump( + "<grp?>", + ij->group_addr, + group_str, + sizeof(group_str)); + inet_ntop(AF_INET, + &ij->source_addr, + source_str, + sizeof(source_str)); + vty_out(vty, + " ip igmp join %s %s\n", + group_str, source_str); + ++writes; + } + } + + writes += + pim_static_write_mroute(pim, vty, ifp); + pim_bfd_write_config(vty, ifp); + } + vty_out(vty, "!\n"); + ++writes; } - vty_out(vty, "!\n"); - ++writes; - /* PIM BFD write */ - pim_bfd_write_config(vty, ifp); } return writes; diff --git a/pimd/pim_vty.h b/pimd/pim_vty.h index 54bab623dc..aef90cacc3 100644 --- a/pimd/pim_vty.h +++ b/pimd/pim_vty.h @@ -24,6 +24,7 @@ int pim_debug_config_write(struct vty *vty); int pim_global_config_write(struct vty *vty); +int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty); int pim_interface_config_write(struct vty *vty); #endif /* PIM_VTY_H */ diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index c5cca7d1b4..7b060aef4b 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -80,8 +80,8 @@ static int pim_zebra_if_add(int command, struct zclient *zclient, if (PIM_DEBUG_ZEBRA) { zlog_debug( - "%s: %s index %d flags %ld metric %d mtu %d operative %d", - __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, + "%s: %s index %d(%d) flags %ld metric %d mtu %d operative %d", + __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id, (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp)); } @@ -89,6 +89,23 @@ static int pim_zebra_if_add(int command, struct zclient *zclient, if (if_is_operative(ifp)) pim_if_addr_add_all(ifp); + /* + * If we are a vrf device that is up, open up the pim_socket for + * listening + * to incoming pim messages irrelevant if the user has configured us + * for pim or not. + */ + if (pim_if_is_vrf_device(ifp)) { + struct pim_interface *pim_ifp; + + if (!ifp->info) { + pim_ifp = pim_if_new(ifp, 0, 0); + ifp->info = pim_ifp; + } + + pim_sock_add(ifp); + } + return 0; } @@ -113,8 +130,8 @@ static int pim_zebra_if_del(int command, struct zclient *zclient, if (PIM_DEBUG_ZEBRA) { zlog_debug( - "%s: %s index %d flags %ld metric %d mtu %d operative %d", - __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, + "%s: %s index %d(%d) flags %ld metric %d mtu %d operative %d", + __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id, (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp)); } @@ -129,6 +146,7 @@ static int pim_zebra_if_state_up(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; + uint32_t table_id; /* zebra api notifies interface up/down events by using the same call @@ -140,8 +158,8 @@ static int pim_zebra_if_state_up(int command, struct zclient *zclient, if (PIM_DEBUG_ZEBRA) { zlog_debug( - "%s: %s index %d flags %ld metric %d mtu %d operative %d", - __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, + "%s: %s index %d(%d) flags %ld metric %d mtu %d operative %d", + __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id, (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp)); } @@ -154,6 +172,23 @@ static int pim_zebra_if_state_up(int command, struct zclient *zclient, pim_if_addr_add_all(ifp); } + /* + * If we have a pimreg device callback and it's for a specific + * table set the master appropriately + */ + if (sscanf(ifp->name, "pimreg%d", &table_id) == 1) { + struct vrf *vrf; + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + if ((table_id == vrf->data.l.table_id) + && (ifp->vrf_id != vrf->vrf_id)) { + struct interface *master = if_lookup_by_name( + vrf->name, vrf->vrf_id); + zclient_interface_set_master(zclient, master, + ifp); + } + } + } return 0; } @@ -172,8 +207,8 @@ static int pim_zebra_if_state_down(int command, struct zclient *zclient, if (PIM_DEBUG_ZEBRA) { zlog_debug( - "%s: %s index %d flags %ld metric %d mtu %d operative %d", - __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, + "%s: %s index %d(%d) flags %ld metric %d mtu %d operative %d", + __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id, (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp)); } @@ -252,11 +287,11 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient, if (PIM_DEBUG_ZEBRA) { char buf[BUFSIZ]; prefix2str(p, buf, BUFSIZ); - zlog_debug("%s: %s connected IP address %s flags %u %s", - __PRETTY_FUNCTION__, c->ifp->name, buf, c->flags, - CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) - ? "secondary" - : "primary"); + zlog_debug("%s: %s(%d) connected IP address %s flags %u %s", + __PRETTY_FUNCTION__, c->ifp->name, vrf_id, buf, + c->flags, CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) + ? "secondary" + : "primary"); #ifdef PIM_DEBUG_IFADDR_DUMP dump_if_address(c->ifp); @@ -292,8 +327,7 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient, struct listnode *ifnode; struct interface *ifp; - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode, - ifp)) { + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(vrf_id), ifnode, ifp)) { if (!if_is_loopback(ifp) && if_is_operative(ifp)) pim_if_addr_add_all(ifp); } @@ -307,6 +341,8 @@ static int pim_zebra_if_address_del(int command, struct zclient *client, { struct connected *c; struct prefix *p; + struct vrf *vrf = vrf_lookup_by_id(vrf_id); + struct pim_instance *pim = vrf->info; /* zebra api notifies address adds/dels events by using the same call @@ -326,8 +362,8 @@ static int pim_zebra_if_address_del(int command, struct zclient *client, char buf[BUFSIZ]; prefix2str(p, buf, BUFSIZ); zlog_debug( - "%s: %s disconnected IP address %s flags %u %s", - __PRETTY_FUNCTION__, c->ifp->name, buf, + "%s: %s(%d) disconnected IP address %s flags %u %s", + __PRETTY_FUNCTION__, c->ifp->name, vrf_id, buf, c->flags, CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" @@ -339,8 +375,8 @@ static int pim_zebra_if_address_del(int command, struct zclient *client, } pim_if_addr_del(c, 0); - pim_rp_setup(); - pim_i_am_rp_re_evaluate(); + pim_rp_setup(pim); + pim_i_am_rp_re_evaluate(pim); } connected_free(c); @@ -355,99 +391,128 @@ static void scan_upstream_rpf_cache() struct listnode *node; struct pim_upstream *up; struct interface *ifp; + struct vrf *vrf; + struct pim_instance *pim; - for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) { - enum pim_rpf_result rpf_result; - struct pim_rpf old; - struct prefix nht_p; + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + pim = vrf->info; + if (!pim) + continue; - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr; - pim_resolve_upstream_nh(&nht_p); + for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, + up)) { + enum pim_rpf_result rpf_result; + struct pim_rpf old; + struct prefix nht_p; - old.source_nexthop.interface = up->rpf.source_nexthop.interface; - old.source_nexthop.nbr = up->rpf.source_nexthop.nbr; - rpf_result = pim_rpf_update(up, &old, 0); + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr; + pim_resolve_upstream_nh(pim, &nht_p); - if (rpf_result == PIM_RPF_FAILURE) - continue; + old.source_nexthop.interface = + up->rpf.source_nexthop.interface; + old.source_nexthop.nbr = up->rpf.source_nexthop.nbr; + rpf_result = pim_rpf_update(pim, up, &old, 0); - if (rpf_result == PIM_RPF_CHANGED) { - struct pim_neighbor *nbr; - - nbr = pim_neighbor_find(old.source_nexthop.interface, - old.rpf_addr.u.prefix4); - if (nbr) - pim_jp_agg_remove_group(nbr->upstream_jp_agg, - up); - - /* - * We have detected a case where we might need to rescan - * the inherited o_list so do it. - */ - if (up->channel_oil->oil_inherited_rescan) { - pim_upstream_inherited_olist_decide(up); - up->channel_oil->oil_inherited_rescan = 0; - } + if (rpf_result == PIM_RPF_FAILURE) + continue; - if (up->join_state == PIM_UPSTREAM_JOINED) { - /* - * If we come up real fast we can be here - * where the mroute has not been installed - * so install it. - */ - if (!up->channel_oil->installed) - pim_mroute_add(up->channel_oil, - __PRETTY_FUNCTION__); + if (rpf_result == PIM_RPF_CHANGED) { + struct pim_neighbor *nbr; + + nbr = pim_neighbor_find( + old.source_nexthop.interface, + old.rpf_addr.u.prefix4); + if (nbr) + pim_jp_agg_remove_group( + nbr->upstream_jp_agg, up); /* - * RFC 4601: 4.5.7. Sending (S,G) Join/Prune - * Messages - * - * Transitions from Joined State - * - * RPF'(S,G) changes not due to an Assert - * - * The upstream (S,G) state machine remains in - * Joined - * state. Send Join(S,G) to the new upstream - * neighbor, which is - * the new value of RPF'(S,G). Send Prune(S,G) - * to the old - * upstream neighbor, which is the old value of - * RPF'(S,G). Set - * the Join Timer (JT) to expire after - * t_periodic seconds. + * We have detected a case where we might need + * to rescan + * the inherited o_list so do it. */ - pim_jp_agg_switch_interface(&old, &up->rpf, up); - - pim_upstream_join_timer_restart(up, &old); - } /* up->join_state == PIM_UPSTREAM_JOINED */ + if (up->channel_oil->oil_inherited_rescan) { + pim_upstream_inherited_olist_decide(pim, + up); + up->channel_oil->oil_inherited_rescan = + 0; + } - /* FIXME can join_desired actually be changed by - pim_rpf_update() - returning PIM_RPF_CHANGED ? */ - pim_upstream_update_join_desired(up); + if (up->join_state == PIM_UPSTREAM_JOINED) { + /* + * If we come up real fast we can be + * here + * where the mroute has not been + * installed + * so install it. + */ + if (!up->channel_oil->installed) + pim_mroute_add( + up->channel_oil, + __PRETTY_FUNCTION__); + + /* + * RFC 4601: 4.5.7. Sending (S,G) + * Join/Prune Messages + * + * Transitions from Joined State + * + * RPF'(S,G) changes not due to an + * Assert + * + * The upstream (S,G) state machine + * remains in Joined + * state. Send Join(S,G) to the new + * upstream neighbor, which is + * the new value of RPF'(S,G). Send + * Prune(S,G) to the old + * upstream neighbor, which is the old + * value of RPF'(S,G). Set + * the Join Timer (JT) to expire after + * t_periodic seconds. + */ + pim_jp_agg_switch_interface( + &old, &up->rpf, up); + + pim_upstream_join_timer_restart(up, + &old); + } /* up->join_state == PIM_UPSTREAM_JOINED */ + + /* FIXME can join_desired actually be changed by + pim_rpf_update() + returning PIM_RPF_CHANGED ? */ + pim_upstream_update_join_desired(pim, up); + + } /* PIM_RPF_CHANGED */ + + } /* for (qpim_upstream_list) */ + } - } /* PIM_RPF_CHANGED */ + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + pim = vrf->info; + if (!pim) + continue; - } /* for (qpim_upstream_list) */ + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode, ifp)) + if (ifp->info) { + struct pim_interface *pim_ifp = ifp->info; + struct pim_iface_upstream_switch *us; - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode, ifp)) - if (ifp->info) { - struct pim_interface *pim_ifp = ifp->info; - struct pim_iface_upstream_switch *us; - - for (ALL_LIST_ELEMENTS_RO(pim_ifp->upstream_switch_list, - node, us)) { - struct pim_rpf rpf; - rpf.source_nexthop.interface = ifp; - rpf.rpf_addr.u.prefix4 = us->address; - pim_joinprune_send(&rpf, us->us); - pim_jp_agg_clear_group(us->us); + for (ALL_LIST_ELEMENTS_RO( + pim_ifp->upstream_switch_list, + node, us)) { + struct pim_rpf rpf; + rpf.source_nexthop.interface = ifp; + rpf.rpf_addr.u.prefix4 = us->address; + pim_joinprune_send(&rpf, us->us); + pim_jp_agg_clear_group(us->us); + } } - } + } } void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) @@ -456,7 +521,8 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) int input_iface_vif_index; int old_vif_index; - if (!pim_rp_set_upstream_addr(&vif_source, c_oil->oil.mfcc_origin, + if (!pim_rp_set_upstream_addr(c_oil->pim, &vif_source, + c_oil->oil.mfcc_origin, c_oil->oil.mfcc_mcastgrp)) return; @@ -480,11 +546,11 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); zlog_debug( - "%s: channel_oil (%s, %s) upstream info is not present.", + "%s: channel_oil (%s,%s) upstream info is not present.", __PRETTY_FUNCTION__, source_str, group_str); } input_iface_vif_index = pim_ecmp_fib_lookup_if_vif_index( - vif_source, &src, &grp); + c_oil->pim, vif_source, &src, &grp); } if (input_iface_vif_index < 1) { @@ -513,10 +579,10 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) } if (PIM_DEBUG_ZEBRA) { - struct interface *old_iif = - pim_if_find_by_vif_index(c_oil->oil.mfcc_parent); - struct interface *new_iif = - pim_if_find_by_vif_index(input_iface_vif_index); + struct interface *old_iif = pim_if_find_by_vif_index( + c_oil->pim, c_oil->oil.mfcc_parent); + struct interface *new_iif = pim_if_find_by_vif_index( + c_oil->pim, input_iface_vif_index); char source_str[INET_ADDRSTRLEN]; char group_str[INET_ADDRSTRLEN]; pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, @@ -532,8 +598,8 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) /* new iif loops to existing oif ? */ if (c_oil->oil.mfcc_ttls[input_iface_vif_index]) { - struct interface *new_iif = - pim_if_find_by_vif_index(input_iface_vif_index); + struct interface *new_iif = pim_if_find_by_vif_index( + c_oil->pim, input_iface_vif_index); if (PIM_DEBUG_ZEBRA) { char source_str[INET_ADDRSTRLEN]; @@ -558,10 +624,10 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) if (pim_mroute_add(c_oil, __PRETTY_FUNCTION__)) { if (PIM_DEBUG_MROUTE) { /* just log warning */ - struct interface *old_iif = - pim_if_find_by_vif_index(old_vif_index); - struct interface *new_iif = - pim_if_find_by_vif_index(input_iface_vif_index); + struct interface *old_iif = pim_if_find_by_vif_index( + c_oil->pim, old_vif_index); + struct interface *new_iif = pim_if_find_by_vif_index( + c_oil->pim, input_iface_vif_index); char source_str[INET_ADDRSTRLEN]; char group_str[INET_ADDRSTRLEN]; pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, @@ -580,28 +646,44 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) } } -void pim_scan_oil() +void pim_scan_oil(struct pim_instance *pim_matcher) { struct listnode *node; struct listnode *nextnode; struct channel_oil *c_oil; ifindex_t ifindex; int vif_index = 0; + struct vrf *vrf; + struct pim_instance *pim; qpim_scan_oil_last = pim_time_monotonic_sec(); ++qpim_scan_oil_events; - for (ALL_LIST_ELEMENTS(pim_channel_oil_list, node, nextnode, c_oil)) { - if (c_oil->up && c_oil->up->rpf.source_nexthop.interface) { - ifindex = c_oil->up->rpf.source_nexthop - .interface->ifindex; - vif_index = pim_if_find_vifindex_by_ifindex(ifindex); - /* Pass Current selected NH vif index to mroute download - */ - if (vif_index) - pim_scan_individual_oil(c_oil, vif_index); - } else - pim_scan_individual_oil(c_oil, 0); + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + pim = vrf->info; + if (!pim) + continue; + + if (pim_matcher && pim != pim_matcher) + continue; + + for (ALL_LIST_ELEMENTS(pim->channel_oil_list, node, nextnode, + c_oil)) { + if (c_oil->up + && c_oil->up->rpf.source_nexthop.interface) { + ifindex = c_oil->up->rpf.source_nexthop + .interface->ifindex; + vif_index = pim_if_find_vifindex_by_ifindex( + pim, ifindex); + /* Pass Current selected NH vif index to mroute + * download */ + if (vif_index) + pim_scan_individual_oil(c_oil, + vif_index); + } else + pim_scan_individual_oil(c_oil, 0); + } } } @@ -611,7 +693,7 @@ static int on_rpf_cache_refresh(struct thread *t) scan_upstream_rpf_cache(); /* update kernel multicast forwarding cache (MFC) */ - pim_scan_oil(); + pim_scan_oil(NULL); qpim_rpf_cache_refresh_last = pim_time_monotonic_sec(); ++qpim_rpf_cache_refresh_events; @@ -649,22 +731,13 @@ static void pim_zebra_connected(struct zclient *zclient) /* Send the client registration */ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER); - zclient_send_reg_requests(zclient, VRF_DEFAULT); + zclient_send_reg_requests(zclient, pimg->vrf_id); } void pim_zebra_init(void) { int i; -#ifdef HAVE_TCP_ZEBRA - zlog_notice( - "zclient update contacting ZEBRA daemon at socket TCP %s,%d", - "127.0.0.1", ZEBRA_PORT); -#else - zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", - zclient_serv_path_get()); -#endif - /* Socket for receiving updates from Zebra daemon */ zclient = zclient_new(master); @@ -689,7 +762,7 @@ void pim_zebra_init(void) for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (i == zclient->redist_default) continue; - vrf_bitmap_set(zclient->redist[AFI_IP][i], VRF_DEFAULT); + vrf_bitmap_set(zclient->redist[AFI_IP][i], pimg->vrf_id); ; if (PIM_DEBUG_PIM_TRACE) { zlog_debug("%s: requesting redistribution for %s (%i)", @@ -700,7 +773,7 @@ void pim_zebra_init(void) /* Request default information */ zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient, - VRF_DEFAULT); + pimg->vrf_id); if (PIM_DEBUG_PIM_TRACE) { zlog_info("%s: requesting default information redistribution", @@ -713,7 +786,8 @@ void pim_zebra_init(void) zclient_lookup_new(); } -void igmp_anysource_forward_start(struct igmp_group *group) +void igmp_anysource_forward_start(struct pim_instance *pim, + struct igmp_group *group) { struct igmp_source *source; struct in_addr src_addr = {.s_addr = 0}; @@ -728,7 +802,7 @@ void igmp_anysource_forward_start(struct igmp_group *group) return; } - igmp_source_forward_start(source); + igmp_source_forward_start(pim, source); } void igmp_anysource_forward_stop(struct igmp_group *group) @@ -741,7 +815,8 @@ void igmp_anysource_forward_stop(struct igmp_group *group) igmp_source_forward_stop(source); } -static void igmp_source_forward_reevaluate_one(struct igmp_source *source) +static void igmp_source_forward_reevaluate_one(struct pim_instance *pim, + struct igmp_source *source) { struct prefix_sg sg; struct igmp_group *group = source->source_group; @@ -756,7 +831,7 @@ static void igmp_source_forward_reevaluate_one(struct igmp_source *source) sg.grp = group->group_addr; ch = pim_ifchannel_find(group->group_igmp_sock->interface, &sg); - if (pim_is_grp_ssm(group->group_addr)) { + if (pim_is_grp_ssm(pim, group->group_addr)) { /* If SSM group withdraw local membership */ if (ch && (ch->local_ifmembership == PIM_IFMEMBERSHIP_INCLUDE)) { @@ -785,39 +860,51 @@ void igmp_source_forward_reevaluate_all(void) { struct listnode *ifnode; struct interface *ifp; + struct vrf *vrf; + struct pim_instance *pim; - for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode, ifp)) { - struct pim_interface *pim_ifp = ifp->info; - struct listnode *sock_node; - struct igmp_sock *igmp; - - if (!pim_ifp) + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + pim = vrf->info; + if (!pim) continue; - /* scan igmp sockets */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, - igmp)) { - struct listnode *grpnode; - struct igmp_group *grp; - - /* scan igmp groups */ - for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, - grpnode, grp)) { - struct listnode *srcnode; - struct igmp_source *src; - - /* scan group sources */ - for (ALL_LIST_ELEMENTS_RO( - grp->group_source_list, srcnode, - src)) { - igmp_source_forward_reevaluate_one(src); - } /* scan group sources */ - } /* scan igmp groups */ - } /* scan igmp sockets */ - } /* scan interfaces */ + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode, + ifp)) { + struct pim_interface *pim_ifp = ifp->info; + struct listnode *sock_node; + struct igmp_sock *igmp; + + if (!pim_ifp) + continue; + + /* scan igmp sockets */ + for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, + sock_node, igmp)) { + struct listnode *grpnode; + struct igmp_group *grp; + + /* scan igmp groups */ + for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, + grpnode, grp)) { + struct listnode *srcnode; + struct igmp_source *src; + + /* scan group sources */ + for (ALL_LIST_ELEMENTS_RO( + grp->group_source_list, + srcnode, src)) { + igmp_source_forward_reevaluate_one( + pim, src); + } /* scan group sources */ + } /* scan igmp groups */ + } /* scan igmp sockets */ + } /* scan interfaces */ + } } -void igmp_source_forward_start(struct igmp_source *source) +void igmp_source_forward_start(struct pim_instance *pim, + struct igmp_source *source) { struct igmp_group *group; struct prefix_sg sg; @@ -849,13 +936,12 @@ void igmp_source_forward_start(struct igmp_source *source) struct in_addr vif_source; struct pim_interface *pim_oif; struct prefix nht_p, src, grp; - int ret = 0; struct pim_nexthop_cache out_pnc; struct pim_nexthop nexthop; struct pim_upstream *up = NULL; - if (!pim_rp_set_upstream_addr(&vif_source, source->source_addr, - sg.grp)) + if (!pim_rp_set_upstream_addr(pim, &vif_source, + source->source_addr, sg.grp)) return; /* Register addr with Zebra NHT */ @@ -871,22 +957,21 @@ void igmp_source_forward_start(struct igmp_source *source) grp.prefixlen = IPV4_MAX_BITLEN; grp.u.prefix4 = sg.grp; - if ((ret = pim_find_or_track_nexthop(&nht_p, NULL, NULL, - &out_pnc)) - == 1) { + if (pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL, + &out_pnc)) { if (out_pnc.nexthop_num) { - up = pim_upstream_find(&sg); - memset(&nexthop, 0, sizeof(struct pim_nexthop)); + up = pim_upstream_find(pim, &sg); + memset(&nexthop, 0, sizeof(nexthop)); if (up) memcpy(&nexthop, &up->rpf.source_nexthop, sizeof(struct pim_nexthop)); - // Compute PIM RPF using Cached nexthop - pim_ecmp_nexthop_search(&out_pnc, &nexthop, + pim_ecmp_nexthop_search(pim, &out_pnc, &nexthop, &src, &grp, 0); if (nexthop.interface) input_iface_vif_index = pim_if_find_vifindex_by_ifindex( + pim, nexthop.interface->ifindex); } else { if (PIM_DEBUG_ZEBRA) { @@ -906,8 +991,8 @@ void igmp_source_forward_start(struct igmp_source *source) } } else input_iface_vif_index = - pim_ecmp_fib_lookup_if_vif_index(vif_source, - &src, &grp); + pim_ecmp_fib_lookup_if_vif_index( + pim, vif_source, &src, &grp); if (PIM_DEBUG_ZEBRA) { char buf2[INET_ADDRSTRLEN]; @@ -966,7 +1051,7 @@ void igmp_source_forward_start(struct igmp_source *source) } source->source_channel_oil = - pim_channel_oil_add(&sg, input_iface_vif_index); + pim_channel_oil_add(pim, &sg, input_iface_vif_index); if (!source->source_channel_oil) { if (PIM_DEBUG_IGMP_TRACE) { zlog_debug( @@ -1072,6 +1157,11 @@ void pim_forward_start(struct pim_ifchannel *ch) struct pim_upstream *up = ch->upstream; uint32_t mask = PIM_OIF_FLAG_PROTO_PIM; int input_iface_vif_index = 0; + struct pim_instance *pim; + struct pim_interface *pim_ifp; + + pim_ifp = ch->interface->info; + pim = pim_ifp->pim; if (PIM_DEBUG_PIM_TRACE) { char source_str[INET_ADDRSTRLEN]; @@ -1096,7 +1186,6 @@ void pim_forward_start(struct pim_ifchannel *ch) || (up->channel_oil && up->channel_oil->oil.mfcc_parent >= MAXVIFS)) { struct prefix nht_p, src, grp; - int ret = 0; struct pim_nexthop_cache out_pnc; /* Register addr with Zebra NHT */ @@ -1108,9 +1197,8 @@ void pim_forward_start(struct pim_ifchannel *ch) grp.u.prefix4 = up->sg.grp; memset(&out_pnc, 0, sizeof(struct pim_nexthop_cache)); - if ((ret = pim_find_or_track_nexthop(&nht_p, NULL, NULL, - &out_pnc)) - == 1) { + if (pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL, + &out_pnc)) { if (out_pnc.nexthop_num) { src.family = AF_INET; src.prefixlen = IPV4_MAX_BITLEN; @@ -1121,11 +1209,12 @@ void pim_forward_start(struct pim_ifchannel *ch) grp.u.prefix4 = up->sg.grp; // Compute PIM RPF using Cached nexthop if (pim_ecmp_nexthop_search( - &out_pnc, &up->rpf.source_nexthop, - &src, &grp, 0) - == 0) + pim, &out_pnc, + &up->rpf.source_nexthop, &src, &grp, + 0)) input_iface_vif_index = pim_if_find_vifindex_by_ifindex( + pim, up->rpf.source_nexthop .interface->ifindex); else { @@ -1154,7 +1243,7 @@ void pim_forward_start(struct pim_ifchannel *ch) } else input_iface_vif_index = pim_ecmp_fib_lookup_if_vif_index( - up->upstream_addr, &src, &grp); + pim, up->upstream_addr, &src, &grp); if (input_iface_vif_index < 1) { if (PIM_DEBUG_PIM_TRACE) { @@ -1169,16 +1258,16 @@ void pim_forward_start(struct pim_ifchannel *ch) return; } if (PIM_DEBUG_TRACE) { - struct interface *in_intf = - pim_if_find_by_vif_index(input_iface_vif_index); + struct interface *in_intf = pim_if_find_by_vif_index( + pim, input_iface_vif_index); zlog_debug( "%s: Update channel_oil IIF %s VIFI %d entry %s ", __PRETTY_FUNCTION__, in_intf ? in_intf->name : "NIL", input_iface_vif_index, up->sg_str); } - up->channel_oil = - pim_channel_oil_add(&up->sg, input_iface_vif_index); + up->channel_oil = pim_channel_oil_add(pim, &up->sg, + input_iface_vif_index); if (!up->channel_oil) { if (PIM_DEBUG_PIM_TRACE) zlog_debug( @@ -1195,17 +1284,21 @@ void pim_forward_start(struct pim_ifchannel *ch) pim_channel_add_oif(up->channel_oil, ch->interface, mask); } -void pim_forward_stop(struct pim_ifchannel *ch) +void pim_forward_stop(struct pim_ifchannel *ch, bool install_it) { struct pim_upstream *up = ch->upstream; if (PIM_DEBUG_PIM_TRACE) { - zlog_debug("%s: (S,G)=%s oif=%s", __PRETTY_FUNCTION__, - ch->sg_str, ch->interface->name); + zlog_debug("%s: (S,G)=%s oif=%s install_it: %d installed: %d", + __PRETTY_FUNCTION__, ch->sg_str, ch->interface->name, + install_it, up->channel_oil->installed); } pim_channel_del_oif(up->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_PIM); + + if (install_it && !up->channel_oil->installed) + pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__); } void pim_zebra_zclient_update(struct vty *vty) diff --git a/pimd/pim_zebra.h b/pimd/pim_zebra.h index 9b5450d66a..d9b17cb82d 100644 --- a/pimd/pim_zebra.h +++ b/pimd/pim_zebra.h @@ -30,17 +30,19 @@ void pim_zebra_init(void); void pim_zebra_zclient_update(struct vty *vty); void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index); -void pim_scan_oil(void); +void pim_scan_oil(struct pim_instance *pim_matcher); -void igmp_anysource_forward_start(struct igmp_group *group); +void igmp_anysource_forward_start(struct pim_instance *pim, + struct igmp_group *group); void igmp_anysource_forward_stop(struct igmp_group *group); -void igmp_source_forward_start(struct igmp_source *source); +void igmp_source_forward_start(struct pim_instance *pim, + struct igmp_source *source); void igmp_source_forward_stop(struct igmp_source *source); void igmp_source_forward_reevaluate_all(void); void pim_forward_start(struct pim_ifchannel *ch); -void pim_forward_stop(struct pim_ifchannel *ch); +void pim_forward_stop(struct pim_ifchannel *ch, bool install_it); void sched_rpf_cache_refresh(void); struct zclient *pim_zebra_zclient_get(void); diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index 027b18e123..df8ad4e428 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -135,13 +135,13 @@ void zclient_lookup_new(void) __PRETTY_FUNCTION__); } -static int zclient_read_nexthop(struct zclient *zlookup, +static int zclient_read_nexthop(struct pim_instance *pim, + struct zclient *zlookup, struct pim_zlookup_nexthop nexthop_tab[], const int tab_size, struct in_addr addr) { int num_ifindex = 0; struct stream *s; - const uint16_t MIN_LEN = 10; /* getipv4=4 getc=1 getl=4 getc=1 */ uint16_t length; u_char marker; u_char version; @@ -153,10 +153,11 @@ static int zclient_read_nexthop(struct zclient *zlookup, int nexthop_num; int i, err; - if (PIM_DEBUG_PIM_TRACE_DETAIL) { + if (PIM_DEBUG_PIM_NHT_DETAIL) { char addr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); - zlog_debug("%s: addr=%s", __PRETTY_FUNCTION__, addr_str); + zlog_debug("%s: addr=%s(%s)", __PRETTY_FUNCTION__, addr_str, + pim->vrf->name); } s = zlookup->ibuf; @@ -166,19 +167,11 @@ static int zclient_read_nexthop(struct zclient *zlookup, err = zclient_read_header(s, zlookup->sock, &length, &marker, &version, &vrf_id, &command); if (err < 0) { - zlog_err("%s %s: zclient_read_header() failed", - __FILE__, __PRETTY_FUNCTION__); + zlog_err("%s: zclient_read_header() failed", + __PRETTY_FUNCTION__); zclient_lookup_failed(zlookup); return -1; } - - if (length < MIN_LEN) { - zlog_err( - "%s %s: failure reading zclient lookup socket: len=%d < MIN_LEN=%d", - __FILE__, __PRETTY_FUNCTION__, length, MIN_LEN); - zclient_lookup_failed(zlookup); - return -2; - } } raddr.s_addr = stream_get_ipv4(s); @@ -188,8 +181,9 @@ static int zclient_read_nexthop(struct zclient *zlookup, char raddr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("<raddr?>", raddr, raddr_str, sizeof(raddr_str)); - zlog_warn("%s: address mismatch: addr=%s raddr=%s", - __PRETTY_FUNCTION__, addr_str, raddr_str); + zlog_warn("%s: address mismatch: addr=%s(%s) raddr=%s", + __PRETTY_FUNCTION__, addr_str, pim->vrf->name, + raddr_str); /* warning only */ } @@ -198,8 +192,9 @@ static int zclient_read_nexthop(struct zclient *zlookup, nexthop_num = stream_getc(s); if (nexthop_num < 1) { - zlog_err("%s: socket %d bad nexthop_num=%d", __func__, - zlookup->sock, nexthop_num); + if (PIM_DEBUG_PIM_NHT_DETAIL) + zlog_debug("%s: socket %d bad nexthop_num=%d", __func__, + zlookup->sock, nexthop_num); return -6; } @@ -214,9 +209,9 @@ static int zclient_read_nexthop(struct zclient *zlookup, pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); zlog_warn( - "%s %s: found too many nexthop ifindexes (%d > %d) for address %s", - __FILE__, __PRETTY_FUNCTION__, - (num_ifindex + 1), tab_size, addr_str); + "%s: found too many nexthop ifindexes (%d > %d) for address %s(%s)", + __PRETTY_FUNCTION__, (num_ifindex + 1), + tab_size, addr_str, pim->vrf->name); return num_ifindex; } switch (nexthop_type) { @@ -256,17 +251,17 @@ static int zclient_read_nexthop(struct zclient *zlookup, * If we are sending v6 secondary assume we receive v6 * secondary */ - if (pimg->send_v6_secondary) + if (pim->send_v6_secondary) nbr = pim_neighbor_find_by_secondary( if_lookup_by_index( nexthop_tab[num_ifindex] .ifindex, - VRF_DEFAULT), + vrf_id), &p); else nbr = pim_neighbor_find_if(if_lookup_by_index( nexthop_tab[num_ifindex].ifindex, - VRF_DEFAULT)); + vrf_id)); if (nbr) { nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET; @@ -283,9 +278,9 @@ static int zclient_read_nexthop(struct zclient *zlookup, pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); zlog_warn( - "%s %s: found non-ifindex nexthop type=%d for address %s", - __FILE__, __PRETTY_FUNCTION__, - nexthop_type, addr_str); + "%s: found non-ifindex nexthop type=%d for address %s(%s)", + __PRETTY_FUNCTION__, nexthop_type, + addr_str, pim->vrf->name); } break; } @@ -294,51 +289,61 @@ static int zclient_read_nexthop(struct zclient *zlookup, return num_ifindex; } -static int zclient_lookup_nexthop_once(struct pim_zlookup_nexthop nexthop_tab[], +static int zclient_lookup_nexthop_once(struct pim_instance *pim, + struct pim_zlookup_nexthop nexthop_tab[], const int tab_size, struct in_addr addr) { struct stream *s; int ret; - if (PIM_DEBUG_PIM_TRACE_DETAIL) { + if (PIM_DEBUG_PIM_NHT_DETAIL) { char addr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); - zlog_debug("%s: addr=%s", __PRETTY_FUNCTION__, addr_str); + zlog_debug("%s: addr=%s(%s)", __PRETTY_FUNCTION__, addr_str, + pim->vrf->name); } /* Check socket. */ if (zlookup->sock < 0) { - zlog_err("%s %s: zclient lookup socket is not connected", - __FILE__, __PRETTY_FUNCTION__); + zlog_err("%s: zclient lookup socket is not connected", + __PRETTY_FUNCTION__); zclient_lookup_failed(zlookup); return -1; } + if (pim->vrf->vrf_id == VRF_UNKNOWN) { + zlog_err( + "%s: VRF: %s does not fully exist yet, delaying lookup", + __PRETTY_FUNCTION__, pim->vrf->name); + return -1; + } + s = zlookup->obuf; stream_reset(s); - zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, VRF_DEFAULT); + zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, pim->vrf_id); stream_put_in_addr(s, &addr); stream_putw_at(s, 0, stream_get_endp(s)); ret = writen(zlookup->sock, s->data, stream_get_endp(s)); if (ret < 0) { zlog_err( - "%s %s: writen() failure: %d writing to zclient lookup socket", - __FILE__, __PRETTY_FUNCTION__, errno); + "%s: writen() failure: %d writing to zclient lookup socket", + __PRETTY_FUNCTION__, errno); zclient_lookup_failed(zlookup); return -2; } if (ret == 0) { - zlog_err("%s %s: connection closed on zclient lookup socket", - __FILE__, __PRETTY_FUNCTION__); + zlog_err("%s: connection closed on zclient lookup socket", + __PRETTY_FUNCTION__); zclient_lookup_failed(zlookup); return -3; } - return zclient_read_nexthop(zlookup, nexthop_tab, tab_size, addr); + return zclient_read_nexthop(pim, zlookup, nexthop_tab, tab_size, addr); } -int zclient_lookup_nexthop(struct pim_zlookup_nexthop nexthop_tab[], +int zclient_lookup_nexthop(struct pim_instance *pim, + struct pim_zlookup_nexthop nexthop_tab[], const int tab_size, struct in_addr addr, int max_lookup) { @@ -353,17 +358,17 @@ int zclient_lookup_nexthop(struct pim_zlookup_nexthop nexthop_tab[], int first_ifindex; struct prefix nexthop_addr; - num_ifindex = zclient_lookup_nexthop_once(nexthop_tab, tab_size, - addr); + num_ifindex = zclient_lookup_nexthop_once(pim, nexthop_tab, + tab_size, addr); if (num_ifindex < 1) { - if (PIM_DEBUG_ZEBRA) { + if (PIM_DEBUG_PIM_NHT) { char addr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); zlog_debug( - "%s %s: lookup=%d/%d: could not find nexthop ifindex for address %s", - __FILE__, __PRETTY_FUNCTION__, lookup, - max_lookup, addr_str); + "%s: lookup=%d/%d: could not find nexthop ifindex for address %s(%s)", + __PRETTY_FUNCTION__, lookup, max_lookup, + addr_str, pim->vrf->name); } return -1; } @@ -393,16 +398,16 @@ int zclient_lookup_nexthop(struct pim_zlookup_nexthop nexthop_tab[], if (lookup > 0) { /* Report non-recursive success after first * lookup */ - if (PIM_DEBUG_ZEBRA) { + if (PIM_DEBUG_PIM_NHT) { char addr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); zlog_debug( - "%s %s: lookup=%d/%d: found non-recursive ifindex=%d for address %s dist=%d met=%d", - __FILE__, __PRETTY_FUNCTION__, - lookup, max_lookup, - first_ifindex, addr_str, + "%s: lookup=%d/%d: found non-recursive ifindex=%d for address %s(%s) dist=%d met=%d", + __PRETTY_FUNCTION__, lookup, + max_lookup, first_ifindex, + addr_str, pim->vrf->name, nexthop_tab[0] .protocol_distance, nexthop_tab[0].route_metric); @@ -420,7 +425,7 @@ int zclient_lookup_nexthop(struct pim_zlookup_nexthop nexthop_tab[], return num_ifindex; } - if (PIM_DEBUG_ZEBRA) { + if (PIM_DEBUG_PIM_NHT) { char addr_str[INET_ADDRSTRLEN]; char nexthop_str[PREFIX_STRLEN]; pim_inet4_dump("<addr?>", addr, addr_str, @@ -428,9 +433,9 @@ int zclient_lookup_nexthop(struct pim_zlookup_nexthop nexthop_tab[], pim_addr_dump("<nexthop?>", &nexthop_addr, nexthop_str, sizeof(nexthop_str)); zlog_debug( - "%s %s: lookup=%d/%d: zebra returned recursive nexthop %s for address %s dist=%d met=%d", - __FILE__, __PRETTY_FUNCTION__, lookup, - max_lookup, nexthop_str, addr_str, + "%s: lookup=%d/%d: zebra returned recursive nexthop %s for address %s(%s) dist=%d met=%d", + __PRETTY_FUNCTION__, lookup, max_lookup, + nexthop_str, addr_str, pim->vrf->name, nexthop_tab[0].protocol_distance, nexthop_tab[0].route_metric); } @@ -441,13 +446,13 @@ int zclient_lookup_nexthop(struct pim_zlookup_nexthop nexthop_tab[], } /* for (max_lookup) */ - if (PIM_DEBUG_ZEBRA) { + if (PIM_DEBUG_PIM_NHT) { char addr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); zlog_warn( - "%s %s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %s", - __FILE__, __PRETTY_FUNCTION__, lookup, max_lookup, - addr_str); + "%s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %s(%s)", + __PRETTY_FUNCTION__, lookup, max_lookup, addr_str, + pim->vrf->name); } return -2; @@ -472,7 +477,7 @@ int pim_zlookup_sg_statistics(struct channel_oil *c_oil) int count = 0; int ret; struct interface *ifp = - pim_if_find_by_vif_index(c_oil->oil.mfcc_parent); + pim_if_find_by_vif_index(c_oil->pim, c_oil->oil.mfcc_parent); if (PIM_DEBUG_ZEBRA) { struct prefix_sg more; @@ -480,15 +485,16 @@ int pim_zlookup_sg_statistics(struct channel_oil *c_oil) more.src = c_oil->oil.mfcc_origin; more.grp = c_oil->oil.mfcc_mcastgrp; zlog_debug( - "Sending Request for New Channel Oil Information(%s) VIIF %d", - pim_str_sg_dump(&more), c_oil->oil.mfcc_parent); + "Sending Request for New Channel Oil Information(%s) VIIF %d(%s)", + pim_str_sg_dump(&more), c_oil->oil.mfcc_parent, + c_oil->pim->vrf->name); } if (!ifp) return -1; stream_reset(s); - zclient_create_header(s, ZEBRA_IPMR_ROUTE_STATS, VRF_DEFAULT); + zclient_create_header(s, ZEBRA_IPMR_ROUTE_STATS, c_oil->pim->vrf_id); stream_put_in_addr(s, &c_oil->oil.mfcc_origin); stream_put_in_addr(s, &c_oil->oil.mfcc_mcastgrp); stream_putl(s, ifp->ifindex); @@ -498,8 +504,8 @@ int pim_zlookup_sg_statistics(struct channel_oil *c_oil) ret = writen(zlookup->sock, s->data, count); if (ret <= 0) { zlog_err( - "%s %s: writen() failure: %d writing to zclient lookup socket", - __FILE__, __PRETTY_FUNCTION__, errno); + "%s: writen() failure: %d writing to zclient lookup socket", + __PRETTY_FUNCTION__, errno); return -1; } @@ -516,8 +522,8 @@ int pim_zlookup_sg_statistics(struct channel_oil *c_oil) err = zclient_read_header(s, zlookup->sock, &length, &marker, &version, &vrf_id, &command); if (err < 0) { - zlog_err("%s %s: zclient_read_header() failed", - __FILE__, __PRETTY_FUNCTION__); + zlog_err("%s: zclient_read_header() failed", + __PRETTY_FUNCTION__); zclient_lookup_failed(zlookup); return -1; } @@ -527,18 +533,22 @@ int pim_zlookup_sg_statistics(struct channel_oil *c_oil) sg.grp.s_addr = stream_get_ipv4(s); if (sg.src.s_addr != c_oil->oil.mfcc_origin.s_addr || sg.grp.s_addr != c_oil->oil.mfcc_mcastgrp.s_addr) { - zlog_err("%s: Received wrong %s information", - __PRETTY_FUNCTION__, pim_str_sg_dump(&sg)); + if (PIM_DEBUG_ZEBRA) { + struct prefix_sg more; + + more.src = c_oil->oil.mfcc_origin; + more.grp = c_oil->oil.mfcc_mcastgrp; + zlog_err( + "%s: Received wrong %s(%s) information requested", + __PRETTY_FUNCTION__, pim_str_sg_dump(&more), + c_oil->pim->vrf->name); + } zclient_lookup_failed(zlookup); return -3; } stream_get(&lastused, s, sizeof(lastused)); - ret = stream_getl(s); - - if (PIM_DEBUG_ZEBRA) - zlog_debug("Received %lld for %s success: %d", lastused, - pim_str_sg_dump(&sg), ret); + stream_getl(s); c_oil->cc.lastused = lastused; diff --git a/pimd/pim_zlookup.h b/pimd/pim_zlookup.h index d168464ce5..f8a2d59f68 100644 --- a/pimd/pim_zlookup.h +++ b/pimd/pim_zlookup.h @@ -36,7 +36,8 @@ struct pim_zlookup_nexthop { void zclient_lookup_new(void); void zclient_lookup_free(void); -int zclient_lookup_nexthop(struct pim_zlookup_nexthop nexthop_tab[], +int zclient_lookup_nexthop(struct pim_instance *pim, + struct pim_zlookup_nexthop nexthop_tab[], const int tab_size, struct in_addr addr, int max_lookup); diff --git a/pimd/pimd.c b/pimd/pimd.c index 89b235bed1..9a8e92cbb2 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -31,19 +31,15 @@ #include "pimd.h" #include "pim_cmd.h" -#include "pim_iface.h" -#include "pim_zebra.h" #include "pim_str.h" #include "pim_oil.h" #include "pim_pim.h" -#include "pim_upstream.h" -#include "pim_rpf.h" #include "pim_ssmpingd.h" #include "pim_static.h" #include "pim_rp.h" #include "pim_ssm.h" #include "pim_zlookup.h" -#include "pim_nht.h" +#include "pim_zebra.h" const char *const PIM_ALL_SYSTEMS = MCAST_ALL_SYSTEMS; const char *const PIM_ALL_ROUTERS = MCAST_ALL_ROUTERS; @@ -52,8 +48,6 @@ const char *const PIM_ALL_IGMP_ROUTERS = MCAST_ALL_IGMP_ROUTERS; struct thread_master *master = NULL; uint32_t qpim_debugs = 0; -int qpim_mroute_socket_fd = -1; -int64_t qpim_mroute_socket_creation = 0; /* timestamp of creation */ int qpim_t_periodic = PIM_DEFAULT_T_PERIODIC; /* Period between Join/Prune Messages */ struct pim_assert_metric qpim_infinite_assert_metric; @@ -62,17 +56,8 @@ struct thread *qpim_rpf_cache_refresher = NULL; int64_t qpim_rpf_cache_refresh_requests = 0; int64_t qpim_rpf_cache_refresh_events = 0; int64_t qpim_rpf_cache_refresh_last = 0; -struct list *qpim_ssmpingd_list = NULL; -struct in_addr qpim_ssmpingd_group_addr; int64_t qpim_scan_oil_events = 0; int64_t qpim_scan_oil_last = 0; -int64_t qpim_mroute_add_events = 0; -int64_t qpim_mroute_add_last = 0; -int64_t qpim_mroute_del_events = 0; -int64_t qpim_mroute_del_last = 0; -struct list *qpim_static_route_list = NULL; -unsigned int qpim_keep_alive_time = PIM_KEEPALIVE_PERIOD; -signed int qpim_rp_keep_alive_time = 0; int64_t qpim_nexthop_lookups = 0; int qpim_packet_process = PIM_DEFAULT_PACKET_PROCESS; uint8_t qpim_ecmp_enable = 0; @@ -82,134 +67,25 @@ struct pim_instance *pimg = NULL; int32_t qpim_register_suppress_time = PIM_REGISTER_SUPPRESSION_TIME_DEFAULT; int32_t qpim_register_probe_time = PIM_REGISTER_PROBE_TIME_DEFAULT; -static struct pim_instance *pim_instance_init(vrf_id_t vrf_id, afi_t afi); -static void pim_instance_terminate(void); - -static int pim_vrf_new(struct vrf *vrf) -{ - zlog_debug("VRF Created: %s(%d)", vrf->name, vrf->vrf_id); - return 0; -} - -static int pim_vrf_delete(struct vrf *vrf) -{ - zlog_debug("VRF Deletion: %s(%d)", vrf->name, vrf->vrf_id); - return 0; -} - -static int pim_vrf_enable(struct vrf *vrf) -{ - - if (!vrf) // unexpected - return -1; - - if (vrf->vrf_id == VRF_DEFAULT) { - pimg = pim_instance_init(VRF_DEFAULT, AFI_IP); - if (pimg == NULL) { - zlog_err("%s %s: pim class init failure ", __FILE__, - __PRETTY_FUNCTION__); - /* - * We will crash and burn otherwise - */ - exit(1); - } - - pimg->send_v6_secondary = 1; - } - return 0; -} - -static int pim_vrf_disable(struct vrf *vrf) -{ - if (vrf->vrf_id == VRF_DEFAULT) - return 0; - - if (vrf->vrf_id == VRF_DEFAULT) - pim_instance_terminate(); - - /* Note: This is a callback, the VRF will be deleted by the caller. */ - return 0; -} - -void pim_vrf_init(void) -{ - vrf_init(pim_vrf_new, pim_vrf_enable, pim_vrf_disable, pim_vrf_delete); -} - -static void pim_vrf_terminate(void) -{ - vrf_terminate(); -} - -/* Key generate for pim->rpf_hash */ -static unsigned int pim_rpf_hash_key(void *arg) -{ - struct pim_nexthop_cache *r = (struct pim_nexthop_cache *)arg; - - return jhash_1word(r->rpf.rpf_addr.u.prefix4.s_addr, 0); -} - -/* Compare pim->rpf_hash node data */ -static int pim_rpf_equal(const void *arg1, const void *arg2) -{ - const struct pim_nexthop_cache *r1 = - (const struct pim_nexthop_cache *)arg1; - const struct pim_nexthop_cache *r2 = - (const struct pim_nexthop_cache *)arg2; - - return prefix_same(&r1->rpf.rpf_addr, &r2->rpf.rpf_addr); -} - -/* Cleanup pim->rpf_hash each node data */ -static void pim_rp_list_hash_clean(void *data) -{ - struct pim_nexthop_cache *pnc; - - pnc = (struct pim_nexthop_cache *)data; - if (pnc->rp_list->count) - list_delete_all_node(pnc->rp_list); - if (pnc->upstream_list->count) - list_delete_all_node(pnc->upstream_list); -} - void pim_prefix_list_update(struct prefix_list *plist) { - pim_rp_prefix_list_update(plist); - pim_ssm_prefix_list_update(plist); - pim_upstream_spt_prefix_list_update(plist); -} + struct pim_instance *pim; + struct vrf *vrf; -static void pim_instance_terminate(void) -{ - /* Traverse and cleanup rpf_hash */ - if (pimg->rpf_hash) { - hash_clean(pimg->rpf_hash, (void *)pim_rp_list_hash_clean); - hash_free(pimg->rpf_hash); - pimg->rpf_hash = NULL; - } + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) + { + pim = vrf->info; + if (!pim) + continue; - if (pimg->ssm_info) { - pim_ssm_terminate(pimg->ssm_info); - pimg->ssm_info = NULL; + pim_rp_prefix_list_update(pim, plist); + pim_ssm_prefix_list_update(pim, plist); + pim_upstream_spt_prefix_list_update(pim, plist); } - - XFREE(MTYPE_PIM_PIM_INSTANCE, pimg); } static void pim_free() { - pim_ssmpingd_destroy(); - - pim_oil_terminate(); - - pim_upstream_terminate(); - - if (qpim_static_route_list) - list_free(qpim_static_route_list); - - pim_if_terminate(); - pim_rp_free(); - pim_route_map_terminate(); zclient_lookup_free(); @@ -217,41 +93,8 @@ static void pim_free() zprivs_terminate(&pimd_privs); } -static struct pim_instance *pim_instance_init(vrf_id_t vrf_id, afi_t afi) -{ - struct pim_instance *pim; - - pim = XCALLOC(MTYPE_PIM_PIM_INSTANCE, sizeof(struct pim_instance)); - if (!pim) - return NULL; - - pim->vrf_id = vrf_id; - pim->afi = afi; - - pim->spt.switchover = PIM_SPT_IMMEDIATE; - pim->spt.plist = NULL; - - pim->rpf_hash = - hash_create_size(256, pim_rpf_hash_key, pim_rpf_equal, NULL); - - if (PIM_DEBUG_ZEBRA) - zlog_debug("%s: NHT rpf hash init ", __PRETTY_FUNCTION__); - - pim->ssm_info = pim_ssm_init(vrf_id); - if (!pim->ssm_info) { - pim_instance_terminate(); - return NULL; - } - - return pim; -} - void pim_init() { - qpim_rp_keep_alive_time = PIM_RP_KEEPALIVE_PERIOD; - - pim_rp_init(); - if (!inet_aton(PIM_ALL_PIM_ROUTERS, &qpim_all_pim_routers_addr)) { zlog_err( "%s %s: could not solve %s to group address: errno=%d: %s", @@ -261,21 +104,6 @@ void pim_init() return; } - pim_oil_init(); - - pim_upstream_init(); - - qpim_static_route_list = list_new(); - if (!qpim_static_route_list) { - zlog_err("%s %s: failure: static_route_list=list_new()", - __FILE__, __PRETTY_FUNCTION__); - return; - } - qpim_static_route_list->del = (void (*)(void *))pim_static_route_free; - - pim_mroute_socket_enable(); - - /* RFC 4601: 4.6.3. Assert Metrics @@ -290,9 +118,7 @@ void pim_init() qpim_infinite_assert_metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX; qpim_infinite_assert_metric.ip_address.s_addr = INADDR_ANY; - pim_if_init(); pim_cmd_init(); - pim_ssmpingd_init(); } void pim_terminate() diff --git a/pimd/pimd.h b/pimd/pimd.h index 7934bce2d4..ed51db3dee 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -27,6 +27,7 @@ #include "vty.h" #include "plist.h" +#include "pim_instance.h" #include "pim_str.h" #include "pim_memory.h" #include "pim_assert.h" @@ -106,6 +107,8 @@ #define PIM_MASK_MSDP_EVENTS (1 << 19) #define PIM_MASK_MSDP_PACKETS (1 << 20) #define PIM_MASK_MSDP_INTERNAL (1 << 21) +#define PIM_MASK_PIM_NHT (1 << 22) +#define PIM_MASK_PIM_NHT_DETAIL (1 << 23) /* PIM error codes */ #define PIM_SUCCESS 0 @@ -128,8 +131,6 @@ const char *const PIM_ALL_IGMP_ROUTERS; extern struct thread_master *master; extern struct zebra_privs_t pimd_privs; uint32_t qpim_debugs; -int qpim_mroute_socket_fd; -int64_t qpim_mroute_socket_creation; /* timestamp of creation */ struct in_addr qpim_all_pim_routers_addr; int qpim_t_periodic; /* Period between Join/Prune Messages */ struct pim_assert_metric qpim_infinite_assert_metric; @@ -138,18 +139,9 @@ struct thread *qpim_rpf_cache_refresher; int64_t qpim_rpf_cache_refresh_requests; int64_t qpim_rpf_cache_refresh_events; int64_t qpim_rpf_cache_refresh_last; -struct list *qpim_ssmpingd_list; /* list of struct ssmpingd_sock */ -struct in_addr qpim_ssmpingd_group_addr; int64_t qpim_scan_oil_events; int64_t qpim_scan_oil_last; -int64_t qpim_mroute_add_events; -int64_t qpim_mroute_add_last; -int64_t qpim_mroute_del_events; -int64_t qpim_mroute_del_last; int64_t qpim_nexthop_lookups; -struct list *qpim_static_route_list; /* list of routes added statically */ -extern unsigned int qpim_keep_alive_time; -extern signed int qpim_rp_keep_alive_time; extern int qpim_packet_process; extern uint8_t qpim_ecmp_enable; extern uint8_t qpim_ecmp_rebalance_enable; @@ -189,6 +181,8 @@ extern int32_t qpim_register_probe_time; #define PIM_DEBUG_MSDP_EVENTS (qpim_debugs & PIM_MASK_MSDP_EVENTS) #define PIM_DEBUG_MSDP_PACKETS (qpim_debugs & PIM_MASK_MSDP_PACKETS) #define PIM_DEBUG_MSDP_INTERNAL (qpim_debugs & PIM_MASK_MSDP_INTERNAL) +#define PIM_DEBUG_PIM_NHT (qpim_debugs & PIM_MASK_PIM_NHT) +#define PIM_DEBUG_PIM_NHT_DETAIL (qpim_debugs & PIM_MASK_PIM_NHT_DETAIL) #define PIM_DEBUG_EVENTS (qpim_debugs & (PIM_MASK_PIM_EVENTS | PIM_MASK_IGMP_EVENTS | PIM_MASK_MSDP_EVENTS)) #define PIM_DEBUG_PACKETS (qpim_debugs & (PIM_MASK_PIM_PACKETS | PIM_MASK_IGMP_PACKETS | PIM_MASK_MSDP_PACKETS)) @@ -199,6 +193,7 @@ extern int32_t qpim_register_probe_time; #define PIM_DO_DEBUG_PIM_PACKETDUMP_SEND (qpim_debugs |= PIM_MASK_PIM_PACKETDUMP_SEND) #define PIM_DO_DEBUG_PIM_PACKETDUMP_RECV (qpim_debugs |= PIM_MASK_PIM_PACKETDUMP_RECV) #define PIM_DO_DEBUG_PIM_TRACE (qpim_debugs |= PIM_MASK_PIM_TRACE) +#define PIM_DO_DEBUG_PIM_TRACE_DETAIL (qpim_debugs |= PIM_MASK_PIM_TRACE_DETAIL) #define PIM_DO_DEBUG_IGMP_EVENTS (qpim_debugs |= PIM_MASK_IGMP_EVENTS) #define PIM_DO_DEBUG_IGMP_PACKETS (qpim_debugs |= PIM_MASK_IGMP_PACKETS) #define PIM_DO_DEBUG_IGMP_TRACE (qpim_debugs |= PIM_MASK_IGMP_TRACE) @@ -214,12 +209,14 @@ extern int32_t qpim_register_probe_time; #define PIM_DO_DEBUG_MSDP_EVENTS (qpim_debugs |= PIM_MASK_MSDP_EVENTS) #define PIM_DO_DEBUG_MSDP_PACKETS (qpim_debugs |= PIM_MASK_MSDP_PACKETS) #define PIM_DO_DEBUG_MSDP_INTERNAL (qpim_debugs |= PIM_MASK_MSDP_INTERNAL) +#define PIM_DO_DEBUG_PIM_NHT (qpim_debugs |= PIM_MASK_PIM_NHT) #define PIM_DONT_DEBUG_PIM_EVENTS (qpim_debugs &= ~PIM_MASK_PIM_EVENTS) #define PIM_DONT_DEBUG_PIM_PACKETS (qpim_debugs &= ~PIM_MASK_PIM_PACKETS) #define PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND (qpim_debugs &= ~PIM_MASK_PIM_PACKETDUMP_SEND) #define PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV (qpim_debugs &= ~PIM_MASK_PIM_PACKETDUMP_RECV) #define PIM_DONT_DEBUG_PIM_TRACE (qpim_debugs &= ~PIM_MASK_PIM_TRACE) +#define PIM_DONT_DEBUG_PIM_TRACE_DETAIL (qpim_debugs &= ~PIM_MASK_PIM_TRACE_DETAIL) #define PIM_DONT_DEBUG_IGMP_EVENTS (qpim_debugs &= ~PIM_MASK_IGMP_EVENTS) #define PIM_DONT_DEBUG_IGMP_PACKETS (qpim_debugs &= ~PIM_MASK_IGMP_PACKETS) #define PIM_DONT_DEBUG_IGMP_TRACE (qpim_debugs &= ~PIM_MASK_IGMP_TRACE) @@ -235,37 +232,13 @@ extern int32_t qpim_register_probe_time; #define PIM_DONT_DEBUG_MSDP_EVENTS (qpim_debugs &= ~PIM_MASK_MSDP_EVENTS) #define PIM_DONT_DEBUG_MSDP_PACKETS (qpim_debugs &= ~PIM_MASK_MSDP_PACKETS) #define PIM_DONT_DEBUG_MSDP_INTERNAL (qpim_debugs &= ~PIM_MASK_MSDP_INTERNAL) - -enum pim_spt_switchover { - PIM_SPT_IMMEDIATE, - PIM_SPT_INFINITY, -}; - -/* Per VRF PIM DB */ -struct pim_instance { - afi_t afi; - vrf_id_t vrf_id; - - struct { - enum pim_spt_switchover switchover; - char *plist; - } spt; - - struct hash *rpf_hash; - - void *ssm_info; /* per-vrf SSM configuration */ - - int send_v6_secondary; -}; - -extern struct pim_instance *pimg; // Pim Global Instance +#define PIM_DONT_DEBUG_PIM_NHT (qpim_debugs &= ~PIM_MASK_PIM_NHT) void pim_init(void); void pim_terminate(void); extern void pim_route_map_init(void); extern void pim_route_map_terminate(void); -void pim_vrf_init(void); void pim_prefix_list_update(struct prefix_list *plist); #endif /* PIMD_H */ diff --git a/pimd/test_igmpv3_join.c b/pimd/test_igmpv3_join.c index 14ec9fb02b..3d104e7c7c 100644 --- a/pimd/test_igmpv3_join.c +++ b/pimd/test_igmpv3_join.c @@ -138,7 +138,8 @@ int main(int argc, const char *argv[]) printf("%s: waiting...\n", prog_name); - getchar(); + if (getchar() == EOF) + fprintf(stderr, "getchar failure\n"); close(fd); diff --git a/pkgsrc/Makefile.am b/pkgsrc/Makefile.am deleted file mode 100644 index 622fbf0748..0000000000 --- a/pkgsrc/Makefile.am +++ /dev/null @@ -1,3 +0,0 @@ -rcdir=@pkgsrcrcdir@ - -rc_SCRIPTS = bgpd.sh ospf6d.sh ospfd.sh ripd.sh ripngd.sh zebra.sh diff --git a/python/Makefile.am b/python/Makefile.am deleted file mode 100644 index 4ad1e36b59..0000000000 --- a/python/Makefile.am +++ /dev/null @@ -1,3 +0,0 @@ -EXTRA_DIST = \ - clidef.py \ - clippy/__init__.py diff --git a/qpb/.gitignore b/qpb/.gitignore index b133c52a42..17e90443e9 100644 --- a/qpb/.gitignore +++ b/qpb/.gitignore @@ -1,4 +1,4 @@ -Makefile +!Makefile Makefile.in *.o tags diff --git a/qpb/Makefile b/qpb/Makefile new file mode 100644 index 0000000000..2237def02c --- /dev/null +++ b/qpb/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. fpm/libfrr_pb.la +%: ALWAYS + @$(MAKE) -s -C .. fpm/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/qpb/Makefile.am b/qpb/Makefile.am deleted file mode 100644 index e5951b2be9..0000000000 --- a/qpb/Makefile.am +++ /dev/null @@ -1,30 +0,0 @@ -include ../common.am - -AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib $(Q_PROTOBUF_C_CLIENT_INCLUDES) - -PROTOBUF_INCLUDES=-I$(top_srcdir) -PROTOBUF_PACKAGE = qpb - -lib_LTLIBRARIES = libfrr_pb.la -libfrr_pb_la_LDFLAGS = -version-info 0:0:0 - -if HAVE_PROTOBUF -protobuf_srcs = \ - qpb_allocator.c - -protobuf_srcs_nodist = \ - qpb.pb-c.c -endif - -libfrr_pb_la_SOURCES = \ - linear_allocator.h \ - qpb.h \ - qpb.c \ - qpb_allocator.h \ - $(protobuf_srcs) - -nodist_libfrr_pb_la_SOURCES = $(protobuf_srcs_nodist) - -CLEANFILES = $(Q_CLEANFILES) -BUILT_SOURCES = $(Q_PROTOBUF_SRCS) -EXTRA_DIST = qpb.proto diff --git a/qpb/qpb.proto b/qpb/qpb.proto index a1595a9abd..c06debb954 100644 --- a/qpb/qpb.proto +++ b/qpb/qpb.proto @@ -20,6 +20,8 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +syntax = "proto2"; + /* * Protobuf definitions pertaining to the Quagga/FRR Protobuf component. */ @@ -87,4 +89,4 @@ enum Protocol { ISIS = 8; BGP = 9; OTHER = 10; -}
\ No newline at end of file +} diff --git a/qpb/qpb_allocator.c b/qpb/qpb_allocator.c index 8b0ee941a5..7e5ba5b0ce 100644 --- a/qpb/qpb_allocator.c +++ b/qpb/qpb_allocator.c @@ -42,8 +42,7 @@ static void _qpb_free(void *allocator_data, void *ptr) linear_allocator_free(allocator_data, ptr); } -static ProtobufCAllocator allocator_template = {_qpb_alloc, _qpb_free, NULL, - 8192, NULL}; +static ProtobufCAllocator allocator_template = {_qpb_alloc, _qpb_free, NULL}; /* * qpb_allocator_init_linear diff --git a/qpb/subdir.am b/qpb/subdir.am new file mode 100644 index 0000000000..71e501b9c2 --- /dev/null +++ b/qpb/subdir.am @@ -0,0 +1,26 @@ +if HAVE_PROTOBUF +lib_LTLIBRARIES += qpb/libfrr_pb.la +endif + +qpb_libfrr_pb_la_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir) -I$(top_builddir)/lib \ + $(Q_PROTOBUF_C_CLIENT_INCLUDES) +qpb_libfrr_pb_la_LDFLAGS = -version-info 0:0:0 + +qpb_libfrr_pb_la_SOURCES = \ + qpb/linear_allocator.h \ + qpb/qpb.h \ + qpb/qpb.c \ + qpb/qpb_allocator.h \ + # end + +if HAVE_PROTOBUF +qpb_libfrr_pb_la_SOURCES += qpb/qpb_allocator.c +nodist_qpb_libfrr_pb_la_SOURCES = qpb/qpb.pb-c.c +BUILT_SOURCES += qpb/qpb.pb-c.c +CLEANFILES += \ + qpb/qpb.pb-c.c \ + qpb/qpb.pb-c.h \ + # end +endif + +EXTRA_DIST += qpb/qpb.proto diff --git a/redhat/Makefile.am b/redhat/Makefile.am deleted file mode 100644 index 74856cfd82..0000000000 --- a/redhat/Makefile.am +++ /dev/null @@ -1,5 +0,0 @@ - -EXTRA_DIST = frr.init frr.service daemons \ - frr.logrotate frr.pam frr.spec \ - README.rpm_build.md - diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index 674ccb2d6f..b23249e04e 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -168,7 +168,8 @@ Requires(pre): initscripts >= 5.60 %endif Provides: routingdaemon = %{version}-%{release} BuildRoot: %{_tmppath}/%{name}-%{version}-root -Obsoletes: bird gated mrt zebra frr-sysvinit +Obsoletes: gated mrt zebra frr-sysvinit +Conflicts: bird %description FRRouting is a free software that manages TCP/IP based routing diff --git a/ripd/rip_peer.c b/ripd/rip_peer.c index 763bfc142c..0a6337bf76 100644 --- a/ripd/rip_peer.c +++ b/ripd/rip_peer.c @@ -143,10 +143,6 @@ static char *rip_peer_uptime(struct rip_peer *peer, char *buf, size_t len) uptime -= peer->uptime; tm = gmtime(&uptime); -/* Making formatted timer strings. */ -#define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND 60*60*24*7 - if (uptime < ONE_DAY_SECOND) snprintf(buf, len, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); diff --git a/ripngd/ripng_peer.c b/ripngd/ripng_peer.c index 2a412f9b64..cd46d97402 100644 --- a/ripngd/ripng_peer.c +++ b/ripngd/ripng_peer.c @@ -151,10 +151,6 @@ static char *ripng_peer_uptime(struct ripng_peer *peer, char *buf, size_t len) uptime -= peer->uptime; tm = gmtime(&uptime); -/* Making formatted timer strings. */ -#define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND 60*60*24*7 - if (uptime < ONE_DAY_SECOND) snprintf(buf, len, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); diff --git a/snapcraft/Makefile.am b/snapcraft/Makefile.am deleted file mode 100644 index a8220670d1..0000000000 --- a/snapcraft/Makefile.am +++ /dev/null @@ -1,8 +0,0 @@ -EXTRA_DIST = snapcraft.yaml \ - README.snap_build.md \ - README.usage.md \ - extra_version_info.txt \ - scripts \ - defaults \ - helpers \ - snap diff --git a/tests/.gitignore b/tests/.gitignore index 6d54ae155b..113bdea098 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -25,6 +25,8 @@ __pycache__ /bgpd/test_ecommunity /bgpd/test_mp_attr /bgpd/test_mpath +/isisd/test_fuzz_isis_tlv +/isisd/test_fuzz_isis_tlv_tests.h /lib/cli/test_cli /lib/cli/test_commands /lib/cli/test_commands_defun.c diff --git a/tests/Makefile.am b/tests/Makefile.am index 43003e7075..0c31c0441a 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -24,6 +24,13 @@ else TESTS_BGPD = endif +if ISISD +TESTS_ISISD = \ + isisd/test_fuzz_isis_tlv +else +TESTS_ISISD = +endif + if OSPF6D TESTS_OSPF6D = \ ospf6d/test_lsdb \ @@ -61,6 +68,7 @@ check_PROGRAMS = \ lib/cli/test_cli \ lib/cli/test_commands \ $(TESTS_BGPD) \ + $(TESTS_ISISD) \ $(TESTS_OSPF6D) \ # end @@ -75,7 +83,12 @@ lib/cli/test_commands_defun.c: ../vtysh/vtysh_cmd.c < ../vtysh/vtysh_cmd.c \ > "$@" -BUILT_SOURCES = lib/cli/test_commands_defun.c +isisd/test_fuzz_isis_tlv_tests.h: $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz + gzip -d < $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz > "$@" + +BUILT_SOURCES = \ + lib/cli/test_commands_defun.c \ + isisd/test_fuzz_isis_tlv_tests.h noinst_HEADERS = \ ./helpers/c/prng.h \ @@ -110,11 +123,14 @@ bgpd_test_capability_SOURCES = bgpd/test_capability.c bgpd_test_ecommunity_SOURCES = bgpd/test_ecommunity.c bgpd_test_mp_attr_SOURCES = bgpd/test_mp_attr.c bgpd_test_mpath_SOURCES = bgpd/test_mpath.c +isisd_test_fuzz_isis_tlv_SOURCES = isisd/test_fuzz_isis_tlv.c +isisd_test_fuzz_isis_tlv_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_builddir)/tests/isisd ospf6d_test_lsdb_SOURCES = ospf6d/test_lsdb.c lib/cli/common_cli.c ALL_TESTS_LDADD = ../lib/libfrr.la @LIBCAP@ BGP_TEST_LDADD = ../bgpd/libbgp.a $(BGP_VNC_RFP_LIB) $(ALL_TESTS_LDADD) -lm +ISISD_TEST_LDADD = ../isisd/libisis.a $(ALL_TESTS_LDADD) OSPF6_TEST_LDADD = ../ospf6d/libospf6.a $(ALL_TESTS_LDADD) lib_test_buffer_LDADD = $(ALL_TESTS_LDADD) @@ -140,6 +156,7 @@ bgpd_test_capability_LDADD = $(BGP_TEST_LDADD) bgpd_test_ecommunity_LDADD = $(BGP_TEST_LDADD) bgpd_test_mp_attr_LDADD = $(BGP_TEST_LDADD) bgpd_test_mpath_LDADD = $(BGP_TEST_LDADD) +isisd_test_fuzz_isis_tlv_LDADD = $(ISISD_TEST_LDADD) ospf6d_test_lsdb_LDADD = $(OSPF6_TEST_LDADD) EXTRA_DIST = \ @@ -151,6 +168,8 @@ EXTRA_DIST = \ bgpd/test_mpath.py \ helpers/python/frrsix.py \ helpers/python/frrtest.py \ + isisd/test_fuzz_isis_tlv.py \ + isisd/test_fuzz_isis_tlv_tests.h.gz \ lib/cli/test_commands.in \ lib/cli/test_commands.py \ lib/cli/test_commands.refout \ diff --git a/tests/bgpd/test_capability.c b/tests/bgpd/test_capability.c index 9ec2b5df19..e8700a8b4a 100644 --- a/tests/bgpd/test_capability.c +++ b/tests/bgpd/test_capability.c @@ -170,7 +170,7 @@ static struct test_segment mp_segments[] = { /* 8 */ { "MP6", - "MP IP4/MPLS-laveled VPN", + "MP IP4/MPLS-labeled VPN", {CAPABILITY_CODE_MP, 0x4, 0x0, 0x1, 0x0, 0x80}, 6, SHOULD_PARSE, diff --git a/tests/bgpd/test_capability.py b/tests/bgpd/test_capability.py index 4cb650092b..872fcb6d12 100644 --- a/tests/bgpd/test_capability.py +++ b/tests/bgpd/test_capability.py @@ -8,7 +8,7 @@ TestCapability.okfail("MPv6: MP IPv6/Uni") TestCapability.okfail("MP2: MP IP/Multicast") TestCapability.okfail("MP3: MP IP6/MPLS-labeled VPN") TestCapability.okfail("MP5: MP IP6/MPLS-VPN") -TestCapability.okfail("MP6: MP IP4/MPLS-laveled VPN") +TestCapability.okfail("MP6: MP IP4/MPLS-labeled VPN") TestCapability.okfail("MP8: MP unknown AFI/SAFI") TestCapability.okfail("MP-short: MP IP4/Unicast, length too short (< minimum)") TestCapability.okfail("MP-overflow: MP IP4/Unicast, length too long") diff --git a/tests/bgpd/test_mp_attr.c b/tests/bgpd/test_mp_attr.c index 7c0afa1b92..30d5fdd6cd 100644 --- a/tests/bgpd/test_mp_attr.c +++ b/tests/bgpd/test_mp_attr.c @@ -1059,7 +1059,7 @@ static void parse_test(struct peer *peer, struct test_segment *t, int type) parse_ret = bgp_mp_unreach_parse(&attr_args, &nlri); if (!parse_ret) { iana_afi_t pkt_afi; - safi_t pkt_safi; + iana_safi_t pkt_safi; /* Convert AFI, SAFI to internal values, check. */ if (bgp_map_afi_safi_int2iana(nlri.afi, nlri.safi, &pkt_afi, diff --git a/tests/isisd/.gitignore b/tests/isisd/.gitignore new file mode 100644 index 0000000000..e124221296 --- /dev/null +++ b/tests/isisd/.gitignore @@ -0,0 +1 @@ +/*_afl/* diff --git a/tests/isisd/test_fuzz_isis_tlv.c b/tests/isisd/test_fuzz_isis_tlv.c new file mode 100644 index 0000000000..6727e663f5 --- /dev/null +++ b/tests/isisd/test_fuzz_isis_tlv.c @@ -0,0 +1,188 @@ +#include "test_fuzz_isis_tlv_tests.h" + +#include <zebra.h> + +#include "memory.h" +#include "sbuf.h" +#include "stream.h" +#include "thread.h" + +#include "isisd/isis_circuit.h" +#include "isisd/isis_tlvs.h" + +#define TEST_STREAM_SIZE 1500 + +struct thread_master *master; +int isis_sock_init(struct isis_circuit *circuit); +int isis_sock_init(struct isis_circuit *circuit) +{ + return 0; +} + +static bool atexit_registered; + +static void show_meminfo_at_exit(void) +{ + log_memstats_stderr("isis fuzztest"); +} + +static int comp_line(const void *p1, const void *p2) +{ + return strcmp(*(char * const *)p1, *(char * const *)p2); +} + +static char *sortlines(char *in) +{ + size_t line_count = 1; + size_t rv_len = strlen(in) + 1; + size_t rv_pos = 0; + char *rv = XMALLOC(MTYPE_TMP, rv_len); + + for (char *c = in; *c; c++) { + if (*c == '\n') + line_count++; + } + + if (line_count == 1) { + strncpy(rv, in, rv_len); + return rv; + } + + char **lines = XCALLOC(MTYPE_TMP, sizeof(char *)*line_count); + char *saveptr = NULL; + size_t i = 0; + + for (char *line = strtok_r(in, "\n", &saveptr); line; + line = strtok_r(NULL, "\n", &saveptr)) { + lines[i++] = line; + assert(i <= line_count); + } + + line_count = i; + + qsort(lines, line_count, sizeof(char *), comp_line); + + for (i = 0; i < line_count; i++) { + int printf_rv = snprintf(rv + rv_pos, rv_len - rv_pos, "%s\n", lines[i]); + assert(printf_rv >= 0); + rv_pos += printf_rv; + } + + XFREE(MTYPE_TMP, lines); + return rv; +} + +static int test(FILE *input, FILE *output) +{ + struct stream *s = stream_new(TEST_STREAM_SIZE); + char buf[TEST_STREAM_SIZE]; + size_t bytes_read = 0; + + if (!atexit_registered) { + atexit(show_meminfo_at_exit); + atexit_registered = true; + } + + while (STREAM_WRITEABLE(s) && !feof(input)) { + bytes_read = fread(buf, 1, STREAM_WRITEABLE(s), input); + if (bytes_read == 0) + break; + stream_put(s, buf, bytes_read); + } + + if (bytes_read && !feof(input)) { + fprintf(output, "Too much input data.\n"); + stream_free(s); + return 1; + } + + stream_set_getp(s, 0); + struct isis_tlvs *tlvs; + const char *log; + int rv = isis_unpack_tlvs(STREAM_READABLE(s), s, &tlvs, &log); + + if (rv) { + fprintf(output, "Could not unpack TLVs:\n%s\n", log); + isis_free_tlvs(tlvs); + stream_free(s); + return 2; + } + + fprintf(output, "Unpack log:\n%s", log); + const char *s_tlvs = isis_format_tlvs(tlvs); + fprintf(output, "Unpacked TLVs:\n%s", s_tlvs); + + struct isis_tlvs *tlv_copy = isis_copy_tlvs(tlvs); + isis_free_tlvs(tlvs); + + struct stream *s2 = stream_new(TEST_STREAM_SIZE); + + if (isis_pack_tlvs(tlv_copy, s2, (size_t)-1, false, false)) { + fprintf(output, "Could not pack TLVs.\n"); + assert(0); + } + + stream_set_getp(s2, 0); + rv = isis_unpack_tlvs(STREAM_READABLE(s2), s2, &tlvs, &log); + if (rv) { + fprintf(output, "Could not unpack own TLVs:\n%s\n", log); + assert(0); + } + + char *orig_tlvs = XSTRDUP(MTYPE_TMP, s_tlvs); + s_tlvs = isis_format_tlvs(tlvs); + + if (strcmp(orig_tlvs, s_tlvs)) { + fprintf(output, + "Deserialized and Serialized LSP seem to differ.\n"); + fprintf(output, "Re-Unpacked TLVs:\n%s", s_tlvs); + assert(0); + } + + isis_free_tlvs(tlv_copy); + stream_free(s); + stream_free(s2); + + struct list *fragments = isis_fragment_tlvs(tlvs, 550); + isis_free_tlvs(tlvs); + if (!fragments) { + XFREE(MTYPE_TMP, orig_tlvs); + return 0; + } + + s = stream_new(550); + + struct sbuf fragment_format; + sbuf_init(&fragment_format, NULL, 0); + + struct listnode *node; + for (ALL_LIST_ELEMENTS_RO(fragments, node, tlvs)) { + stream_reset(s); + int rv = isis_pack_tlvs(tlvs, s, (size_t)-1, false, false); + if (rv) { + fprintf(output, "Could not pack fragment, too large.\n"); + assert(0); + } + sbuf_push(&fragment_format, 0, "%s", isis_format_tlvs(tlvs)); + isis_free_tlvs(tlvs); + } + list_delete(fragments); + stream_free(s); + + char *fragment_content = sortlines((char *)sbuf_buf(&fragment_format)); + sbuf_free(&fragment_format); + char *orig_tlv_content = sortlines(orig_tlvs); + XFREE(MTYPE_TMP, orig_tlvs); + + if (strcmp(fragment_content, orig_tlv_content)) { + fprintf(output, "Fragmented and unfragmented LSP seem to differ.\n"); + fprintf(output, "Original:\n%s\nFragmented:\n%s\n", + orig_tlv_content, fragment_content); + assert(0); + } + + XFREE(MTYPE_TMP, fragment_content); + XFREE(MTYPE_TMP, orig_tlv_content); + + return 0; +} diff --git a/tests/isisd/test_fuzz_isis_tlv.py b/tests/isisd/test_fuzz_isis_tlv.py new file mode 100644 index 0000000000..60938472b5 --- /dev/null +++ b/tests/isisd/test_fuzz_isis_tlv.py @@ -0,0 +1,6 @@ +import frrtest + +class TestFuzzIsisTLV(frrtest.TestMultiOut): + program = './test_fuzz_isis_tlv' + +TestFuzzIsisTLV.exit_cleanly() diff --git a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz Binary files differnew file mode 100644 index 0000000000..3eb0205a5d --- /dev/null +++ b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index 8b66ba2564..d179ed1d99 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -147,6 +147,7 @@ vtysh_cmd_FILES = $(vtysh_scan) \ $(top_srcdir)/zebra/zebra_fpm.c \ $(top_srcdir)/zebra/zebra_ptm.c \ $(top_srcdir)/zebra/zebra_mpls_vty.c \ + $(top_srcdir)/zebra/zebra_pw.c \ $(top_srcdir)/watchfrr/watchfrr_vty.c \ $(BGP_VNC_RFAPI_SRC) $(BGP_VNC_RFP_SRC) diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index ca280c5872..f33c7b9603 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -85,7 +85,7 @@ foreach (@ARGV) { $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_EIGRPD"; } elsif ($file =~ /lib\/vrf\.c$/) { - $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_EIGRPD|VTYSH_BABELD"; + $protocol = "VTYSH_ALL"; } elsif ($file =~ /lib\/filter\.c$/) { $protocol = "VTYSH_ALL"; diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index f6a2c92586..76c42173da 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -218,15 +218,27 @@ static int vtysh_client_run_all(struct vtysh_client *head_client, { struct vtysh_client *client; int rc, rc_all = CMD_SUCCESS; + int correct_instance = 0, wrong_instance = 0; for (client = head_client; client; client = client->next) { rc = vtysh_client_run(client, line, fp, callback, cbarg); + if (rc == CMD_NOT_MY_INSTANCE) { + wrong_instance++; + continue; + } + correct_instance++; if (rc != CMD_SUCCESS) { if (!continue_on_err) return rc; rc_all = rc; } } + if (wrong_instance && !correct_instance && fp) { + fprintf(fp, + "%% [%s]: command ignored as it targets an instance that is not running\n", + head_client->name); + rc_all = CMD_WARNING_CONFIG_FAILED; + } return rc_all; } @@ -911,6 +923,10 @@ static struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", }; +static struct cmd_node pw_node = { + PW_NODE, "%s(config-pw)# ", +}; + static struct cmd_node ns_node = { NS_NODE, "%s(config-logical-router)# ", }; @@ -1406,6 +1422,7 @@ static int vtysh_exit(struct vty *vty) vty->node = ENABLE_NODE; break; case INTERFACE_NODE: + case PW_NODE: case NS_NODE: case VRF_NODE: case ZEBRA_NODE: @@ -1659,6 +1676,15 @@ DEFUNSH(VTYSH_INTERFACE, vtysh_interface, vtysh_interface_cmd, return CMD_SUCCESS; } +DEFUNSH(VTYSH_ZEBRA, vtysh_pseudowire, vtysh_pseudowire_cmd, + "pseudowire IFNAME", + "Static pseudowire configuration\n" + "Pseudowire name\n") +{ + vty->node = PW_NODE; + return CMD_SUCCESS; +} + /* TODO Implement "no interface command in isisd. */ DEFSH(VTYSH_ZEBRA | VTYSH_RIPD | VTYSH_RIPNGD | VTYSH_OSPFD | VTYSH_OSPF6D | VTYSH_EIGRPD, @@ -2909,6 +2935,7 @@ void vtysh_init_vty(void) install_node(&bgp_node, NULL); install_node(&rip_node, NULL); install_node(&interface_node, NULL); + install_node(&pw_node, NULL); install_node(&link_params_node, NULL); install_node(&ns_node, NULL); install_node(&vrf_node, NULL); @@ -3081,6 +3108,10 @@ void vtysh_init_vty(void) install_element(LINK_PARAMS_NODE, &vtysh_exit_interface_cmd); install_element(INTERFACE_NODE, &vtysh_quit_interface_cmd); + install_element(PW_NODE, &vtysh_end_all_cmd); + install_element(PW_NODE, &vtysh_exit_interface_cmd); + install_element(PW_NODE, &vtysh_quit_interface_cmd); + install_element(NS_NODE, &vtysh_end_all_cmd); install_element(CONFIG_NODE, &vtysh_ns_cmd); @@ -3156,6 +3187,7 @@ void vtysh_init_vty(void) install_element(CONFIG_NODE, &vtysh_interface_cmd); install_element(CONFIG_NODE, &vtysh_no_interface_cmd); install_element(CONFIG_NODE, &vtysh_no_interface_vrf_cmd); + install_element(CONFIG_NODE, &vtysh_pseudowire_cmd); install_element(INTERFACE_NODE, &vtysh_link_params_cmd); install_element(ENABLE_NODE, &vtysh_show_running_config_cmd); install_element(ENABLE_NODE, &vtysh_copy_running_config_cmd); diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index bef4b82d3f..b0866ec7f3 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -47,7 +47,7 @@ DECLARE_MGROUP(MVTYSH) #define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_PIMD|VTYSH_EIGRPD #define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD #define VTYSH_NS VTYSH_ZEBRA -#define VTYSH_VRF VTYSH_ZEBRA +#define VTYSH_VRF VTYSH_ZEBRA|VTYSH_PIMD /* vtysh local configuration file. */ #define VTYSH_DEFAULT_CONFIG "vtysh.conf" diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 74509d1ec8..43aff0e3a5 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -181,6 +181,8 @@ void vtysh_config_parse_line(void *arg, const char *line) default: if (strncmp(line, "interface", strlen("interface")) == 0) config = config_get(INTERFACE_NODE, line); + else if (strncmp(line, "pseudowire", strlen("pseudowire")) == 0) + config = config_get(PW_NODE, line); else if (strncmp(line, "logical-router", strlen("ns")) == 0) config = config_get(NS_NODE, line); else if (strncmp(line, "vrf", strlen("vrf")) == 0) diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c index 1aa25b41d0..6adb25f322 100644 --- a/watchfrr/watchfrr.c +++ b/watchfrr/watchfrr.c @@ -684,9 +684,11 @@ static void daemon_send_ready(void) fp = fopen(DAEMON_VTY_DIR "/watchfrr.started", "w"); fclose(fp); +#if defined HAVE_SYSTEMD zlog_notice( "Watchfrr: Notifying Systemd we are up and running"); systemd_send_started(master, 0); +#endif sent = 1; } } diff --git a/zebra/.gitignore b/zebra/.gitignore index d0a7528539..7a1321e546 100644 --- a/zebra/.gitignore +++ b/zebra/.gitignore @@ -1,4 +1,4 @@ -Makefile +!Makefile Makefile.in *.o zebra diff --git a/zebra/Makefile b/zebra/Makefile new file mode 100644 index 0000000000..625a7168eb --- /dev/null +++ b/zebra/Makefile @@ -0,0 +1,10 @@ +all: ALWAYS + @$(MAKE) -s -C .. zebra/zebra +%: ALWAYS + @$(MAKE) -s -C .. zebra/$@ + +Makefile: + #nothing +ALWAYS: +.PHONY: ALWAYS makefiles +.SUFFIXES: diff --git a/zebra/Makefile.am b/zebra/Makefile.am deleted file mode 100644 index 67031ea361..0000000000 --- a/zebra/Makefile.am +++ /dev/null @@ -1,96 +0,0 @@ -include ../common.am - -## Process this file with automake to produce Makefile.in. - -AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib -DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -INSTALL_SDATA=@INSTALL@ -m 600 - -LIBCAP = @LIBCAP@ - -ipforward = @IPFORWARD@ -if_method = @IF_METHOD@ -rt_method = @RT_METHOD@ -rtread_method = @RTREAD_METHOD@ -kernel_method = @KERNEL_METHOD@ -ioctl_method = @IOCTL_METHOD@ -mpls_method = @MPLS_METHOD@ - -otherobj = $(ioctl_method) $(ipforward) $(if_method) \ - $(rt_method) $(rtread_method) $(kernel_method) $(mpls_method) - -AM_CFLAGS = $(WERROR) - -sbin_PROGRAMS = zebra -module_LTLIBRARIES = - -zebra_SOURCES = \ - zebra_memory.c \ - zserv.c main.c interface.c connected.c zebra_rib.c zebra_routemap.c \ - redistribute.c debug.c rtadv.c zebra_vty.c \ - irdp_main.c irdp_interface.c irdp_packet.c router-id.c \ - zebra_ptm.c zebra_rnh.c zebra_ptm_redistribute.c \ - zebra_ns.c zebra_vrf.c zebra_static.c zebra_mpls.c zebra_mpls_vty.c \ - zebra_mroute.c \ - label_manager.c \ - zebra_l2.c \ - zebra_vxlan.c \ - # end - -zebra_vty.o: zebra_vty_clippy.c - -noinst_HEADERS = \ - zebra_memory.h \ - connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \ - interface.h ipforward.h irdp.h router-id.h kernel_socket.h \ - rt_netlink.h zebra_fpm_private.h zebra_rnh.h \ - zebra_ptm_redistribute.h zebra_ptm.h zebra_routemap.h \ - zebra_ns.h zebra_vrf.h ioctl_solaris.h zebra_static.h zebra_mpls.h \ - kernel_netlink.h if_netlink.h zebra_mroute.h label_manager.h \ - zebra_l2.h zebra_vxlan_private.h zebra_vxlan.h - -zebra_LDADD = $(otherobj) ../lib/libfrr.la $(LIBCAP) - -zebra_DEPENDENCIES = $(otherobj) - -if SNMP -module_LTLIBRARIES += zebra_snmp.la -endif -zebra_snmp_la_SOURCES = zebra_snmp.c -zebra_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -zebra_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic -zebra_snmp_la_LIBADD = ../lib/libfrrsnmp.la - -if FPM -module_LTLIBRARIES += zebra_fpm.la -endif -zebra_fpm_la_LDFLAGS = -avoid-version -module -shared -export-dynamic -zebra_fpm_la_LIBADD = $(Q_FPM_PB_CLIENT_LDOPTS) -zebra_fpm_la_SOURCES = zebra_fpm.c -if HAVE_NETLINK -zebra_fpm_la_SOURCES += zebra_fpm_netlink.c -endif -if HAVE_PROTOBUF -zebra_fpm_la_SOURCES += zebra_fpm_protobuf.c -if DEV_BUILD -zebra_fpm_la_SOURCES += zebra_fpm_dt.c -endif -endif - - -EXTRA_DIST = if_ioctl.c if_ioctl_solaris.c if_netlink.c \ - if_sysctl.c ipforward_proc.c \ - ipforward_solaris.c ipforward_sysctl.c rt_netlink.c \ - rt_socket.c rtread_netlink.c rtread_sysctl.c \ - rtread_getmsg.c kernel_socket.c kernel_netlink.c \ - ioctl.c ioctl_solaris.c \ - zebra_mpls_netlink.c zebra_mpls_openbsd.c zebra_mpls_null.c \ - GNOME-SMI GNOME-PRODUCT-ZEBRA-MIB - -client : client_main.o ../lib/libfrr.la - $(CC) -g -o client client_main.o ../liblzebra.la $(LIBS) $(LIB_IPV6) - -frrconfdir = $(sysconfdir) - -examplesdir = $(exampledir) -dist_examples_DATA = zebra.conf.sample diff --git a/zebra/debug.c b/zebra/debug.c index 6aedea1e39..25f47bc51a 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -32,6 +32,7 @@ unsigned long zebra_debug_fpm; unsigned long zebra_debug_nht; unsigned long zebra_debug_mpls; unsigned long zebra_debug_vxlan; +unsigned long zebra_debug_pw; DEFUN (show_debugging_zebra, show_debugging_zebra_cmd, @@ -82,6 +83,8 @@ DEFUN (show_debugging_zebra, vty_out(vty, " Zebra next-hop tracking debugging is on\n"); if (IS_ZEBRA_DEBUG_MPLS) vty_out(vty, " Zebra MPLS debugging is on\n"); + if (IS_ZEBRA_DEBUG_PW) + vty_out(vty, " Zebra pseudowire debugging is on\n"); return CMD_SUCCESS; } @@ -130,6 +133,21 @@ DEFUN (debug_zebra_vxlan, return CMD_WARNING; } +DEFUN (debug_zebra_pw, + debug_zebra_pw_cmd, + "[no] debug zebra pseudowires", + "Negate a command or set its defaults\n" + DEBUG_STR + "Zebra configuration\n" + "Debug option set for zebra pseudowires\n") +{ + if (strmatch(argv[0]->text, "no")) + UNSET_FLAG(zebra_debug_pw, ZEBRA_DEBUG_PW); + else + SET_FLAG(zebra_debug_pw, ZEBRA_DEBUG_PW); + return CMD_WARNING; +} + DEFUN (debug_zebra_packet, debug_zebra_packet_cmd, "debug zebra packet [<recv|send>] [detail]", @@ -419,6 +437,10 @@ static int config_write_debug(struct vty *vty) vty_out(vty, "debug zebra vxlan\n"); write++; } + if (IS_ZEBRA_DEBUG_PW) { + vty_out(vty, "debug zebra pseudowires\n"); + write++; + } return write; } @@ -431,6 +453,7 @@ void zebra_debug_init(void) zebra_debug_fpm = 0; zebra_debug_mpls = 0; zebra_debug_vxlan = 0; + zebra_debug_pw = 0; install_node(&debug_node, config_write_debug); @@ -440,6 +463,7 @@ void zebra_debug_init(void) install_element(ENABLE_NODE, &debug_zebra_nht_cmd); install_element(ENABLE_NODE, &debug_zebra_mpls_cmd); install_element(ENABLE_NODE, &debug_zebra_vxlan_cmd); + install_element(ENABLE_NODE, &debug_zebra_pw_cmd); install_element(ENABLE_NODE, &debug_zebra_packet_cmd); install_element(ENABLE_NODE, &debug_zebra_kernel_cmd); install_element(ENABLE_NODE, &debug_zebra_kernel_msgdump_cmd); @@ -459,6 +483,7 @@ void zebra_debug_init(void) install_element(CONFIG_NODE, &debug_zebra_nht_cmd); install_element(CONFIG_NODE, &debug_zebra_mpls_cmd); install_element(CONFIG_NODE, &debug_zebra_vxlan_cmd); + install_element(CONFIG_NODE, &debug_zebra_pw_cmd); install_element(CONFIG_NODE, &debug_zebra_packet_cmd); install_element(CONFIG_NODE, &debug_zebra_kernel_cmd); install_element(CONFIG_NODE, &debug_zebra_kernel_msgdump_cmd); diff --git a/zebra/debug.h b/zebra/debug.h index b52bb7d0e9..987f9d0125 100644 --- a/zebra/debug.h +++ b/zebra/debug.h @@ -44,6 +44,8 @@ #define ZEBRA_DEBUG_VXLAN 0x01 +#define ZEBRA_DEBUG_PW 0x01 + /* Debug related macro. */ #define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT) @@ -66,6 +68,7 @@ #define IS_ZEBRA_DEBUG_NHT (zebra_debug_nht & ZEBRA_DEBUG_NHT) #define IS_ZEBRA_DEBUG_MPLS (zebra_debug_mpls & ZEBRA_DEBUG_MPLS) #define IS_ZEBRA_DEBUG_VXLAN (zebra_debug_vxlan & ZEBRA_DEBUG_VXLAN) +#define IS_ZEBRA_DEBUG_PW (zebra_debug_pw & ZEBRA_DEBUG_PW) extern unsigned long zebra_debug_event; extern unsigned long zebra_debug_packet; @@ -75,6 +78,7 @@ extern unsigned long zebra_debug_fpm; extern unsigned long zebra_debug_nht; extern unsigned long zebra_debug_mpls; extern unsigned long zebra_debug_vxlan; +extern unsigned long zebra_debug_pw; extern void zebra_debug_init(void); diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index 2d5d604a8b..a65fcb2b8c 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.c @@ -21,6 +21,8 @@ #include <zebra.h> +#ifdef OPEN_BSD + #include "if.h" #include "sockunion.h" #include "prefix.h" @@ -328,3 +330,5 @@ void interface_list(struct zebra_ns *zns) ifaddr_proc_ipv6(); #endif /* HAVE_PROC_NET_IF_INET6 */ } + +#endif /* OPEN_BSD */ diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c index fce36ebc1d..3d53194593 100644 --- a/zebra/if_ioctl_solaris.c +++ b/zebra/if_ioctl_solaris.c @@ -21,6 +21,8 @@ #include <zebra.h> +#ifdef SUNOS_5 + #include "if.h" #include "sockunion.h" #include "prefix.h" @@ -358,3 +360,5 @@ struct connected *if_lookup_linklocal(struct interface *ifp) return NULL; } + +#endif /* SUNOS_5 */ diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index acec2db526..a46657dd2e 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -21,6 +21,8 @@ #include <zebra.h> +#ifdef GNU_LINUX + /* The following definition is to workaround an issue in the Linux kernel * header files with redefinition of 'struct in6_addr' in both * netinet/in.h and linux/in6.h. @@ -768,6 +770,33 @@ int interface_lookup_netlink(struct zebra_ns *zns) return 0; } +int kernel_interface_set_master(struct interface *master, + struct interface *slave) +{ + struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); + + struct { + struct nlmsghdr n; + struct ifinfomsg ifa; + char buf[NL_PKT_BUF_SIZE]; + } req; + + memset(&req, 0, sizeof req); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_SETLINK; + req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid; + + req.ifa.ifi_index = slave->ifindex; + + addattr_l(&req.n, sizeof req, IFLA_MASTER, &master->ifindex, 4); + addattr_l(&req.n, sizeof req, IFLA_LINK, &slave->ifindex, 4); + + return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, + 0); +} + /* Interface address modification. */ static int netlink_address(int cmd, int family, struct interface *ifp, struct connected *ifc) @@ -1218,3 +1247,5 @@ void interface_list(struct zebra_ns *zns) { interface_lookup_netlink(zns); } + +#endif /* GNU_LINUX */ diff --git a/zebra/if_sysctl.c b/zebra/if_sysctl.c index 99b0f9d942..39b7204e8e 100644 --- a/zebra/if_sysctl.c +++ b/zebra/if_sysctl.c @@ -21,6 +21,8 @@ #include <zebra.h> +#if !defined(GNU_LINUX) && !defined(OPEN_BSD) && !defined(SUNOS_5) + #include "if.h" #include "sockunion.h" #include "prefix.h" @@ -134,3 +136,5 @@ void interface_list(struct zebra_ns *zns) /* Free sysctl buffer. */ XFREE(MTYPE_TMP, ref); } + +#endif /* !defined(GNU_LINUX) && !defined(OPEN_BSD) && !defined(SUNOS_5) */ diff --git a/zebra/interface.c b/zebra/interface.c index 03ddf8d386..c4d0363994 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -48,6 +48,7 @@ #include "zebra/rt_netlink.h" #include "zebra/interface.h" #include "zebra/zebra_vxlan.h" +#include "zebra/zebra_static.h" #define ZEBRA_PTM_SUPPORT @@ -119,8 +120,6 @@ static int if_zebra_new_hook(struct interface *ifp) route_table_init_with_delegate(&zebra_if_table_delegate); ifp->info = zebra_if; - - zebra_vrf_static_route_interface_fixup(ifp); return 0; } @@ -510,6 +509,8 @@ void if_add_update(struct interface *ifp) zlog_debug( "interface %s vrf %u index %d becomes active.", ifp->name, ifp->vrf_id, ifp->ifindex); + + static_ifindex_update(ifp, true); } else { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("interface %s vrf %u index %d is added.", @@ -675,6 +676,8 @@ void if_delete_update(struct interface *ifp) zlog_debug("interface %s vrf %u index %d is now inactive.", ifp->name, ifp->vrf_id, ifp->ifindex); + static_ifindex_update(ifp, false); + /* Delete connected routes from the kernel. */ if_delete_connected(ifp); @@ -714,6 +717,8 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id) old_vrf_id = ifp->vrf_id; + static_ifindex_update(ifp, false); + /* Uninstall connected routes. */ if_uninstall_connected(ifp); @@ -737,6 +742,8 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id) /* Install connected routes (in new VRF). */ if_install_connected(ifp); + static_ifindex_update(ifp, true); + /* Due to connected route change, schedule RIB processing for both old * and new VRF. */ @@ -745,8 +752,6 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id) ifp->vrf_id, ifp->name); rib_update(old_vrf_id, RIB_UPDATE_IF_CHANGE); rib_update(ifp->vrf_id, RIB_UPDATE_IF_CHANGE); - - zebra_vrf_static_route_interface_fixup(ifp); } static void ipv6_ll_address_to_mac(struct in6_addr *address, u_char *mac) @@ -859,8 +864,6 @@ void if_up(struct interface *ifp) ifp->vrf_id, ifp->name); rib_update(ifp->vrf_id, RIB_UPDATE_IF_CHANGE); - zebra_vrf_static_route_interface_fixup(ifp); - /* Handle interface up for specific types for EVPN. Non-VxLAN interfaces * are checked to see if (remote) neighbor entries need to be installed * on them for ARP suppression. diff --git a/zebra/ioctl.c b/zebra/ioctl.c index 72d98943ef..835f1f4934 100644 --- a/zebra/ioctl.c +++ b/zebra/ioctl.c @@ -33,6 +33,8 @@ #include "zebra/rt.h" #include "zebra/interface.h" +#ifndef SUNOS_5 + #ifdef HAVE_BSD_LINK_DETECT #include <net/if_media.h> #endif /* HAVE_BSD_LINK_DETECT*/ @@ -563,3 +565,5 @@ int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc) #endif /* HAVE_STRUCT_IN6_ALIASREQ */ #endif /* LINUX_IPV6 */ + +#endif /* !SUNOS_5 */ diff --git a/zebra/ioctl_solaris.c b/zebra/ioctl_solaris.c index df1554ae6f..e8b65925f8 100644 --- a/zebra/ioctl_solaris.c +++ b/zebra/ioctl_solaris.c @@ -21,6 +21,8 @@ #include <zebra.h> +#ifdef SUNOS_5 + #include "linklist.h" #include "if.h" #include "prefix.h" @@ -398,3 +400,5 @@ int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc) return 0; } + +#endif /* SUNOS_5 */ diff --git a/zebra/ipforward_proc.c b/zebra/ipforward_proc.c index c3dcdda55f..2834eeeb9c 100644 --- a/zebra/ipforward_proc.c +++ b/zebra/ipforward_proc.c @@ -21,6 +21,8 @@ #include <zebra.h> +#ifdef GNU_LINUX + #include "log.h" #include "privs.h" @@ -193,3 +195,5 @@ int ipforward_ipv6_off(void) return ipforward_ipv6(); } + +#endif /* GNU_LINUX */ diff --git a/zebra/ipforward_solaris.c b/zebra/ipforward_solaris.c index 0d6b7dac03..123cf1bd08 100644 --- a/zebra/ipforward_solaris.c +++ b/zebra/ipforward_solaris.c @@ -20,6 +20,9 @@ */ #include <zebra.h> + +#ifdef SUNOS_5 + #include "log.h" #include "prefix.h" @@ -153,3 +156,5 @@ int ipforward_ipv6_off(void) (void)solaris_nd_set("ip6_forwarding", 0); return ipforward_ipv6(); } + +#endif /* SUNOS_5 */ diff --git a/zebra/ipforward_sysctl.c b/zebra/ipforward_sysctl.c index 00be92bb6d..36212a0132 100644 --- a/zebra/ipforward_sysctl.c +++ b/zebra/ipforward_sysctl.c @@ -19,6 +19,9 @@ */ #include <zebra.h> + +#if !defined(GNU_LINUX) && !defined(SUNOS_5) + #include "privs.h" #include "zebra/ipforward.h" @@ -147,3 +150,5 @@ int ipforward_ipv6_off(void) zlog_err("Can't lower privileges"); return ip6forwarding; } + +#endif /* !defined(GNU_LINUX) && !defined(SUNOS_5) */ diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 7fc2d61332..015e11b3a5 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -20,6 +20,8 @@ #include <zebra.h> +#ifdef HAVE_NETLINK + #include "linklist.h" #include "if.h" #include "log.h" @@ -260,8 +262,9 @@ static int netlink_information_fetch(struct sockaddr_nl *snl, return netlink_neigh_change(snl, h, ns_id); break; default: - zlog_warn("Unknown netlink nlmsg_type %d vrf %u\n", - h->nlmsg_type, ns_id); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("Unknown netlink nlmsg_type %d vrf %u\n", + h->nlmsg_type, ns_id); break; } return 0; @@ -826,3 +829,5 @@ void kernel_terminate(struct zebra_ns *zns) zns->netlink_cmd.sock = -1; } } + +#endif /* HAVE_NETLINK */ diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 4b63a3eb04..5ca6a488c3 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -19,6 +19,9 @@ */ #include <zebra.h> + +#ifndef HAVE_NETLINK + #include <net/if_types.h> #ifdef __OpenBSD__ #include <netmpls/mpls.h> @@ -624,6 +627,7 @@ int ifm_read(struct if_msghdr *ifm) #ifdef HAVE_NET_RT_IFLIST ifp->stats = ifm->ifm_data; #endif /* HAVE_NET_RT_IFLIST */ + ifp->speed = ifm->ifm_data.ifi_baudrate / 1000000; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("%s: interface %s index %d", __func__, ifp->name, @@ -1376,3 +1380,5 @@ void kernel_terminate(struct zebra_ns *zns) { return; } + +#endif /* !HAVE_NETLINK */ diff --git a/zebra/main.c b/zebra/main.c index 27a6f3e027..f0bdafa353 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -299,6 +299,7 @@ int main(int argc, char **argv) zebra_mpls_init(); zebra_mpls_vty_init(); + zebra_pw_vty_init(); /* For debug purpose. */ /* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */ diff --git a/zebra/rib.h b/zebra/rib.h index eca2be5eee..de941bcbbe 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -89,6 +89,7 @@ struct route_entry { #define ROUTE_ENTRY_NEXTHOPS_CHANGED 0x2 #define ROUTE_ENTRY_CHANGED 0x4 #define ROUTE_ENTRY_SELECTED_FIB 0x8 +#define ROUTE_ENTRY_LABELS_CHANGED 0x10 /* Nexthop information. */ u_char nexthop_num; diff --git a/zebra/rt.h b/zebra/rt.h index 81dffdf441..f5f0fa195b 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -36,13 +36,14 @@ extern int kernel_route_rib(struct prefix *, struct prefix *, extern int kernel_address_add_ipv4(struct interface *, struct connected *); extern int kernel_address_delete_ipv4(struct interface *, struct connected *); extern int kernel_neigh_update(int, int, uint32_t, char *, int); - +extern int kernel_interface_set_master(struct interface *master, + struct interface *slave); extern int kernel_add_lsp(zebra_lsp_t *); extern int kernel_upd_lsp(zebra_lsp_t *); extern int kernel_del_lsp(zebra_lsp_t *); extern int mpls_kernel_init(void); -extern int kernel_get_ipmr_sg_stats(void *mroute); +extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute); extern int kernel_add_vtep(vni_t vni, struct interface *ifp, struct in_addr *vtep_ip); extern int kernel_del_vtep(vni_t vni, struct interface *ifp, diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index c02774ca64..192fffd29c 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -19,6 +19,9 @@ */ #include <zebra.h> + +#ifdef HAVE_NETLINK + #include <net/if_arp.h> /* Hack for GNU libc version 2. */ @@ -503,6 +506,7 @@ static int netlink_route_change_read_multicast(struct sockaddr_nl *snl, char gbuf[40]; char oif_list[256] = "\0"; vrf_id_t vrf = ns_id; + int table; if (mroute) m = mroute; @@ -518,6 +522,13 @@ static int netlink_route_change_read_multicast(struct sockaddr_nl *snl, memset(tb, 0, sizeof tb); netlink_parse_rtattr(tb, RTA_MAX, RTM_RTA(rtm), len); + if (tb[RTA_TABLE]) + table = *(int *)RTA_DATA(tb[RTA_TABLE]); + else + table = rtm->rtm_table; + + vrf = vrf_lookup_by_table(table); + if (tb[RTA_IIF]) iif = *(int *)RTA_DATA(tb[RTA_IIF]); @@ -558,10 +569,12 @@ static int netlink_route_change_read_multicast(struct sockaddr_nl *snl, sprintf(temp, "%s ", ifp->name); strcat(oif_list, temp); } + struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(vrf); ifp = if_lookup_by_index(iif, vrf); - zlog_debug("MCAST %s (%s,%s) IIF: %s OIF: %s jiffies: %lld", - nl_msg_type_to_str(h->nlmsg_type), sbuf, gbuf, - ifp->name, oif_list, m->lastused); + zlog_debug( + "MCAST VRF: %s(%d) %s (%s,%s) IIF: %s OIF: %s jiffies: %lld", + zvrf->vrf->name, vrf, nl_msg_type_to_str(h->nlmsg_type), + sbuf, gbuf, ifp->name, oif_list, m->lastused); } return 0; } @@ -1503,7 +1516,7 @@ skip: 0); } -int kernel_get_ipmr_sg_stats(void *in) +int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) { int suc = 0; struct mcast_route_data *mr = (struct mcast_route_data *)in; @@ -1523,13 +1536,14 @@ int kernel_get_ipmr_sg_stats(void *in) req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid; - req.ndm.ndm_family = AF_INET; + req.ndm.ndm_family = RTNL_FAMILY_IPMR; req.n.nlmsg_type = RTM_GETROUTE; addattr_l(&req.n, sizeof(req), RTA_IIF, &mroute->ifindex, 4); addattr_l(&req.n, sizeof(req), RTA_OIF, &mroute->ifindex, 4); addattr_l(&req.n, sizeof(req), RTA_SRC, &mroute->sg.src.s_addr, 4); addattr_l(&req.n, sizeof(req), RTA_DST, &mroute->sg.grp.s_addr, 4); + addattr_l(&req.n, sizeof(req), RTA_TABLE, &zvrf->table_id, 4); suc = netlink_talk(netlink_route_change_read_multicast, &req.n, &zns->netlink_cmd, zns, 0); @@ -1690,17 +1704,17 @@ static int netlink_macfdb_change(struct sockaddr_nl *snl, struct nlmsghdr *h, return 0; } - if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETHER_ADDR_LEN) { + if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETH_ALEN) { zlog_warn( - "%s family %s IF %s(%u) brIF %u - LLADDR is not MAC, len %ld", + "%s family %s IF %s(%u) brIF %u - LLADDR is not MAC, len %lu", nl_msg_type_to_str(h->nlmsg_type), nl_family_to_str(ndm->ndm_family), ifp->name, ndm->ndm_ifindex, zif->brslave_info.bridge_ifindex, - RTA_PAYLOAD(tb[NDA_LLADDR])); + (unsigned long)RTA_PAYLOAD(tb[NDA_LLADDR])); return 0; } - memcpy(&mac, RTA_DATA(tb[NDA_LLADDR]), ETHER_ADDR_LEN); + memcpy(&mac, RTA_DATA(tb[NDA_LLADDR]), ETH_ALEN); if ((NDA_VLAN <= NDA_MAX) && tb[NDA_VLAN]) { vid_present = 1; @@ -2019,18 +2033,18 @@ static int netlink_ipneigh_change(struct sockaddr_nl *snl, struct nlmsghdr *h, if (h->nlmsg_type == RTM_NEWNEIGH) { if (tb[NDA_LLADDR]) { - if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETHER_ADDR_LEN) { + if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETH_ALEN) { zlog_warn( - "%s family %s IF %s(%u) - LLADDR is not MAC, len %ld", + "%s family %s IF %s(%u) - LLADDR is not MAC, len %lu", nl_msg_type_to_str(h->nlmsg_type), nl_family_to_str(ndm->ndm_family), ifp->name, ndm->ndm_ifindex, - RTA_PAYLOAD(tb[NDA_LLADDR])); + (unsigned long)RTA_PAYLOAD(tb[NDA_LLADDR])); return 0; } mac_present = 1; - memcpy(&mac, RTA_DATA(tb[NDA_LLADDR]), ETHER_ADDR_LEN); + memcpy(&mac, RTA_DATA(tb[NDA_LLADDR]), ETH_ALEN); } ext_learned = (ndm->ndm_flags & NTF_EXT_LEARNED) ? 1 : 0; @@ -2442,3 +2456,5 @@ void clear_nhlfe_installed(zebra_lsp_t *lsp) UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); } } + +#endif /* HAVE_NETLINK */ diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 827d398704..4e4d726b46 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -20,6 +20,9 @@ */ #include <zebra.h> + +#ifndef HAVE_NETLINK + #ifdef __OpenBSD__ #include <netmpls/mpls.h> #endif @@ -406,7 +409,7 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, return 0; } -extern int kernel_get_ipmr_sg_stats(void *mroute) +extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute) { return 0; } @@ -443,3 +446,11 @@ int kernel_del_neigh(struct interface *ifp, struct ipaddr *ip) { return 0; } + +extern int kernel_interface_set_master(struct interface *master, + struct interface *slave) +{ + return 0; +} + +#endif /* !HAVE_NETLINK */ diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index 5384231f88..1bba003a0a 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -21,6 +21,8 @@ #include <zebra.h> +#ifdef SUNOS_5 + #include "prefix.h" #include "log.h" #include "if.h" @@ -258,3 +260,5 @@ void neigh_read(struct zebra_ns *zns) void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) { } + +#endif /* SUNOS_5 */ diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c index 304f441367..f38cba65e7 100644 --- a/zebra/rtread_netlink.c +++ b/zebra/rtread_netlink.c @@ -21,6 +21,8 @@ #include <zebra.h> +#ifdef GNU_LINUX + #include "vty.h" #include "zebra/zserv.h" #include "zebra/rt_netlink.h" @@ -50,3 +52,5 @@ void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) { netlink_neigh_read_for_vlan(zns, vlan_if); } + +#endif /* GNU_LINUX */ diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c index d3e2eb6fac..53ed0e7906 100644 --- a/zebra/rtread_sysctl.c +++ b/zebra/rtread_sysctl.c @@ -21,6 +21,8 @@ #include <zebra.h> +#if !defined(GNU_LINUX) && !defined(SUNOS_5) + #include "memory.h" #include "zebra_memory.h" #include "log.h" @@ -90,3 +92,5 @@ void neigh_read(struct zebra_ns *zns) void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) { } + +#endif /* !defined(GNU_LINUX) && !defined(SUNOS_5) */ diff --git a/zebra/subdir.am b/zebra/subdir.am new file mode 100644 index 0000000000..0391cab9fd --- /dev/null +++ b/zebra/subdir.am @@ -0,0 +1,133 @@ +# +# zebra +# + +if ZEBRA +sbin_PROGRAMS += zebra/zebra +dist_examples_DATA += zebra/zebra.conf.sample + +if SNMP +module_LTLIBRARIES += zebra/zebra_snmp.la +endif +if FPM +module_LTLIBRARIES += zebra/zebra_fpm.la +endif + +## endif ZEBRA +endif + +zebra_zebra_LDADD = lib/libfrr.la $(LIBCAP) +zebra_zebra_SOURCES = \ + zebra/connected.c \ + zebra/debug.c \ + zebra/if_ioctl.c \ + zebra/if_ioctl_solaris.c \ + zebra/if_netlink.c \ + zebra/if_sysctl.c \ + zebra/interface.c \ + zebra/ioctl.c \ + zebra/ioctl_solaris.c \ + zebra/ipforward_proc.c \ + zebra/ipforward_solaris.c \ + zebra/ipforward_sysctl.c \ + zebra/irdp_interface.c \ + zebra/irdp_main.c \ + zebra/irdp_packet.c \ + zebra/kernel_netlink.c \ + zebra/kernel_socket.c \ + zebra/label_manager.c \ + zebra/main.c \ + zebra/redistribute.c \ + zebra/router-id.c \ + zebra/rt_netlink.c \ + zebra/rt_socket.c \ + zebra/rtadv.c \ + zebra/rtread_getmsg.c \ + zebra/rtread_netlink.c \ + zebra/rtread_sysctl.c \ + zebra/zebra_l2.c \ + zebra/zebra_memory.c \ + zebra/zebra_mpls.c \ + zebra/zebra_mpls_netlink.c \ + zebra/zebra_mpls_openbsd.c \ + zebra/zebra_mpls_null.c \ + zebra/zebra_mpls_vty.c \ + zebra/zebra_mroute.c \ + zebra/zebra_ns.c \ + zebra/zebra_ptm.c \ + zebra/zebra_ptm_redistribute.c \ + zebra/zebra_pw.c \ + zebra/zebra_rib.c \ + zebra/zebra_rnh.c \ + zebra/zebra_routemap.c \ + zebra/zebra_static.c \ + zebra/zebra_vrf.c \ + zebra/zebra_vty.c \ + zebra/zebra_vxlan.c \ + zebra/zserv.c \ + # end + +zebra/zebra_vty_clippy.c: $(CLIPPY_DEPS) +zebra/zebra_vty.$(OBJEXT): zebra/zebra_vty_clippy.c + +noinst_HEADERS += \ + zebra/connected.h \ + zebra/debug.h \ + zebra/if_netlink.h \ + zebra/interface.h \ + zebra/ioctl.h \ + zebra/ioctl_solaris.h \ + zebra/ipforward.h \ + zebra/irdp.h \ + zebra/kernel_netlink.h \ + zebra/kernel_socket.h \ + zebra/label_manager.h \ + zebra/redistribute.h \ + zebra/rib.h \ + zebra/router-id.h \ + zebra/rt.h \ + zebra/rt_netlink.h \ + zebra/rtadv.h \ + zebra/zebra_fpm_private.h \ + zebra/zebra_l2.h \ + zebra/zebra_memory.h \ + zebra/zebra_mpls.h \ + zebra/zebra_mroute.h \ + zebra/zebra_ns.h \ + zebra/zebra_ptm.h \ + zebra/zebra_ptm_redistribute.h \ + zebra/zebra_pw.h \ + zebra/zebra_rnh.h \ + zebra/zebra_routemap.h \ + zebra/zebra_static.h \ + zebra/zebra_vrf.h \ + zebra/zebra_vxlan.h \ + zebra/zebra_vxlan_private.h \ + zebra/zserv.h \ + # end + +zebra_zebra_snmp_la_SOURCES = zebra/zebra_snmp.c +zebra_zebra_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) +zebra_zebra_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic +zebra_zebra_snmp_la_LIBADD = lib/libfrrsnmp.la + +zebra_zebra_fpm_la_LDFLAGS = -avoid-version -module -shared -export-dynamic +zebra_zebra_fpm_la_LIBADD = $(Q_FPM_PB_CLIENT_LDOPTS) +zebra_zebra_fpm_la_SOURCES = zebra/zebra_fpm.c +zebra_zebra_fpm_la_SOURCES += zebra/zebra_fpm_netlink.c +if HAVE_PROTOBUF +zebra_zebra_fpm_la_SOURCES += zebra/zebra_fpm_protobuf.c +if DEV_BUILD +zebra_zebra_fpm_la_SOURCES += zebra/zebra_fpm_dt.c +endif +endif + +EXTRA_DIST += \ + zebra/GNOME-SMI \ + zebra/GNOME-PRODUCT-ZEBRA-MIB \ + # end + +# -- unmaintained -- +# noinst_PROGRAMS += zebra/client +# zebra_client_SOURCES = zebra/client_main.c +# zebra_client_LDADD = lib/libfrr.la diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index 862049cb85..28f7956639 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -24,6 +24,8 @@ #include <zebra.h> +#ifdef HAVE_NETLINK + #include "log.h" #include "rib.h" #include "vty.h" @@ -457,3 +459,5 @@ int zfpm_netlink_encode_route(int cmd, rib_dest_t *dest, struct route_entry *re, return netlink_route_info_encode(ri, in_buf, in_buf_len); } + +#endif /* HAVE_NETLINK */ diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index e44e5d2e6b..d1ab2dbb85 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -2222,7 +2222,7 @@ found: return 0; SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); - SET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED); + SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED); rib_queue_add(rn); return 0; @@ -2405,7 +2405,7 @@ void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi) nexthop_del_labels(nexthop); SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); SET_FLAG(re->status, - ROUTE_ENTRY_NEXTHOPS_CHANGED); + ROUTE_ENTRY_LABELS_CHANGED); update = 1; } diff --git a/zebra/zebra_mpls_netlink.c b/zebra/zebra_mpls_netlink.c index c5053563b9..8b30783a9a 100644 --- a/zebra/zebra_mpls_netlink.c +++ b/zebra/zebra_mpls_netlink.c @@ -19,6 +19,9 @@ */ #include <zebra.h> + +#ifdef HAVE_NETLINK + #include "zebra/rt.h" #include "zebra/rt_netlink.h" #include "zebra/zebra_mpls.h" @@ -105,3 +108,5 @@ int mpls_kernel_init(void) return 0; }; + +#endif /* HAVE_NETLINK */ diff --git a/zebra/zebra_mpls_null.c b/zebra/zebra_mpls_null.c index a9da5c29c6..e4dc570fd9 100644 --- a/zebra/zebra_mpls_null.c +++ b/zebra/zebra_mpls_null.c @@ -22,6 +22,8 @@ #include "zebra/rt.h" #include "zebra/zebra_mpls.h" +#if !defined(HAVE_NETLINK) && !defined(OPEN_BSD) + int kernel_add_lsp(zebra_lsp_t *lsp) { return 0; @@ -38,3 +40,5 @@ int mpls_kernel_init(void) { return -1; }; + +#endif /* !defined(HAVE_NETLINK) && !defined(OPEN_BSD) */ diff --git a/zebra/zebra_mpls_openbsd.c b/zebra/zebra_mpls_openbsd.c index fc1df9227f..119cd5b700 100644 --- a/zebra/zebra_mpls_openbsd.c +++ b/zebra/zebra_mpls_openbsd.c @@ -19,6 +19,9 @@ */ #include <zebra.h> + +#ifdef OPEN_BSD + #include <netmpls/mpls.h> #include "zebra/rt.h" #include "zebra/zebra_mpls.h" @@ -34,6 +37,7 @@ extern struct zebra_privs_t zserv_privs; struct { u_int32_t rtseq; int fd; + int ioctl_fd; } kr_state; static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label, @@ -327,6 +331,85 @@ int kernel_del_lsp(zebra_lsp_t *lsp) return ret; } +static int kmpw_install(struct zebra_pw *pw) +{ + struct ifreq ifr; + struct ifmpwreq imr; + struct sockaddr_storage ss; + struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; + struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; + + memset(&imr, 0, sizeof(imr)); + switch (pw->type) { + case PW_TYPE_ETHERNET: + imr.imr_type = IMR_TYPE_ETHERNET; + break; + case PW_TYPE_ETHERNET_TAGGED: + imr.imr_type = IMR_TYPE_ETHERNET_TAGGED; + break; + default: + zlog_err("%s: unhandled pseudowire type (%#X)", __func__, + pw->type); + return -1; + } + + if (pw->flags & F_PSEUDOWIRE_CWORD) + imr.imr_flags |= IMR_FLAG_CONTROLWORD; + + /* pseudowire nexthop */ + memset(&ss, 0, sizeof(ss)); + switch (pw->af) { + case AF_INET: + sa_in->sin_family = AF_INET; + sa_in->sin_len = sizeof(struct sockaddr_in); + sa_in->sin_addr = pw->nexthop.ipv4; + break; + case AF_INET6: + sa_in6->sin6_family = AF_INET6; + sa_in6->sin6_len = sizeof(struct sockaddr_in6); + sa_in6->sin6_addr = pw->nexthop.ipv6; + break; + default: + zlog_err("%s: unhandled pseudowire address-family (%u)", + __func__, pw->af); + return -1; + } + memcpy(&imr.imr_nexthop, (struct sockaddr *)&ss, + sizeof(imr.imr_nexthop)); + + /* pseudowire local/remote labels */ + imr.imr_lshim.shim_label = pw->local_label; + imr.imr_rshim.shim_label = pw->remote_label; + + /* ioctl */ + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, pw->ifname, sizeof(ifr.ifr_name)); + ifr.ifr_data = (caddr_t)&imr; + if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1) { + zlog_err("ioctl SIOCSETMPWCFG: %s", safe_strerror(errno)); + return -1; + } + + return 0; +} + +static int kmpw_uninstall(struct zebra_pw *pw) +{ + struct ifreq ifr; + struct ifmpwreq imr; + + memset(&ifr, 0, sizeof(ifr)); + memset(&imr, 0, sizeof(imr)); + strlcpy(ifr.ifr_name, pw->ifname, sizeof(ifr.ifr_name)); + ifr.ifr_data = (caddr_t)&imr; + if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1) { + zlog_err("ioctl SIOCSETMPWCFG: %s", safe_strerror(errno)); + return -1; + } + + return 0; +} + #define MAX_RTSOCK_BUF 128 * 1024 int mpls_kernel_init(void) { @@ -338,6 +421,12 @@ int mpls_kernel_init(void) return -1; } + if ((kr_state.ioctl_fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0)) + == -1) { + zlog_warn("%s: ioctl socket", __func__); + return -1; + } + /* grow receive buffer, don't wanna miss messages */ optlen = sizeof(default_rcvbuf); if (getsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF, &default_rcvbuf, @@ -356,5 +445,11 @@ int mpls_kernel_init(void) kr_state.rtseq = 1; + /* register hook to install/uninstall pseudowires */ + hook_register(pw_install, kmpw_install); + hook_register(pw_uninstall, kmpw_uninstall); + return 0; } + +#endif /* OPEN_BSD */ diff --git a/zebra/zebra_mroute.c b/zebra/zebra_mroute.c index c00498171d..c4d674df23 100644 --- a/zebra/zebra_mroute.c +++ b/zebra/zebra_mroute.c @@ -30,6 +30,7 @@ #include "zebra/zebra_vrf.h" #include "zebra/zebra_mroute.h" #include "zebra/rt.h" +#include "zebra/debug.h" int zebra_ipmr_route_stats(struct zserv *client, int fd, u_short length, struct zebra_vrf *zvrf) @@ -38,18 +39,22 @@ int zebra_ipmr_route_stats(struct zserv *client, int fd, u_short length, struct stream *s; int suc; - char sbuf[40]; - char gbuf[40]; - memset(&mroute, 0, sizeof(mroute)); stream_get(&mroute.sg.src, client->ibuf, 4); stream_get(&mroute.sg.grp, client->ibuf, 4); mroute.ifindex = stream_getl(client->ibuf); - strcpy(sbuf, inet_ntoa(mroute.sg.src)); - strcpy(gbuf, inet_ntoa(mroute.sg.grp)); + if (IS_ZEBRA_DEBUG_KERNEL) { + char sbuf[40]; + char gbuf[40]; + + strcpy(sbuf, inet_ntoa(mroute.sg.src)); + strcpy(gbuf, inet_ntoa(mroute.sg.grp)); + + zlog_debug("Asking for (%s,%s) mroute information", sbuf, gbuf); + } - suc = kernel_get_ipmr_sg_stats(&mroute); + suc = kernel_get_ipmr_sg_stats(zvrf, &mroute); s = client->obuf; diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c new file mode 100644 index 0000000000..4f1d8b0915 --- /dev/null +++ b/zebra/zebra_pw.c @@ -0,0 +1,533 @@ +/* Zebra PW code + * Copyright (C) 2016 Volta Networks, Inc. + * + * This program 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 of the License, or + * (at your option) any later version. + * + * This program 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 this program; see the file COPYING; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <zebra.h> + +#include "log.h" +#include "memory.h" +#include "thread.h" +#include "command.h" +#include "vrf.h" + +#include "zebra/debug.h" +#include "zebra/rib.h" +#include "zebra/zserv.h" +#include "zebra/zebra_rnh.h" +#include "zebra/zebra_vrf.h" +#include "zebra/zebra_pw.h" + +DEFINE_MTYPE_STATIC(LIB, PW, "Pseudowire") + +DEFINE_QOBJ_TYPE(zebra_pw) + +DEFINE_HOOK(pw_install, (struct zebra_pw * pw), (pw)) +DEFINE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw)) + +#define MPLS_NO_LABEL MPLS_INVALID_LABEL + +extern struct zebra_t zebrad; + +static int zebra_pw_enabled(struct zebra_pw *); +static void zebra_pw_install(struct zebra_pw *); +static void zebra_pw_uninstall(struct zebra_pw *); +static int zebra_pw_install_retry(struct thread *); +static int zebra_pw_check_reachability(struct zebra_pw *); +static void zebra_pw_update_status(struct zebra_pw *, int); + +static inline int zebra_pw_compare(const struct zebra_pw *a, + const struct zebra_pw *b) +{ + return (strcmp(a->ifname, b->ifname)); +} + +RB_GENERATE(zebra_pw_head, zebra_pw, pw_entry, zebra_pw_compare) +RB_GENERATE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare) + +struct zebra_pw *zebra_pw_add(struct zebra_vrf *zvrf, const char *ifname, + uint8_t protocol, struct zserv *client) +{ + struct zebra_pw *pw; + + if (IS_ZEBRA_DEBUG_PW) + zlog_debug("%u: adding pseudowire %s protocol %s", + zvrf_id(zvrf), ifname, zebra_route_string(protocol)); + + pw = XCALLOC(MTYPE_PW, sizeof(*pw)); + strlcpy(pw->ifname, ifname, sizeof(pw->ifname)); + pw->protocol = protocol; + pw->vrf_id = zvrf_id(zvrf); + pw->client = client; + pw->status = PW_STATUS_UP; + pw->local_label = MPLS_NO_LABEL; + pw->remote_label = MPLS_NO_LABEL; + pw->flags = F_PSEUDOWIRE_CWORD; + + RB_INSERT(zebra_pw_head, &zvrf->pseudowires, pw); + if (pw->protocol == ZEBRA_ROUTE_STATIC) { + RB_INSERT(zebra_static_pw_head, &zvrf->static_pseudowires, pw); + QOBJ_REG(pw, zebra_pw); + } + + return pw; +} + +void zebra_pw_del(struct zebra_vrf *zvrf, struct zebra_pw *pw) +{ + if (IS_ZEBRA_DEBUG_PW) + zlog_debug("%u: deleting pseudowire %s protocol %s", pw->vrf_id, + pw->ifname, zebra_route_string(pw->protocol)); + + /* remove nexthop tracking */ + zebra_deregister_rnh_pseudowire(pw->vrf_id, pw); + + /* uninstall */ + if (pw->status == PW_STATUS_UP) + hook_call(pw_uninstall, pw); + else if (pw->install_retry_timer) + THREAD_TIMER_OFF(pw->install_retry_timer); + + /* unlink and release memory */ + RB_REMOVE(zebra_pw_head, &zvrf->pseudowires, pw); + if (pw->protocol == ZEBRA_ROUTE_STATIC) + RB_REMOVE(zebra_static_pw_head, &zvrf->static_pseudowires, pw); + XFREE(MTYPE_PW, pw); +} + +void zebra_pw_change(struct zebra_pw *pw, ifindex_t ifindex, int type, int af, + union g_addr *nexthop, uint32_t local_label, + uint32_t remote_label, uint8_t flags, + union pw_protocol_fields *data) +{ + zebra_deregister_rnh_pseudowire(pw->vrf_id, pw); + + pw->ifindex = ifindex; + pw->type = type; + pw->af = af; + pw->nexthop = *nexthop; + pw->local_label = local_label; + pw->remote_label = remote_label; + pw->flags = flags; + pw->data = *data; + + if (zebra_pw_enabled(pw)) + zebra_register_rnh_pseudowire(pw->vrf_id, pw); + else + zebra_pw_uninstall(pw); +} + +struct zebra_pw *zebra_pw_find(struct zebra_vrf *zvrf, const char *ifname) +{ + struct zebra_pw pw; + strlcpy(pw.ifname, ifname, sizeof(pw.ifname)); + return (RB_FIND(zebra_pw_head, &zvrf->pseudowires, &pw)); +} + +static int zebra_pw_enabled(struct zebra_pw *pw) +{ + if (pw->protocol == ZEBRA_ROUTE_STATIC) { + if (pw->local_label == MPLS_NO_LABEL + || pw->remote_label == MPLS_NO_LABEL || pw->af == AF_UNSPEC) + return 0; + return 1; + } else + return pw->enabled; +} + +void zebra_pw_update(struct zebra_pw *pw) +{ + if (zebra_pw_check_reachability(pw) < 0) { + zebra_pw_uninstall(pw); + /* wait for NHT and try again later */ + } else { + /* + * Install or reinstall the pseudowire (e.g. to update + * parameters like the nexthop or the use of the control word). + */ + zebra_pw_install(pw); + } +} + +static void zebra_pw_install(struct zebra_pw *pw) +{ + if (IS_ZEBRA_DEBUG_PW) + zlog_debug("%u: installing pseudowire %s protocol %s", + pw->vrf_id, pw->ifname, + zebra_route_string(pw->protocol)); + + if (hook_call(pw_install, pw)) { + zebra_pw_install_failure(pw); + return; + } + + if (pw->status == PW_STATUS_DOWN) + zebra_pw_update_status(pw, PW_STATUS_UP); +} + +static void zebra_pw_uninstall(struct zebra_pw *pw) +{ + if (pw->status == PW_STATUS_DOWN) + return; + + if (IS_ZEBRA_DEBUG_PW) + zlog_debug("%u: uninstalling pseudowire %s protocol %s", + pw->vrf_id, pw->ifname, + zebra_route_string(pw->protocol)); + + /* ignore any possible error */ + hook_call(pw_uninstall, pw); + + if (zebra_pw_enabled(pw)) + zebra_pw_update_status(pw, PW_STATUS_DOWN); +} + +/* + * Installation of the pseudowire in the kernel or hardware has failed. This + * function will notify the pseudowire client about the failure and schedule + * to retry the installation later. This function can be called by an external + * agent that performs the pseudowire installation in an asynchronous way. + */ +void zebra_pw_install_failure(struct zebra_pw *pw) +{ + if (IS_ZEBRA_DEBUG_PW) + zlog_debug( + "%u: failed installing pseudowire %s, " + "scheduling retry in %u seconds", + pw->vrf_id, pw->ifname, PW_INSTALL_RETRY_INTERVAL); + + /* schedule to retry later */ + THREAD_TIMER_OFF(pw->install_retry_timer); + thread_add_timer(zebrad.master, zebra_pw_install_retry, pw, + PW_INSTALL_RETRY_INTERVAL, &pw->install_retry_timer); + + zebra_pw_update_status(pw, PW_STATUS_DOWN); +} + +static int zebra_pw_install_retry(struct thread *thread) +{ + struct zebra_pw *pw = THREAD_ARG(thread); + + pw->install_retry_timer = NULL; + zebra_pw_install(pw); + + return 0; +} + +static void zebra_pw_update_status(struct zebra_pw *pw, int status) +{ + pw->status = status; + if (pw->client) + zsend_pw_update(pw->client, pw); +} + +static int zebra_pw_check_reachability(struct zebra_pw *pw) +{ + struct route_entry *re; + struct nexthop *nexthop; + + /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */ + + /* find route to the remote end of the pseudowire */ + re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id, + &pw->nexthop, NULL); + if (!re) { + if (IS_ZEBRA_DEBUG_PW) + zlog_warn("%s: no route found for %s", __func__, + pw->ifname); + return -1; + } + + /* + * Need to ensure that there's a label binding for all nexthops. + * Otherwise, ECMP for this route could render the pseudowire unusable. + */ + for (ALL_NEXTHOPS(re->nexthop, nexthop)) { + if (!nexthop->nh_label) { + if (IS_ZEBRA_DEBUG_PW) + zlog_warn("%s: unlabeled route for %s", + __func__, pw->ifname); + return -1; + } + } + + return 0; +} + +void zebra_pw_client_close(struct zserv *client) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf; + struct zebra_pw *pw, *tmp; + + RB_FOREACH(vrf, vrf_id_head, &vrfs_by_id) + { + zvrf = vrf->info; + RB_FOREACH_SAFE(pw, zebra_pw_head, &zvrf->pseudowires, tmp) + { + if (pw->client != client) + continue; + zebra_pw_del(zvrf, pw); + } + } +} + +void zebra_pw_init(struct zebra_vrf *zvrf) +{ + RB_INIT(zebra_pw_head, &zvrf->pseudowires); + RB_INIT(zebra_static_pw_head, &zvrf->static_pseudowires); +} + +void zebra_pw_exit(struct zebra_vrf *zvrf) +{ + struct zebra_pw *pw; + + while ((pw = RB_ROOT(zebra_pw_head, &zvrf->pseudowires)) != NULL) + zebra_pw_del(zvrf, pw); +} + +DEFUN_NOSH (pseudowire_if, + pseudowire_if_cmd, + "[no] pseudowire IFNAME", + NO_STR + "Static pseudowire configuration\n" + "Pseudowire name\n") +{ + struct zebra_vrf *zvrf; + struct zebra_pw *pw; + int idx = 0; + const char *ifname; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + if (!zvrf) + return CMD_WARNING; + + argv_find(argv, argc, "IFNAME", &idx); + ifname = argv[idx]->arg; + pw = zebra_pw_find(zvrf, ifname); + if (pw && pw->protocol != ZEBRA_ROUTE_STATIC) { + vty_out(vty, "%% Pseudowire is not static\n"); + return CMD_WARNING; + } + + if (argv_find(argv, argc, "no", &idx)) { + if (!pw) + return CMD_SUCCESS; + zebra_pw_del(zvrf, pw); + } + + if (!pw) + pw = zebra_pw_add(zvrf, ifname, ZEBRA_ROUTE_STATIC, NULL); + VTY_PUSH_CONTEXT(PW_NODE, pw); + + return CMD_SUCCESS; +} + +DEFUN (pseudowire_labels, + pseudowire_labels_cmd, + "[no] mpls label local (16-1048575) remote (16-1048575)", + NO_STR + "MPLS L2VPN PW command\n" + "MPLS L2VPN static labels\n" + "Local pseudowire label\n" + "Local pseudowire label\n" + "Remote pseudowire label\n" + "Remote pseudowire label\n") +{ + VTY_DECLVAR_CONTEXT(zebra_pw, pw); + int idx = 0; + mpls_label_t local_label, remote_label; + + if (argv_find(argv, argc, "no", &idx)) { + local_label = MPLS_NO_LABEL; + remote_label = MPLS_NO_LABEL; + } else { + argv_find(argv, argc, "local", &idx); + local_label = atoi(argv[idx + 1]->arg); + argv_find(argv, argc, "remote", &idx); + remote_label = atoi(argv[idx + 1]->arg); + } + + zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop, + local_label, remote_label, pw->flags, &pw->data); + + return CMD_SUCCESS; +} + +DEFUN (pseudowire_neighbor, + pseudowire_neighbor_cmd, + "[no] neighbor <A.B.C.D|X:X::X:X>", + NO_STR + "Specify the IPv4 or IPv6 address of the remote endpoint\n" + "IPv4 address\n" + "IPv6 address\n") +{ + VTY_DECLVAR_CONTEXT(zebra_pw, pw); + int idx = 0; + const char *address; + int af; + union g_addr nexthop; + + af = AF_UNSPEC; + memset(&nexthop, 0, sizeof(nexthop)); + + if (!argv_find(argv, argc, "no", &idx)) { + argv_find(argv, argc, "neighbor", &idx); + address = argv[idx + 1]->arg; + + if (inet_pton(AF_INET, address, &nexthop.ipv4) == 1) + af = AF_INET; + else if (inet_pton(AF_INET6, address, &nexthop.ipv6) == 1) + af = AF_INET6; + else { + vty_out(vty, "%% Malformed address\n"); + return CMD_WARNING; + } + } + + zebra_pw_change(pw, pw->ifindex, pw->type, af, &nexthop, + pw->local_label, pw->remote_label, pw->flags, + &pw->data); + + return CMD_SUCCESS; +} + +DEFUN (pseudowire_control_word, + pseudowire_control_word_cmd, + "[no] control-word <exclude|include>", + NO_STR + "Control-word options\n" + "Exclude control-word in pseudowire packets\n" + "Include control-word in pseudowire packets\n") +{ + VTY_DECLVAR_CONTEXT(zebra_pw, pw); + int idx = 0; + uint8_t flags = 0; + + if (argv_find(argv, argc, "no", &idx)) + flags = F_PSEUDOWIRE_CWORD; + else { + argv_find(argv, argc, "control-word", &idx); + if (argv[idx + 1]->text[0] == 'i') + flags = F_PSEUDOWIRE_CWORD; + } + + zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop, + pw->local_label, pw->remote_label, flags, &pw->data); + + return CMD_SUCCESS; +} + +DEFUN (show_pseudowires, + show_pseudowires_cmd, + "show pseudowires", + SHOW_STR + "Pseudowires") +{ + struct zebra_vrf *zvrf; + struct zebra_pw *pw; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + if (!zvrf) + return 0; + + vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", "Interface", "Neighbor", + "Labels", "Protocol", "Status"); + + RB_FOREACH(pw, zebra_pw_head, &zvrf->pseudowires) + { + char buf_nbr[INET6_ADDRSTRLEN]; + char buf_labels[64]; + + inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr)); + + if (pw->local_label != MPLS_NO_LABEL + && pw->remote_label != MPLS_NO_LABEL) + snprintf(buf_labels, sizeof(buf_labels), "%u/%u", + pw->local_label, pw->remote_label); + else + snprintf(buf_labels, sizeof(buf_labels), "-"); + + vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", pw->ifname, + (pw->af != AF_UNSPEC) ? buf_nbr : "-", buf_labels, + zebra_route_string(pw->protocol), + (zebra_pw_enabled(pw) && pw->status == PW_STATUS_UP) + ? "UP" + : "DOWN"); + } + + return CMD_SUCCESS; +} + +/* Pseudowire configuration write function. */ +static int zebra_pw_config(struct vty *vty) +{ + int write = 0; + struct zebra_vrf *zvrf; + struct zebra_pw *pw; + + zvrf = vrf_info_lookup(VRF_DEFAULT); + if (!zvrf) + return 0; + + RB_FOREACH(pw, zebra_static_pw_head, &zvrf->static_pseudowires) + { + vty_out(vty, "pseudowire %s\n", pw->ifname); + if (pw->local_label != MPLS_NO_LABEL + && pw->remote_label != MPLS_NO_LABEL) + vty_out(vty, " mpls label local %u remote %u\n", + pw->local_label, pw->remote_label); + else + vty_out(vty, + " ! Incomplete config, specify the static " + "MPLS labels\n"); + + if (pw->af != AF_UNSPEC) { + char buf[INET6_ADDRSTRLEN]; + inet_ntop(pw->af, &pw->nexthop, buf, sizeof(buf)); + vty_out(vty, " neighbor %s\n", buf); + } else + vty_out(vty, + " ! Incomplete config, specify a neighbor " + "address\n"); + + if (!(pw->flags & F_PSEUDOWIRE_CWORD)) + vty_out(vty, " control-word exclude\n"); + + vty_out(vty, "!\n"); + write = 1; + } + + return write; +} + +static struct cmd_node pw_node = { + PW_NODE, "%s(config-pw)# ", 1, +}; + +void zebra_pw_vty_init(void) +{ + install_node(&pw_node, zebra_pw_config); + install_default(PW_NODE); + + install_element(CONFIG_NODE, &pseudowire_if_cmd); + install_element(PW_NODE, &pseudowire_labels_cmd); + install_element(PW_NODE, &pseudowire_neighbor_cmd); + install_element(PW_NODE, &pseudowire_control_word_cmd); + + install_element(VIEW_NODE, &show_pseudowires_cmd); +} diff --git a/zebra/zebra_pw.h b/zebra/zebra_pw.h new file mode 100644 index 0000000000..417d26fe65 --- /dev/null +++ b/zebra/zebra_pw.h @@ -0,0 +1,75 @@ +/* Zebra PW code + * Copyright (C) 2016 Volta Networks, Inc. + * + * This program 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 of the License, or + * (at your option) any later version. + * + * This program 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 this program; see the file COPYING; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef ZEBRA_PW_H_ +#define ZEBRA_PW_H_ + +#include <net/if.h> +#include <netinet/in.h> + +#include "hook.h" +#include "qobj.h" + +#define PW_INSTALL_RETRY_INTERVAL 30 + +struct zebra_pw { + RB_ENTRY(zebra_pw) pw_entry, static_pw_entry; + vrf_id_t vrf_id; + char ifname[IF_NAMESIZE]; + ifindex_t ifindex; + int type; + int af; + union g_addr nexthop; + uint32_t local_label; + uint32_t remote_label; + uint8_t flags; + union pw_protocol_fields data; + int enabled; + int status; + uint8_t protocol; + struct zserv *client; + struct rnh *rnh; + struct thread *install_retry_timer; + QOBJ_FIELDS +}; +DECLARE_QOBJ_TYPE(zebra_pw) + +RB_HEAD(zebra_pw_head, zebra_pw); +RB_PROTOTYPE(zebra_pw_head, zebra_pw, pw_entry, zebra_pw_compare); + +RB_HEAD(zebra_static_pw_head, zebra_pw); +RB_PROTOTYPE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare); + +DECLARE_HOOK(pw_install, (struct zebra_pw * pw), (pw)) +DECLARE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw)) + +struct zebra_pw *zebra_pw_add(struct zebra_vrf *, const char *, uint8_t, + struct zserv *); +void zebra_pw_del(struct zebra_vrf *, struct zebra_pw *); +void zebra_pw_change(struct zebra_pw *, ifindex_t, int, int, union g_addr *, + uint32_t, uint32_t, uint8_t, union pw_protocol_fields *); +struct zebra_pw *zebra_pw_find(struct zebra_vrf *, const char *); +void zebra_pw_update(struct zebra_pw *); +void zebra_pw_install_failure(struct zebra_pw *); +void zebra_pw_client_close(struct zserv *); +void zebra_pw_init(struct zebra_vrf *); +void zebra_pw_exit(struct zebra_vrf *); +void zebra_pw_vty_init(void); + +#endif /* ZEBRA_PW_H_ */ diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 98508aaa89..e61c2e7b0e 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -505,6 +505,8 @@ static int nexthop_active(afi_t afi, struct route_entry *re, } resolved = 1; } + if (resolved && set) + re->nexthop_mtu = match->mtu; return resolved; } else if (re->type == ZEBRA_ROUTE_STATIC) { resolved = 0; @@ -2237,13 +2239,12 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, continue; if (same->type == re->type && same->instance == re->instance - && same->table == re->table - && same->type != ZEBRA_ROUTE_CONNECT) + && same->table == re->table && !RIB_SYSTEM_ROUTE(same)) break; } /* If this route is kernel route, set FIB flag to the route. */ - if (re->type == ZEBRA_ROUTE_KERNEL || re->type == ZEBRA_ROUTE_CONNECT) + if (RIB_SYSTEM_ROUTE(re)) for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); @@ -2467,11 +2468,11 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance, continue; if (re->instance != instance) continue; - if (re->type != ZEBRA_ROUTE_CONNECT) { + if (!RIB_SYSTEM_ROUTE(re)) { same = re; break; } - /* Duplicate connected route comes in. */ + /* Duplicate system route comes in. */ else if ((nexthop = re->nexthop) && nexthop->type == NEXTHOP_TYPE_IFINDEX && nexthop->ifindex == ifindex @@ -2515,7 +2516,7 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance, route_entry_nexthop_ifindex_add(re, ifindex); /* If this route is kernel route, set FIB flag to the route. */ - if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT) + if (RIB_SYSTEM_ROUTE(re)) for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 8a326c27fc..77cfa9860f 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -126,6 +126,7 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type) rnh->client_list = list_new(); rnh->vrf_id = vrfid; rnh->zebra_static_route_list = list_new(); + rnh->zebra_pseudowire_list = list_new(); route_lock_node(rn); rn->info = rnh; rnh->node = rn; @@ -161,6 +162,7 @@ void zebra_free_rnh(struct rnh *rnh) rnh->flags |= ZEBRA_NHT_DELETED; list_free(rnh->client_list); list_free(rnh->zebra_static_route_list); + list_free(rnh->zebra_pseudowire_list); free_state(rnh->vrf_id, rnh->state, rnh->node); XFREE(MTYPE_RNH, rnh); } @@ -210,7 +212,8 @@ void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client, } listnode_delete(rnh->client_list, client); if (list_isempty(rnh->client_list) - && list_isempty(rnh->zebra_static_route_list)) + && list_isempty(rnh->zebra_static_route_list) + && list_isempty(rnh->zebra_pseudowire_list)) zebra_delete_rnh(rnh, type); } @@ -237,7 +240,8 @@ void zebra_deregister_rnh_static_nh(vrf_id_t vrf_id, struct prefix *nh, listnode_delete(rnh->zebra_static_route_list, static_rn); if (list_isempty(rnh->client_list) - && list_isempty(rnh->zebra_static_route_list)) + && list_isempty(rnh->zebra_static_route_list) + && list_isempty(rnh->zebra_pseudowire_list)) zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE); } @@ -284,6 +288,58 @@ void zebra_deregister_rnh_static_nexthops(vrf_id_t vrf_id, } } +/* XXX move this utility function elsewhere? */ +static void addr2hostprefix(int af, const union g_addr *addr, + struct prefix *prefix) +{ + switch (af) { + case AF_INET: + prefix->family = AF_INET; + prefix->prefixlen = IPV4_MAX_BITLEN; + prefix->u.prefix4 = addr->ipv4; + break; + case AF_INET6: + prefix->family = AF_INET6; + prefix->prefixlen = IPV6_MAX_BITLEN; + prefix->u.prefix6 = addr->ipv6; + break; + default: + zlog_warn("%s: unknown address family %d", __func__, af); + break; + } +} + +void zebra_register_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw) +{ + struct prefix nh; + struct rnh *rnh; + + addr2hostprefix(pw->af, &pw->nexthop, &nh); + rnh = zebra_add_rnh(&nh, vrf_id, RNH_NEXTHOP_TYPE); + if (rnh && !listnode_lookup(rnh->zebra_pseudowire_list, pw)) { + listnode_add(rnh->zebra_pseudowire_list, pw); + pw->rnh = rnh; + zebra_evaluate_rnh(vrf_id, pw->af, 1, RNH_NEXTHOP_TYPE, &nh); + } +} + +void zebra_deregister_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw) +{ + struct rnh *rnh; + + rnh = pw->rnh; + if (!rnh) + return; + + listnode_delete(rnh->zebra_pseudowire_list, pw); + pw->rnh = NULL; + + if (list_isempty(rnh->client_list) + && list_isempty(rnh->zebra_static_route_list) + && list_isempty(rnh->zebra_pseudowire_list)) + zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE); +} + /* Apply the NHT route-map for a client to the route (and nexthops) * resolving a NH. */ @@ -595,6 +651,15 @@ static void zebra_rnh_process_static_routes(vrf_id_t vrfid, int family, } } +static void zebra_rnh_process_pseudowires(vrf_id_t vrfid, struct rnh *rnh) +{ + struct zebra_pw *pw; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(rnh->zebra_pseudowire_list, node, pw)) + zebra_pw_update(pw); +} + /* * See if a tracked nexthop entry has undergone any change, and if so, * take appropriate action; this involves notifying any clients and/or @@ -636,6 +701,9 @@ static void zebra_rnh_eval_nexthop_entry(vrf_id_t vrfid, int family, int force, /* Process static routes attached to this nexthop */ zebra_rnh_process_static_routes(vrfid, family, nrn, rnh, prn, rnh->state); + + /* Process pseudowires attached to this nexthop */ + zebra_rnh_process_pseudowires(vrfid, rnh); } } @@ -694,8 +762,10 @@ static void zebra_rnh_clear_nhc_flag(vrf_id_t vrfid, int family, re = zebra_rnh_resolve_entry(vrfid, family, type, nrn, rnh, &prn); - if (re) + if (re) { UNSET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED); + UNSET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED); + } } /* Evaluate all tracked entries (nexthops or routes for import into BGP) @@ -815,6 +885,7 @@ static void copy_state(struct rnh *rnh, struct route_entry *re, state = XCALLOC(MTYPE_RE, sizeof(struct route_entry)); state->type = re->type; + state->distance = re->distance; state->metric = re->metric; route_entry_copy_nexthops(state, re->nexthop); @@ -830,13 +901,17 @@ static int compare_state(struct route_entry *r1, struct route_entry *r2) if ((!r1 && r2) || (r1 && !r2)) return 1; + if (r1->distance != r2->distance) + return 1; + if (r1->metric != r2->metric) return 1; if (r1->nexthop_num != r2->nexthop_num) return 1; - if (CHECK_FLAG(r1->status, ROUTE_ENTRY_NEXTHOPS_CHANGED)) + if (CHECK_FLAG(r1->status, ROUTE_ENTRY_NEXTHOPS_CHANGED) + || CHECK_FLAG(r1->status, ROUTE_ENTRY_LABELS_CHANGED)) return 1; return 0; @@ -999,5 +1074,7 @@ static void print_rnh(struct route_node *rn, struct vty *vty) if (!list_isempty(rnh->zebra_static_route_list)) vty_out(vty, " zebra%s", rnh->filtered[ZEBRA_ROUTE_STATIC] ? "(filtered)" : ""); + if (!list_isempty(rnh->zebra_pseudowire_list)) + vty_out(vty, " zebra[pseudowires]"); vty_out(vty, "\n"); } diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index f8d89ec8ca..7e183684da 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -42,6 +42,8 @@ struct rnh { struct list * zebra_static_route_list; /* static routes dependent on this NH */ + struct list + *zebra_pseudowire_list; /* pseudowires dependent on this NH */ struct route_node *node; int filtered[ZEBRA_ROUTE_MAX]; /* if this has been filtered for client */ @@ -67,6 +69,8 @@ extern void zebra_deregister_rnh_static_nexthops(vrf_id_t, struct route_node *rn); extern void zebra_deregister_rnh_static_nh(vrf_id_t, struct prefix *, struct route_node *); +extern void zebra_register_rnh_pseudowire(vrf_id_t, struct zebra_pw *); +extern void zebra_deregister_rnh_pseudowire(vrf_id_t, struct zebra_pw *); extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client, rnh_type_t type); extern void zebra_evaluate_rnh(vrf_id_t vrfid, int family, int force, diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 0176b36840..c738cde0ac 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -256,7 +256,7 @@ DEFUN (no_match_ip_nexthop_prefix_len, DEFUN (match_source_protocol, match_source_protocol_cmd, - "match source-protocol <bgp|ospf|rip|ripng|isis|ospf6|connected|system|kernel|static>", + "match source-protocol <bgp|ospf|rip|ripng|isis|ospf6|pim|nhrp|eigrp|babel|connected|system|kernel|static>", MATCH_STR "Match protocol via which the route was learnt\n" "BGP protocol\n" @@ -265,6 +265,10 @@ DEFUN (match_source_protocol, "RIPNG protocol\n" "ISIS protocol\n" "OSPF6 protocol\n" + "PIM protocol\n" + "NHRP protocol\n" + "EIGRP protocol\n" + "BABEL protocol\n" "Routes from directly connected peer\n" "Routes from system configuration\n" "Routes from kernel\n" @@ -284,7 +288,7 @@ DEFUN (match_source_protocol, DEFUN (no_match_source_protocol, no_match_source_protocol_cmd, - "no match source-protocol [<bgp|ospf|rip|ripng|isis|ospf6|connected|system|kernel|static>]", + "no match source-protocol [<bgp|ospf|rip|ripng|isis|ospf6|pim|nhrp|eigrp|babel|connected|system|kernel|static>]", NO_STR MATCH_STR "No match protocol via which the route was learnt\n" @@ -294,6 +298,10 @@ DEFUN (no_match_source_protocol, "RIPNG protocol\n" "ISIS protocol\n" "OSPF6 protocol\n" + "PIM protocol\n" + "NHRP protocol\n" + "EIGRP protocol\n" + "BABEL protocol\n" "Routes from directly connected peer\n" "Routes from system configuration\n" "Routes from kernel\n" diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c index 6cebae997c..dba228ea35 100644 --- a/zebra/zebra_static.c +++ b/zebra/zebra_static.c @@ -24,6 +24,7 @@ #include <lib/nexthop.h> #include <lib/memory.h> #include <lib/srcdest_table.h> +#include <lib/if.h> #include "vty.h" #include "zebra/debug.h" @@ -81,11 +82,11 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, nh_p.u.prefix4 = si->addr.ipv4; zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); break; - case STATIC_IPV4_GATEWAY_IFINDEX: + case STATIC_IPV4_GATEWAY_IFNAME: nexthop = route_entry_nexthop_ipv4_ifindex_add( re, &si->addr.ipv4, NULL, si->ifindex); break; - case STATIC_IFINDEX: + case STATIC_IFNAME: nexthop = route_entry_nexthop_ifindex_add(re, si->ifindex); break; @@ -100,7 +101,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, nh_p.u.prefix6 = si->addr.ipv6; zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); break; - case STATIC_IPV6_GATEWAY_IFINDEX: + case STATIC_IPV6_GATEWAY_IFNAME: nexthop = route_entry_nexthop_ipv6_ifindex_add( re, &si->addr.ipv6, si->ifindex); break; @@ -156,11 +157,11 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, nh_p.u.prefix4 = si->addr.ipv4; zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); break; - case STATIC_IPV4_GATEWAY_IFINDEX: + case STATIC_IPV4_GATEWAY_IFNAME: nexthop = route_entry_nexthop_ipv4_ifindex_add( re, &si->addr.ipv4, NULL, si->ifindex); break; - case STATIC_IFINDEX: + case STATIC_IFNAME: nexthop = route_entry_nexthop_ifindex_add(re, si->ifindex); break; @@ -175,7 +176,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, nh_p.u.prefix6 = si->addr.ipv6; zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn); break; - case STATIC_IPV6_GATEWAY_IFINDEX: + case STATIC_IPV6_GATEWAY_IFNAME: nexthop = route_entry_nexthop_ipv6_ifindex_add( re, &si->addr.ipv6, si->ifindex); break; @@ -214,6 +215,9 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p, } } +/* this works correctly with IFNAME<>IFINDEX because a static route on a + * non-active interface will have IFINDEX_INTERNAL and thus compare false + */ static int static_nexthop_same(struct nexthop *nexthop, struct static_route *si) { if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE @@ -225,12 +229,12 @@ static int static_nexthop_same(struct nexthop *nexthop, struct static_route *si) && IPV4_ADDR_SAME(&nexthop->gate.ipv4, &si->addr.ipv4)) return 1; else if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX - && si->type == STATIC_IPV4_GATEWAY_IFINDEX + && si->type == STATIC_IPV4_GATEWAY_IFNAME && IPV4_ADDR_SAME(&nexthop->gate.ipv4, &si->addr.ipv4) && nexthop->ifindex == si->ifindex) return 1; else if (nexthop->type == NEXTHOP_TYPE_IFINDEX - && si->type == STATIC_IFINDEX + && si->type == STATIC_IFNAME && nexthop->ifindex == si->ifindex) return 1; else if (nexthop->type == NEXTHOP_TYPE_IPV6 @@ -238,7 +242,7 @@ static int static_nexthop_same(struct nexthop *nexthop, struct static_route *si) && IPV6_ADDR_SAME(&nexthop->gate.ipv6, &si->addr.ipv6)) return 1; else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX - && si->type == STATIC_IPV6_GATEWAY_IFINDEX + && si->type == STATIC_IPV6_GATEWAY_IFNAME && IPV6_ADDR_SAME(&nexthop->gate.ipv6, &si->addr.ipv6) && nexthop->ifindex == si->ifindex) return 1; @@ -360,7 +364,7 @@ void static_uninstall_route(afi_t afi, safi_t safi, struct prefix *p, int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, struct prefix_ipv6 *src_p, union g_addr *gate, - ifindex_t ifindex, const char *ifname, u_char flags, + const char *ifname, u_char flags, route_tag_t tag, u_char distance, struct zebra_vrf *zvrf, struct static_nh_label *snh_label) { @@ -376,15 +380,15 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, if (!gate && (type == STATIC_IPV4_GATEWAY - || type == STATIC_IPV4_GATEWAY_IFINDEX + || type == STATIC_IPV4_GATEWAY_IFNAME || type == STATIC_IPV6_GATEWAY - || type == STATIC_IPV6_GATEWAY_IFINDEX)) + || type == STATIC_IPV6_GATEWAY_IFNAME)) return -1; - if (!ifindex - && (type == STATIC_IFINDEX - || type == STATIC_IPV4_GATEWAY_IFINDEX - || type == STATIC_IPV6_GATEWAY_IFINDEX)) + if (!ifname + && (type == STATIC_IFNAME + || type == STATIC_IPV4_GATEWAY_IFNAME + || type == STATIC_IPV6_GATEWAY_IFNAME)) return -1; /* Lookup static route prefix. */ @@ -397,7 +401,7 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, && IPV4_ADDR_SAME(gate, &si->addr.ipv4)) || (afi == AFI_IP6 && IPV6_ADDR_SAME(gate, &si->addr.ipv6)))) - && (!ifindex || ifindex == si->ifindex)) { + && (!strcmp (ifname ? ifname : "", si->ifname))) { if ((distance == si->distance) && (tag == si->tag) && !memcmp(&si->snh_label, snh_label, sizeof(struct static_nh_label)) @@ -411,7 +415,7 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, /* Distance or tag or label changed, delete existing first. */ if (update) - static_delete_route(afi, safi, type, p, src_p, gate, ifindex, + static_delete_route(afi, safi, type, p, src_p, gate, ifname, update->tag, update->distance, zvrf, &update->snh_label); @@ -423,20 +427,20 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, si->flags = flags; si->tag = tag; si->vrf_id = zvrf_id(zvrf); - si->ifindex = ifindex; - if (si->ifindex) - strcpy(si->ifname, ifname); + if (ifname) + strlcpy(si->ifname, ifname, sizeof(si->ifname)); + si->ifindex = IFINDEX_INTERNAL; switch (type) { case STATIC_IPV4_GATEWAY: - case STATIC_IPV4_GATEWAY_IFINDEX: + case STATIC_IPV4_GATEWAY_IFNAME: si->addr.ipv4 = gate->ipv4; break; case STATIC_IPV6_GATEWAY: - case STATIC_IPV6_GATEWAY_IFINDEX: + case STATIC_IPV6_GATEWAY_IFNAME: si->addr.ipv6 = gate->ipv6; break; - case STATIC_IFINDEX: + case STATIC_IFNAME: break; } @@ -471,15 +475,25 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, si->prev = pp; si->next = cp; - /* Install into rib. */ - static_install_route(afi, safi, p, src_p, si); + /* check whether interface exists in system & install if it does */ + if (!ifname) + static_install_route(afi, safi, p, src_p, si); + else { + struct interface *ifp; + + ifp = if_lookup_by_name(ifname, zvrf_id(zvrf)); + if (ifp && ifp->ifindex != IFINDEX_INTERNAL) { + si->ifindex = ifp->ifindex; + static_install_route(afi, safi, p, src_p, si); + } + } return 1; } int static_delete_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, struct prefix_ipv6 *src_p, union g_addr *gate, - ifindex_t ifindex, route_tag_t tag, u_char distance, + const char *ifname, route_tag_t tag, u_char distance, struct zebra_vrf *zvrf, struct static_nh_label *snh_label) { @@ -504,7 +518,7 @@ int static_delete_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, && IPV4_ADDR_SAME(gate, &si->addr.ipv4)) || (afi == AFI_IP6 && IPV6_ADDR_SAME(gate, &si->addr.ipv6)))) - && (!ifindex || ifindex == si->ifindex) + && (!strcmp(ifname ? ifname : "", si->ifname)) && (!tag || (tag == si->tag)) && (!snh_label->num_labels || !memcmp(&si->snh_label, snh_label, @@ -517,8 +531,9 @@ int static_delete_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, return 0; } - /* Install into rib. */ - static_uninstall_route(afi, safi, p, src_p, si); + /* Uninstall from rib. */ + if (!si->ifname[0] || si->ifindex != IFINDEX_INTERNAL) + static_uninstall_route(afi, safi, p, src_p, si); /* Unlink static route from linked list. */ if (si->prev) @@ -536,3 +551,49 @@ int static_delete_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, return 1; } + +static void static_ifindex_update_af(struct interface *ifp, bool up, + afi_t afi, safi_t safi) +{ + struct route_table *stable; + struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id); + struct route_node *rn; + struct static_route *si; + struct prefix *p, *src_pp; + struct prefix_ipv6 *src_p; + + stable = zebra_vrf_static_table(afi, safi, zvrf); + if (!stable) + return; + + for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) { + srcdest_rnode_prefixes(rn, &p, &src_pp); + src_p = (struct prefix_ipv6 *)src_pp; + + for (si = rn->info; si; si = si->next) { + if (!si->ifname[0]) + continue; + if (up) { + if (strcmp(si->ifname, ifp->name)) + continue; + si->ifindex = ifp->ifindex; + static_install_route(afi, safi, p, src_p, si); + } else { + if (si->ifindex != ifp->ifindex) + continue; + static_uninstall_route(afi, safi, p, src_p, + si); + si->ifindex = IFINDEX_INTERNAL; + } + } + } +} + +/* called from if_{add,delete}_update, i.e. when ifindex becomes [in]valid */ +void static_ifindex_update(struct interface *ifp, bool up) +{ + static_ifindex_update_af(ifp, up, AFI_IP, SAFI_UNICAST); + static_ifindex_update_af(ifp, up, AFI_IP, SAFI_MULTICAST); + static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_UNICAST); + static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_MULTICAST); +} diff --git a/zebra/zebra_static.h b/zebra/zebra_static.h index 885774895f..6ab47094a1 100644 --- a/zebra/zebra_static.h +++ b/zebra/zebra_static.h @@ -30,12 +30,12 @@ struct static_nh_label { }; typedef enum { - STATIC_IFINDEX, + STATIC_IFNAME, STATIC_IPV4_GATEWAY, - STATIC_IPV4_GATEWAY_IFINDEX, + STATIC_IPV4_GATEWAY_IFNAME, STATIC_BLACKHOLE, STATIC_IPV6_GATEWAY, - STATIC_IPV6_GATEWAY_IFINDEX, + STATIC_IPV6_GATEWAY_IFNAME, } zebra_static_types; /* Static route information. */ @@ -84,16 +84,18 @@ extern void static_uninstall_route(afi_t afi, safi_t safi, struct prefix *p, extern int static_add_route(afi_t, safi_t safi, u_char type, struct prefix *p, struct prefix_ipv6 *src_p, union g_addr *gate, - ifindex_t ifindex, const char *ifname, u_char flags, + const char *ifname, u_char flags, route_tag_t tag, u_char distance, struct zebra_vrf *zvrf, struct static_nh_label *snh_label); extern int static_delete_route(afi_t, safi_t safi, u_char type, struct prefix *p, struct prefix_ipv6 *src_p, - union g_addr *gate, ifindex_t ifindex, + union g_addr *gate, const char *ifname, route_tag_t tag, u_char distance, struct zebra_vrf *zvrf, struct static_nh_label *snh_label); +extern void static_ifindex_update(struct interface *ifp, bool up); + #endif diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index feca13d3a2..ff140bad67 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -95,51 +95,6 @@ static int zebra_vrf_new(struct vrf *vrf) return 0; } -/* - * Moving an interface amongst different vrf's - * causes the interface to get a new ifindex - * so we need to find static routes with - * the old ifindex and replace with new - * ifindex to insert back into the table - */ -void zebra_vrf_static_route_interface_fixup(struct interface *ifp) -{ - afi_t afi; - safi_t safi; - struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id); - struct route_table *stable = NULL; - struct route_node *rn = NULL; - struct static_route *si = NULL; - - if (!zvrf) - return; - - for (afi = AFI_IP; afi < AFI_MAX; afi++) { - for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { - stable = zvrf->stable[afi][safi]; - if (stable) - for (rn = route_top(stable); rn; - rn = route_next(rn)) { - if (rn->info) { - si = rn->info; - if ((strcmp(si->ifname, - ifp->name) - == 0) - && (si->ifindex - != ifp->ifindex)) { - si->ifindex = - ifp->ifindex; - static_install_route( - afi, safi, - &rn->p, NULL, - si); - } - } - } - } - } -} - /* Callback upon enabling a VRF. */ static int zebra_vrf_enable(struct vrf *vrf) { @@ -248,6 +203,7 @@ static int zebra_vrf_delete(struct vrf *vrf) zebra_vxlan_close_tables(zvrf); zebra_mpls_close_tables(zvrf); + zebra_pw_exit(zvrf); for (ALL_LIST_ELEMENTS_RO(vrf->iflist, node, ifp)) if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp); @@ -417,6 +373,7 @@ struct zebra_vrf *zebra_vrf_alloc(void) zebra_vxlan_init_tables(zvrf); zebra_mpls_init_tables(zvrf); + zebra_pw_init(zvrf); return zvrf; } diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index eb0687bf8a..dca53bb9f3 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -23,6 +23,7 @@ #define __ZEBRA_RIB_H__ #include <zebra/zebra_ns.h> +#include <zebra/zebra_pw.h> /* MPLS (Segment Routing) global block */ typedef struct mpls_srgb_t_ { @@ -89,6 +90,10 @@ struct zebra_vrf { /* MPLS Segment Routing Global block */ mpls_srgb_t mpls_srgb; + /* Pseudowires. */ + struct zebra_pw_head pseudowires; + struct zebra_static_pw_head static_pseudowires; + /* MPLS processing flags */ u_int16_t mpls_flags; #define MPLS_FLAG_SCHEDULE_LSPS (1 << 0) @@ -124,7 +129,6 @@ struct route_table *zebra_vrf_table_with_table_id(afi_t afi, safi_t safi, vrf_id_t vrf_id, u_int32_t table_id); -extern void zebra_vrf_static_route_interface_fixup(struct interface *ifp); extern void zebra_vrf_update_all(struct zserv *client); extern struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id); extern struct zebra_vrf *zebra_vrf_lookup_by_name(const char *); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index e8b82ecf90..e260338131 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -55,9 +55,6 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, int mcast); -#define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND 60*60*24*7 - /* VNI range as per RFC 7432 */ #define CMD_VNI_RANGE "(1-16777215)" @@ -80,7 +77,6 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, u_char flag = 0; route_tag_t tag = 0; struct zebra_vrf *zvrf; - unsigned int ifindex = 0; u_char type; struct static_nh_label snh_label; @@ -207,26 +203,15 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, gatep = &gate; } - if (ifname) { - struct interface *ifp; - ifp = if_lookup_by_name(ifname, zvrf_id(zvrf)); - if (!ifp) { - vty_out(vty, "%% Malformed Interface name %s\n", - ifname); - ifindex = IFINDEX_DELETED; - } else - ifindex = ifp->ifindex; - } - if (gate_str == NULL && ifname == NULL) type = STATIC_BLACKHOLE; else if (gate_str && ifname) { if (afi == AFI_IP) - type = STATIC_IPV4_GATEWAY_IFINDEX; + type = STATIC_IPV4_GATEWAY_IFNAME; else - type = STATIC_IPV6_GATEWAY_IFINDEX; + type = STATIC_IPV6_GATEWAY_IFNAME; } else if (ifname) - type = STATIC_IFINDEX; + type = STATIC_IFNAME; else { if (afi == AFI_IP) type = STATIC_IPV4_GATEWAY; @@ -235,10 +220,10 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi, } if (!negate) - static_add_route(afi, safi, type, &p, src_p, gatep, ifindex, - ifname, flag, tag, distance, zvrf, &snh_label); + static_add_route(afi, safi, type, &p, src_p, gatep, ifname, + flag, tag, distance, zvrf, &snh_label); else - static_delete_route(afi, safi, type, &p, src_p, gatep, ifindex, + static_delete_route(afi, safi, type, &p, src_p, gatep, ifname, tag, distance, zvrf, &snh_label); return CMD_SUCCESS; @@ -540,6 +525,9 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, break; } + if (re->nexthop_mtu) + vty_out(vty, ", mtu %u", re->nexthop_mtu); + /* Label information */ if (nexthop->nh_label && nexthop->nh_label->num_labels) { @@ -586,8 +574,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) json_object_boolean_true_add(json_route, "selected"); - if (re->type != ZEBRA_ROUTE_CONNECT - && re->type != ZEBRA_ROUTE_KERNEL) { + if (re->type != ZEBRA_ROUTE_CONNECT) { json_object_int_add(json_route, "distance", re->distance); json_object_int_add(json_route, "metric", re->metric); @@ -774,8 +761,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, srcdest_rnode2str(rn, buf, sizeof buf)); /* Distance and metric display. */ - if (re->type != ZEBRA_ROUTE_CONNECT - && re->type != ZEBRA_ROUTE_KERNEL) + if (re->type != ZEBRA_ROUTE_CONNECT) len += vty_out(vty, " [%d/%d]", re->distance, re->metric); } else @@ -1704,7 +1690,7 @@ static int static_config(struct vty *vty, afi_t afi, safi_t safi, &si->addr.ipv6, buf, sizeof buf)); break; - case STATIC_IFINDEX: + case STATIC_IFNAME: vty_out(vty, " %s", si->ifname); break; /* blackhole and Null0 mean the same thing */ @@ -1714,7 +1700,7 @@ static int static_config(struct vty *vty, afi_t afi, safi_t safi, else vty_out(vty, " Null0"); break; - case STATIC_IPV4_GATEWAY_IFINDEX: + case STATIC_IPV4_GATEWAY_IFNAME: vty_out(vty, " %s %s", inet_ntop(AF_INET, &si->addr.ipv4, buf, @@ -1722,7 +1708,7 @@ static int static_config(struct vty *vty, afi_t afi, safi_t safi, ifindex2ifname(si->ifindex, si->vrf_id)); break; - case STATIC_IPV6_GATEWAY_IFINDEX: + case STATIC_IPV6_GATEWAY_IFNAME: vty_out(vty, " %s %s", inet_ntop(AF_INET6, &si->addr.ipv6, buf, diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index c96f073064..7d265af309 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -469,7 +469,7 @@ static int zvni_macip_send_msg_to_client(struct zebra_vrf *zvrf, vni_t vni, zserv_create_header(s, cmd, zvrf_id(zvrf)); stream_putl(s, vni); - stream_put(s, macaddr->octet, ETHER_ADDR_LEN); + stream_put(s, macaddr->octet, ETH_ALEN); if (ip) { ipa_len = 0; if (IS_IPADDR_V4(ip)) @@ -776,18 +776,9 @@ static void zvni_install_neigh_hash(struct hash_backet *backet, void *ctxt) static unsigned int mac_hash_keymake(void *p) { zebra_mac_t *pmac = p; - char *pnt = (char *)pmac->macaddr.octet; - unsigned int key = 0; - int c = 0; + const void *pnt = (void *)pmac->macaddr.octet; - key += pnt[c]; - key += pnt[c + 1]; - key += pnt[c + 2]; - key += pnt[c + 3]; - key += pnt[c + 4]; - key += pnt[c + 5]; - - return (key); + return jhash(pnt, ETH_ALEN, 0xa5a5a55a); } /* @@ -805,7 +796,7 @@ static int mac_cmp(const void *p1, const void *p2) return 0; return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet, - ETHER_ADDR_LEN) + ETH_ALEN) == 0); } @@ -832,7 +823,7 @@ static zebra_mac_t *zvni_mac_add(zebra_vni_t *zvni, struct ethaddr *macaddr) zebra_mac_t *mac = NULL; memset(&tmp_mac, 0, sizeof(zebra_mac_t)); - memcpy(&tmp_mac.macaddr, macaddr, ETHER_ADDR_LEN); + memcpy(&tmp_mac.macaddr, macaddr, ETH_ALEN); mac = hash_get(zvni->mac_table, &tmp_mac, zvni_mac_alloc); assert(mac); @@ -940,7 +931,7 @@ static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *mac) zebra_mac_t *pmac; memset(&tmp, 0, sizeof(tmp)); - memcpy(&tmp.macaddr, mac, ETHER_ADDR_LEN); + memcpy(&tmp.macaddr, mac, ETH_ALEN); pmac = hash_lookup(zvni->mac_table, &tmp); return pmac; @@ -1976,7 +1967,7 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, if (n) { if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { if (memcmp(n->emac.octet, macaddr->octet, - ETHER_ADDR_LEN) + ETH_ALEN) == 0) { if (n->ifindex == ifp->ifindex) /* we're not interested in whatever has @@ -2022,7 +2013,7 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, /* Set "local" forwarding info. */ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); - memcpy(&n->emac, macaddr, ETHER_ADDR_LEN); + memcpy(&n->emac, macaddr, ETH_ALEN); n->ifindex = ifp->ifindex; /* Inform BGP if required. */ @@ -2062,14 +2053,14 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, int sock, u_short length, n = NULL; memset(&ip, 0, sizeof(ip)); vni = (vni_t)stream_getl(s); - stream_get(&macaddr.octet, s, ETHER_ADDR_LEN); + stream_get(&macaddr.octet, s, ETH_ALEN); ipa_len = stream_getl(s); if (ipa_len) { ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4 : IPADDR_V6; stream_get(&ip.ip.addr, s, ipa_len); } - l += 4 + ETHER_ADDR_LEN + 4 + ipa_len; + l += 4 + ETH_ALEN + 4 + ipa_len; vtep_ip.s_addr = stream_get_ipv4(s); l += IPV4_MAX_BYTELEN; @@ -2148,7 +2139,7 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, int sock, u_short length, */ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE) && (memcmp(n->emac.octet, macaddr.octet, - ETHER_ADDR_LEN) + ETH_ALEN) == 0)) { zvni_neigh_uninstall(zvni, n); zvni_neigh_del(zvni, n); @@ -2205,14 +2196,14 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, int sock, u_short length, n = NULL; memset(&ip, 0, sizeof(ip)); vni = (vni_t)stream_getl(s); - stream_get(&macaddr.octet, s, ETHER_ADDR_LEN); + stream_get(&macaddr.octet, s, ETH_ALEN); ipa_len = stream_getl(s); if (ipa_len) { ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4 : IPADDR_V6; stream_get(&ip.ip.addr, s, ipa_len); } - l += 4 + ETHER_ADDR_LEN + 4 + ipa_len; + l += 4 + ETH_ALEN + 4 + ipa_len; vtep_ip.s_addr = stream_get_ipv4(s); l += IPV4_MAX_BYTELEN; @@ -2363,7 +2354,7 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, int sock, u_short length, /* Set "remote" forwarding info. */ UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); /* TODO: Handle MAC change. */ - memcpy(&n->emac, &macaddr, ETHER_ADDR_LEN); + memcpy(&n->emac, &macaddr, ETH_ALEN); n->r_vtep_ip = vtep_ip; SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE); diff --git a/zebra/zserv.c b/zebra/zserv.c index 3bc5f83f64..bdb7755b63 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -55,6 +55,7 @@ #include "zebra/zebra_mroute.h" #include "zebra/label_manager.h" #include "zebra/zebra_vxlan.h" +#include "zebra/rt.h" /* Event list of zebra. */ enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE }; @@ -1084,6 +1085,27 @@ int zsend_router_id_update(struct zserv *client, struct prefix *p, return zebra_server_send_message(client); } +/* + * Function used by Zebra to send a PW status update to LDP daemon + */ +int zsend_pw_update(struct zserv *client, struct zebra_pw *pw) +{ + struct stream *s; + + s = client->obuf; + stream_reset(s); + + zserv_create_header(s, ZEBRA_PW_STATUS_UPDATE, pw->vrf_id); + stream_write(s, pw->ifname, IF_NAMESIZE); + stream_putl(s, pw->ifindex); + stream_putl(s, pw->status); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return zebra_server_send_message(client); +} + /* Register zebra server interface information. Send current all interface and address information. */ static int zread_interface_add(struct zserv *client, u_short length, @@ -1876,14 +1898,12 @@ static void zread_mpls_labels(int command, struct zserv *client, u_short length, if (command == ZEBRA_MPLS_LABELS_ADD) { mpls_lsp_install(zvrf, type, in_label, out_label, gtype, &gate, ifindex); - if (out_label != MPLS_IMP_NULL_LABEL) - mpls_ftn_update(1, zvrf, type, &prefix, gtype, &gate, - ifindex, distance, out_label); + mpls_ftn_update(1, zvrf, type, &prefix, gtype, &gate, ifindex, + distance, out_label); } else if (command == ZEBRA_MPLS_LABELS_DELETE) { mpls_lsp_uninstall(zvrf, type, in_label, gtype, &gate, ifindex); - if (out_label != MPLS_IMP_NULL_LABEL) - mpls_ftn_update(0, zvrf, type, &prefix, gtype, &gate, - ifindex, distance, out_label); + mpls_ftn_update(0, zvrf, type, &prefix, gtype, &gate, ifindex, + distance, out_label); } } /* Send response to a label manager connect request to client */ @@ -2038,6 +2058,97 @@ static void zread_label_manager_request(int cmd, struct zserv *client, } } +static int zread_pseudowire(int command, struct zserv *client, u_short length, + vrf_id_t vrf_id) +{ + struct stream *s; + struct zebra_vrf *zvrf; + char ifname[IF_NAMESIZE]; + ifindex_t ifindex; + int type; + int af; + union g_addr nexthop; + uint32_t local_label; + uint32_t remote_label; + uint8_t flags; + union pw_protocol_fields data; + uint8_t protocol; + struct zebra_pw *pw; + + zvrf = vrf_info_lookup(vrf_id); + if (!zvrf) + return -1; + + /* Get input stream. */ + s = client->ibuf; + + /* Get data. */ + stream_get(ifname, s, IF_NAMESIZE); + ifindex = stream_getl(s); + type = stream_getl(s); + af = stream_getl(s); + switch (af) { + case AF_INET: + nexthop.ipv4.s_addr = stream_get_ipv4(s); + break; + case AF_INET6: + stream_get(&nexthop.ipv6, s, 16); + break; + default: + return -1; + } + local_label = stream_getl(s); + remote_label = stream_getl(s); + flags = stream_getc(s); + stream_get(&data, s, sizeof(data)); + protocol = client->proto; + + pw = zebra_pw_find(zvrf, ifname); + switch (command) { + case ZEBRA_PW_ADD: + if (pw) { + zlog_warn("%s: pseudowire %s already exists [%s]", + __func__, ifname, + zserv_command_string(command)); + return -1; + } + + zebra_pw_add(zvrf, ifname, protocol, client); + break; + case ZEBRA_PW_DELETE: + if (!pw) { + zlog_warn("%s: pseudowire %s not found [%s]", __func__, + ifname, zserv_command_string(command)); + return -1; + } + + zebra_pw_del(zvrf, pw); + break; + case ZEBRA_PW_SET: + case ZEBRA_PW_UNSET: + if (!pw) { + zlog_warn("%s: pseudowire %s not found [%s]", __func__, + ifname, zserv_command_string(command)); + return -1; + } + + switch (command) { + case ZEBRA_PW_SET: + pw->enabled = 1; + break; + case ZEBRA_PW_UNSET: + pw->enabled = 0; + break; + } + + zebra_pw_change(pw, ifindex, type, af, &nexthop, local_label, + remote_label, flags, &data); + break; + } + + return 0; +} + /* Cleanup registered nexthops (across VRFs) upon client disconnect. */ static void zebra_client_close_cleanup_rnh(struct zserv *client) { @@ -2082,6 +2193,9 @@ static void zebra_client_close(struct zserv *client) zebra_mpls_cleanup_fecs_for_client(vrf_info_lookup(VRF_DEFAULT), client); + /* Remove pseudowires associated with this client */ + zebra_pw_client_close(client); + /* Close file descriptor. */ if (client->sock) { unsigned long nroutes; @@ -2164,6 +2278,31 @@ static void zebra_client_create(int sock) zebra_vrf_update_all(client); } +static int zread_interface_set_master(struct zserv *client, int sock, + u_short length) +{ + struct interface *master; + struct interface *slave; + struct stream *s = client->ibuf; + int ifindex; + vrf_id_t vrf_id; + + vrf_id = stream_getw(s); + ifindex = stream_getl(s); + master = if_lookup_by_index(ifindex, vrf_id); + + vrf_id = stream_getw(s); + ifindex = stream_getl(s); + slave = if_lookup_by_index(ifindex, vrf_id); + + if (!master || !slave) + return 0; + + kernel_interface_set_master(master, slave); + + return 1; +} + /* Handler of zebra service request. */ static int zebra_client_read(struct thread *thread) { @@ -2407,6 +2546,15 @@ static int zebra_client_read(struct thread *thread) case ZEBRA_REMOTE_MACIP_DEL: zebra_vxlan_remote_macip_del(client, sock, length, zvrf); break; + case ZEBRA_INTERFACE_SET_MASTER: + zread_interface_set_master(client, sock, length); + break; + case ZEBRA_PW_ADD: + case ZEBRA_PW_DELETE: + case ZEBRA_PW_SET: + case ZEBRA_PW_UNSET: + zread_pseudowire(command, client, length, vrf_id); + break; default: zlog_info("Zebra received unknown command %d", command); break; @@ -2618,10 +2766,6 @@ static char *zserv_time_buf(time_t *time1, char *buf, int buflen) now -= *time1; tm = gmtime(&now); -/* Making formatted timer strings. */ -#define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND 60*60*24*7 - if (now < ONE_DAY_SECOND) snprintf(buf, buflen, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); diff --git a/zebra/zserv.h b/zebra/zserv.h index a2cf5d9f41..f661572d53 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -30,6 +30,8 @@ #include "zclient.h" #include "zebra/zebra_ns.h" +#include "zebra/zebra_pw.h" + /* Default port information. */ #define ZEBRA_VTY_PORT 2601 @@ -175,6 +177,7 @@ extern int zsend_interface_vrf_update(struct zserv *, struct interface *, vrf_id_t); extern int zsend_interface_link_params(struct zserv *, struct interface *); +extern int zsend_pw_update(struct zserv *, struct zebra_pw *); extern pid_t pid; |
