## 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
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
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);
{
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;
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;
{
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 */
{
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);
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);
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);
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);
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",
} 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 {
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
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)
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));
/* 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);
/* 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);
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;
}
/* 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],
}
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))
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 */
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. */
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))
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;
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);
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;
/* 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 {
{
struct stream *s;
iana_afi_t pkt_afi;
- safi_t pkt_safi;
+ iana_safi_t pkt_safi;
if (DISABLE_BGP_ANNOUNCE)
return NULL;
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;
{
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);
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. */
{
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;
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;
{
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
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)
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;
}
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);
}
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);
/* 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);
case SAFI_MPLS_VPN:
return BGP_VPNV4_NODE;
break;
+ default:
+ /* not expected */
+ return BGP_IPV4_NODE;
+ break;
}
break;
case AFI_IP6:
case SAFI_MPLS_VPN:
return BGP_VPNV6_NODE;
break;
+ default:
+ /* not expected */
+ return BGP_IPV4_NODE;
+ break;
}
break;
case AFI_L2VPN:
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;
}
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) {
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.
}
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).
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;
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) {
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;
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);
#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
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;
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);
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 */
/* 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;
if (pEncap->value[1] == 14) {
memcpy(l2o->macaddr.octet,
pEncap->value + 2,
- ETHER_ADDR_LEN);
+ ETH_ALEN);
l2o->label =
((pEncap->value[10]
>> 4)
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(
case SAFI_ENCAP:
return rfapiBgpInfoFilteredImportEncap;
+
+ default:
+ /* not expected */
+ return NULL;
}
zlog_err("%s: bad safi %d", __func__, safi);
return NULL;
(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);
}
/*
* 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]);
}
/* 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(
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",
adb->u.s.prefix_eth.u
.prefix_eth
.octet,
- ETHER_ADDR_LEN)) {
+ ETH_ALEN)) {
continue;
}
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.
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.
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)
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
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"
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
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"
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
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 --------------------------
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 ------------------------------------
}]])],[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 ---------------------------------------------------------------
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 ------------------
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=""
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
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)
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 ---------------------------
)
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
@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
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)
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)
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;
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++)
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++)
{
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;
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;
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;
}
{
struct eigrp_header *eigrph;
+ stream_reset(s);
eigrph = (struct eigrp_header *)STREAM_DATA(s);
eigrph->version = (u_char)EIGRP_HEADER_VERSION;
}
}
+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;
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];
/* 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)
-Makefile
+!Makefile
Makefile.in
*.o
tags
--- /dev/null
+all: ALWAYS
+ @$(MAKE) -s -C .. fpm/libfrrfpm_pb.la
+%: ALWAYS
+ @$(MAKE) -s -C .. fpm/$@
+
+Makefile:
+ #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
+++ /dev/null
-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
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
+syntax = "proto2";
+
//
// Protobuf definitions pertaining to the Forwarding Plane Manager component.
//
--- /dev/null
+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
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) \
* 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;
}
return 1;
}
+#endif
/*
* Compute the actual count of nodes by traversing the tree and
* detect a mismatch.
*/
+#ifdef EXTREME_DICT_DEBUG
static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root)
{
if (root == nil)
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
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 */
return 0;
if (verify_node_count(nil, root) != dict_count(dict))
return 0;
+#endif
return 1;
}
#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"
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 {
/* 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);
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);
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));
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));
&& (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",
}
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");
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 */
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));
*/
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));
#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"
#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"
#include "vty.h"
#include "if.h"
#include "qobj.h"
+#include "prefix.h"
#include "isis_constants.h"
#include "isis_common.h"
u_char passwd[255];
};
-/*
- * (Dynamic) Hostname
- * one struct for cache list
- * one struct for LSP TLV
- */
-struct hostname {
- u_char namelen;
- u_char name[255];
-};
-
/*
* Supported Protocol IDs
*/
((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
#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"
#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"
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)
return;
listnode_delete(dyn_cache, dyn);
XFREE(MTYPE_ISIS_DYNHN, dyn);
- return;
}
/*
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),
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);
#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"
#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"
#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 ? */
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)
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;
}
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));
}
/*
* 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 {
* 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;
}
* 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;
}
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);
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);
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) {
/*
}
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;
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);
- }
}
/*
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;
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)
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
}
/* 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';
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 */
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;
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;
}
/*
*/
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);
* 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(
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 {
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))
/* 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:
}
}
- 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;
}
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);
/* 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);
&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.",
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)
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.",
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;
}
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);
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;
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);
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;
* 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);
/*
* 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
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],
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;
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;
#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? */
/* 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);
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);
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
(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);
#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 */
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")
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)
#include "hash.h"
#include "if.h"
#include "command.h"
+#include "log_int.h"
#include "isisd/dict.h"
#include "isisd/isis_constants.h"
#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"
/* 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];
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
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, ", ");
}
return nlpidstring;
}
-/*
- * 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
*/
*/
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)
dyn = dynhn_find_by_id(sysid);
if (dyn)
- return (const char *)dyn->name.name;
+ return dyn->hostname;
return sysid_print(sysid);
}
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");
+}
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);
/*
* misc functions
*/
-int speaks(struct nlpids *nlpids, int family);
unsigned long isis_jitter(unsigned long timer, unsigned long jitter);
const char *unix_hostname(void);
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
#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)
{
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;
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) {
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)
{
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);
}
#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
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);
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,
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
#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"
#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)
-{
- 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)
+static int ack_lsp(struct isis_lsp_hdr *hdr, struct isis_circuit *circuit,
+ int level)
{
- 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);
&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) {
/* (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,
}
/* 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 */
}
/* 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
}
}
/* 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,
}
/* 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,
"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,
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);
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;
-
- 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 (circuit->circ_type != CIRCUIT_T_BROADCAST) {
- zlog_warn("lan hello on non broadcast circuit");
- return ISIS_WARNING;
- }
-
- if ((stream_get_endp(circuit->rcv_stream)
- - stream_get_getp(circuit->rcv_stream))
- < ISIS_LANHELLO_HDRLEN) {
- zlog_warn("Packet too short");
- return ISIS_WARNING;
- }
-
- if (circuit->ext_domain) {
- zlog_debug(
- "level %d LAN Hello received over circuit with "
- "externalDomain = true",
- level);
- return ISIS_WARNING;
- }
-
- if (!accept_level(level, circuit->is_type)) {
- if (isis->debugs & DEBUG_ADJ_PACKETS) {
- zlog_debug(
- "ISIS-Adj (%s): Interface level mismatch, %s",
- circuit->area->area_tag,
- circuit->interface->name);
+ 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;
}
- return ISIS_WARNING;
- }
+ isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING, NULL);
-#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);
+ 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);
+ }
}
- 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)) {
- 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);
- 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);
- /*
- * 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);
+ 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);
- 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) {
- zlog_err("Level %d LAN Hello with Circuit Type %d", level,
- hdr.circuit_t);
- return ISIS_ERROR;
- }
+ /* 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);
/*
- * Then get the tlvs
+ * If the snpa for this circuit is found from LAN Neighbours TLV
+ * we have two-way communication -> adjacency can be put to state "up"
*/
- 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");
- 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;
- goto out;
- }
-
- if (!(found & TLVFLAG_NLPID)) {
- zlog_warn(
- "No supported protocols TLV in Level %d LAN IS to IS hello",
- level);
- retval = ISIS_WARNING;
- 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;
+ 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");
}
- }
-
- 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;
- }
-
- /*
- * 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 (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);
+ } else {
+ if (!own_snpa_found) {
+ isis_adj_state_change(
+ adj, ISIS_ADJ_INITIALIZING,
+ "own SNPA not found in LAN Neighbours TLV");
}
- 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);
+ if (adj->adj_state == ISIS_ADJ_UP && changed)
+ lsp_regenerate_schedule(adj->circuit->area, iih->level, 0);
- retval = ISIS_OK;
- goto 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",
+ 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;
+}
- /*
- * 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;
- }
+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 (!v6_usable)
- zlog_warn(
- "ISIS-Adj: IPv6 addresses present but no link-local "
- "in LAN IIH from %s\n",
- circuit->interface->name);
- }
+ if (pdu_len < stream_get_endp(circuit->rcv_stream))
+ stream_set_endp(circuit->rcv_stream, pdu_len);
+ return 0;
+}
- 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);
+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 (!v6_usable && !v4_usable) {
- free_tlvs(&tlvs);
- return ISIS_WARNING;
+ 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;
+ }
- 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;
+ if (circuit->ext_domain) {
+ zlog_debug(
+ "level %d LAN Hello received over circuit with externalDomain = true",
+ level);
+ return ISIS_WARNING;
}
- 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);
+ 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);
}
- break;
+ return ISIS_WARNING;
}
+ }
- adj->hold_time = hdr.hold_time;
- adj->last_upd = time(NULL);
- adj->prio[level - 1] = hdr.prio;
+ struct iih_info iih = {
+ .circuit = circuit, .ssnpa = ssnpa, .level = level};
- memcpy(adj->lanid, hdr.lan_id, ISIS_SYS_ID_LEN + 1);
+ /* 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);
- tlvs_to_adj_area_addrs(&tlvs, adj);
+ 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);
+ }
- /* which protocol are spoken ??? */
- if (tlvs_to_adj_nlpids(&tlvs, adj)) {
- retval = ISIS_WARNING;
- goto out;
+ if (pdu_len_validate(iih.pdu_len, circuit)) {
+ zlog_warn(
+ "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;
}
- /* we need to copy addresses to the adj */
- if (found & TLVFLAG_IPV4_ADDR)
- tlvs_to_adj_ipv4_addrs(&tlvs, adj);
+ if (!p2p_hello && !(level & iih.circ_type)) {
+ zlog_err("Level %d LAN Hello with Circuit Type %d", level,
+ iih.circ_type);
+ return ISIS_ERROR;
+ }
- if (found & TLVFLAG_IPV6_ADDR)
- tlvs_to_adj_ipv6_addrs(&tlvs, adj);
+ const char *error_log;
+ int retval = ISIS_WARNING;
- adj->circuit_t = hdr.circuit_t;
+ 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;
+ }
- bool mt_set_changed =
- tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj);
+ if (!iih.tlvs->area_addresses.count) {
+ zlog_warn("No Area addresses TLV in %s", pdu_name);
+ goto out;
+ }
- /* 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 (!iih.tlvs->protocols_supported.count) {
+ zlog_warn("No supported protocols TLV in %s", pdu_name);
+ goto out;
+ }
- /*
- * 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 (!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 (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");
+ 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;
+ }
+
+ 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);
}
- } else if (adj->adj_state == ISIS_ADJ_UP) {
- isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING,
- "no LAN Neighbours TLV found");
+ goto out;
}
- if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed)
- lsp_regenerate_schedule(adj->circuit->area, level, 0);
+ iih.v4_usable = (circuit->ip_addrs && listcount(circuit->ip_addrs)
+ && iih.tlvs->ipv4_address.count);
-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));
- }
+ iih.v6_usable = (circuit->ipv6_link && listcount(circuit->ipv6_link)
+ && iih.tlvs->ipv6_address.count);
+
+ if (!iih.v4_usable && !iih.v6_usable)
+ goto out;
- free_tlvs(&tlvs);
+ retval = p2p_hello ? process_p2p_hello(&iih) : process_lan_hello(&iih);
+out:
+ isis_free_tlvs(iih.tlvs);
return retval;
}
* 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(
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;
}
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;
/* 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
|| ((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 */
/* 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 */
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);
}
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 */
* 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 */
* 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]);
}
/* 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);
/* 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);
}
ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
}
}
+
+ retval = ISIS_OK;
+
+out:
+ isis_free_tlvs(tlvs);
return retval;
}
* 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) {
}
/* 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",
}
/* 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",
/* 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) {
}
}
- /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented */
-
- /* 7.3.15.2 a) 9 - Passwords for level 2 - not implemented */
-
- memset(&tlvs, 0, sizeof(struct tlvs));
+ struct isis_tlvs *tlvs;
+ int retval = ISIS_WARNING;
+ const char *error_log;
- /* 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);
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;
}
/*
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;
+ }
+
+ 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 ((hdr->idrp != ISO10589_ISIS) && (hdr->idrp != ISO9542_ESIS)) {
- zlog_err("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp);
+ 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;
}
}
/* 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;
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)
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
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->pad_hellos)
- if (tlv_add_padding(circuit->snd_stream))
- return ISIS_WARNING;
+ if (circuit->ip_router && circuit->ip_addrs)
+ isis_tlvs_add_ipv4_addresses(tlvs, circuit->ip_addrs);
- 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) {
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",
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;
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) {
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;
}
*/
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;
}
}
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)
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;
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);
- if (listcount(list) == 0) {
- list_delete(list);
+ 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 (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) {
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;
}
* 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)
* 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)
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));
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;
-}
#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
/*
#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
/*
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 */
#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"
#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"
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(
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(
#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"
#include "if.h"
#include "table.h"
#include "spf_backoff.h"
+#include "jhash.h"
#include "isis_constants.h"
#include "isis_common.h"
#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"
#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;
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)) {
} 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();
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;
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;
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;
}
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;
}
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",
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);
}
/*
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
*/
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;
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;
}
{
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) */
/* 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))
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)
}
/* c) */
- vertex = isis_find_vertex(spftree->paths, id, vtype);
+ vertex = isis_find_vertex(&spftree->paths, id, vtype);
if (vertex) {
#ifdef EXTREME_DEBUG
zlog_debug(
return;
}
- vertex = isis_find_vertex(spftree->tents, id, vtype);
+ vertex = isis_find_vertex(&spftree->tents, id, vtype);
/* d) */
if (vertex) {
/* 1) */
} 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))
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;
#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);
}
}
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:
->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)",
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)",
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
{
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",
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;
u_char *sysid)
{
int retval = ISIS_OK;
- struct listnode *node;
struct isis_vertex *vertex;
struct isis_vertex *root_vertex;
struct isis_spftree *spftree = NULL;
/*
* 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(
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);
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;
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), "", "");
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");
}
{
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);
+}
#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);
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 */
#include "md5.h"
#include "sockunion.h"
#include "network.h"
+#include "sbuf.h"
#include "isisd/dict.h"
#include "isisd/isis_constants.h"
#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"
/* 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");
}
/* 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;
return 0;
}
- mtc->length = (u_char)length;
+ mtc->length = (uint8_t)length;
return mtc->length;
}
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]);
}
}
* 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;
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;
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;
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;
}
}
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)) {
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;
}
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)
/* 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 *);
+++ /dev/null
-/*
- * 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;
-}
+++ /dev/null
-/*
- * 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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
#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"
#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"
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",
{
struct listnode *node, *node2;
struct isis_area *area;
- struct isis_spftree *spftree;
int level;
if (isis == NULL) {
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
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");
/* 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;
return 1;
checksum = fletcher_checksum(buffer, len, offset);
- if (checksum == csum)
+ if (checksum == htons(csum))
return 0;
return 1;
}
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__);
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);
}
l2vpn_pw_init(struct l2vpn_pw *pw)
{
struct fec fec;
+ struct zapi_pw zpw;
l2vpn_pw_reset(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
{
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;
}
}
+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)
{
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));
}
}
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 +
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) {
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;
}
}
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) {
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;
}
}
*/
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;
}
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;
}
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);
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);
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);
pw = (struct l2vpn_pw *) fn->data;
if (pw == NULL)
continue;
+ pw->remote_status = PW_NOT_FORWARDING;
break;
default:
break;
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);
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;
#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
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")
{
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"
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")
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"
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"
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"
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")
{
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"
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"
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"
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")
{
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"
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")
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")
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"
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"
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"
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"
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")
{
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")
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")
{
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")
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")
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")
{
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")
{
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")
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")
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"
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")
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"
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")
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")
{
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")
{
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"
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"
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"
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"
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;
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
}
}
+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)
{
}
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
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)
{
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
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 +
#include "prefix.h"
#include "filter.h"
#include "vty.h"
+#include "pw.h"
+#include "zclient.h"
#include "ldp.h"
#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
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,
IMSG_DEBUG_UPDATE,
IMSG_LOG,
IMSG_ACL_CHECK,
- IMSG_INIT
+ IMSG_INIT,
+ IMSG_PW_UPDATE
};
struct ldpd_init {
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);
unsigned int ifindex;
uint32_t remote_group;
uint16_t remote_mtu;
+ uint32_t local_status;
uint32_t remote_status;
uint8_t flags;
QOBJ_FIELDS
#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;
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;
unsigned short ifindex;
int flags;
int operative;
- uint8_t mac[ETHER_ADDR_LEN];
+ uint8_t mac[ETH_ALEN];
int mtu;
};
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);
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);
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);
-Makefile
+!Makefile
Makefile.in
*.o
*.lo
--- /dev/null
+all: ALWAYS
+ @$(MAKE) -s -C .. lib/libfrr.la
+%: ALWAYS
+ @$(MAKE) -s -C .. lib/$@
+
+Makefile:
+ #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
+++ /dev/null
-## 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
"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,
vty_config_unlock(vty);
break;
case INTERFACE_NODE:
+ case PW_NODE:
case NS_NODE:
case VRF_NODE:
case ZEBRA_NODE:
break;
case CONFIG_NODE:
case INTERFACE_NODE:
+ case PW_NODE:
case NS_NODE:
case VRF_NODE:
case ZEBRA_NODE:
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 */
#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
break;
case START_TKN:
- case END_TKN:
case JOIN_TKN:
/* "<foo|bar> WORD" -> word is not "bar" or "foo" */
prevname = NULL;
cmd_token_varname_set(tailtok, jointok->varname);
}
break;
+
+ case END_TKN:
+ return;
}
for (i = 0; i < vector_active(gn->to); i++) {
%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
/* 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
%option noyywrap
%option noinput
%option nounput
-%option outfile="defun_lex.c"
+%option outfile="lib/defun_lex.c"
%option prefix="def_yy"
%option 8bit
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)
/* 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
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;
/* 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 *);
/* Architectual Constants */
#ifdef DEBUG
-#define OSPF_LS_REFRESH_TIME 60
+#define OSPF_LS_REFRESH_TIME 120
#else
#define OSPF_LS_REFRESH_TIME 1800
#endif
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),
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
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
#include "sockunion.h"
#include "memory.h"
#include "log.h"
+#include "jhash.h"
DEFINE_MTYPE_STATIC(LIB, PREFIX, "Prefix")
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. */
return IPV6_MAX_BYTELEN;
break;
case AF_ETHERNET:
- return ETHER_ADDR_LEN;
+ return ETH_ALEN;
}
return 0;
}
(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);
+}
#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));
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;
--- /dev/null
+/* 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 */
--- /dev/null
+/*
+ * 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!");
+}
--- /dev/null
+/*
+ * 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
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)
--- /dev/null
+#
+# 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
#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")
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;
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;
}
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);
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;
/* initializer, only ever called once */
static void initializer()
{
- if (!masters)
- masters = list_new();
-
pthread_key_create(&thread_current, NULL);
}
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);
pthread_mutex_lock(&masters_mtx);
{
listnode_delete(masters, m);
+ if (masters->count == 0) {
+ list_free (masters);
+ masters = NULL;
+ }
}
pthread_mutex_unlock(&masters_mtx);
/* 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
* - 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);
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);
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)
struct thread_master {
char *name;
+ int tick_since_io;
struct thread **read;
struct thread **write;
struct pqueue *timer;
{
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);
break;
case CONFIG_NODE:
case INTERFACE_NODE:
+ case PW_NODE:
case ZEBRA_NODE:
case RIP_NODE:
case RIPNG_NODE:
break;
case CONFIG_NODE:
case INTERFACE_NODE:
+ case PW_NODE:
case ZEBRA_NODE:
case RIP_NODE:
case RIPNG_NODE:
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;
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;
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;
#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;
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)
{
(*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;
}
/* 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);
+}
/* 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
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,
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 {
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. */
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);
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 *,
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 {
#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>
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
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
#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;
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 */
+++ /dev/null
-EXTRA_DIST=Makefile.am README.txt
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 ||
/* 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
/* 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:
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]),
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;
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)
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);
/* 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);
/* 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));
THREAD_OFF(lsa->refresh);
/* do free */
- XFREE(MTYPE_OSPF6_LSA, lsa->header);
+ XFREE(MTYPE_OSPF6_LSA_HEADER, lsa->header);
XFREE(MTYPE_OSPF6_LSA, lsa);
}
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);
(*lsdb->hook_add)(lsa);
}
}
+ /* to free the lookup lock in node get*/
+ route_unlock_node(current);
ospf6_lsa_unlock(old);
}
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")
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)
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;
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);
}
}
return NULL;
route = (struct ospf6_route *)node->info;
+ route_unlock_node(node); /* to free the lookup lock */
return route;
}
SET_FLAG(old->flag, OSPF6_ROUTE_ADD);
ospf6_route_table_assert(table);
+ /* to free the lookup lock */
+ route_unlock_node(node);
return old;
}
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));
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);
/* 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 */
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);
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);
}
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)) {
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);
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();
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;
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;
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) {
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) {
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);
}
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);
}
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);
}
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);
}
"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)) {
"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)) {
((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);
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);
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);
#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;
/* 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 */
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);
{
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();
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);
OspfRI.registered = 1;
OspfRI.scope = scope;
- return 0;
+ return rc;
}
static int ospf_router_info_unregister()
OspfRI.pce_info.pce_domain = NULL;
OspfRI.pce_info.pce_neighbor = NULL;
- OspfRI.status = disabled;
+ OspfRI.enabled = false;
ospf_router_info_unregister();
/* 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;
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);
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));
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));
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);
}
-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;
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);
| 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;
}
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;
}
static void ospf_router_info_nsm_change(struct ospf_neighbor *nbr,
int old_state)
{
-
/* So far, nothing to do here. */
return;
}
* 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;
}
/* 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);
/* 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);
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
memcpy(new->data, lsah, length);
stream_free(s);
-out:
return new;
}
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;
}
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 */
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. */
}
rc = 0;
-out:
return rc;
}
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 {
/* 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;
}
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.
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);
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. */
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;
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(
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:
*------------------------------------------------------------------------*/
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;
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;
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;
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;
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 =
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;
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",
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);
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:
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;
}
u_int8_t scope;
- if (OspfRI.status == enabled)
+ if (OspfRI.enabled)
return CMD_SUCCESS;
/* Check and get Area value if present */
/* 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",
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);
}
"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)
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);
}
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;
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);
}
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;
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;
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;
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;
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;
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);
}
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;
"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 {
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)
* +--------+--------+--------+--------+ ---
*/
-/*
- * 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.
*/
#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;
};
#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;
/* 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 */
#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;
/* 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;
#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;
};
*/
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.
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;
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)
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;
}
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;
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;
}
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;
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);
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",
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);
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;
}
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();
/* Schedule Opaque-LSA refresh. */ /* XXX */
rc = 0;
-out:
return rc;
}
/* Schedule Opaque-LSA refresh. */ /* XXX */
rc = 0;
- /*out:*/
return rc;
}
/* 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;
}
/* 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;
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
!= 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;
}
* 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;
}
/* 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);
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;
memcpy(new->data, lsah, length);
stream_free(s);
-out:
return new;
}
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. */
}
rc = 0;
-out:
return rc;
}
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)) {
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.",
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;
}
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. */
}
rc = 0;
-out:
return rc;
}
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)) {
|| !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.",
}
rc = 0;
-out:
return rc;
}
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.
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);
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
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;
*------------------------------------------------------------------------*/
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;
}
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;
}
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";
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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",
}
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;
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;
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;
}
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);
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));
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,
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;
}
"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;
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))
ospf_mpls_te_foreach_area(ospf_mpls_te_lsa_schedule,
REORIGINATE_THIS_LSA);
}
-out:
+
return CMD_SUCCESS;
}
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)
}
/* 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 */
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)
"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)
{
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
#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)
#define LPFLG_LOOKUP_DONE 0x4
#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
/* 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 */
};
#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. */
};
#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 */
};
#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 */
};
/* 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 */
};
/* 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 */
/* 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;
/* 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;
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);
{
struct ospf *ospf;
u_short instance = 0;
+ int ret = CMD_SUCCESS;
ospf = ospf_lookup();
if (!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);
ospf_router_id_update(ospf);
}
- return CMD_SUCCESS;
+ return ret;
}
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);
"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;
"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;
"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;
"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};
"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};
"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;
"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;
"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;
"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;
"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;
"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;
"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;
"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;
"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;
"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;
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;
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;
"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;
"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;
"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;
"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;
"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;
"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;
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;
"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;
"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;
"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;
"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;
"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;
"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;
"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;
"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;
"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;
"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;
"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;
"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;
"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;
"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;
"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);
"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);
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);
"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;
"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);
"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);
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;
"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;
"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)",
}
-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"
"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)
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)]]",
"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;
"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;
"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;
"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;
"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;
"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;
"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;
"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;
"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;
"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;
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));
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)
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);
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);
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);
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);
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);
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);
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);
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();
}
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));
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();
ospf = ospf_lookup();
ospf->if_ospf_cli_count--;
}
- return CMD_SUCCESS;
+ return CMD_NOT_MY_INSTANCE;
}
ret = str2area_id(areaid, &area_id, &format);
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);
"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;
"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;
"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;
"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;
OUT_STR
FRR_REDIST_HELP_STR_OSPFD)
{
- VTY_DECLVAR_CONTEXT(ospf, ospf);
+ VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
int idx_word = 1;
int source;
OUT_STR
FRR_REDIST_HELP_STR_OSPFD)
{
- VTY_DECLVAR_CONTEXT(ospf, ospf);
+ VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
int idx_word = 2;
int source;
"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;
"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;
"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;
"Set metric of redistributed routes\n"
"Default metric\n")
{
- VTY_DECLVAR_CONTEXT(ospf, ospf);
+ VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
ospf->default_metric = -1;
"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);
"Administrative distance\n"
"OSPF Administrative distance\n")
{
- VTY_DECLVAR_CONTEXT(ospf, ospf);
+ VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
ospf->distance_all = 0;
"External routes\n"
"Distance for external routes\n")
{
- VTY_DECLVAR_CONTEXT(ospf, ospf);
+ VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
int idx = 0;
if (!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))
"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;
"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;
"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;
"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;
"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;
"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;
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);
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);
/* 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);
#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))
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();
list_free(om->external[type]);
om->external[type] = NULL;
}
+ XFREE(MTYPE_OSPF_EXTERNAL, ext);
}
}
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;
list_free(ospf->redist[type]);
ospf->redist[type] = NULL;
}
+ XFREE(MTYPE_OSPF_REDISTRIBUTE, red);
}
}
route_unlock_node(rn);
}
}
+ route_table_finish(ospf->networks);
for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) {
listnode_delete(ospf->areas, area);
}
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;
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);
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. */
/* 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 {
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 \
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)
+++ /dev/null
-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--
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);
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);
}
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",
}
/* 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 */
#include "vty.h"
#include "zclient.h"
+#include "pim_instance.h"
#include "pim_cmd.h"
#include "pim_vty.h"
#include "pim_iface.h"
#include "plist.h"
#include "hash.h"
#include "nexthop.h"
+#include "vrf.h"
#include "pimd.h"
#include "pim_mroute.h"
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;
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();
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"
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;
- char ch_src_str[INET_ADDRSTRLEN];
- char ch_grp_str[INET_ADDRSTRLEN];
+ 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));
- 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 */
+ am = pim_macro_spt_assert_metric(&ch->upstream->rpf,
+ 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("<addr?>", am.ip_address, addr_str,
+ sizeof(addr_str));
+
+ 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];
- char ch_src_str[INET_ADDRSTRLEN];
- char ch_grp_str[INET_ADDRSTRLEN];
- char addr_str[INET_ADDRSTRLEN];
- struct pim_assert_metric am;
+ ifaddr = pim_ifp->primary_address;
- am = pim_macro_spt_assert_metric(&ch->upstream->rpf,
- pim_ifp->primary_address);
+ 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));
+ 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 %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,
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(
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;
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;
}
}
-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;
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;
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)
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();
}
}
-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;
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;
} /* 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;
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;
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;
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];
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
// 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) {
}
}
-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;
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++;
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;
"---------------------------------------------------------------------------------------------------------------\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)
}
}
-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;
"---------------------------------------------------------------------------------------------------------------\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;
}
}
-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();
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;
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)
}
}
-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;
"\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];
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);
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]);
}
}
-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;
"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)
}
}
-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;
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;
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;
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];
}
}
-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);
}
}
}
}
-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;
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];
}
}
-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];
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;
"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];
}
}
+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;
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");
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;
"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;
}
}
-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;
"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;
} /* 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;
"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;
} /* 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;
"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;
} /* 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");
}
}
-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];
}
}
-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];
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;
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
- "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);
- igmp_show_groups(vty, uj);
+
+ 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
+ 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);
+ 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(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;
+ }
- pim_show_state(vty, src_or_group, group, uj);
+ 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"
+ 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_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"
- "JavaScript Object Notation\n")
+ JSON_STR)
{
u_char uj = use_json(argc, argv);
- pim_rp_show_information(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_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"
- "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_rpf(vty, uj);
+
+ 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"
+ 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_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")
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);
- addr_str = argv[4]->arg;
+ if (!vrf)
+ return CMD_WARNING;
+
+ 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,
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,
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));
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,
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;
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;
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));
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,
}
}
-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");
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;
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)
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);
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]);
}
/* 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)
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)
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
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';
}
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);
}
}
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);
+ 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;
+}
+
+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);
- show_mroute(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);
+ show_mroute(vrf->info, vty, uj);
+ }
+ if (uj)
+ vty_out(vty, "}\n");
+
return CMD_SUCCESS;
}
-static void show_mroute_count(struct vty *vty)
+static void show_mroute_count(struct pim_instance *pim, struct vty *vty)
{
struct listnode *node;
struct channel_oil *c_oil;
"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];
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];
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,
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);
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;
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;
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");
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;
}
"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,
"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,
"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,
"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,
"Join Prune Send Interval\n"
"Seconds\n")
{
+ PIM_DECLVAR_CONTEXT(vrf, pim);
qpim_t_periodic = atoi(argv[3]->arg);
return CMD_SUCCESS;
}
"Join Prune Send Interval\n"
"Seconds\n")
{
+ PIM_DECLVAR_CONTEXT(vrf, pim);
qpim_t_periodic = PIM_DEFAULT_T_PERIODIC;
return CMD_SUCCESS;
}
"Register Suppress Timer\n"
"Seconds\n")
{
+ PIM_DECLVAR_CONTEXT(vrf, pim);
qpim_register_suppress_time = atoi(argv[3]->arg);
return CMD_SUCCESS;
}
"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)",
"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;
}
"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;
}
"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;
}
"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;
}
"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;
}
"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;
}
"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);
}
"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);
"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);
}
"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;
"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,
"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,
"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;
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;
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";
}
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;
}
CONF_SSMPINGD_STR
"Source address\n")
{
+ PIM_DECLVAR_CONTEXT(vrf, pim);
int idx_ipv4 = 2;
int result;
struct in_addr source_addr;
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);
CONF_SSMPINGD_STR
"Source address\n")
{
+ PIM_DECLVAR_CONTEXT(vrf, pim);
int idx_ipv4 = 3;
int result;
struct in_addr source_addr;
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);
"pim multicast routing\n"
"Enable PIM ECMP \n")
{
+ PIM_DECLVAR_CONTEXT(vrf, pim);
qpim_ecmp_enable = 1;
return CMD_SUCCESS;
"pim multicast routing\n"
"Disable PIM ECMP \n")
{
+ PIM_DECLVAR_CONTEXT(vrf, pim);
qpim_ecmp_enable = 0;
return CMD_SUCCESS;
"Enable PIM ECMP \n"
"Enable PIM ECMP Rebalance\n")
{
+ PIM_DECLVAR_CONTEXT(vrf, pim);
qpim_ecmp_enable = 1;
qpim_ecmp_rebalance_enable = 1;
"Disable PIM ECMP \n"
"Disable PIM ECMP Rebalance\n")
{
+ PIM_DECLVAR_CONTEXT(vrf, pim);
qpim_ecmp_rebalance_enable = 0;
return CMD_SUCCESS;
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;
}
"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;
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;
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;
"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;
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;
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;
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;
"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;
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;
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;
"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;
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;
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;
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;
return CMD_SUCCESS;
}
-
DEFUN (interface_no_ip_pim_hello,
interface_no_ip_pim_hello_cmd,
"no ip pim hello [(1-180) (1-180)]",
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,
return CMD_SUCCESS;
}
-
DEFUN (debug_pim_packetdump_recv,
debug_pim_packetdump_recv_cmd,
"debug pim packet-dump receive",
return CMD_SUCCESS;
}
-
DEFUN (debug_pim_trace,
debug_pim_trace_cmd,
"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",
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,
return CMD_SUCCESS;
}
-
DEFUN (debug_pim_zebra,
debug_pim_zebra_cmd,
"debug pim zebra",
return CMD_SUCCESS;
}
-
DEFUN (debug_msdp,
debug_msdp_cmd,
"debug msdp",
"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;
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:
"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;
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;
"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;
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;
"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)
{
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;
"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;
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;
"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;
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;
"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);
}
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];
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"
+ JSON_STR)
+{
+ u_char uj = use_json(argc, argv);
+ 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;
+}
+
+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"
- "JavaScript Object Notation\n")
+ JSON_STR)
{
u_char uj = use_json(argc, argv);
- ip_msdp_show_mesh_group(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);
+ 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 vty *vty, u_char uj)
+static void ip_msdp_show_peers(struct pim_instance *pim, struct vty *vty,
+ u_char uj)
{
struct listnode *mpnode;
struct pim_msdp_peer *mp;
"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),
}
}
-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;
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;
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 (argc > 4)
- ip_msdp_show_peers_detail(vty, argv[4]->arg, uj);
+ 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 (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;
+}
+
+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 vty *vty, u_char uj)
+static void ip_msdp_show_sa(struct pim_instance *pim, struct vty *vty,
+ u_char uj)
{
struct listnode *sanode;
struct pim_msdp_sa *sa;
"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));
}
}
-
if (uj) {
vty_out(vty, "%s\n", json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
}
}
-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;
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,
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"
+ JSON_STR)
+{
+ u_char uj = use_json(argc, argv);
+ 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;
+}
+
+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"
- "JavaScript Object Notation\n")
+ JSON_STR)
{
u_char uj = use_json(argc, argv);
- ip_msdp_show_sa_detail(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);
+ 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 vty *vty, const char *addr, u_char uj)
+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;
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)) {
}
}
-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;
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)) {
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)
: 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,
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);
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);
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);
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);
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);
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);
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);
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 */
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,
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
}
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) {
#include "hash.h"
#include "pimd.h"
+#include "pim_instance.h"
#include "pim_zebra.h"
#include "pim_iface.h"
#include "pim_igmp.h"
#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;
}
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;
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;
/* 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;
void pim_if_delete(struct interface *ifp)
{
struct pim_interface *pim_ifp;
+ struct pim_ifchannel *ch;
zassert(ifp);
pim_ifp = ifp->info;
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);
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);
}
}
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);
}
}
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;
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;
{
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;
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)) {
}
}
- 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;
}
}
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;
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 */
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 */
ifp = ifc->ifp;
zassert(ifp);
- if (ifc->address->family != AF_INET)
- return;
-
if (PIM_DEBUG_ZEBRA) {
char buf[BUFSIZ];
prefix2str(ifc->address, buf, BUFSIZ);
}
pim_ifchannel_scan_forward_start(ifp);
- pim_rp_setup();
+ pim_rp_setup(pim_ifp->pim);
pim_rp_check_on_if_add(pim_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)
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)
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;
*/
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);
}
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.
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;
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;
}
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;
/*
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;
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;
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);
}
}
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);
}
}
* 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);
}
}
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;
}
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
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;
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
? ((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);
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);
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 */
#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;
{
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)
&& (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)) {
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);
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 ",
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);
}
}
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(
child)) {
struct channel_oil *c_oil =
child->channel_oil;
- struct pim_interface *pim_ifp =
- ch->interface->info;
if (PIM_DEBUG_PIM_TRACE)
zlog_debug(
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);
}
/*
* 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);
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);
}
}
}
*/
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);
}
}
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;
}
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;
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);
}
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);
- }
}
/*
}
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;
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);
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);
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);
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);
*/
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.
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)
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;
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);
}
/*
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:
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;
&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:
{
struct pim_ifchannel *ch, *starch;
struct pim_interface *pim_ifp;
+ struct pim_instance *pim;
/* PIM enabled on interface? */
pim_ifp = ifp->info;
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",
}
}
- 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;
}
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;
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;
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);
}
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;
*/
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)
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)
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;
-}
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;
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);
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);
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 */
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);
}
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);
{
struct pim_interface *pim_ifp;
struct igmp_sock *igmp;
+ char hash_name[64];
pim_ifp = ifp->info;
}
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;
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];
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,
*/
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);
}
}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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
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;
*/
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;
}
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)
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)
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);
#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)
#include "libfrr.h"
#include "pimd.h"
+#include "pim_instance.h"
#include "pim_version.h"
#include "pim_signals.h"
#include "pim_zebra.h"
pim_route_map_init();
pim_init();
- pim_msdp_init(master);
/*
* Initialize zclient "update" and "lookup" sockets
#include "prefix.h"
#include "vty.h"
#include "plist.h"
+#include "sockopt.h"
#include "pimd.h"
#include "pim_rpf.h"
#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;
}
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(
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
}
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);
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;
}
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(
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",
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)))) {
* 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",
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;
}
#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;
* 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;
*/
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(
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(
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);
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;
* 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,
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);
} 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;
"%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;
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)
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)
}
/* 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;
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));
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;
}
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
}
#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];
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;
}
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) {
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));
}
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)));
}
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) {
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
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;
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;
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;
#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
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 */
#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);
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);
/* 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);
}
}
{
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);
}
}
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;
}
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;
}
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
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;
/* 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 */
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;
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);
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)
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);
/* 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;
}
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;
}
}
}
}
-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;
}
} 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);
*/
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;
}
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;
}
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);
}
/* 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",
*/
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;
}
}
/* 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
/* 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;
/* 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;
}
}
}
-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;
/* 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;
}
}
}
-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);
}
}
* 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
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);
}
}
{
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);
}
}
{
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);
}
}
}
/* 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) {
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;
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);
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)
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;
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 */
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);
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;
}
}
/************************** 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)) {
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)
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)) {
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;
}
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;
}
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;
}
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;
/* 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);
}
}
}
-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)) {
}
}
-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;
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;
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);
}
}
/*********************** 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;
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;
}
}
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 */
};
struct pim_msdp_peer {
+ struct pim_instance *pim;
+
/* configuration */
struct in_addr local;
struct in_addr peer;
};
#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);
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
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;
/* 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;
}
/* 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
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);
}
}
-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)
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)
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);
#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"
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;
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);
}
/* 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));
}
/* 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;
}
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));
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;
}
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 */
#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
#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)
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)
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;
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
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;
* 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;
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);
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;
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));
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;
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));
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;
/* 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);
}
/* 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;
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
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;
}
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)
{
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
// 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,
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,
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;
// 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
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
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++;
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];
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
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));
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(
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 =
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)));
}
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)));
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)
{
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);
}
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++;
}
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++;
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?>",
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);
}
}
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];
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;
}
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;
#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
#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)
{
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)
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;
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;
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(
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;
}
* 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);
}
*/
struct channel_oil {
+ struct pim_instance *pim;
+
struct mfcctl oil;
int installed;
int oil_inherited_rescan;
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);
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:
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;
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;
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)
result = 0; /* good */
done:
- pim_sock_read_on(ifp);
+ pim_sock_read_on(orig_ifp);
if (result) {
++pim_ifp->pim_ifstat_hello_recvfail;
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)) {
{
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",
struct interface *ifp;
ifp = THREAD_ARG(t);
-
pim_ifp = ifp->info;
/*
{
struct pim_interface *pim_ifp;
- zassert(ifp);
pim_ifp = ifp->info;
- zassert(pim_ifp);
/*
* Reset next hello timer
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
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;
}
++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;
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;
}
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;
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];
return 0;
}
- pim_ifp = ifp->info;
- zassert(pim_ifp);
++pim_ifp->pim_ifstat_reg_recv;
/*
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];
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) {
}
}
- 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;
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);
}
}
#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,
#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)
{
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;
/*
* 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;
}
* 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;
/*
* 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);
*
* 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;
}
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,
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)
}
}
-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;
/*
* 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;
/*
* 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;
}
/*
* 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);
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
/*
* 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);
}
}
__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;
/*
* 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) {
}
}
- 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;
}
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;
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;
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;
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;
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));
"%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;
}
/*
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;
}
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;
}
if (i_am_rp_changed) {
- pim_msdp_i_am_rp_changed();
+ pim_msdp_i_am_rp_changed(pim);
}
}
*
* 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;
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;
*
* 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;
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;
__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];
__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);
* 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;
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)) {
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;
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),
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;
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;
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];
}
}
-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;
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;
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);
}
}
}
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
#include "log.h"
#include "prefix.h"
#include "memory.h"
+#include "jhash.h"
#include "pimd.h"
#include "pim_rpf.h"
#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;
__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;
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));
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];
|| (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;
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;
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);
}
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);
+}
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);
#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
* 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))) {
return;
}
- pim_ssm_range_reevaluate();
+ pim_ssm_range_reevaluate(pim);
}
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;
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);
}
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))
}
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;
}
};
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
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;
static void ssmpingd_delete(struct ssmpingd_sock *ss)
{
zassert(ss);
- zassert(qpim_ssmpingd_list);
THREAD_OFF(ss->t_sock_read);
/* warning only */
}
- listnode_delete(qpim_ssmpingd_list, ss);
+ listnode_delete(ss->pim->ssmpingd_list, ss);
ssmpingd_free(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];
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;
&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 =
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;
__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,
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,
#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 */
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 */
}
-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;
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
* 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];
} 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);
}
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;
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
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);
}
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;
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) {
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",
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_ */
#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);
* 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;
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;
* 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;
&& (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)) {
* 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;
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);
/* 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;
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;
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 */
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);
/* 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 */
}
/* 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
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)
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;
}
"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;
}
}
}
-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;
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 {
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 ",
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;
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;
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;
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);
}
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;
}
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(
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;
}
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)) {
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;
}
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) {
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;
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;
/*
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
/* 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;
}
}
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;
/*
* 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];
/* 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;
/* 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;
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 :)
}
/* 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;
/* 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)
* 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;
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];
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:
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;
&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;
__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;
* 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
* 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);
* 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;
/*
* 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;
*/
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,
* 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;
}
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);
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);
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);
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);
}
}
* 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;
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;
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;
}
*/
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)
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);
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);
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,
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 */
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;
}
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;
}
++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;
}
}
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;
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 */
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));
}
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;
}
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));
}
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
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));
}
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;
}
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));
}
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);
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);
}
{
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
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"
}
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);
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)
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;
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) {
}
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,
/* 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];
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,
}
}
-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);
+ }
}
}
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;
/* 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);
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)",
/* 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",
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};
return;
}
- igmp_source_forward_start(source);
+ igmp_source_forward_start(pim, source);
}
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;
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)) {
{
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;
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 */
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) {
}
} 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];
}
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(
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];
|| (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 */
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;
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 {
} 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) {
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(
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)
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);
__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;
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;
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);
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 */
}
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;
}
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) {
* 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;
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;
}
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)
{
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;
}
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);
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,
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);
}
} /* 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;
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;
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);
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;
}
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;
}
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;
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);
#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;
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;
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;
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();
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",
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
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()
#include "vty.h"
#include "plist.h"
+#include "pim_instance.h"
#include "pim_str.h"
#include "pim_memory.h"
#include "pim_assert.h"
#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
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;
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;
#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))
#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)
#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)
#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 */
printf("%s: waiting...\n", prog_name);
- getchar();
+ if (getchar() == EOF)
+ fprintf(stderr, "getchar failure\n");
close(fd);
+++ /dev/null
-rcdir=@pkgsrcrcdir@
-
-rc_SCRIPTS = bgpd.sh ospf6d.sh ospfd.sh ripd.sh ripngd.sh zebra.sh
+++ /dev/null
-EXTRA_DIST = \
- clidef.py \
- clippy/__init__.py
-Makefile
+!Makefile
Makefile.in
*.o
tags
--- /dev/null
+all: ALWAYS
+ @$(MAKE) -s -C .. fpm/libfrr_pb.la
+%: ALWAYS
+ @$(MAKE) -s -C .. fpm/$@
+
+Makefile:
+ #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
+++ /dev/null
-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
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+syntax = "proto2";
+
/*
* Protobuf definitions pertaining to the Quagga/FRR Protobuf component.
*/
ISIS = 8;
BGP = 9;
OTHER = 10;
-}
\ No newline at end of file
+}
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
--- /dev/null
+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
+++ /dev/null
-
-EXTRA_DIST = frr.init frr.service daemons \
- frr.logrotate frr.pam frr.spec \
- README.rpm_build.md
-
%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
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);
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);
+++ /dev/null
-EXTRA_DIST = snapcraft.yaml \
- README.snap_build.md \
- README.usage.md \
- extra_version_info.txt \
- scripts \
- defaults \
- helpers \
- snap
/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
TESTS_BGPD =
endif
+if ISISD
+TESTS_ISISD = \
+ isisd/test_fuzz_isis_tlv
+else
+TESTS_ISISD =
+endif
+
if OSPF6D
TESTS_OSPF6D = \
ospf6d/test_lsdb \
lib/cli/test_cli \
lib/cli/test_commands \
$(TESTS_BGPD) \
+ $(TESTS_ISISD) \
$(TESTS_OSPF6D) \
# end
< ../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 \
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)
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 = \
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 \
/* 8 */
{
"MP6",
- "MP IP4/MPLS-laveled VPN",
+ "MP IP4/MPLS-labeled VPN",
{CAPABILITY_CODE_MP, 0x4, 0x0, 0x1, 0x0, 0x80},
6,
SHOULD_PARSE,
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")
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,
--- /dev/null
+#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;
+}
--- /dev/null
+import frrtest
+
+class TestFuzzIsisTLV(frrtest.TestMultiOut):
+ program = './test_fuzz_isis_tlv'
+
+TestFuzzIsisTLV.exit_cleanly()
$(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)
$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";
{
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;
}
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)# ",
};
vty->node = ENABLE_NODE;
break;
case INTERFACE_NODE:
+ case PW_NODE:
case NS_NODE:
case VRF_NODE:
case ZEBRA_NODE:
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,
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);
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);
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);
#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"
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)
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;
}
}
-Makefile
+!Makefile
Makefile.in
*.o
zebra
--- /dev/null
+all: ALWAYS
+ @$(MAKE) -s -C .. zebra/zebra
+%: ALWAYS
+ @$(MAKE) -s -C .. zebra/$@
+
+Makefile:
+ #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
+++ /dev/null
-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
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,
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;
}
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]",
vty_out(vty, "debug zebra vxlan\n");
write++;
}
+ if (IS_ZEBRA_DEBUG_PW) {
+ vty_out(vty, "debug zebra pseudowires\n");
+ write++;
+ }
return write;
}
zebra_debug_fpm = 0;
zebra_debug_mpls = 0;
zebra_debug_vxlan = 0;
+ zebra_debug_pw = 0;
install_node(&debug_node, config_write_debug);
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);
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);
#define ZEBRA_DEBUG_VXLAN 0x01
+#define ZEBRA_DEBUG_PW 0x01
+
/* Debug related macro. */
#define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT)
#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;
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);
#include <zebra.h>
+#ifdef OPEN_BSD
+
#include "if.h"
#include "sockunion.h"
#include "prefix.h"
ifaddr_proc_ipv6();
#endif /* HAVE_PROC_NET_IF_INET6 */
}
+
+#endif /* OPEN_BSD */
#include <zebra.h>
+#ifdef SUNOS_5
+
#include "if.h"
#include "sockunion.h"
#include "prefix.h"
return NULL;
}
+
+#endif /* SUNOS_5 */
#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.
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)
{
interface_lookup_netlink(zns);
}
+
+#endif /* GNU_LINUX */
#include <zebra.h>
+#if !defined(GNU_LINUX) && !defined(OPEN_BSD) && !defined(SUNOS_5)
+
#include "if.h"
#include "sockunion.h"
#include "prefix.h"
/* Free sysctl buffer. */
XFREE(MTYPE_TMP, ref);
}
+
+#endif /* !defined(GNU_LINUX) && !defined(OPEN_BSD) && !defined(SUNOS_5) */
#include "zebra/rt_netlink.h"
#include "zebra/interface.h"
#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_static.h"
#define ZEBRA_PTM_SUPPORT
route_table_init_with_delegate(&zebra_if_table_delegate);
ifp->info = zebra_if;
-
- zebra_vrf_static_route_interface_fixup(ifp);
return 0;
}
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.",
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);
old_vrf_id = ifp->vrf_id;
+ static_ifindex_update(ifp, false);
+
/* Uninstall connected routes. */
if_uninstall_connected(ifp);
/* 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.
*/
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)
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.
#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*/
#endif /* HAVE_STRUCT_IN6_ALIASREQ */
#endif /* LINUX_IPV6 */
+
+#endif /* !SUNOS_5 */
#include <zebra.h>
+#ifdef SUNOS_5
+
#include "linklist.h"
#include "if.h"
#include "prefix.h"
return 0;
}
+
+#endif /* SUNOS_5 */
#include <zebra.h>
+#ifdef GNU_LINUX
+
#include "log.h"
#include "privs.h"
return ipforward_ipv6();
}
+
+#endif /* GNU_LINUX */
*/
#include <zebra.h>
+
+#ifdef SUNOS_5
+
#include "log.h"
#include "prefix.h"
(void)solaris_nd_set("ip6_forwarding", 0);
return ipforward_ipv6();
}
+
+#endif /* SUNOS_5 */
*/
#include <zebra.h>
+
+#if !defined(GNU_LINUX) && !defined(SUNOS_5)
+
#include "privs.h"
#include "zebra/ipforward.h"
zlog_err("Can't lower privileges");
return ip6forwarding;
}
+
+#endif /* !defined(GNU_LINUX) && !defined(SUNOS_5) */
#include <zebra.h>
+#ifdef HAVE_NETLINK
+
#include "linklist.h"
#include "if.h"
#include "log.h"
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;
zns->netlink_cmd.sock = -1;
}
}
+
+#endif /* HAVE_NETLINK */
*/
#include <zebra.h>
+
+#ifndef HAVE_NETLINK
+
#include <net/if_types.h>
#ifdef __OpenBSD__
#include <netmpls/mpls.h>
#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,
{
return;
}
+
+#endif /* !HAVE_NETLINK */
zebra_mpls_init();
zebra_mpls_vty_init();
+ zebra_pw_vty_init();
/* For debug purpose. */
/* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */
#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;
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,
*/
#include <zebra.h>
+
+#ifdef HAVE_NETLINK
+
#include <net/if_arp.h>
/* Hack for GNU libc version 2. */
char gbuf[40];
char oif_list[256] = "\0";
vrf_id_t vrf = ns_id;
+ int table;
if (mroute)
m = mroute;
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]);
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;
}
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;
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);
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;
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;
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
}
}
+
+#endif /* HAVE_NETLINK */
*/
#include <zebra.h>
+
+#ifndef HAVE_NETLINK
+
#ifdef __OpenBSD__
#include <netmpls/mpls.h>
#endif
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;
}
{
return 0;
}
+
+extern int kernel_interface_set_master(struct interface *master,
+ struct interface *slave)
+{
+ return 0;
+}
+
+#endif /* !HAVE_NETLINK */
#include <zebra.h>
+#ifdef SUNOS_5
+
#include "prefix.h"
#include "log.h"
#include "if.h"
void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if)
{
}
+
+#endif /* SUNOS_5 */
#include <zebra.h>
+#ifdef GNU_LINUX
+
#include "vty.h"
#include "zebra/zserv.h"
#include "zebra/rt_netlink.h"
{
netlink_neigh_read_for_vlan(zns, vlan_if);
}
+
+#endif /* GNU_LINUX */
#include <zebra.h>
+#if !defined(GNU_LINUX) && !defined(SUNOS_5)
+
#include "memory.h"
#include "zebra_memory.h"
#include "log.h"
void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if)
{
}
+
+#endif /* !defined(GNU_LINUX) && !defined(SUNOS_5) */
--- /dev/null
+#
+# 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
#include <zebra.h>
+#ifdef HAVE_NETLINK
+
#include "log.h"
#include "rib.h"
#include "vty.h"
return netlink_route_info_encode(ri, in_buf, in_buf_len);
}
+
+#endif /* HAVE_NETLINK */
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;
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;
}
*/
#include <zebra.h>
+
+#ifdef HAVE_NETLINK
+
#include "zebra/rt.h"
#include "zebra/rt_netlink.h"
#include "zebra/zebra_mpls.h"
return 0;
};
+
+#endif /* HAVE_NETLINK */
#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;
{
return -1;
};
+
+#endif /* !defined(HAVE_NETLINK) && !defined(OPEN_BSD) */
*/
#include <zebra.h>
+
+#ifdef OPEN_BSD
+
#include <netmpls/mpls.h>
#include "zebra/rt.h"
#include "zebra/zebra_mpls.h"
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,
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)
{
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,
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 */
#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)
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;
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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_ */
}
resolved = 1;
}
+ if (resolved && set)
+ re->nexthop_mtu = match->mtu;
return resolved;
} else if (re->type == ZEBRA_ROUTE_STATIC) {
resolved = 0;
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);
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
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);
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;
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);
}
}
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);
}
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);
}
}
}
+/* 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.
*/
}
}
+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
/* 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);
}
}
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)
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);
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;
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");
}
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
*/
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,
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"
"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"
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"
"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"
#include <lib/nexthop.h>
#include <lib/memory.h>
#include <lib/srcdest_table.h>
+#include <lib/if.h>
#include "vty.h"
#include "zebra/debug.h"
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;
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;
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;
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;
}
}
+/* 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
&& 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
&& 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;
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)
{
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. */
&& 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))
/* 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);
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;
}
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)
{
&& 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,
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)
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);
+}
};
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. */
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
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)
{
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);
zebra_vxlan_init_tables(zvrf);
zebra_mpls_init_tables(zvrf);
+ zebra_pw_init(zvrf);
return zvrf;
}
#define __ZEBRA_RIB_H__
#include <zebra/zebra_ns.h>
+#include <zebra/zebra_pw.h>
/* MPLS (Segment Routing) global block */
typedef struct mpls_srgb_t_ {
/* 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)
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 *);
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)"
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;
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;
}
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;
break;
}
+ if (re->nexthop_mtu)
+ vty_out(vty, ", mtu %u", re->nexthop_mtu);
+
/* Label information */
if (nexthop->nh_label
&& nexthop->nh_label->num_labels) {
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);
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
&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 */
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,
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,
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))
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);
}
/*
return 0;
return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet,
- ETHER_ADDR_LEN)
+ ETH_ALEN)
== 0);
}
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);
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;
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
/* 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. */
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;
*/
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);
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;
/* 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);
#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 };
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,
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 */
}
}
+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)
{
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;
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)
{
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;
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);
#include "zclient.h"
#include "zebra/zebra_ns.h"
+#include "zebra/zebra_pw.h"
+
/* Default port information. */
#define ZEBRA_VTY_PORT 2601
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;