summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/Makefile.am6
-rw-r--r--bgpd/bgp_attr.c113
-rw-r--r--bgpd/bgp_attr.h5
-rw-r--r--bgpd/bgp_clist.c320
-rw-r--r--bgpd/bgp_clist.h18
-rw-r--r--bgpd/bgp_ecommunity.c1
-rw-r--r--bgpd/bgp_encap.c1
-rw-r--r--bgpd/bgp_encap.h10
-rw-r--r--bgpd/bgp_lcommunity.c569
-rw-r--r--bgpd/bgp_lcommunity.h74
-rw-r--r--bgpd/bgp_memory.c4
-rw-r--r--bgpd/bgp_memory.h3
-rw-r--r--bgpd/bgp_mpath.c14
-rw-r--r--bgpd/bgp_mplsvpn.c2
-rw-r--r--bgpd/bgp_mplsvpn.h13
-rw-r--r--bgpd/bgp_nexthop.c4
-rw-r--r--bgpd/bgp_open.c34
-rw-r--r--bgpd/bgp_open.h2
-rw-r--r--bgpd/bgp_packet.c26
-rw-r--r--bgpd/bgp_route.c942
-rw-r--r--bgpd/bgp_route.h3
-rw-r--r--bgpd/bgp_routemap.c422
-rw-r--r--bgpd/bgp_vty.c570
-rw-r--r--bgpd/bgp_vty.h6
-rw-r--r--bgpd/bgpd.c33
-rw-r--r--bgpd/bgpd.h6
-rw-r--r--bgpd/rfapi/bgp_rfapi_cfg.c786
-rw-r--r--bgpd/rfapi/bgp_rfapi_cfg.h23
-rw-r--r--bgpd/rfapi/rfapi.c101
-rw-r--r--bgpd/rfapi/rfapi_ap.c62
-rw-r--r--bgpd/rfapi/rfapi_ap.h1
-rw-r--r--bgpd/rfapi/rfapi_backend.h9
-rw-r--r--bgpd/rfapi/rfapi_import.c17
-rw-r--r--bgpd/rfapi/rfapi_import.h8
-rw-r--r--bgpd/rfapi/rfapi_private.h33
-rw-r--r--bgpd/rfapi/rfapi_rib.c24
-rw-r--r--bgpd/rfapi/rfapi_rib.h33
-rw-r--r--bgpd/rfapi/rfapi_vty.c663
-rwxr-xr-xconfigure.ac3
-rw-r--r--isisd/isis_spf.c4
-rw-r--r--lib/Makefile.am8
-rw-r--r--lib/bfd.c2
-rw-r--r--lib/command.c35
-rw-r--r--lib/command.h25
-rw-r--r--lib/command_lex.l13
-rw-r--r--lib/command_match.c39
-rw-r--r--lib/command_parse.y253
-rw-r--r--lib/grammar_sandbox.c242
-rw-r--r--lib/grammar_sandbox.h56
-rw-r--r--lib/grammar_sandbox_main.c64
-rw-r--r--lib/graph.c48
-rw-r--r--lib/log.c2
-rw-r--r--lib/monotime.h77
-rw-r--r--lib/network.c9
-rw-r--r--lib/routemap.c7
-rw-r--r--lib/routemap.h2
-rw-r--r--lib/thread.c200
-rw-r--r--lib/thread.h11
-rw-r--r--lib/vrf.h1
-rw-r--r--lib/vty.c1
-rw-r--r--lib/zclient.c1
-rw-r--r--lib/zebra.h25
-rw-r--r--ospf6d/ospf6_abr.c2
-rw-r--r--ospf6d/ospf6_area.c2
-rw-r--r--ospf6d/ospf6_bfd.c2
-rw-r--r--ospf6d/ospf6_flood.c6
-rw-r--r--ospf6d/ospf6_interface.c2
-rw-r--r--ospf6d/ospf6_intra.c4
-rw-r--r--ospf6d/ospf6_lsa.c10
-rw-r--r--ospf6d/ospf6_message.c5
-rw-r--r--ospf6d/ospf6_neighbor.c16
-rw-r--r--ospf6d/ospf6_route.c6
-rw-r--r--ospf6d/ospf6_spf.c11
-rw-r--r--ospf6d/ospf6_top.c4
-rw-r--r--ospf6d/ospf6d.h24
-rw-r--r--ospfd/ospf_ase.c4
-rw-r--r--ospfd/ospf_bfd.c2
-rw-r--r--ospfd/ospf_dump.c5
-rw-r--r--ospfd/ospf_flood.c9
-rw-r--r--ospfd/ospf_lsa.c97
-rw-r--r--ospfd/ospf_lsa.h6
-rw-r--r--ospfd/ospf_nsm.c4
-rw-r--r--ospfd/ospf_packet.c39
-rw-r--r--ospfd/ospf_spf.c48
-rw-r--r--ospfd/ospf_vty.c70
-rw-r--r--ospfd/ospfd.c6
-rw-r--r--pimd/Makefile.am14
-rw-r--r--pimd/README81
-rw-r--r--pimd/pim_assert.c252
-rw-r--r--pimd/pim_br.c24
-rw-r--r--pimd/pim_br.h6
-rw-r--r--pimd/pim_cmd.c4835
-rw-r--r--pimd/pim_cmd.h7
-rw-r--r--pimd/pim_hello.c43
-rw-r--r--pimd/pim_iface.c443
-rw-r--r--pimd/pim_iface.h24
-rw-r--r--pimd/pim_ifchannel.c906
-rw-r--r--pimd/pim_ifchannel.h43
-rw-r--r--pimd/pim_igmp.c765
-rw-r--r--pimd/pim_igmp.h22
-rw-r--r--pimd/pim_igmpv2.c190
-rw-r--r--pimd/pim_igmpv2.h41
-rw-r--r--pimd/pim_igmpv3.c563
-rw-r--r--pimd/pim_igmpv3.h44
-rw-r--r--pimd/pim_join.c264
-rw-r--r--pimd/pim_join.h3
-rw-r--r--pimd/pim_macro.c78
-rw-r--r--pimd/pim_main.c33
-rw-r--r--pimd/pim_memory.c8
-rw-r--r--pimd/pim_memory.h8
-rw-r--r--pimd/pim_mroute.c657
-rw-r--r--pimd/pim_mroute.h8
-rw-r--r--pimd/pim_msdp.c1606
-rw-r--r--pimd/pim_msdp.h233
-rw-r--r--pimd/pim_msdp_packet.c696
-rw-r--r--pimd/pim_msdp_packet.h72
-rw-r--r--pimd/pim_msdp_socket.c229
-rw-r--r--pimd/pim_msdp_socket.h25
-rw-r--r--pimd/pim_msg.c180
-rw-r--r--pimd/pim_msg.h11
-rw-r--r--pimd/pim_neighbor.c112
-rw-r--r--pimd/pim_neighbor.h10
-rw-r--r--pimd/pim_oil.c311
-rw-r--r--pimd/pim_oil.h14
-rw-r--r--pimd/pim_pim.c469
-rw-r--r--pimd/pim_pim.h23
-rw-r--r--pimd/pim_register.c300
-rw-r--r--pimd/pim_register.h7
-rw-r--r--pimd/pim_rp.c785
-rw-r--r--pimd/pim_rp.h22
-rw-r--r--pimd/pim_rpf.c310
-rw-r--r--pimd/pim_rpf.h48
-rw-r--r--pimd/pim_sock.c129
-rw-r--r--pimd/pim_sock.h2
-rw-r--r--pimd/pim_ssmpingd.c48
-rw-r--r--pimd/pim_static.c62
-rw-r--r--pimd/pim_str.c55
-rw-r--r--pimd/pim_str.h14
-rw-r--r--pimd/pim_time.c19
-rw-r--r--pimd/pim_time.h1
-rw-r--r--pimd/pim_tlv.c144
-rw-r--r--pimd/pim_tlv.h7
-rw-r--r--pimd/pim_upstream.c1318
-rw-r--r--pimd/pim_upstream.h117
-rw-r--r--pimd/pim_util.c41
-rw-r--r--pimd/pim_util.h2
-rw-r--r--pimd/pim_vty.c116
-rw-r--r--pimd/pim_zebra.c498
-rw-r--r--pimd/pim_zebra.h1
-rw-r--r--pimd/pim_zlookup.c258
-rw-r--r--pimd/pim_zlookup.h10
-rw-r--r--pimd/pimd.c57
-rw-r--r--pimd/pimd.h58
-rw-r--r--tests/test-timer-performance.c6
-rw-r--r--tests/testcli.refout8
-rw-r--r--tools/permutations.c2
-rw-r--r--vtysh/vtysh.c39
-rw-r--r--zebra/Makefile.am4
-rw-r--r--zebra/if_netlink.c42
-rw-r--r--zebra/kernel_null.c2
-rw-r--r--zebra/rt.h1
-rw-r--r--zebra/rt_netlink.c73
-rw-r--r--zebra/rt_socket.c6
-rw-r--r--zebra/zebra_fpm.c20
-rw-r--r--zebra/zebra_fpm_dt.c2
-rw-r--r--zebra/zebra_fpm_netlink.c1
-rw-r--r--zebra/zebra_mroute.c68
-rw-r--r--zebra/zebra_mroute.h35
-rw-r--r--zebra/zebra_rnh.c2
-rw-r--r--zebra/zserv.c20
170 files changed, 17766 insertions, 6820 deletions
diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am
index 69c0504af4..6e36a950d6 100644
--- a/bgpd/Makefile.am
+++ b/bgpd/Makefile.am
@@ -75,7 +75,8 @@ libbgp_a_SOURCES = \
bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \
bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \
bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \
- bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \
+ bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_lcommunity.c \
+ bgp_mplsvpn.c bgp_nexthop.c \
bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \
bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \
bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC)
@@ -85,7 +86,8 @@ noinst_HEADERS = \
bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \
bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \
bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \
- bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
+ bgp_ecommunity.h bgp_lcommunity.h \
+ bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgp_nht.h \
bgp_updgrp.h bgp_bfd.h bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h \
$(BGP_VNC_RFAPI_HD)
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 87cff44293..f4995faab0 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -42,6 +42,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_updgrp.h"
#include "bgpd/bgp_encap_types.h"
#if ENABLE_BGP_VNC
@@ -76,6 +77,7 @@ static const struct message attr_str [] =
#if ENABLE_BGP_VNC
{ BGP_ATTR_VNC, "VNC" },
#endif
+ { BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY" }
};
static const int attr_str_max = array_size(attr_str);
@@ -670,6 +672,8 @@ attrhash_key_make (void *p)
if (extra)
{
+ if (extra->lcommunity)
+ MIX(lcommunity_hash_make (extra->lcommunity));
if (extra->ecommunity)
MIX(ecommunity_hash_make (extra->ecommunity));
if (extra->cluster)
@@ -718,6 +722,7 @@ attrhash_cmp (const void *p1, const void *p2)
&& IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
&& IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
&& ae1->ecommunity == ae2->ecommunity
+ && ae1->lcommunity == ae2->lcommunity
&& ae1->cluster == ae2->cluster
&& ae1->transit == ae2->transit
&& (ae1->encap_tunneltype == ae2->encap_tunneltype)
@@ -836,6 +841,13 @@ bgp_attr_intern (struct attr *attr)
attre->ecommunity->refcnt++;
}
+ if (attre->lcommunity)
+ {
+ if (! attre->lcommunity->refcnt)
+ attre->lcommunity = lcommunity_intern (attre->lcommunity);
+ else
+ attre->lcommunity->refcnt++;
+ }
if (attre->cluster)
{
if (! attre->cluster->refcnt)
@@ -1026,7 +1038,11 @@ bgp_attr_unintern_sub (struct attr *attr)
if (attr->extra->ecommunity)
ecommunity_unintern (&attr->extra->ecommunity);
UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES));
-
+
+ if (attr->extra->lcommunity)
+ lcommunity_unintern (&attr->extra->lcommunity);
+ UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES));
+
if (attr->extra->cluster)
cluster_unintern (attr->extra->cluster);
UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST));
@@ -1096,6 +1112,8 @@ bgp_attr_flush (struct attr *attr)
if (attre->ecommunity && ! attre->ecommunity->refcnt)
ecommunity_free (&attre->ecommunity);
+ if (attre->lcommunity && ! attre->lcommunity->refcnt)
+ lcommunity_free (&attre->lcommunity);
if (attre->cluster && ! attre->cluster->refcnt)
{
cluster_free (attre->cluster);
@@ -1254,6 +1272,7 @@ const u_int8_t attr_flags_values [] = {
[BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
[BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
[BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_LARGE_COMMUNITIES]= BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
};
static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1;
@@ -1849,7 +1868,8 @@ int
bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
struct bgp_nlri *mp_update)
{
- afi_t pkt_afi, afi;
+ iana_afi_t pkt_afi;
+ afi_t afi;
safi_t pkt_safi, safi;
bgp_size_t nlri_len;
size_t start;
@@ -2000,7 +2020,8 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
struct bgp_nlri *mp_withdraw)
{
struct stream *s;
- afi_t pkt_afi, afi;
+ iana_afi_t pkt_afi;
+ afi_t afi;
safi_t pkt_safi, safi;
u_int16_t withdraw_len;
struct peer *const peer = args->peer;
@@ -2042,6 +2063,40 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
return BGP_ATTR_PARSE_PROCEED;
}
+/* Large Community attribute. */
+static bgp_attr_parse_ret_t
+bgp_attr_large_community (struct bgp_attr_parser_args *args)
+{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
+ /*
+ * Large community follows new attribute format.
+ */
+ if (length == 0)
+ {
+ if (attr->extra)
+ attr->extra->lcommunity = NULL;
+ /* Empty extcomm doesn't seem to be invalid per se */
+ return BGP_ATTR_PARSE_PROCEED;
+ }
+
+ (bgp_attr_extra_get (attr))->lcommunity =
+ lcommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
+ /* XXX: fix ecommunity_parse to use stream API */
+ stream_forward_getp (peer->ibuf, length);
+
+ if (attr->extra && !attr->extra->lcommunity)
+ return bgp_attr_malformed (args,
+ BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ args->total);
+
+ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
+
+ return BGP_ATTR_PARSE_PROCEED;
+}
+
/* Extended Community attribute. */
static bgp_attr_parse_ret_t
bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
@@ -2063,7 +2118,7 @@ bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
/* XXX: fix ecommunity_parse to use stream API */
stream_forward_getp (peer->ibuf, length);
- if (!attr->extra->ecommunity)
+ if (attr->extra && !attr->extra->ecommunity)
return bgp_attr_malformed (args,
BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
args->total);
@@ -2477,6 +2532,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
case BGP_ATTR_COMMUNITIES:
ret = bgp_attr_community (&attr_args);
break;
+ case BGP_ATTR_LARGE_COMMUNITIES:
+ ret = bgp_attr_large_community (&attr_args);
+ break;
case BGP_ATTR_ORIGINATOR_ID:
ret = bgp_attr_originator_id (&attr_args);
break;
@@ -2648,7 +2706,7 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi,
struct attr *attr)
{
size_t sizep;
- afi_t pkt_afi;
+ iana_afi_t pkt_afi;
safi_t pkt_safi;
/* Set extended bit always to encode the attribute length as 2 bytes */
@@ -3104,6 +3162,28 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
stream_put (s, attr->community->val, attr->community->size * 4);
}
+ /*
+ * Large Community attribute.
+ */
+ if (attr->extra &&
+ CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY)
+ && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)))
+ {
+ if (attr->extra->lcommunity->size * 12 > 255)
+ {
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
+ stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES);
+ stream_putw (s, attr->extra->lcommunity->size * 12);
+ }
+ else
+ {
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+ stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES);
+ stream_putc (s, attr->extra->lcommunity->size * 12);
+ }
+ stream_put (s, attr->extra->lcommunity->val, attr->extra->lcommunity->size * 12);
+ }
+
/* Route Reflector. */
if (peer->sort == BGP_PEER_IBGP
&& from
@@ -3282,7 +3362,7 @@ size_t
bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi)
{
unsigned long attrlen_pnt;
- afi_t pkt_afi;
+ iana_afi_t pkt_afi;
safi_t pkt_safi;
/* Set extended bit always to encode the attribute length as 2 bytes */
@@ -3336,6 +3416,7 @@ bgp_attr_init (void)
attrhash_init ();
community_init ();
ecommunity_init ();
+ lcommunity_init ();
cluster_init ();
transit_init ();
encap_init ();
@@ -3348,6 +3429,7 @@ bgp_attr_finish (void)
attrhash_finish ();
community_finish ();
ecommunity_finish ();
+ lcommunity_finish ();
cluster_finish ();
transit_finish ();
encap_finish ();
@@ -3451,6 +3533,25 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
stream_put (s, attr->community->val, attr->community->size * 4);
}
+ /* Large Community attribute. */
+ if (attr->extra && attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES))
+ {
+ if (attr->extra->lcommunity->size * 12 > 255)
+ {
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
+ stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES);
+ stream_putw (s, attr->extra->lcommunity->size * 12);
+ }
+ else
+ {
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+ stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES);
+ stream_putc (s, attr->extra->lcommunity->size * 12);
+ }
+
+ stream_put (s, attr->extra->lcommunity->val, attr->extra->lcommunity->size * 12);
+ }
+
/* Add a MP_NLRI attribute to dump the IPv6 next hop */
if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
(attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL ||
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 6e639078d6..c5799ccd0d 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -92,7 +92,10 @@ struct attr_extra
/* Extended Communities attribute. */
struct ecommunity *ecommunity;
-
+
+ /* Large Communities attribute. */
+ struct lcommunity *lcommunity;
+
/* Route-Reflector Cluster attribute */
struct cluster_list *cluster;
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index 9032b1e2f4..b37034bf29 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgpd.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_regex.h"
#include "bgpd/bgp_clist.h"
@@ -42,9 +43,11 @@ community_list_master_lookup (struct community_list_handler *ch, int master)
switch (master)
{
case COMMUNITY_LIST_MASTER:
- return &ch->community_list;
+ return &ch->community_list;
case EXTCOMMUNITY_LIST_MASTER:
- return &ch->extcommunity_list;
+ return &ch->extcommunity_list;
+ case LARGE_COMMUNITY_LIST_MASTER:
+ return &ch->lcommunity_list;
}
return NULL;
}
@@ -66,6 +69,10 @@ community_entry_free (struct community_entry *entry)
if (entry->u.com)
community_free (entry->u.com);
break;
+ case LARGE_COMMUNITY_LIST_STANDARD:
+ if (entry->u.lcom)
+ lcommunity_free (&entry->u.lcom);
+ break;
case EXTCOMMUNITY_LIST_STANDARD:
/* In case of standard extcommunity-list, configuration string
is made by ecommunity_ecom2str(). */
@@ -76,6 +83,7 @@ community_entry_free (struct community_entry *entry)
break;
case COMMUNITY_LIST_EXPANDED:
case EXTCOMMUNITY_LIST_EXPANDED:
+ case LARGE_COMMUNITY_LIST_EXPANDED:
if (entry->config)
XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
if (entry->reg)
@@ -320,8 +328,13 @@ community_list_entry_lookup (struct community_list *list, const void *arg,
if (entry->direct == direct && ecommunity_cmp (entry->u.ecom, arg))
return entry;
break;
+ case LARGE_COMMUNITY_LIST_STANDARD:
+ if (entry->direct == direct && lcommunity_cmp (entry->u.lcom, arg))
+ return entry;
+ break;
case COMMUNITY_LIST_EXPANDED:
case EXTCOMMUNITY_LIST_EXPANDED:
+ case LARGE_COMMUNITY_LIST_EXPANDED:
if (entry->direct == direct && strcmp (entry->config, arg) == 0)
return entry;
break;
@@ -399,15 +412,14 @@ community_str_get (struct community *com, int i)
}
/* Internal function to perform regular expression match for
- * * a single community. */
+ * a single community. */
static int
community_regexp_include (regex_t * reg, struct community *com, int i)
{
char *str;
int rv;
- /* When there is no communities attribute it is treated as empty
- * string. */
+ /* When there is no communities attribute it is treated as empty string. */
if (com == NULL || com->size == 0)
str = XSTRDUP(MTYPE_COMMUNITY_STR, "");
else
@@ -447,6 +459,90 @@ community_regexp_match (struct community *com, regex_t * reg)
return 0;
}
+static char *
+lcommunity_str_get (struct lcommunity *lcom, int i)
+{
+ struct lcommunity_val lcomval;
+ u_int32_t globaladmin;
+ u_int32_t localdata1;
+ u_int32_t localdata2;
+ char *str;
+ u_char *ptr;
+ char *pnt;
+
+ ptr = lcom->val;
+ ptr += (i * LCOMMUNITY_SIZE);
+
+ memcpy (&lcomval, ptr, LCOMMUNITY_SIZE);
+
+ /* Allocate memory. 48 bytes taken off bgp_lcommunity.c */
+ str = pnt = XMALLOC (MTYPE_LCOMMUNITY_STR, 48);
+
+ ptr = (u_char *)lcomval.val;
+ globaladmin = (*ptr++ << 24);
+ globaladmin |= (*ptr++ << 16);
+ globaladmin |= (*ptr++ << 8);
+ globaladmin |= (*ptr++);
+
+ localdata1 = (*ptr++ << 24);
+ localdata1 |= (*ptr++ << 16);
+ localdata1 |= (*ptr++ << 8);
+ localdata1 |= (*ptr++);
+
+ localdata2 = (*ptr++ << 24);
+ localdata2 |= (*ptr++ << 16);
+ localdata2 |= (*ptr++ << 8);
+ localdata2 |= (*ptr++);
+
+ sprintf (pnt, "%u:%u:%u", globaladmin, localdata1, localdata2);
+ pnt += strlen (pnt);
+ *pnt = '\0';
+
+ return str;
+}
+
+/* Internal function to perform regular expression match for
+ * a single community. */
+static int
+lcommunity_regexp_include (regex_t * reg, struct lcommunity *lcom, int i)
+{
+ const char *str;
+
+ /* When there is no communities attribute it is treated as empty string. */
+ if (lcom == NULL || lcom->size == 0)
+ str = "";
+ else
+ str = lcommunity_str_get (lcom, i);
+
+ /* Regular expression match. */
+ if (regexec (reg, str, 0, NULL, 0) == 0)
+ return 1;
+
+ /* No match. */
+ return 0;
+}
+
+static int
+lcommunity_regexp_match (struct lcommunity *com, regex_t * reg)
+{
+ const char *str;
+
+ /* When there is no communities attribute it is treated as empty
+ string. */
+ if (com == NULL || com->size == 0)
+ str = "";
+ else
+ str = lcommunity_str (com);
+
+ /* Regular expression match. */
+ if (regexec (reg, str, 0, NULL, 0) == 0)
+ return 1;
+
+ /* No match. */
+ return 0;
+}
+
+
static int
ecommunity_regexp_match (struct ecommunity *ecom, regex_t * reg)
{
@@ -547,6 +643,30 @@ community_list_match (struct community *com, struct community_list *list)
}
int
+lcommunity_list_match (struct lcommunity *lcom, struct community_list *list)
+{
+ struct community_entry *entry;
+
+ for (entry = list->head; entry; entry = entry->next)
+ {
+ if (entry->any)
+ return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
+
+ if (entry->style == LARGE_COMMUNITY_LIST_STANDARD)
+ {
+ if (lcommunity_match (lcom, entry->u.lcom))
+ return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
+ }
+ else if (entry->style == LARGE_COMMUNITY_LIST_EXPANDED)
+ {
+ if (lcommunity_regexp_match (lcom, entry->reg))
+ return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
+ }
+ }
+ return 0;
+}
+
+int
ecommunity_list_match (struct ecommunity *ecom, struct community_list *list)
{
struct community_entry *entry;
@@ -694,12 +814,17 @@ community_list_dup_check (struct community_list *list,
if (community_cmp (entry->u.com, new->u.com))
return 1;
break;
+ case LARGE_COMMUNITY_LIST_STANDARD:
+ if (lcommunity_cmp (entry->u.lcom, new->u.lcom))
+ return 1;
+ break;
case EXTCOMMUNITY_LIST_STANDARD:
if (ecommunity_cmp (entry->u.ecom, new->u.ecom))
return 1;
break;
case COMMUNITY_LIST_EXPANDED:
case EXTCOMMUNITY_LIST_EXPANDED:
+ case LARGE_COMMUNITY_LIST_EXPANDED:
if (strcmp (entry->config, new->config) == 0)
return 1;
break;
@@ -817,6 +942,185 @@ community_list_unset (struct community_list_handler *ch,
return 0;
}
+/* Delete all permitted large communities in the list from com. */
+struct lcommunity *
+lcommunity_list_match_delete (struct lcommunity *lcom,
+ struct community_list *list)
+{
+ struct community_entry *entry;
+ u_int32_t com_index_to_delete[lcom->size];
+ u_char *ptr;
+ int delete_index = 0;
+ int i;
+
+ /* Loop over each lcommunity value and evaluate each against the
+ * community-list. If we need to delete a community value add its index to
+ * com_index_to_delete.
+ */
+ ptr = lcom->val;
+ for (i = 0; i < lcom->size; i++)
+ {
+ ptr += (i * LCOMMUNITY_SIZE);
+ for (entry = list->head; entry; entry = entry->next)
+ {
+ if (entry->any)
+ {
+ if (entry->direct == COMMUNITY_PERMIT)
+ {
+ com_index_to_delete[delete_index] = i;
+ delete_index++;
+ }
+ break;
+ }
+
+ else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD)
+ && lcommunity_include (entry->u.lcom, ptr) )
+ {
+ if (entry->direct == COMMUNITY_PERMIT)
+ {
+ com_index_to_delete[delete_index] = i;
+ delete_index++;
+ }
+ break;
+ }
+
+ else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD)
+ && lcommunity_regexp_include (entry->reg, lcom, i))
+ {
+ if (entry->direct == COMMUNITY_PERMIT)
+ {
+ com_index_to_delete[delete_index] = i;
+ delete_index++;
+ }
+ break;
+ }
+ }
+ }
+
+ /* Delete all of the communities we flagged for deletion */
+ ptr = lcom->val;
+ for (i = delete_index-1; i >= 0; i--)
+ {
+ ptr += (com_index_to_delete[i] * LCOMMUNITY_SIZE);
+ lcommunity_del_val (lcom, ptr);
+ }
+
+ return lcom;
+}
+
+/* Set lcommunity-list. */
+int
+lcommunity_list_set (struct community_list_handler *ch,
+ const char *name, const char *str, int direct, int style)
+{
+ struct community_entry *entry = NULL;
+ struct community_list *list;
+ struct lcommunity *lcom = NULL;
+ regex_t *regex = NULL;
+
+ /* Get community list. */
+ list = community_list_get (ch, name, LARGE_COMMUNITY_LIST_MASTER);
+
+ /* When community-list already has entry, new entry should have same
+ style. If you want to have mixed style community-list, you can
+ comment out this check. */
+ if (!community_list_empty_p (list))
+ {
+ struct community_entry *first;
+
+ first = list->head;
+
+ if (style != first->style)
+ {
+ return (first->style == COMMUNITY_LIST_STANDARD
+ ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
+ : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
+ }
+ }
+
+ if (str)
+ {
+ if (style == LARGE_COMMUNITY_LIST_STANDARD)
+ lcom = lcommunity_str2com (str);
+ else
+ regex = bgp_regcomp (str);
+
+ if (! lcom && ! regex)
+ return COMMUNITY_LIST_ERR_MALFORMED_VAL;
+ }
+
+ entry = community_entry_new ();
+ entry->direct = direct;
+ entry->style = style;
+ entry->any = (str ? 0 : 1);
+ entry->u.lcom = lcom;
+ entry->reg = regex;
+ if (lcom)
+ entry->config = lcommunity_lcom2str (lcom, LCOMMUNITY_FORMAT_COMMUNITY_LIST);
+ else if (regex)
+ entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
+ else
+ entry->config = NULL;
+
+ /* Do not put duplicated community entry. */
+ if (community_list_dup_check (list, entry))
+ community_entry_free (entry);
+ else
+ community_list_entry_add (list, entry);
+
+ return 0;
+}
+
+/* Unset community-list. When str is NULL, delete all of
+ community-list entry belongs to the specified name. */
+int
+lcommunity_list_unset (struct community_list_handler *ch,
+ const char *name, const char *str,
+ int direct, int style)
+{
+ struct community_entry *entry = NULL;
+ struct community_list *list;
+ struct lcommunity *lcom = NULL;
+ regex_t *regex = NULL;
+
+ /* Lookup community list. */
+ list = community_list_lookup (ch, name, LARGE_COMMUNITY_LIST_MASTER);
+ if (list == NULL)
+ return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
+
+ /* Delete all of entry belongs to this community-list. */
+ if (!str)
+ {
+ community_list_delete (list);
+ return 0;
+ }
+
+ if (style == LARGE_COMMUNITY_LIST_STANDARD)
+ lcom = lcommunity_str2com (str);
+ else
+ regex = bgp_regcomp (str);
+
+ if (! lcom && ! regex)
+ return COMMUNITY_LIST_ERR_MALFORMED_VAL;
+
+ if (lcom)
+ entry = community_list_entry_lookup (list, lcom, direct);
+ else
+ entry = community_list_entry_lookup (list, str, direct);
+
+ if (lcom)
+ lcommunity_free (&lcom);
+ if (regex)
+ bgp_regex_free (regex);
+
+ if (!entry)
+ return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
+
+ community_list_entry_delete (list, entry, style);
+
+ return 0;
+}
+
/* Set extcommunity-list. */
int
extcommunity_list_set (struct community_list_handler *ch,
@@ -959,6 +1263,12 @@ community_list_terminate (struct community_list_handler *ch)
while ((list = cm->str.head) != NULL)
community_list_delete (list);
+ cm = &ch->lcommunity_list;
+ while ((list = cm->num.head) != NULL)
+ community_list_delete (list);
+ while ((list = cm->str.head) != NULL)
+ community_list_delete (list);
+
cm = &ch->extcommunity_list;
while ((list = cm->num.head) != NULL)
community_list_delete (list);
diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h
index 277ab7226c..68e45c8f7b 100644
--- a/bgpd/bgp_clist.h
+++ b/bgpd/bgp_clist.h
@@ -24,6 +24,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
/* Master Community-list. */
#define COMMUNITY_LIST_MASTER 0
#define EXTCOMMUNITY_LIST_MASTER 1
+#define LARGE_COMMUNITY_LIST_MASTER 2
/* Community-list deny and permit. */
#define COMMUNITY_DENY 0
@@ -38,6 +39,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#define COMMUNITY_LIST_EXPANDED 1 /* Expanded community-list. */
#define EXTCOMMUNITY_LIST_STANDARD 2 /* Standard extcommunity-list. */
#define EXTCOMMUNITY_LIST_EXPANDED 3 /* Expanded extcommunity-list. */
+#define LARGE_COMMUNITY_LIST_STANDARD 4 /* Standard Large community-list. */
+#define LARGE_COMMUNITY_LIST_EXPANDED 5 /* Expanded Large community-list. */
/* Community-list. */
struct community_list
@@ -80,6 +83,7 @@ struct community_entry
{
struct community *com;
struct ecommunity *ecom;
+ struct lcommunity *lcom;
} u;
/* Configuration string. */
@@ -112,6 +116,9 @@ struct community_list_handler
/* Exteded community-list. */
struct community_list_master extcommunity_list;
+
+ /* Large community-list. */
+ struct community_list_master lcommunity_list;
};
/* Error code of community-list. */
@@ -139,6 +146,12 @@ extern int extcommunity_list_set (struct community_list_handler *ch,
extern int extcommunity_list_unset (struct community_list_handler *ch,
const char *name, const char *str,
int direct, int style, int delete_all);
+extern int lcommunity_list_set (struct community_list_handler *ch,
+ const char *name, const char *str,
+ int direct, int style);
+extern int lcommunity_list_unset (struct community_list_handler *ch,
+ const char *name, const char *str,
+ int direct, int style);
extern struct community_list_master *
community_list_master_lookup (struct community_list_handler *, int);
@@ -148,9 +161,12 @@ community_list_lookup (struct community_list_handler *, const char *, int);
extern int community_list_match (struct community *, struct community_list *);
extern int ecommunity_list_match (struct ecommunity *, struct community_list *);
+extern int lcommunity_list_match (struct lcommunity *, struct community_list *);
extern int community_list_exact_match (struct community *,
struct community_list *);
extern struct community *
community_list_match_delete (struct community *, struct community_list *);
-
+extern struct lcommunity *
+lcommunity_list_match_delete (struct lcommunity *lcom,
+ struct community_list *list);
#endif /* _QUAGGA_BGP_CLIST_H */
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index b65af9e1fa..6689883d94 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgpd.h"
#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_aspath.h"
/* Hash of community attribute. */
diff --git a/bgpd/bgp_encap.c b/bgpd/bgp_encap.c
index 201f7bde06..11282a505d 100644
--- a/bgpd/bgp_encap.c
+++ b/bgpd/bgp_encap.c
@@ -41,6 +41,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_encap.h"
diff --git a/bgpd/bgp_encap.h b/bgpd/bgp_encap.h
index f06dfc128c..0de737c49b 100644
--- a/bgpd/bgp_encap.h
+++ b/bgpd/bgp_encap.h
@@ -24,14 +24,8 @@
extern void bgp_encap_init (void);
extern int bgp_nlri_parse_encap (struct peer *, struct attr *, struct bgp_nlri *);
-int
-bgp_show_encap (
- struct vty *vty,
- afi_t afi,
- struct prefix_rd *prd,
- enum bgp_show_type type,
- void *output_arg,
- int tags);
+extern int bgp_show_encap (struct vty *vty, afi_t afi, struct prefix_rd *prd,
+ enum bgp_show_type type, void *output_arg, int tags);
#include "bgp_encap_types.h"
#endif /* _QUAGGA_BGP_ENCAP_H */
diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c
new file mode 100644
index 0000000000..549a2ebad8
--- /dev/null
+++ b/bgpd/bgp_lcommunity.c
@@ -0,0 +1,569 @@
+/* BGP Large Communities Attribute
+ *
+ * Copyright (C) 2016 Keyur Patel <keyur@arrcus.com>
+ *
+ * This file is part of FreeRangeRouting (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 "hash.h"
+#include "memory.h"
+#include "prefix.h"
+#include "command.h"
+#include "filter.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_lcommunity.h"
+#include "bgpd/bgp_aspath.h"
+
+/* Hash of community attribute. */
+static struct hash *lcomhash;
+
+/* Allocate a new lcommunities. */
+static struct lcommunity *
+lcommunity_new (void)
+{
+ return (struct lcommunity *) XCALLOC (MTYPE_LCOMMUNITY,
+ sizeof (struct lcommunity));
+}
+
+/* Allocate lcommunities. */
+void
+lcommunity_free (struct lcommunity **lcom)
+{
+ if ((*lcom)->val)
+ XFREE (MTYPE_LCOMMUNITY_VAL, (*lcom)->val);
+ if ((*lcom)->str)
+ XFREE (MTYPE_LCOMMUNITY_STR, (*lcom)->str);
+ XFREE (MTYPE_LCOMMUNITY, *lcom);
+ lcom = NULL;
+}
+
+static void
+lcommunity_hash_free (struct lcommunity *lcom)
+{
+ lcommunity_free (&lcom);
+}
+
+/* Add a new Large Communities value to Large Communities
+ Attribute structure. When the value is already exists in the
+ structure, we don't add the value. Newly added value is sorted by
+ numerical order. When the value is added to the structure return 1
+ else return 0. */
+static int
+lcommunity_add_val (struct lcommunity *lcom, struct lcommunity_val *lval)
+{
+ u_int8_t *p;
+ int ret;
+ int c;
+
+ /* When this is fist value, just add it. */
+ if (lcom->val == NULL)
+ {
+ lcom->size++;
+ lcom->val = XMALLOC (MTYPE_LCOMMUNITY_VAL, lcom_length (lcom));
+ memcpy (lcom->val, lval->val, LCOMMUNITY_SIZE);
+ return 1;
+ }
+
+ /* If the value already exists in the structure return 0. */
+ c = 0;
+ for (p = lcom->val; c < lcom->size; p += LCOMMUNITY_SIZE, c++)
+ {
+ ret = memcmp (p, lval->val, LCOMMUNITY_SIZE);
+ if (ret == 0)
+ return 0;
+ if (ret > 0)
+ break;
+ }
+
+ /* Add the value to the structure with numerical sorting. */
+ lcom->size++;
+ lcom->val = XREALLOC (MTYPE_LCOMMUNITY_VAL, lcom->val, lcom_length (lcom));
+
+ memmove (lcom->val + (c + 1) * LCOMMUNITY_SIZE,
+ lcom->val + c * LCOMMUNITY_SIZE,
+ (lcom->size - 1 - c) * LCOMMUNITY_SIZE);
+ memcpy (lcom->val + c * LCOMMUNITY_SIZE, lval->val, LCOMMUNITY_SIZE);
+
+ return 1;
+}
+
+/* This function takes pointer to Large Communites strucutre then
+ create a new Large Communities structure by uniq and sort each
+ Large Communities value. */
+struct lcommunity *
+lcommunity_uniq_sort (struct lcommunity *lcom)
+{
+ int i;
+ struct lcommunity *new;
+ struct lcommunity_val *lval;
+
+ if (! lcom)
+ return NULL;
+
+ new = lcommunity_new ();
+
+ for (i = 0; i < lcom->size; i++)
+ {
+ lval = (struct lcommunity_val *) (lcom->val + (i * LCOMMUNITY_SIZE));
+ lcommunity_add_val (new, lval);
+ }
+ return new;
+}
+
+/* Parse Large Communites Attribute in BGP packet. */
+struct lcommunity *
+lcommunity_parse (u_int8_t *pnt, u_short length)
+{
+ struct lcommunity tmp;
+ struct lcommunity *new;
+
+ /* Length check. */
+ if (length % LCOMMUNITY_SIZE)
+ return NULL;
+
+ /* Prepare tmporary structure for making a new Large Communities
+ Attribute. */
+ tmp.size = length / LCOMMUNITY_SIZE;
+ tmp.val = pnt;
+
+ /* Create a new Large Communities Attribute by uniq and sort each
+ Large Communities value */
+ new = lcommunity_uniq_sort (&tmp);
+
+ return lcommunity_intern (new);
+}
+
+/* Duplicate the Large Communities Attribute structure. */
+struct lcommunity *
+lcommunity_dup (struct lcommunity *lcom)
+{
+ struct lcommunity *new;
+
+ new = XCALLOC (MTYPE_LCOMMUNITY, sizeof (struct lcommunity));
+ new->size = lcom->size;
+ if (new->size)
+ {
+ new->val = XMALLOC (MTYPE_LCOMMUNITY_VAL, lcom->size * LCOMMUNITY_SIZE);
+ memcpy (new->val, lcom->val, lcom->size * LCOMMUNITY_SIZE);
+ }
+ else
+ new->val = NULL;
+ return new;
+}
+
+/* Retrun string representation of communities attribute. */
+char *
+lcommunity_str (struct lcommunity *lcom)
+{
+ if (! lcom->str)
+ lcom->str = lcommunity_lcom2str (lcom, LCOMMUNITY_FORMAT_DISPLAY);
+ return lcom->str;
+}
+
+/* Merge two Large Communities Attribute structure. */
+struct lcommunity *
+lcommunity_merge (struct lcommunity *lcom1, struct lcommunity *lcom2)
+{
+ if (lcom1->val)
+ lcom1->val = XREALLOC (MTYPE_LCOMMUNITY_VAL, lcom1->val,
+ (lcom1->size + lcom2->size) * LCOMMUNITY_SIZE);
+ else
+ lcom1->val = XMALLOC (MTYPE_LCOMMUNITY_VAL,
+ (lcom1->size + lcom2->size) * LCOMMUNITY_SIZE);
+
+ memcpy (lcom1->val + (lcom1->size * LCOMMUNITY_SIZE),
+ lcom2->val, lcom2->size * LCOMMUNITY_SIZE);
+ lcom1->size += lcom2->size;
+
+ return lcom1;
+}
+
+/* Intern Large Communities Attribute. */
+struct lcommunity *
+lcommunity_intern (struct lcommunity *lcom)
+{
+ struct lcommunity *find;
+
+ assert (lcom->refcnt == 0);
+
+ find = (struct lcommunity *) hash_get (lcomhash, lcom, hash_alloc_intern);
+
+ if (find != lcom)
+ lcommunity_free (&lcom);
+
+ find->refcnt++;
+
+ if (! find->str)
+ find->str = lcommunity_lcom2str (find, LCOMMUNITY_FORMAT_DISPLAY);
+
+ return find;
+}
+
+/* Unintern Large Communities Attribute. */
+void
+lcommunity_unintern (struct lcommunity **lcom)
+{
+ struct lcommunity *ret;
+
+ if ((*lcom)->refcnt)
+ (*lcom)->refcnt--;
+
+ /* Pull off from hash. */
+ if ((*lcom)->refcnt == 0)
+ {
+ /* Large community must be in the hash. */
+ ret = (struct lcommunity *) hash_release (lcomhash, *lcom);
+ assert (ret != NULL);
+
+ lcommunity_free (lcom);
+ }
+}
+
+/* Utility function to make hash key. */
+unsigned int
+lcommunity_hash_make (void *arg)
+{
+ const struct lcommunity *lcom = arg;
+ int size = lcom->size * LCOMMUNITY_SIZE;
+ u_int8_t *pnt = lcom->val;
+ unsigned int key = 0;
+ int c;
+
+ for (c = 0; c < size; c += LCOMMUNITY_SIZE)
+ {
+ key += pnt[c];
+ key += pnt[c + 1];
+ key += pnt[c + 2];
+ key += pnt[c + 3];
+ key += pnt[c + 4];
+ key += pnt[c + 5];
+ key += pnt[c + 6];
+ key += pnt[c + 7];
+ key += pnt[c + 8];
+ key += pnt[c + 9];
+ key += pnt[c + 10];
+ key += pnt[c + 11];
+ }
+
+ return key;
+}
+
+/* Compare two Large Communities Attribute structure. */
+int
+lcommunity_cmp (const void *arg1, const void *arg2)
+{
+ const struct lcommunity *lcom1 = arg1;
+ const struct lcommunity *lcom2 = arg2;
+
+ return (lcom1->size == lcom2->size
+ && memcmp (lcom1->val, lcom2->val, lcom1->size * LCOMMUNITY_SIZE) == 0);
+}
+
+/* Return communities hash. */
+struct hash *
+lcommunity_hash (void)
+{
+ return lcomhash;
+}
+
+/* Initialize Large Comminities related hash. */
+void
+lcommunity_init (void)
+{
+ lcomhash = hash_create (lcommunity_hash_make, lcommunity_cmp);
+}
+
+void
+lcommunity_finish (void)
+{
+ hash_clean (lcomhash, (void (*)(void *))lcommunity_hash_free);
+ hash_free (lcomhash);
+ lcomhash = NULL;
+}
+
+/* Large Communities token enum. */
+enum lcommunity_token
+{
+ lcommunity_token_unknown = 0,
+ lcommunity_token_val,
+};
+
+/* Get next Large Communities token from the string. */
+static const char *
+lcommunity_gettoken (const char *str, struct lcommunity_val *lval,
+ enum lcommunity_token *token)
+{
+ const char *p = str;
+
+ /* Skip white space. */
+ while (isspace ((int) *p))
+ {
+ p++;
+ str++;
+ }
+
+ /* Check the end of the line. */
+ if (*p == '\0')
+ return NULL;
+
+ /* Community value. */
+ if (isdigit ((int) *p))
+ {
+ int separator = 0;
+ int digit = 0;
+ u_int32_t globaladmin = 0;
+ u_int32_t localdata1 = 0;
+ u_int32_t localdata2 = 0;
+
+ while (isdigit ((int) *p) || *p == ':')
+ {
+ if (*p == ':')
+ {
+ if (separator == 2)
+ {
+ *token = lcommunity_token_unknown;
+ return NULL;
+ }
+ else
+ {
+ separator++;
+ digit = 0;
+ if (separator == 1) {
+ globaladmin = localdata2;
+ } else {
+ localdata1 = localdata2;
+ }
+ localdata2 = 0;
+ }
+ }
+ else
+ {
+ digit = 1;
+ localdata2 *= 10;
+ localdata2 += (*p - '0');
+ }
+ p++;
+ }
+ if (! digit)
+ {
+ *token = lcommunity_token_unknown;
+ return NULL;
+ }
+
+ /*
+ * Copy the large comm.
+ */
+ lval->val[0] = (globaladmin >> 24) & 0xff;
+ lval->val[1] = (globaladmin >> 16) & 0xff;
+ lval->val[2] = (globaladmin >> 8) & 0xff;
+ lval->val[3] = globaladmin & 0xff;
+ lval->val[4] = (localdata1 >> 24) & 0xff;
+ lval->val[5] = (localdata1 >> 16) & 0xff;
+ lval->val[6] = (localdata1 >> 8) & 0xff;
+ lval->val[7] = localdata1 & 0xff;
+ lval->val[8] = (localdata2 >> 24) & 0xff;
+ lval->val[9] = (localdata2 >> 16) & 0xff;
+ lval->val[10] = (localdata2 >> 8) & 0xff;
+ lval->val[11] = localdata2 & 0xff;
+
+ *token = lcommunity_token_val;
+ return p;
+ }
+ *token = lcommunity_token_unknown;
+ return p;
+}
+
+/*
+ Convert string to large community attribute.
+ When type is already known, please specify both str and type.
+
+ When string includes keyword for each large community value.
+ Please specify keyword_included as non-zero value.
+*/
+struct lcommunity *
+lcommunity_str2com (const char *str)
+{
+ struct lcommunity *lcom = NULL;
+ enum lcommunity_token token = lcommunity_token_unknown;
+ struct lcommunity_val lval;
+
+ while ((str = lcommunity_gettoken (str, &lval, &token)))
+ {
+ switch (token)
+ {
+ case lcommunity_token_val:
+ if (lcom == NULL)
+ lcom = lcommunity_new ();
+ lcommunity_add_val (lcom, &lval);
+ break;
+ case lcommunity_token_unknown:
+ default:
+ if (lcom)
+ lcommunity_free (&lcom);
+ return NULL;
+ }
+ }
+ return lcom;
+}
+
+int
+lcommunity_include (struct lcommunity *lcom, u_char *ptr)
+{
+ int i;
+ u_char *lcom_ptr;
+
+ lcom_ptr = lcom->val;
+ for (i = 0; i < lcom->size; i++) {
+ lcom_ptr += (i * LCOMMUNITY_SIZE);
+ if (memcmp (ptr, lcom_ptr, LCOMMUNITY_SIZE) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+/* Convert large community attribute to string.
+ The large coms will be in 65535:65531:0 format.
+*/
+char *
+lcommunity_lcom2str (struct lcommunity *lcom, int format)
+{
+ int i;
+ u_int8_t *pnt;
+#define LCOMMUNITY_STR_DEFAULT_LEN 40
+ int str_size;
+ int str_pnt;
+ char *str_buf;
+ int len = 0;
+ int first = 1;
+ u_int32_t globaladmin, localdata1, localdata2;
+
+ if (lcom->size == 0)
+ {
+ str_buf = XMALLOC (MTYPE_LCOMMUNITY_STR, 1);
+ str_buf[0] = '\0';
+ return str_buf;
+ }
+
+ /* Prepare buffer. */
+ str_buf = XMALLOC (MTYPE_LCOMMUNITY_STR, LCOMMUNITY_STR_DEFAULT_LEN + 1);
+ str_size = LCOMMUNITY_STR_DEFAULT_LEN + 1;
+ str_pnt = 0;
+
+ for (i = 0; i < lcom->size; i++)
+ {
+ /* Make it sure size is enough. */
+ while (str_pnt + LCOMMUNITY_STR_DEFAULT_LEN >= str_size)
+ {
+ str_size *= 2;
+ str_buf = XREALLOC (MTYPE_LCOMMUNITY_STR, str_buf, str_size);
+ }
+
+ /* Space between each value. */
+ if (! first)
+ str_buf[str_pnt++] = ' ';
+
+ pnt = lcom->val + (i * 12);
+
+ globaladmin = (*pnt++ << 24);
+ globaladmin |= (*pnt++ << 16);
+ globaladmin |= (*pnt++ << 8);
+ globaladmin |= (*pnt++);
+
+ localdata1 = (*pnt++ << 24);
+ localdata1 |= (*pnt++ << 16);
+ localdata1 |= (*pnt++ << 8);
+ localdata1 |= (*pnt++);
+
+ localdata2 = (*pnt++ << 24);
+ localdata2 |= (*pnt++ << 16);
+ localdata2 |= (*pnt++ << 8);
+ localdata2 |= (*pnt++);
+
+ len = sprintf( str_buf + str_pnt, "%u:%u:%u", globaladmin,
+ localdata1, localdata2);
+ str_pnt += len;
+ first = 0;
+ }
+ return str_buf;
+}
+
+int
+lcommunity_match (const struct lcommunity *lcom1,
+ const struct lcommunity *lcom2)
+{
+ int i = 0;
+ int j = 0;
+
+ if (lcom1 == NULL && lcom2 == NULL)
+ return 1;
+
+ if (lcom1 == NULL || lcom2 == NULL)
+ return 0;
+
+ if (lcom1->size < lcom2->size)
+ return 0;
+
+ /* Every community on com2 needs to be on com1 for this to match */
+ while (i < lcom1->size && j < lcom2->size)
+ {
+ if (memcmp (lcom1->val + (i*12), lcom2->val + (j*12), LCOMMUNITY_SIZE) == 0)
+ j++;
+ i++;
+ }
+
+ if (j == lcom2->size)
+ return 1;
+ else
+ return 0;
+}
+
+/* Delete one lcommunity. */
+void
+lcommunity_del_val (struct lcommunity *lcom, u_char *ptr)
+{
+ int i = 0;
+ int c = 0;
+
+ if (! lcom->val)
+ return;
+
+ while (i < lcom->size)
+ {
+ if (memcmp (lcom->val + i*LCOMMUNITY_SIZE, ptr, LCOMMUNITY_SIZE) == 0)
+ {
+ c = lcom->size -i -1;
+
+ if (c > 0)
+ memmove (lcom->val + i*LCOMMUNITY_SIZE, lcom->val + (i + 1)*LCOMMUNITY_SIZE, c * LCOMMUNITY_SIZE);
+
+ lcom->size--;
+
+ if (lcom->size > 0)
+ lcom->val = XREALLOC (MTYPE_COMMUNITY_VAL, lcom->val,
+ lcom_length (lcom));
+ else
+ {
+ XFREE (MTYPE_COMMUNITY_VAL, lcom->val);
+ lcom->val = NULL;
+ }
+ return;
+ }
+ i++;
+ }
+}
diff --git a/bgpd/bgp_lcommunity.h b/bgpd/bgp_lcommunity.h
new file mode 100644
index 0000000000..de3697f477
--- /dev/null
+++ b/bgpd/bgp_lcommunity.h
@@ -0,0 +1,74 @@
+/* BGP Large Communities Attribute.
+ *
+ * Copyright (C) 2016 Keyur Patel <keyur@arrcus.com>
+ *
+ * This file is part of FreeRangeRouting (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 _QUAGGA_BGP_LCOMMUNITY_H
+#define _QUAGGA_BGP_LCOMMUNITY_H
+
+/* Extended communities attribute string format. */
+#define LCOMMUNITY_FORMAT_ROUTE_MAP 0
+#define LCOMMUNITY_FORMAT_COMMUNITY_LIST 1
+#define LCOMMUNITY_FORMAT_DISPLAY 2
+
+/* Large Communities value is twelve octets long. */
+#define LCOMMUNITY_SIZE 12
+
+/* Large Communities attribute. */
+struct lcommunity
+{
+ /* Reference counter. */
+ unsigned long refcnt;
+
+ /* Size of Extended Communities attribute. */
+ int size;
+
+ /* Extended Communities value. */
+ u_int8_t *val;
+
+ /* Human readable format string. */
+ char *str;
+};
+
+/* Extended community value is eight octet. */
+struct lcommunity_val
+{
+ char val[LCOMMUNITY_SIZE];
+};
+
+#define lcom_length(X) ((X)->size * LCOMMUNITY_SIZE)
+
+extern void lcommunity_init (void);
+extern void lcommunity_finish (void);
+extern void lcommunity_free (struct lcommunity **);
+extern struct lcommunity *lcommunity_parse (u_int8_t *, u_short);
+extern struct lcommunity *lcommunity_dup (struct lcommunity *);
+extern struct lcommunity *lcommunity_merge (struct lcommunity *, struct lcommunity *);
+extern struct lcommunity *lcommunity_uniq_sort (struct lcommunity *);
+extern struct lcommunity *lcommunity_intern (struct lcommunity *);
+extern int lcommunity_cmp (const void *, const void *);
+extern void lcommunity_unintern (struct lcommunity **);
+extern unsigned int lcommunity_hash_make (void *);
+extern struct hash *lcommunity_hash (void);
+extern struct lcommunity *lcommunity_str2com (const char *);
+extern char *lcommunity_lcom2str (struct lcommunity *, int);
+extern int lcommunity_match (const struct lcommunity *, const struct lcommunity *);
+extern char *lcommunity_str (struct lcommunity *);
+extern int lcommunity_include (struct lcommunity *lcom, u_char *ptr);
+extern void lcommunity_del_val (struct lcommunity *lcom, u_char *ptr);
+#endif /* _QUAGGA_BGP_LCOMMUNITY_H */
diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c
index 72c0311c17..85e32645ee 100644
--- a/bgpd/bgp_memory.c
+++ b/bgpd/bgp_memory.c
@@ -111,3 +111,7 @@ DEFINE_MTYPE(BGPD, ENCAP_TLV, "ENCAP TLV")
DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS, "BGP TEA Options")
DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS_VALUE, "BGP TEA Options Value")
+
+DEFINE_MTYPE(BGPD, LCOMMUNITY, "Large Community")
+DEFINE_MTYPE(BGPD, LCOMMUNITY_STR, "Large Community display string")
+DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value")
diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h
index a4ce8b891b..341fb235d0 100644
--- a/bgpd/bgp_memory.h
+++ b/bgpd/bgp_memory.h
@@ -108,4 +108,7 @@ DECLARE_MTYPE(ENCAP_TLV)
DECLARE_MTYPE(BGP_TEA_OPTIONS)
DECLARE_MTYPE(BGP_TEA_OPTIONS_VALUE)
+DECLARE_MTYPE(LCOMMUNITY)
+DECLARE_MTYPE(LCOMMUNITY_STR)
+DECLARE_MTYPE(LCOMMUNITY_VAL)
#endif /* _QUAGGA_BGP_MEMORY_H */
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c
index 1701c70441..f564ff1691 100644
--- a/bgpd/bgp_mpath.c
+++ b/bgpd/bgp_mpath.c
@@ -38,6 +38,7 @@
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_mpath.h"
/*
@@ -662,6 +663,7 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
u_char origin;
struct community *community, *commerge;
struct ecommunity *ecomm, *ecommerge;
+ struct lcommunity *lcomm, *lcommerge;
struct attr_extra *ae;
struct attr attr = { 0 };
@@ -698,6 +700,7 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
community = attr.community ? community_dup (attr.community) : NULL;
ae = attr.extra;
ecomm = (ae && ae->ecommunity) ? ecommunity_dup (ae->ecommunity) : NULL;
+ lcomm = (ae && ae->lcommunity) ? lcommunity_dup (ae->lcommunity) : NULL;
for (mpinfo = bgp_info_mpath_first (new_best); mpinfo;
mpinfo = bgp_info_mpath_next (mpinfo))
@@ -733,6 +736,17 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
else
ecomm = ecommunity_dup (ae->ecommunity);
}
+ if (ae && ae->lcommunity)
+ {
+ if (lcomm)
+ {
+ lcommerge = lcommunity_merge (lcomm, ae->lcommunity);
+ lcomm = lcommunity_uniq_sort (lcommerge);
+ lcommunity_free (&lcommerge);
+ }
+ else
+ lcomm = lcommunity_dup (ae->lcommunity);
+ }
}
attr.aspath = aspath;
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 7a2717acc0..6e722bbb55 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -566,6 +566,7 @@ DEFUN (no_vpnv6_network,
return bgp_static_unset_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg);
}
+#if defined(KEEP_OLD_VPN_COMMANDS)
static int
show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd, u_char use_json, afi_t afi)
{
@@ -732,6 +733,7 @@ show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd, u
}
return CMD_SUCCESS;
}
+#endif
int
bgp_show_mpls_vpn (struct vty *vty, afi_t afi, struct prefix_rd *prd,
diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h
index 97eed3c35a..ea6cbcd272 100644
--- a/bgpd/bgp_mplsvpn.h
+++ b/bgpd/bgp_mplsvpn.h
@@ -30,6 +30,10 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#define RD_ADDRSTRLEN 28
+#ifdef MPLS_LABEL_MAX
+# undef MPLS_LABEL_MAX
+#endif
+
typedef enum {
MPLS_LABEL_IPV4_EXPLICIT_NULL = 0, /* [RFC3032] */
MPLS_LABEL_ROUTER_ALERT = 1, /* [RFC3032] */
@@ -45,7 +49,9 @@ typedef enum {
MPLS_LABEL_UNASSIGNED11 = 11,
MPLS_LABEL_GAL = 13, /* [RFC5586] */
MPLS_LABEL_OAM_ALERT = 14, /* [RFC3429] */
- MPLS_LABEL_EXTENSION = 15 /* [RFC7274] */
+ MPLS_LABEL_EXTENSION = 15, /* [RFC7274] */
+ MPLS_LABEL_MAX = 1048575,
+ MPLS_LABEL_ILLEGAL = 0xFFFFFFFF /* for internal use only */
} mpls_special_label_t;
#define MPLS_LABEL_IS_SPECIAL(label) \
@@ -100,8 +106,7 @@ extern char *prefix_rd2str (struct prefix_rd *, char *, size_t);
extern int
argv_find_and_parse_vpnvx(struct cmd_token **argv, int argc, int *index, afi_t *afi);
-int
-bgp_show_mpls_vpn (struct vty *vty, afi_t afi, struct prefix_rd *prd,
- enum bgp_show_type type, void *output_arg, int tags, u_char use_json);
+extern int bgp_show_mpls_vpn (struct vty *vty, afi_t afi, struct prefix_rd *prd,
+ enum bgp_show_type type, void *output_arg, int tags, u_char use_json);
#endif /* _QUAGGA_BGP_MPLSVPN_H */
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index 0a9747b526..0cf96101c2 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -492,7 +492,7 @@ bgp_show_all_instances_nexthops_vty (struct vty *vty)
DEFUN (show_ip_bgp_nexthop,
show_ip_bgp_nexthop_cmd,
- "show [ip] bgp [<view|vrf> VRFNAME] nexthop [detail]",
+ "show [ip] bgp [<view|vrf> WORD] nexthop [detail]",
SHOW_STR
IP_STR
BGP_STR
@@ -501,7 +501,7 @@ DEFUN (show_ip_bgp_nexthop,
"Show detailed information\n")
{
int idx = 0;
- char *vrf = argv_find (argv, argc, "VRFNAME", &idx) ? argv[idx]->arg : NULL;
+ char *vrf = argv_find (argv, argc, "WORD", &idx) ? argv[idx]->arg : NULL;
int detail = argv_find (argv, argc, "detail", &idx) ? 1 : 0;
return show_ip_bgp_nexthop_table (vty, vrf, detail);
}
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 4a06881041..7dbb439be1 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -188,7 +188,9 @@ bgp_capability_mp (struct peer *peer, struct capability_header *hdr)
{
struct capability_mp_data mpc;
struct stream *s = BGP_INPUT (peer);
-
+ afi_t afi;
+ safi_t safi;
+
/* Verify length is 4 */
if (hdr->length != 4)
{
@@ -204,14 +206,14 @@ bgp_capability_mp (struct peer *peer, struct capability_header *hdr)
peer->host, mpc.afi, mpc.safi);
/* Convert AFI, SAFI to internal values, check. */
- if (bgp_map_afi_safi_iana2int (mpc.afi, mpc.safi, &mpc.afi, &mpc.safi))
+ if (bgp_map_afi_safi_iana2int (mpc.afi, mpc.safi, &afi, &safi))
return -1;
/* Now safi remapped, and afi/safi are valid array indices */
- peer->afc_recv[mpc.afi][mpc.safi] = 1;
+ peer->afc_recv[afi][safi] = 1;
- if (peer->afc[mpc.afi][mpc.safi])
- peer->afc_nego[mpc.afi][mpc.safi] = 1;
+ if (peer->afc[afi][safi])
+ peer->afc_nego[afi][safi] = 1;
else
return -1;
@@ -219,7 +221,7 @@ bgp_capability_mp (struct peer *peer, struct capability_header *hdr)
}
static void
-bgp_capability_orf_not_support (struct peer *peer, afi_t afi, safi_t safi,
+bgp_capability_orf_not_support (struct peer *peer, iana_afi_t afi, safi_t safi,
u_char type, u_char mode)
{
if (bgp_debug_neighbor_events(peer))
@@ -247,7 +249,8 @@ bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)
{
struct stream *s = BGP_INPUT (peer);
struct capability_orf_entry entry;
- afi_t pkt_afi, afi;
+ iana_afi_t pkt_afi;
+ afi_t afi;
safi_t pkt_safi, safi;
u_char type;
u_char mode;
@@ -274,7 +277,7 @@ bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)
return 0;
}
- entry.mpc.afi = afi;
+ entry.mpc.afi = pkt_afi;
entry.mpc.safi = safi;
/* validate number field */
@@ -418,7 +421,7 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)
{
afi_t afi;
safi_t safi;
- afi_t pkt_afi = stream_getw (s);
+ iana_afi_t pkt_afi = stream_getw (s);
safi_t pkt_safi = stream_getc (s);
u_char flag = stream_getc (s);
@@ -496,7 +499,7 @@ bgp_capability_addpath (struct peer *peer, struct capability_header *hdr)
{
afi_t afi;
safi_t safi;
- afi_t pkt_afi = stream_getw (s);
+ iana_afi_t pkt_afi = stream_getw (s);
safi_t pkt_safi = stream_getc (s);
u_char send_receive = stream_getc (s);
@@ -550,9 +553,11 @@ bgp_capability_enhe (struct peer *peer, struct capability_header *hdr)
while (stream_get_getp (s) + 6 <= end)
{
- afi_t afi, pkt_afi = stream_getw (s);
+ iana_afi_t pkt_afi = stream_getw (s);
+ afi_t afi;
safi_t safi, pkt_safi = stream_getw (s);
- afi_t nh_afi, pkt_nh_afi = stream_getw (s);
+ iana_afi_t pkt_nh_afi = stream_getw (s);
+ afi_t nh_afi;
if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s Received with afi/safi/next-hop afi: %u/%u/%u",
@@ -1162,7 +1167,7 @@ bgp_open_capability_orf (struct stream *s, struct peer *peer,
unsigned long orfp;
unsigned long numberp;
int number_of_orfs = 0;
- afi_t pkt_afi;
+ iana_afi_t pkt_afi;
safi_t pkt_safi;
/* Convert AFI, SAFI to values for packet. */
@@ -1225,7 +1230,8 @@ bgp_open_capability (struct stream *s, struct peer *peer)
{
u_char len;
unsigned long cp, capp, rcapp;
- afi_t afi, pkt_afi;
+ iana_afi_t pkt_afi;
+ afi_t afi;
safi_t safi, pkt_safi;
as_t local_as;
u_int32_t restart_time;
diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h
index b0a396ec11..9275b3a101 100644
--- a/bgpd/bgp_open.h
+++ b/bgpd/bgp_open.h
@@ -31,7 +31,7 @@ struct capability_header
/* Generic MP capability data */
struct capability_mp_data
{
- afi_t afi;
+ iana_afi_t afi;
u_char reserved;
safi_t safi;
};
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 38470a3c7e..2df22ab568 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -46,6 +46,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_network.h"
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_encap.h"
@@ -147,7 +148,7 @@ static struct stream *
bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi)
{
struct stream *s;
- afi_t pkt_afi;
+ iana_afi_t pkt_afi;
safi_t pkt_safi;
if (DISABLE_BGP_ANNOUNCE)
@@ -695,7 +696,7 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi,
struct stream *s;
struct bgp_filter *filter;
int orf_refresh = 0;
- afi_t pkt_afi;
+ iana_afi_t pkt_afi;
safi_t pkt_safi;
if (DISABLE_BGP_ANNOUNCE)
@@ -782,7 +783,7 @@ bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi,
int capability_code, int action)
{
struct stream *s;
- afi_t pkt_afi;
+ iana_afi_t pkt_afi;
safi_t pkt_safi;
/* Convert AFI, SAFI to values for packet. */
@@ -1711,7 +1712,8 @@ bgp_keepalive_receive (struct peer *peer, bgp_size_t size)
static void
bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
{
- afi_t pkt_afi, afi;
+ iana_afi_t pkt_afi;
+ afi_t afi;
safi_t pkt_safi, safi;
struct stream *s;
struct peer_af *paf;
@@ -1932,7 +1934,8 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
struct capability_mp_data mpc;
struct capability_header *hdr;
u_char action;
- afi_t pkt_afi, afi;
+ iana_afi_t pkt_afi;
+ afi_t afi;
safi_t pkt_safi, safi;
end = pnt + length;
@@ -2153,15 +2156,6 @@ bgp_marker_all_one (struct stream *s, int length)
return 1;
}
-/* Recent thread time.
- On same clock base as bgp_clock (MONOTONIC)
- but can be time of last context switch to bgp_read thread. */
-static time_t
-bgp_recent_clock (void)
-{
- return recent_relative_time().tv_sec;
-}
-
/* Starting point of packet process function. */
int
bgp_read (struct thread *thread)
@@ -2288,14 +2282,14 @@ bgp_read (struct thread *thread)
bgp_open_receive (peer, size); /* XXX return value ignored! */
break;
case BGP_MSG_UPDATE:
- peer->readtime = bgp_recent_clock ();
+ peer->readtime = monotime (NULL);
bgp_update_receive (peer, size);
break;
case BGP_MSG_NOTIFY:
bgp_notify_receive (peer, size);
break;
case BGP_MSG_KEEPALIVE:
- peer->readtime = bgp_recent_clock ();
+ peer->readtime = monotime (NULL);
bgp_keepalive_receive (peer, size);
break;
case BGP_MSG_ROUTE_REFRESH_NEW:
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index eea0f86b34..fb33b234f4 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1,5 +1,6 @@
/* BGP routing information
Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro
+ Copyright (C) 2016 Job Snijders <job@instituut.net>
This file is part of GNU Zebra.
@@ -46,6 +47,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_regex.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_clist.h"
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_filter.h"
@@ -2112,10 +2114,10 @@ bgp_maximum_prefix_restart_timer (struct thread *thread)
}
int
-bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
+bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
safi_t safi, int always)
{
- afi_t pkt_afi;
+ iana_afi_t pkt_afi;
safi_t pkt_safi;
if (!CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX))
@@ -7061,7 +7063,12 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
}
}
- /* Line 6 display Originator, Cluster-id */
+ /* Line 6 display Large community */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))
+ vty_out (vty, " Large Community: %s%s",
+ attr->extra->lcommunity->str, VTY_NEWLINE);
+
+ /* Line 7 display Originator, Cluster-id */
if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) ||
(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)))
{
@@ -7117,7 +7124,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (binfo->extra && binfo->extra->damp_info)
bgp_damp_info_vty (vty, binfo, json_path);
- /* Line 7 display Addpath IDs */
+ /* Line 8 display Addpath IDs */
if (binfo->addpath_rx_id || binfo->addpath_tx_id)
{
if (json_paths)
@@ -7172,7 +7179,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
}
}
- /* Line 8 display Uptime */
+ /* Line 9 display Uptime */
tbuf = time(NULL) - (bgp_clock() - binfo->uptime);
if (json_paths)
{
@@ -7215,30 +7222,30 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
#define BGP_SHOW_FLAP_HEADER " Network From Flaps Duration Reuse Path%s"
static int
-bgp_show_prefix_list (struct vty *vty, const char *name,
+bgp_show_prefix_list (struct vty *vty, struct bgp *bgp,
const char *prefix_list_str, afi_t afi,
safi_t safi, enum bgp_show_type type);
static int
-bgp_show_filter_list (struct vty *vty, const char *name,
+bgp_show_filter_list (struct vty *vty, struct bgp *bgp,
const char *filter, afi_t afi,
safi_t safi, enum bgp_show_type type);
static int
-bgp_show_route_map (struct vty *vty, const char *name,
+bgp_show_route_map (struct vty *vty, struct bgp *bgp,
const char *rmap_str, afi_t afi,
safi_t safi, enum bgp_show_type type);
static int
-bgp_show_community_list (struct vty *vty, const char *name,
+bgp_show_community_list (struct vty *vty, struct bgp *bgp,
const char *com, int exact,
afi_t afi, safi_t safi);
static int
-bgp_show_prefix_longer (struct vty *vty, const char *name,
+bgp_show_prefix_longer (struct vty *vty, struct bgp *bgp,
const char *prefix, afi_t afi,
safi_t safi, enum bgp_show_type type);
static int
bgp_show_regexp (struct vty *vty, const char *regstr, afi_t afi,
safi_t safi, enum bgp_show_type type);
static int
-bgp_show_community (struct vty *vty, const char *view_name, int argc,
+bgp_show_community (struct vty *vty, struct bgp *bgp, int argc,
struct cmd_token **argv, int exact, afi_t afi, safi_t safi);
static int
@@ -7397,6 +7404,27 @@ bgp_show_table (struct vty *vty, struct bgp *bgp, struct bgp_table *table,
if (! community_list_exact_match (ri->attr->community, list))
continue;
}
+ if (type == bgp_show_type_lcommunity)
+ {
+ struct lcommunity *lcom = output_arg;
+
+ if (! ri->attr->extra || ! ri->attr->extra->lcommunity ||
+ ! lcommunity_match (ri->attr->extra->lcommunity, lcom))
+ continue;
+ }
+ if (type == bgp_show_type_lcommunity_list)
+ {
+ struct community_list *list = output_arg;
+
+ if (! ri->attr->extra ||
+ ! lcommunity_list_match (ri->attr->extra->lcommunity, list))
+ continue;
+ }
+ if (type == bgp_show_type_lcommunity_all)
+ {
+ if (! ri->attr->extra || ! ri->attr->extra->lcommunity)
+ continue;
+ }
if (type == bgp_show_type_dampend_paths
|| type == bgp_show_type_damp_neighbor)
{
@@ -7781,41 +7809,173 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
/* Display specified route of Main RIB */
static int
-bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str,
+bgp_show_route (struct vty *vty, struct bgp *bgp, const char *ip_str,
afi_t afi, safi_t safi, struct prefix_rd *prd,
int prefix_check, enum bgp_path_type pathtype,
u_char use_json)
{
- struct bgp *bgp;
+ return bgp_show_route_in_table (vty, bgp, bgp->rib[afi][safi], ip_str,
+ afi, safi, prd, prefix_check, pathtype,
+ use_json);
+}
- /* BGP structure lookup. */
- if (view_name)
+static int
+bgp_show_lcommunity (struct vty *vty, struct bgp *bgp, int argc,
+ struct cmd_token **argv, afi_t afi, safi_t safi, u_char uj)
+{
+ struct lcommunity *lcom;
+ struct buffer *b;
+ int i;
+ char *str;
+ int first = 0;
+
+ b = buffer_new (1024);
+ for (i = 0; i < argc; i++)
{
- bgp = bgp_lookup_by_name (view_name);
- if (bgp == NULL)
- {
- vty_out (vty, "Can't find BGP instance %s%s", view_name, VTY_NEWLINE);
- return CMD_WARNING;
- }
+ if (first)
+ buffer_putc (b, ' ');
+ else
+ {
+ if (strmatch (argv[i]->text, "<AA:BB:CC>"))
+ {
+ first = 1;
+ buffer_putstr (b, argv[i]->arg);
+ }
+ }
}
- else
+ buffer_putc (b, '\0');
+
+ str = buffer_getstr (b);
+ buffer_free (b);
+
+ lcom = lcommunity_str2com (str);
+ XFREE (MTYPE_TMP, str);
+ if (! lcom)
{
- bgp = bgp_get_default ();
- if (bgp == NULL)
- {
- vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
+ vty_out (vty, "%% Large-community malformed: %s", VTY_NEWLINE);
+ return CMD_WARNING;
}
-
- return bgp_show_route_in_table (vty, bgp, bgp->rib[afi][safi], ip_str,
- afi, safi, prd, prefix_check, pathtype,
- use_json);
+
+ return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity, lcom, uj);
+}
+
+static int
+bgp_show_lcommunity_list (struct vty *vty, struct bgp *bgp, const char *lcom,
+ afi_t afi, safi_t safi, u_char uj)
+{
+ struct community_list *list;
+
+ list = community_list_lookup (bgp_clist, lcom, LARGE_COMMUNITY_LIST_MASTER);
+ if (list == NULL)
+ {
+ vty_out (vty, "%% %s is not a valid large-community-list name%s", lcom,
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_list, list, uj);
}
+DEFUN (show_ip_bgp_large_community_list,
+ show_ip_bgp_large_community_list_cmd,
+ "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] large-community-list <(1-500)|WORD> [json]",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ BGP_INSTANCE_HELP_STR
+ "Address Family\n"
+ "Address Family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the large-community-list\n"
+ "large-community-list number\n"
+ "large-community-list name\n"
+ JSON_STR)
+{
+ char *vrf = NULL;
+ afi_t afi = AFI_IP6;
+ safi_t safi = SAFI_UNICAST;
+ int idx = 0;
+
+ if (argv_find (argv, argc, "ip", &idx))
+ afi = AFI_IP;
+ if (argv_find (argv, argc, "view", &idx) || argv_find (argv, argc, "vrf", &idx))
+ vrf = argv[++idx]->arg;
+ if (argv_find (argv, argc, "ipv4", &idx) || argv_find (argv, argc, "ipv6", &idx))
+ {
+ afi = strmatch(argv[idx]->text, "ipv6") ? AFI_IP6 : AFI_IP;
+ if (argv_find (argv, argc, "unicast", &idx) || argv_find (argv, argc, "multicast", &idx))
+ safi = bgp_vty_safi_from_arg (argv[idx]->text);
+ }
+
+ int uj = use_json (argc, argv);
+
+ struct bgp *bgp = bgp_lookup_by_name (vrf);
+ if (bgp == NULL)
+ {
+ vty_out (vty, "Can't find BGP instance %s%s", vrf, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ argv_find (argv, argc, "large-community-list", &idx);
+ return bgp_show_lcommunity_list (vty, bgp, argv[idx+1]->arg, afi, safi, uj);
+}
+DEFUN (show_ip_bgp_large_community,
+ show_ip_bgp_large_community_cmd,
+ "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] large-community [AA:BB:CC] [json]",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ BGP_INSTANCE_HELP_STR
+ "Address Family\n"
+ "Address Family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the large-communities\n"
+ "List of large-community numbers\n"
+ JSON_STR)
+{
+ char *vrf = NULL;
+ afi_t afi = AFI_IP6;
+ safi_t safi = SAFI_UNICAST;
+ int idx = 0;
+
+ if (argv_find (argv, argc, "ip", &idx))
+ afi = AFI_IP;
+ if (argv_find (argv, argc, "view", &idx) || argv_find (argv, argc, "vrf", &idx))
+ vrf = argv[++idx]->arg;
+ if (argv_find (argv, argc, "ipv4", &idx) || argv_find (argv, argc, "ipv6", &idx))
+ {
+ afi = strmatch(argv[idx]->text, "ipv6") ? AFI_IP6 : AFI_IP;
+ if (argv_find (argv, argc, "unicast", &idx) || argv_find (argv, argc, "multicast", &idx))
+ safi = bgp_vty_safi_from_arg (argv[idx]->text);
+ }
+
+ int uj = use_json (argc, argv);
+
+ struct bgp *bgp = bgp_lookup_by_name (vrf);
+ if (bgp == NULL)
+ {
+ vty_out (vty, "Can't find BGP instance %s%s", vrf, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ argv_find (argv, argc, "large-community", &idx);
+ if (strmatch(argv[idx+1]->text, "AA:BB:CC"))
+ return bgp_show_lcommunity (vty, bgp, argc, argv, afi, safi, uj);
+ else
+ return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_all, NULL, uj);
+}
+
+static int bgp_table_stats (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi);
+
/* BGP route print out function. */
-DEFUN (show_ip_bgp_ipv4,
- show_ip_bgp_ipv4_cmd,
+DEFUN (show_ip_bgp,
+ show_ip_bgp_cmd,
"show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]]\
[<\
cidr-only\
@@ -7823,6 +7983,7 @@ DEFUN (show_ip_bgp_ipv4,
|route-map WORD\
|prefix-list WORD\
|filter-list WORD\
+ |statistics\
|community [<AA:NN|local-AS|no-advertise|no-export> [exact-match]]\
|community-list <(1-500)|WORD> [exact-match]\
|A.B.C.D/M longer-prefixes\
@@ -7842,13 +8003,14 @@ DEFUN (show_ip_bgp_ipv4,
"Display detailed information about dampening\n"
"Display flap statistics of routes\n"
"Display paths suppressed due to dampening\n"
- "Display dampening parameters\n"
+ "Display detail of configured dampening parameters\n"
"Display routes matching the route-map\n"
"A route-map to match on\n"
"Display routes conforming to the prefix-list\n"
"Prefix-list name\n"
"Display routes conforming to the filter-list\n"
"Regular expression access list name\n"
+ "BGP RIB advertisement statistics\n"
"Display routes matching the communities\n"
COMMUNITY_AANN_STR
"Do not send outside local AS (well-known community)\n"
@@ -7865,87 +8027,80 @@ DEFUN (show_ip_bgp_ipv4,
"Display route and more specific routes\n"
JSON_STR)
{
- char *vrf = NULL;
+ vrf_id_t vrf = VRF_DEFAULT;
afi_t afi = AFI_IP6;
safi_t safi = SAFI_UNICAST;
int exact_match = 0;
enum bgp_show_type sh_type = bgp_show_type_normal;
-
+ struct bgp *bgp = NULL;
int idx = 0;
- if (argv_find (argv, argc, "ip", &idx))
- afi = AFI_IP;
- if (argv_find (argv, argc, "view", &idx) || argv_find (argv, argc, "vrf", &idx))
- vrf = argv[++idx]->arg;
- if (argv_find (argv, argc, "ipv4", &idx) || argv_find (argv, argc, "ipv6", &idx))
- {
- afi = strmatch(argv[idx]->text, "ipv6") ? AFI_IP6 : AFI_IP;
- if (argv_find (argv, argc, "unicast", &idx) || argv_find (argv, argc, "multicast", &idx))
- safi = bgp_vty_safi_from_arg (argv[idx]->text);
- else if (argv_find (argv, argc, "encap", &idx) || argv_find (argv, argc, "vpn", &idx))
- safi = strmatch (argv[idx]->text, "encap") ? SAFI_ENCAP : SAFI_MPLS_VPN;
- }
+ bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+ if (!idx)
+ return CMD_WARNING;
+
int uj = use_json (argc, argv);
if (uj) argc--;
- struct bgp *bgp = bgp_lookup_by_name (vrf);
+ bgp = bgp_lookup_by_vrf_id (vrf);
if (bgp == NULL)
- {
- vty_out (vty, "Can't find BGP instance %s%s", vrf, VTY_NEWLINE);
- return CMD_WARNING;
- }
+ {
+ vty_out (vty, "Can't find BGP instance %s%s", argv[5]->arg, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
- if (++idx < argc)
- {
- if (strmatch(argv[idx]->text, "cidr-only"))
- return bgp_show (vty, bgp, afi, safi, bgp_show_type_cidr_only, NULL, uj);
+ if (argv_find(argv, argc, "cidr-only", &idx))
+ return bgp_show (vty, bgp, afi, safi, bgp_show_type_cidr_only, NULL, uj);
- else if (strmatch(argv[idx]->text, "dampening"))
+ if (argv_find(argv, argc, "dampening", &idx))
{
if (argv_find (argv, argc, "dampened-paths", &idx))
return bgp_show (vty, bgp, afi, safi, bgp_show_type_dampend_paths, NULL, uj);
else if (argv_find (argv, argc, "flap-statistics", &idx))
return bgp_show (vty, bgp, afi, safi, bgp_show_type_flap_statistics, NULL, uj);
else if (argv_find (argv, argc, "parameters", &idx))
- return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_UNICAST);
+ return bgp_show_dampening_parameters (vty, afi, safi);
}
- else if (strmatch(argv[idx]->text, "prefix-list"))
- return bgp_show_prefix_list (vty, vrf, argv[idx + 1]->arg, afi, safi, bgp_show_type_prefix_list);
+ if (argv_find(argv, argc, "prefix-list", &idx))
+ return bgp_show_prefix_list (vty, bgp, argv[idx + 1]->arg, afi, safi, bgp_show_type_prefix_list);
- else if (strmatch(argv[idx]->text, "filter-list"))
- return bgp_show_filter_list (vty, vrf, argv[idx + 1]->arg, afi, safi, bgp_show_type_filter_list);
+ if (argv_find(argv, argc, "filter-list", &idx))
+ return bgp_show_filter_list (vty, bgp, argv[idx + 1]->arg, afi, safi, bgp_show_type_filter_list);
- else if (strmatch(argv[idx]->text, "route-map"))
- return bgp_show_route_map (vty, vrf, argv[idx + 1]->arg, afi, safi, bgp_show_type_route_map);
+ if (argv_find(argv, argc, "statistics", &idx))
+ return bgp_table_stats (vty, bgp, afi, safi);
- else if (strmatch(argv[idx]->text, "community"))
+ if (argv_find(argv, argc, "route-map", &idx))
+ return bgp_show_route_map (vty, bgp, argv[idx + 1]->arg, afi, safi, bgp_show_type_route_map);
+
+ if (argv_find(argv, argc, "community", &idx))
{
/* show a specific community */
- if (argv[idx + 1]->type == VARIABLE_TKN ||
- strmatch(argv[idx + 1]->text, "local-AS") ||
- strmatch(argv[idx + 1]->text, "no-advertise") ||
- strmatch(argv[idx + 1]->text, "no-export"))
+ if (argv_find (argv, argc, "local-AS", &idx) ||
+ argv_find (argv, argc, "no-advertise", &idx) ||
+ argv_find (argv, argc, "no-export", &idx))
{
- if (strmatch(argv[idx + 2]->text, "exact_match"))
+ if (argv_find (argv, argc, "exact_match", &idx))
exact_match = 1;
- return bgp_show_community (vty, vrf, argc, argv, exact_match, afi, safi);
+ return bgp_show_community (vty, bgp, argc, argv, exact_match, afi, safi);
}
/* show all communities */
else
return bgp_show (vty, bgp, afi, safi, bgp_show_type_community_all, NULL, uj);
}
- else if (strmatch(argv[idx]->text, "community-list"))
- {
- const char *clist_number_or_name = argv[++idx]->arg;
- if (++idx < argc && strmatch (argv[idx]->arg, "exact-match"))
- exact_match = 1;
- return bgp_show_community_list (vty, vrf, clist_number_or_name, exact_match, afi, safi);
- }
- /* prefix-longer */
- else if (argv[idx]->type == IPV4_TKN || argv[idx]->type == IPV6_TKN)
- return bgp_show_prefix_longer (vty, vrf, argv[idx + 1]->arg, afi, safi, bgp_show_type_prefix_longer);
- }
+
+ if (argv_find(argv, argc, "community-list", &idx))
+ {
+ const char *clist_number_or_name = argv[++idx]->arg;
+ if (++idx < argc && strmatch (argv[idx]->text, "exact-match"))
+ exact_match = 1;
+ return bgp_show_community_list (vty, bgp, clist_number_or_name, exact_match, afi, safi);
+ }
+ /* prefix-longer */
+ if (argv_find(argv, argc, "A.B.C.D/M", &idx) || argv_find(argv, argc, "X:X::X:X/M", &idx))
+ return bgp_show_prefix_longer (vty, bgp, argv[idx + 1]->arg, afi, safi, bgp_show_type_prefix_longer);
+
if (safi == SAFI_MPLS_VPN)
return bgp_show_mpls_vpn (vty, afi, NULL, bgp_show_type_normal, NULL, 0, uj);
else if (safi == SAFI_ENCAP)
@@ -7980,34 +8135,32 @@ DEFUN (show_ip_bgp_route,
afi_t afi = AFI_IP6;
safi_t safi = SAFI_UNICAST;
- char *vrf = NULL;
+ vrf_id_t vrf = VRF_DEFAULT;;
char *prefix = NULL;
-
+ struct bgp *bgp = NULL;
enum bgp_path_type path_type;
u_char uj = use_json(argc, argv);
int idx = 0;
- /* show [ip] bgp */
- if (argv_find (argv, argc, "ip", &idx))
- afi = AFI_IP;
- /* [<view|vrf> WORD] */
- if (argv_find (argv, argc, "view", &idx) || argv_find (argv, argc, "vrf", &idx))
- vrf = argv[++idx]->arg;
- /* [<ipv4 [<unicast|multicast>]|ipv6 [<unicast|multicast>]|encap [unicast]|vpnv4 [unicast]>] */
- if (argv_find (argv, argc, "ipv4", &idx) || argv_find (argv, argc, "ipv6", &idx))
- {
- afi = strmatch(argv[idx]->text, "ipv6") ? AFI_IP6 : AFI_IP;
- if (argv_find (argv, argc, "unicast", &idx) || argv_find (argv, argc, "multicast", &idx))
- safi = strmatch (argv[idx]->text, "unicast") ? SAFI_UNICAST : SAFI_MULTICAST;
- }
- else if (argv_find (argv, argc, "encap", &idx) || argv_find (argv, argc, "vpnv4", &idx))
- {
- afi = AFI_IP;
- safi = strmatch (argv[idx]->text, "encap") ? SAFI_ENCAP : SAFI_MPLS_VPN;
- // advance idx if necessary
- argv_find (argv, argc, "unicast", &idx);
- }
+ bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+ if (!idx)
+ return CMD_WARNING;
+
+ if (vrf != VRF_ALL)
+ {
+ bgp = bgp_lookup_by_vrf_id (vrf);
+ if (bgp == NULL)
+ {
+ vty_out (vty, "Can't find BGP instance %s%s", argv[5]->arg, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ else
+ {
+ vty_out (vty, "Specified 'all' vrf's but this command currently only works per view/vrf%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
/* <A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M> */
if (argv_find (argv, argc, "A.B.C.D", &idx) || argv_find (argv, argc, "X:X::X:X", &idx))
@@ -8036,51 +8189,33 @@ DEFUN (show_ip_bgp_route,
else
path_type = BGP_PATH_ALL;
- return bgp_show_route (vty, vrf, prefix, afi, safi, NULL, prefix_check, path_type, uj);
+ return bgp_show_route (vty, bgp, prefix, afi, safi, NULL, prefix_check, path_type, uj);
}
DEFUN (show_ip_bgp_regexp,
show_ip_bgp_regexp_cmd,
- "show [ip] bgp [<ipv4 [<unicast|multicast|vpn|encap>]|ipv6 [<unicast|multicast|vpn|encap>]|encap [unicast]|vpnv4 [unicast]>] regexp REGEX...",
+ "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] regexp REGEX...",
SHOW_STR
IP_STR
BGP_STR
+ BGP_INSTANCE_HELP_STR
"Address Family\n"
- "Address Family modifier\n"
- "Address Family modifier\n"
- "Address Family modifier\n"
- "Address Family modifier\n"
"Address Family\n"
"Address Family modifier\n"
"Address Family modifier\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Address Family\n"
- "Address Family modifier\n"
- "Address Family\n"
- "Address Family modifier\n"
"Display routes matching the AS path regular expression\n"
"A regular-expression to match the BGP AS paths\n")
{
+ vrf_id_t vrf = VRF_DEFAULT;
afi_t afi = AFI_IP6;
safi_t safi = SAFI_UNICAST;
int idx = 0;
-
- /* [<ipv4 [<unicast|multicast>]|ipv6 [<unicast|multicast>]|encap [unicast]|vpnv4 [unicast]>] */
- if (argv_find (argv, argc, "ipv4", &idx) || argv_find (argv, argc, "ipv6", &idx))
- {
- afi = strmatch(argv[idx]->text, "ipv6") ? AFI_IP6 : AFI_IP;
- if (argv_find (argv, argc, "unicast", &idx) || argv_find (argv, argc, "multicast", &idx))
- safi = strmatch (argv[idx]->text, "unicast") ? SAFI_UNICAST : SAFI_MULTICAST;
- }
- else if (argv_find (argv, argc, "encap", &idx) || argv_find (argv, argc, "vpnv4", &idx))
- {
- afi = AFI_IP;
- safi = strmatch (argv[idx]->text, "encap") ? SAFI_ENCAP : SAFI_MPLS_VPN;
- // advance idx if necessary
- argv_find (argv, argc, "unicast", &idx);
- }
+ bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+ if (!idx)
+ return CMD_WARNING;
// get index of regex
argv_find (argv, argc, "regexp", &idx);
@@ -8094,53 +8229,35 @@ DEFUN (show_ip_bgp_regexp,
DEFUN (show_ip_bgp_instance_all,
show_ip_bgp_instance_all_cmd,
- "show [ip] bgp <view|vrf> all [<ipv4 [<unicast|multicast>]|ipv6 [<unicast|multicast>]|encap [unicast]|vpnv4 [unicast]>] [json]",
+ "show [ip] bgp <view|vrf> all [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] [json]",
SHOW_STR
IP_STR
BGP_STR
BGP_INSTANCE_ALL_HELP_STR
"Address Family\n"
- "Address Family modifier\n"
- "Address Family modifier\n"
"Address Family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Address Family\n"
"Address Family modifier\n"
- "Address Family\n"
"Address Family modifier\n"
JSON_STR)
{
+ vrf_id_t vrf = VRF_DEFAULT;
afi_t afi = AFI_IP;
safi_t safi = SAFI_UNICAST;
int idx = 0;
+ bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+ if (!idx)
+ return CMD_WARNING;
- /* show [ip] bgp */
- if (argv_find (argv, argc, "ip", &idx))
- afi = AFI_IP;
- /* [<ipv4 [<unicast|multicast>]|ipv6 [<unicast|multicast>]|encap [unicast]|vpnv4 [unicast]>] */
- if (argv_find (argv, argc, "ipv4", &idx) || argv_find (argv, argc, "ipv6", &idx))
- {
- afi = strmatch(argv[idx]->text, "ipv6") ? AFI_IP6 : AFI_IP;
- if (argv_find (argv, argc, "unicast", &idx) || argv_find (argv, argc, "multicast", &idx))
- safi = strmatch (argv[idx]->text, "unicast") ? SAFI_UNICAST : SAFI_MULTICAST;
- }
- else if (argv_find (argv, argc, "encap", &idx) || argv_find (argv, argc, "vpnv4", &idx))
- {
- afi = AFI_IP;
- safi = strmatch (argv[idx]->text, "encap") ? SAFI_ENCAP : SAFI_MPLS_VPN;
- // advance idx if necessary
- argv_find (argv, argc, "unicast", &idx);
- }
-
- u_char uj = use_json(argc, argv);
+ int uj = use_json (argc, argv);
+ if (uj) argc--;
bgp_show_all_instances_routes_vty (vty, afi, safi, uj);
return CMD_SUCCESS;
}
-
static int
bgp_show_regexp (struct vty *vty, const char *regstr, afi_t afi,
safi_t safi, enum bgp_show_type type)
@@ -8163,18 +8280,11 @@ bgp_show_regexp (struct vty *vty, const char *regstr, afi_t afi,
}
static int
-bgp_show_prefix_list (struct vty *vty, const char *name,
+bgp_show_prefix_list (struct vty *vty, struct bgp *bgp,
const char *prefix_list_str, afi_t afi,
safi_t safi, enum bgp_show_type type)
{
struct prefix_list *plist;
- struct bgp *bgp = NULL;
-
- if (name && !(bgp = bgp_lookup_by_name(name)))
- {
- vty_out (vty, "%% No such BGP instance exists%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
plist = prefix_list_lookup (afi, prefix_list_str);
if (plist == NULL)
@@ -8188,18 +8298,11 @@ bgp_show_prefix_list (struct vty *vty, const char *name,
}
static int
-bgp_show_filter_list (struct vty *vty, const char *name,
+bgp_show_filter_list (struct vty *vty, struct bgp *bgp,
const char *filter, afi_t afi,
safi_t safi, enum bgp_show_type type)
{
struct as_list *as_list;
- struct bgp *bgp = NULL;
-
- if (name && !(bgp = bgp_lookup_by_name(name)))
- {
- vty_out (vty, "%% No such BGP instance exists%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
as_list = as_list_lookup (filter);
if (as_list == NULL)
@@ -8211,53 +8314,12 @@ bgp_show_filter_list (struct vty *vty, const char *name,
return bgp_show (vty, bgp, afi, safi, type, as_list, 0);
}
-DEFUN (show_ip_bgp_dampening_info,
- show_ip_bgp_dampening_params_cmd,
- "show [ip] bgp dampening parameters",
- SHOW_STR
- IP_STR
- BGP_STR
- "Display detailed information about dampening\n"
- "Display detail of configured dampening parameters\n")
-{
- return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_UNICAST);
-}
-
-
-DEFUN (show_ip_bgp_ipv4_dampening_parameters,
- show_ip_bgp_ipv4_dampening_parameters_cmd,
- "show [ip] bgp ipv4 <unicast|multicast> dampening parameters",
- SHOW_STR
- IP_STR
- BGP_STR
- "Address Family\n"
- "Address Family modifier\n"
- "Address Family modifier\n"
- "Display detailed information about dampening\n"
- "Display detail of configured dampening parameters\n")
-{
- int idx_safi = 4;
- if (strncmp(argv[idx_safi]->arg, "m", 1) == 0)
- return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_MULTICAST);
-
- return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_UNICAST);
-}
-
static int
-bgp_show_route_map (struct vty *vty, const char *name,
+bgp_show_route_map (struct vty *vty, struct bgp *bgp,
const char *rmap_str, afi_t afi,
safi_t safi, enum bgp_show_type type)
{
struct route_map *rmap;
- struct bgp *bgp = NULL;
-
- if (name && !(bgp = bgp_lookup_by_name(name)))
- {
-
-
- vty_out (vty, "%% No such BGP instance exists%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
rmap = route_map_lookup_by_name (rmap_str);
if (! rmap)
@@ -8271,36 +8333,15 @@ bgp_show_route_map (struct vty *vty, const char *name,
}
static int
-bgp_show_community (struct vty *vty, const char *view_name, int argc,
+bgp_show_community (struct vty *vty, struct bgp *bgp, int argc,
struct cmd_token **argv, int exact, afi_t afi, safi_t safi)
{
struct community *com;
struct buffer *b;
- struct bgp *bgp;
int i;
char *str;
int first = 0;
- /* BGP structure lookup */
- if (view_name)
- {
- bgp = bgp_lookup_by_name (view_name);
- if (bgp == NULL)
- {
- vty_out (vty, "Can't find BGP instance %s%s", view_name, VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
- else
- {
- bgp = bgp_get_default ();
- if (bgp == NULL)
- {
- vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
-
b = buffer_new (1024);
for (i = 0; i < argc; i++)
{
@@ -8334,18 +8375,11 @@ bgp_show_community (struct vty *vty, const char *view_name, int argc,
}
static int
-bgp_show_community_list (struct vty *vty, const char *name,
+bgp_show_community_list (struct vty *vty, struct bgp *bgp,
const char *com, int exact,
afi_t afi, safi_t safi)
{
struct community_list *list;
- struct bgp *bgp = NULL;
-
- if (name && !(bgp = bgp_lookup_by_name(name)))
- {
- vty_out (vty, "%% No such BGP instance exists%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
list = community_list_lookup (bgp_clist, com, COMMUNITY_LIST_MASTER);
if (list == NULL)
@@ -8361,19 +8395,12 @@ bgp_show_community_list (struct vty *vty, const char *name,
}
static int
-bgp_show_prefix_longer (struct vty *vty, const char *name,
+bgp_show_prefix_longer (struct vty *vty, struct bgp *bgp,
const char *prefix, afi_t afi,
safi_t safi, enum bgp_show_type type)
{
int ret;
struct prefix *p;
- struct bgp *bgp = NULL;
-
- if (name && !(bgp = bgp_lookup_by_name(name)))
- {
- vty_out (vty, "%% No such BGP instance exists%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
p = prefix_new();
@@ -8390,52 +8417,13 @@ bgp_show_prefix_longer (struct vty *vty, const char *name,
}
static struct peer *
-peer_lookup_in_view (struct vty *vty, const char *view_name,
+peer_lookup_in_view (struct vty *vty, struct bgp *bgp,
const char *ip_str, u_char use_json)
{
int ret;
- struct bgp *bgp;
struct peer *peer;
union sockunion su;
- /* BGP structure lookup. */
- if (view_name)
- {
- bgp = bgp_lookup_by_name (view_name);
- if (! bgp)
- {
- if (use_json)
- {
- json_object *json_no = NULL;
- json_no = json_object_new_object();
- json_object_string_add(json_no, "warning", "Can't find BGP view");
- vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
- json_object_free(json_no);
- }
- else
- vty_out (vty, "Can't find BGP instance %s%s", view_name, VTY_NEWLINE);
- return NULL;
- }
- }
- else
- {
- bgp = bgp_get_default ();
- if (! bgp)
- {
- if (use_json)
- {
- json_object *json_no = NULL;
- json_no = json_object_new_object();
- json_object_string_add(json_no, "warning", "No BGP process configured");
- vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
- json_object_free(json_no);
- }
- else
- vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
- return NULL;
- }
- }
-
/* Get peer sockunion. */
ret = str2sockunion (ip_str, &su);
if (ret < 0)
@@ -8731,81 +8719,6 @@ bgp_table_stats (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi)
return CMD_SUCCESS;
}
-static int
-bgp_table_stats_vty (struct vty *vty, const char *name,
- const char *afi_str, const char *safi_str)
-{
- struct bgp *bgp;
- afi_t afi;
- safi_t safi;
-
- if (name)
- bgp = bgp_lookup_by_name (name);
- else
- bgp = bgp_get_default ();
-
- if (!bgp)
- {
- vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- afi = bgp_vty_afi_from_arg(afi_str);
- if (afi == AFI_MAX)
- {
- vty_out (vty, "%% Invalid address family \"%s\"%s",
- afi_str, VTY_NEWLINE);
- return CMD_WARNING;
- }
- safi = bgp_vty_safi_from_arg(safi_str);
- if (safi == SAFI_MAX)
- {
- vty_out (vty, "%% Invalid subsequent address family %s%s",
- safi_str, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- return bgp_table_stats (vty, bgp, afi, safi);
-}
-
-DEFUN (show_bgp_statistics,
- show_bgp_statistics_cmd,
- "show [ip] bgp <ipv4|ipv6> <encap|multicast|unicast|vpn> statistics",
- SHOW_STR
- IP_STR
- BGP_STR
- "Address Family\n"
- "Address Family\n"
- "Address Family modifier\n"
- "Address Family modifier\n"
- "Address Family modifier\n"
- "Address Family modifier\n"
- "BGP RIB advertisement statistics\n")
-{
- int idx_afi = 2;
- int idx_safi = 3;
- return bgp_table_stats_vty (vty, NULL, argv[idx_afi]->arg, argv[idx_safi]->arg);
-}
-
-DEFUN (show_bgp_statistics_view,
- show_bgp_statistics_view_cmd,
- "show [ip] bgp <view|vrf> WORD <ipv4|ipv6> <unicast|multicast|vpn|encap> statistics",
- SHOW_STR
- IP_STR
- BGP_STR
- BGP_INSTANCE_HELP_STR
- "Address Family\n"
- "Address Family\n"
- "Address Family modifier\n"
- "Address Family modifier\n"
- "Address Family modifier\n"
- "Address Family modifier\n"
- "BGP RIB advertisement statistics\n")
-{
- int idx_word = 3;
- int idx_afi = 4;
- return bgp_table_stats_vty (vty, NULL, argv[idx_word]->arg, argv[idx_afi]->arg);
-}
-
enum bgp_pcounts
{
PCOUNT_ADJ_IN = 0,
@@ -8997,89 +8910,20 @@ bgp_peer_counts (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, u_c
return CMD_SUCCESS;
}
-DEFUN (show_ip_bgp_neighbor_prefix_counts,
- show_ip_bgp_neighbor_prefix_counts_cmd,
- "show [ip] bgp neighbors <A.B.C.D|X:X::X:X|WORD> prefix-counts [json]",
- SHOW_STR
- IP_STR
- BGP_STR
- "Detailed information on TCP and BGP neighbor connections\n"
- "Neighbor to display information about\n"
- "Neighbor to display information about\n"
- "Neighbor on BGP configured interface\n"
- "Display detailed prefix count information\n"
- JSON_STR)
-{
- int idx_peer = 4;
- struct peer *peer;
- u_char uj = use_json(argc, argv);
-
- peer = peer_lookup_in_view (vty, NULL, argv[idx_peer]->arg, uj);
- if (! peer)
- return CMD_WARNING;
-
- return bgp_peer_counts (vty, peer, AFI_IP, SAFI_UNICAST, uj);
-}
-
DEFUN (show_ip_bgp_instance_neighbor_prefix_counts,
show_ip_bgp_instance_neighbor_prefix_counts_cmd,
- "show [ip] bgp <view|vrf> WORD neighbors <A.B.C.D|X:X::X:X|WORD> prefix-counts [json]",
+ "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] "
+ "neighbors <A.B.C.D|X:X::X:X|WORD> prefix-counts [json]",
SHOW_STR
IP_STR
BGP_STR
BGP_INSTANCE_HELP_STR
- "Detailed information on TCP and BGP neighbor connections\n"
- "Neighbor to display information about\n"
- "Neighbor to display information about\n"
- "Neighbor on BGP configured interface\n"
- "Display detailed prefix count information\n"
- JSON_STR)
-{
- int idx_word = 4;
- int idx_peer = 6;
- struct peer *peer;
- u_char uj = use_json(argc, argv);
-
- peer = peer_lookup_in_view (vty, argv[idx_word]->arg, argv[idx_peer]->arg, uj);
- if (! peer)
- return CMD_WARNING;
-
- return bgp_peer_counts (vty, peer, AFI_IP, SAFI_UNICAST, uj);
-}
-
-DEFUN (show_bgp_ipv6_neighbor_prefix_counts,
- show_bgp_ipv6_neighbor_prefix_counts_cmd,
- "show [ip] bgp ipv6 neighbors <A.B.C.D|X:X::X:X|WORD> prefix-counts [json]",
- SHOW_STR
- IP_STR
- BGP_STR
"Address Family\n"
- "Detailed information on TCP and BGP neighbor connections\n"
- "Neighbor to display information about\n"
- "Neighbor to display information about\n"
- "Neighbor on BGP configured interface\n"
- "Display detailed prefix count information\n"
- JSON_STR)
-{
- int idx_peer = 4;
- struct peer *peer;
- u_char uj = use_json(argc, argv);
-
- peer = peer_lookup_in_view (vty, NULL, argv[idx_peer]->arg, uj);
- if (! peer)
- return CMD_WARNING;
-
- return bgp_peer_counts (vty, peer, AFI_IP6, SAFI_UNICAST, uj);
-}
-
-DEFUN (show_bgp_instance_ipv6_neighbor_prefix_counts,
- show_bgp_instance_ipv6_neighbor_prefix_counts_cmd,
- "show [ip] bgp <view|vrf> WORD ipv6 neighbors <A.B.C.D|X:X::X:X|WORD> prefix-counts [json]",
- SHOW_STR
- IP_STR
- BGP_STR
- BGP_INSTANCE_HELP_STR
"Address Family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
@@ -9087,46 +8931,46 @@ DEFUN (show_bgp_instance_ipv6_neighbor_prefix_counts,
"Display detailed prefix count information\n"
JSON_STR)
{
- int idx_word = 3;
- int idx_peer = 6;
+ vrf_id_t vrf = VRF_DEFAULT;
+ afi_t afi = AFI_IP6;
+ safi_t safi = SAFI_UNICAST;
struct peer *peer;
- u_char uj = use_json(argc, argv);
+ int idx = 0;
+ struct bgp *bgp = NULL;
- peer = peer_lookup_in_view (vty, argv[idx_word]->arg, argv[idx_peer]->arg, uj);
- if (! peer)
+ bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+ if (!idx)
return CMD_WARNING;
- return bgp_peer_counts (vty, peer, AFI_IP6, SAFI_UNICAST, uj);
-}
+ int uj = use_json (argc, argv);
+ if (uj) argc--;
-DEFUN (show_ip_bgp_ipv4_neighbor_prefix_counts,
- show_ip_bgp_ipv4_neighbor_prefix_counts_cmd,
- "show [ip] bgp ipv4 <unicast|multicast> neighbors <A.B.C.D|X:X::X:X|WORD> prefix-counts [json]",
- SHOW_STR
- IP_STR
- BGP_STR
- "Address Family\n"
- "Address Family modifier\n"
- "Address Family modifier\n"
- "Detailed information on TCP and BGP neighbor connections\n"
- "Neighbor to display information about\n"
- "Neighbor to display information about\n"
- "Neighbor on BGP configured interface\n"
- "Display detailed prefix count information\n"
- JSON_STR)
-{
- int idx_safi = 4;
- int idx_peer = 6;
- struct peer *peer;
- u_char uj = use_json(argc, argv);
+ if (vrf != VRF_ALL)
+ {
+ bgp = bgp_lookup_by_vrf_id (vrf);
+ if (bgp == NULL)
+ {
+ if (uj)
+ {
+ json_object *json_no = NULL;
+ json_no = json_object_new_object();
+ json_object_string_add(json_no, "warning", "Can't find BGP view");
+ vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
+ json_object_free(json_no);
+ }
+ else
+ vty_out (vty, "Can't find BGP instance %s%s", argv[5]->arg, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ else
+ bgp = NULL;
- peer = peer_lookup_in_view (vty, NULL, argv[idx_peer]->arg, uj);
+ argv_find (argv, argc, "neighbors", &idx);
+ peer = peer_lookup_in_view (vty, bgp, argv[idx+1]->arg, uj);
if (! peer)
return CMD_WARNING;
- if (strncmp (argv[idx_safi]->arg, "m", 1) == 0)
- return bgp_peer_counts (vty, peer, AFI_IP, SAFI_MULTICAST, uj);
-
return bgp_peer_counts (vty, peer, AFI_IP, SAFI_UNICAST, uj);
}
@@ -9171,9 +9015,15 @@ DEFUN (show_ip_bgp_vpn_all_route_prefix,
{
int idx = 0;
char *network = NULL;
+ struct bgp *bgp = bgp_get_default();
+ if (!bgp)
+ {
+ vty_out (vty, "Can't find default instance%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
network = argv_find (argv, argc, "A.B.C.D", &idx) ? argv[idx]->arg : NULL;
network = argv_find (argv, argc, "A.B.C.D/M", &idx) ? argv[idx]->arg : NULL;
- return bgp_show_route (vty, NULL, network, AFI_IP, SAFI_MPLS_VPN, NULL, 0, BGP_PATH_ALL, use_json(argc, argv));
+ return bgp_show_route (vty, bgp, network, AFI_IP, SAFI_MPLS_VPN, NULL, 0, BGP_PATH_ALL, use_json(argc, argv));
}
#endif /* KEEP_OLD_VPN_COMMANDS */
@@ -9419,20 +9269,17 @@ peer_adj_routes (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi,
DEFUN (show_ip_bgp_instance_neighbor_advertised_route,
show_ip_bgp_instance_neighbor_advertised_route_cmd,
- "show [ip] bgp [<view|vrf> WORD] [<ipv4 [<unicast|multicast>]|ipv6 [<unicast|multicast>]|encap [unicast]|vpnv4 [unicast]>] neighbors <A.B.C.D|X:X::X:X|WORD> [<received-routes|advertised-routes> [route-map WORD]] [json]",
+ "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] "
+ "neighbors <A.B.C.D|X:X::X:X|WORD> [<received-routes|advertised-routes> [route-map WORD]] [json]",
SHOW_STR
IP_STR
BGP_STR
BGP_INSTANCE_HELP_STR
"Address Family\n"
- "Address Family modifier\n"
- "Address Family modifier\n"
"Address Family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Address Family\n"
"Address Family modifier\n"
- "Address Family\n"
"Address Family modifier\n"
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
@@ -9444,51 +9291,47 @@ DEFUN (show_ip_bgp_instance_neighbor_advertised_route,
"Name of the route map\n"
JSON_STR)
{
+ vrf_id_t vrf = VRF_DEFAULT;
afi_t afi = AFI_IP6;
safi_t safi = SAFI_UNICAST;
- char *vrf = NULL;
char *rmap_name = NULL;
char *peerstr = NULL;
int rcvd = 0;
-
+ struct bgp *bgp = NULL;
struct peer *peer;
int idx = 0;
- /* show [ip] bgp */
- if (argv_find (argv, argc, "ip", &idx))
- afi = AFI_IP;
- /* [<view|vrf> WORD] */
- if (argv_find (argv, argc, "view", &idx) || argv_find (argv, argc, "vrf", &idx))
- vrf = argv[++idx]->arg;
- /* [<ipv4 [<unicast|multicast>]|ipv6 [<unicast|multicast>]|encap [unicast]|vpnv4 [unicast]>] */
- if (argv_find (argv, argc, "ipv4", &idx) || argv_find (argv, argc, "ipv6", &idx))
- {
- afi = strmatch(argv[idx]->text, "ipv6") ? AFI_IP6 : AFI_IP;
- if (argv_find (argv, argc, "unicast", &idx) || argv_find (argv, argc, "multicast", &idx))
- safi = strmatch (argv[idx]->text, "unicast") ? SAFI_UNICAST : SAFI_MULTICAST;
- }
- else if (argv_find (argv, argc, "encap", &idx) || argv_find (argv, argc, "vpnv4", &idx))
- {
- afi = AFI_IP;
- safi = strmatch (argv[idx]->text, "encap") ? SAFI_ENCAP : SAFI_MPLS_VPN;
- // advance idx if necessary
- argv_find (argv, argc, "unicast", &idx);
- }
+ bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+ if (!idx)
+ return CMD_WARNING;
+
+ int uj = use_json (argc, argv);
+ if (uj) argc--;
+
+ bgp = bgp_lookup_by_vrf_id (vrf);
+ if (bgp == NULL)
+ {
+ if (uj)
+ {
+ json_object *json_no = NULL;
+ json_no = json_object_new_object();
+ json_object_string_add(json_no, "warning", "Can't find BGP view");
+ vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
+ json_object_free(json_no);
+ }
+ else
+ vty_out (vty, "Can't find BGP instance %s%s", argv[5]->arg, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
/* neighbors <A.B.C.D|X:X::X:X|WORD> */
argv_find (argv, argc, "neighbors", &idx);
peerstr = argv[++idx]->arg;
- u_char uj = use_json(argc, argv);
-
- peer = peer_lookup_in_view (vty, vrf, peerstr, uj);
-
+ peer = peer_lookup_in_view (vty, bgp, peerstr, uj);
if (! peer)
- {
- vty_out (vty, "No such neighbor%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
+ return CMD_WARNING;
if (argv_find (argv, argc, "received-routes", &idx))
rcvd = 1;
@@ -9611,20 +9454,17 @@ bgp_show_neighbor_route (struct vty *vty, struct peer *peer, afi_t afi,
DEFUN (show_ip_bgp_neighbor_routes,
show_ip_bgp_neighbor_routes_cmd,
- "show [ip] bgp [<view|vrf> WORD] [<ipv4 [<unicast|multicast>]|ipv6 [<unicast|multicast>]|encap [unicast]|vpnv4 [unicast]>] neighbors <A.B.C.D|X:X::X:X|WORD> <flap-statistics|dampened-routes|routes> [json]",
+ "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] "
+ "neighbors <A.B.C.D|X:X::X:X|WORD> <flap-statistics|dampened-routes|routes> [json]",
SHOW_STR
IP_STR
BGP_STR
BGP_INSTANCE_HELP_STR
"Address Family\n"
- "Address Family modifier\n"
- "Address Family modifier\n"
"Address Family\n"
"Address Family modifier\n"
"Address Family modifier\n"
- "Address Family\n"
"Address Family modifier\n"
- "Address Family\n"
"Address Family modifier\n"
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
@@ -9635,9 +9475,9 @@ DEFUN (show_ip_bgp_neighbor_routes,
"Display routes learned from neighbor\n"
JSON_STR)
{
- char *vrf = NULL;
+ vrf_id_t vrf = VRF_DEFAULT;
char *peerstr = NULL;
-
+ struct bgp *bgp = NULL;
afi_t afi = AFI_IP6;
safi_t safi = SAFI_UNICAST;
struct peer *peer;
@@ -9645,33 +9485,39 @@ DEFUN (show_ip_bgp_neighbor_routes,
int idx = 0;
- /* show [ip] bgp */
- if (argv_find (argv, argc, "ip", &idx))
- afi = AFI_IP;
- /* [<view|vrf> WORD] */
- if (argv_find (argv, argc, "view", &idx) || argv_find (argv, argc, "vrf", &idx))
- vrf = argv[++idx]->arg;
- /* [<ipv4 [<unicast|multicast>]|ipv6 [<unicast|multicast>]|encap [unicast]|vpnv4 [unicast]>] */
- if (argv_find (argv, argc, "ipv4", &idx) || argv_find (argv, argc, "ipv6", &idx))
- {
- afi = strmatch(argv[idx]->text, "ipv6") ? AFI_IP6 : AFI_IP;
- if (argv_find (argv, argc, "unicast", &idx) || argv_find (argv, argc, "multicast", &idx))
- safi = strmatch (argv[idx]->text, "unicast") ? SAFI_UNICAST : SAFI_MULTICAST;
- }
- else if (argv_find (argv, argc, "encap", &idx) || argv_find (argv, argc, "vpnv4", &idx))
- {
- afi = AFI_IP;
- safi = strmatch (argv[idx]->text, "encap") ? SAFI_ENCAP : SAFI_MPLS_VPN;
- // advance idx if necessary
- argv_find (argv, argc, "unicast", &idx);
- }
+ bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf);
+ if (!idx)
+ return CMD_WARNING;
+
+ int uj = use_json (argc, argv);
+ if (uj) argc--;
+
+ if (vrf != VRF_ALL)
+ {
+ bgp = bgp_lookup_by_vrf_id (vrf);
+ if (bgp == NULL)
+ {
+ if (uj)
+ {
+ json_object *json_no = NULL;
+ json_no = json_object_new_object();
+ json_object_string_add(json_no, "warning", "Can't find BGP view");
+ vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE);
+ json_object_free(json_no);
+ }
+ else
+ vty_out (vty, "Can't find BGP instance %s%s", argv[5]->arg, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ else
+ bgp = NULL;
+
/* neighbors <A.B.C.D|X:X::X:X|WORD> */
argv_find (argv, argc, "neighbors", &idx);
peerstr = argv[++idx]->arg;
- u_char uj = use_json(argc, argv);
-
- peer = peer_lookup_in_view (vty, vrf, peerstr, uj);
+ peer = peer_lookup_in_view (vty, bgp, peerstr, uj);
if (! peer)
{
vty_out (vty, "No such neighbor%s", VTY_NEWLINE);
@@ -10505,14 +10351,13 @@ bgp_route_init (void)
install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_cmd);
install_element (VIEW_NODE, &show_ip_bgp_instance_all_cmd);
- install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_cmd);
install_element (VIEW_NODE, &show_ip_bgp_route_cmd);
install_element (VIEW_NODE, &show_ip_bgp_regexp_cmd);
+
install_element (VIEW_NODE, &show_ip_bgp_instance_neighbor_advertised_route_cmd);
install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd);
install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd);
- install_element (VIEW_NODE, &show_ip_bgp_dampening_params_cmd);
- install_element (VIEW_NODE, &show_ip_bgp_ipv4_dampening_parameters_cmd);
#ifdef KEEP_OLD_VPN_COMMANDS
install_element (VIEW_NODE, &show_ip_bgp_vpn_all_route_prefix_cmd);
#endif /* KEEP_OLD_VPN_COMMANDS */
@@ -10520,18 +10365,15 @@ bgp_route_init (void)
/* BGP dampening clear commands */
install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd);
install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd);
+
install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_cmd);
install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd);
/* prefix count */
- install_element (ENABLE_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbor_prefix_counts_cmd);
- install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd);
#ifdef KEEP_OLD_VPN_COMMANDS
install_element (ENABLE_NODE, &show_ip_bgp_vpn_neighbor_prefix_counts_cmd);
#endif /* KEEP_OLD_VPN_COMMANDS */
- install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_prefix_counts_cmd);
- install_element (ENABLE_NODE, &show_bgp_instance_ipv6_neighbor_prefix_counts_cmd);
/* New config IPv6 BGP commands. */
install_element (BGP_IPV6_NODE, &bgp_table_map_cmd);
@@ -10546,10 +10388,6 @@ bgp_route_init (void)
install_element (BGP_IPV6M_NODE, &ipv6_bgp_network_cmd);
install_element (BGP_IPV6M_NODE, &no_ipv6_bgp_network_cmd);
- /* Statistics */
- install_element (ENABLE_NODE, &show_bgp_statistics_cmd);
- install_element (ENABLE_NODE, &show_bgp_statistics_view_cmd);
-
install_element (BGP_NODE, &bgp_distance_cmd);
install_element (BGP_NODE, &no_bgp_distance_cmd);
install_element (BGP_NODE, &bgp_distance_source_cmd);
@@ -10589,6 +10427,10 @@ bgp_route_init (void)
/* IPv4 Multicast Mode */
install_element (BGP_IPV4M_NODE, &bgp_damp_set_cmd);
install_element (BGP_IPV4M_NODE, &bgp_damp_unset_cmd);
+
+ /* Large Communities */
+ install_element (VIEW_NODE, &show_ip_bgp_large_community_list_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_large_community_cmd);
}
void
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index f2e6273b84..2103338b7d 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -41,6 +41,9 @@ enum bgp_show_type
bgp_show_type_community_exact,
bgp_show_type_community_list,
bgp_show_type_community_list_exact,
+ bgp_show_type_lcommunity_all,
+ bgp_show_type_lcommunity,
+ bgp_show_type_lcommunity_list,
bgp_show_type_flap_statistics,
bgp_show_type_flap_neighbor,
bgp_show_type_dampend_paths,
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 50524baa01..8f2486314a 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -52,6 +52,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_filter.h"
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_debug.h"
@@ -84,6 +85,8 @@ o Cisco route-map
as-path tag : Not yet
automatic-tag : (This will not be implemented by bgpd)
community : Done
+ large-community : Done
+ large-comm-list : Done
comm-list : Not yet
dampning : Not yet
default : (This will not be implemented by bgpd)
@@ -847,6 +850,78 @@ struct route_map_rule_cmd route_match_community_cmd =
route_match_community_free
};
+/* Match function for lcommunity match. */
+static route_map_result_t
+route_match_lcommunity (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct community_list *list;
+ struct bgp_info *bgp_info;
+ struct rmap_community *rcom;
+
+ if (type == RMAP_BGP)
+ {
+ bgp_info = object;
+ rcom = rule;
+
+ list = community_list_lookup (bgp_clist, rcom->name,
+ LARGE_COMMUNITY_LIST_MASTER);
+ if (! list)
+ return RMAP_NOMATCH;
+
+ if (bgp_info->attr->extra &&
+ lcommunity_list_match (bgp_info->attr->extra->lcommunity, list))
+ return RMAP_MATCH;
+
+ }
+ return RMAP_NOMATCH;
+}
+
+/* Compile function for community match. */
+static void *
+route_match_lcommunity_compile (const char *arg)
+{
+ struct rmap_community *rcom;
+ int len;
+ char *p;
+
+ rcom = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_community));
+
+ p = strchr (arg, ' ');
+ if (p)
+ {
+ len = p - arg;
+ rcom->name = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1);
+ memcpy (rcom->name, arg, len);
+ }
+ else
+ {
+ rcom->name = XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+ rcom->exact = 0;
+ }
+ return rcom;
+}
+
+/* Compile function for community match. */
+static void
+route_match_lcommunity_free (void *rule)
+{
+ struct rmap_community *rcom = rule;
+
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom->name);
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom);
+}
+
+/* Route map commands for community matching. */
+struct route_map_rule_cmd route_match_lcommunity_cmd =
+{
+ "large-community",
+ route_match_lcommunity,
+ route_match_lcommunity_compile,
+ route_match_lcommunity_free
+};
+
+
/* Match function for extcommunity match. */
static route_map_result_t
route_match_ecommunity (void *rule, struct prefix *prefix,
@@ -1544,6 +1619,224 @@ struct route_map_rule_cmd route_set_community_cmd =
route_set_community_free,
};
+/* `set community COMMUNITY' */
+struct rmap_lcom_set
+{
+ struct lcommunity *lcom;
+ int additive;
+ int none;
+};
+
+
+/* For lcommunity set mechanism. */
+static route_map_result_t
+route_set_lcommunity (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct rmap_lcom_set *rcs;
+ struct bgp_info *binfo;
+ struct attr *attr;
+ struct lcommunity *new = NULL;
+ struct lcommunity *old;
+ struct lcommunity *merge;
+
+ if (type == RMAP_BGP)
+ {
+ rcs = rule;
+ binfo = object;
+ attr = binfo->attr;
+ old = (attr->extra) ? attr->extra->lcommunity : NULL;
+
+ /* "none" case. */
+ if (rcs->none)
+ {
+ attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES));
+ if (attr->extra)
+ attr->extra->lcommunity = NULL;
+
+ /* See the longer comment down below. */
+ if (old && old->refcnt == 0)
+ lcommunity_free(&old);
+ return RMAP_OKAY;
+ }
+
+ if (rcs->additive && old)
+ {
+ merge = lcommunity_merge (lcommunity_dup (old), rcs->lcom);
+
+ /* HACK: if the old large-community is not intern'd,
+ * we should free it here, or all reference to it may be lost.
+ * Really need to cleanup attribute caching sometime.
+ */
+ if (old->refcnt == 0)
+ lcommunity_free (&old);
+ new = lcommunity_uniq_sort (merge);
+ lcommunity_free (&merge);
+ }
+ else
+ new = lcommunity_dup (rcs->lcom);
+
+ /* will be intern()'d or attr_flush()'d by bgp_update_main() */
+ (bgp_attr_extra_get (attr))->lcommunity = new;
+
+ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
+ }
+
+ return RMAP_OKAY;
+}
+
+/* Compile function for set community. */
+static void *
+route_set_lcommunity_compile (const char *arg)
+{
+ struct rmap_lcom_set *rcs;
+ struct lcommunity *lcom = NULL;
+ char *sp;
+ int additive = 0;
+ int none = 0;
+
+ if (strcmp (arg, "none") == 0)
+ none = 1;
+ else
+ {
+ sp = strstr (arg, "additive");
+
+ if (sp && sp > arg)
+ {
+ /* "additive" keyworkd is included. */
+ additive = 1;
+ *(sp - 1) = '\0';
+ }
+
+ lcom = lcommunity_str2com (arg);
+
+ if (additive)
+ *(sp - 1) = ' ';
+
+ if (! lcom)
+ return NULL;
+ }
+
+ rcs = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_com_set));
+ rcs->lcom = lcom;
+ rcs->additive = additive;
+ rcs->none = none;
+
+ return rcs;
+}
+
+/* Free function for set lcommunity. */
+static void
+route_set_lcommunity_free (void *rule)
+{
+ struct rmap_lcom_set *rcs = rule;
+
+ if (rcs->lcom) {
+ lcommunity_free (&rcs->lcom);
+ }
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rcs);
+}
+
+/* Set community rule structure. */
+struct route_map_rule_cmd route_set_lcommunity_cmd =
+{
+ "large-community",
+ route_set_lcommunity,
+ route_set_lcommunity_compile,
+ route_set_lcommunity_free,
+};
+
+/* `set large-comm-list (<1-99>|<100-500>|WORD) delete' */
+
+/* For large community set mechanism. */
+static route_map_result_t
+route_set_lcommunity_delete (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct community_list *list;
+ struct lcommunity *merge;
+ struct lcommunity *new;
+ struct lcommunity *old;
+ struct bgp_info *binfo;
+
+ if (type == RMAP_BGP)
+ {
+ if (! rule)
+ return RMAP_OKAY;
+
+ binfo = object;
+ list = community_list_lookup (bgp_clist, rule,
+ LARGE_COMMUNITY_LIST_MASTER);
+ old = ((binfo->attr->extra) ? binfo->attr->extra->lcommunity : NULL);
+
+ if (list && old)
+ {
+ merge = lcommunity_list_match_delete (lcommunity_dup (old), list);
+ new = lcommunity_uniq_sort (merge);
+ lcommunity_free (&merge);
+
+ /* HACK: if the old community is not intern'd,
+ * we should free it here, or all reference to it may be lost.
+ * Really need to cleanup attribute caching sometime.
+ */
+ if (old->refcnt == 0)
+ lcommunity_free (&old);
+
+ if (new->size == 0)
+ {
+ binfo->attr->extra->lcommunity = NULL;
+ binfo->attr->flag &= ~ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
+ lcommunity_free (&new);
+ }
+ else
+ {
+ binfo->attr->extra->lcommunity = new;
+ binfo->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
+ }
+ }
+ }
+
+ return RMAP_OKAY;
+}
+
+/* Compile function for set lcommunity. */
+static void *
+route_set_lcommunity_delete_compile (const char *arg)
+{
+ char *p;
+ char *str;
+ int len;
+
+ p = strchr (arg, ' ');
+ if (p)
+ {
+ len = p - arg;
+ str = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1);
+ memcpy (str, arg, len);
+ }
+ else
+ str = NULL;
+
+ return str;
+}
+
+/* Free function for set lcommunity. */
+static void
+route_set_lcommunity_delete_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set lcommunity rule structure. */
+struct route_map_rule_cmd route_set_lcommunity_delete_cmd =
+{
+ "large-comm-list",
+ route_set_lcommunity_delete,
+ route_set_lcommunity_delete_compile,
+ route_set_lcommunity_delete_free,
+};
+
+
/* `set comm-list (<1-99>|<100-500>|WORD) delete' */
/* For community set mechanism. */
@@ -3164,7 +3457,32 @@ DEFUN (no_match_community,
RMAP_EVENT_CLIST_DELETED);
}
+DEFUN (match_lcommunity,
+ match_lcommunity_cmd,
+ "match large-community [<(1-99)|(100-500)|WORD>]",
+ MATCH_STR
+ "Match BGP large community list\n"
+ "Large Community-list number (standard)\n"
+ "Large Community-list number (expanded)\n"
+ "Large Community-list name\n")
+{
+ return bgp_route_match_add (vty, "large-community", argv[2]->arg,
+ RMAP_EVENT_LLIST_ADDED);
+}
+DEFUN (no_match_lcommunity,
+ no_match_lcommunity_cmd,
+ "no match large-community [<(1-99)|(100-500)|WORD>]",
+ NO_STR
+ MATCH_STR
+ "Match BGP large community list\n"
+ "Large Community-list number (standard)\n"
+ "Large Community-list number (expanded)\n"
+ "Large Community-list name\n")
+{
+ return bgp_route_match_delete (vty, "large-community", NULL,
+ RMAP_EVENT_LLIST_DELETED);
+}
DEFUN (match_ecommunity,
match_ecommunity_cmd,
@@ -3597,6 +3915,95 @@ DEFUN (no_set_community_delete,
"comm-list", NULL);
}
+DEFUN (set_lcommunity,
+ set_lcommunity_cmd,
+ "set large-community AA:BB:CC...",
+ SET_STR
+ "BGP large community attribute\n"
+ "Large Community number in aa:bb:cc format or additive\n")
+{
+ int ret;
+ char *str;
+
+ str = argv_concat (argv, argc, 2);
+ ret = generic_set_add (vty, VTY_GET_CONTEXT(route_map_index), "large-community", str);
+ XFREE (MTYPE_TMP, str);
+
+ return ret;
+}
+
+DEFUN (set_lcommunity_none,
+ set_lcommunity_none_cmd,
+ "set large-community none",
+ SET_STR
+ "BGP large community attribute\n"
+ "No large community attribute\n")
+{
+ return generic_set_add (vty, VTY_GET_CONTEXT(route_map_index),
+ "large-community", "none");
+}
+
+DEFUN (no_set_lcommunity,
+ no_set_lcommunity_cmd,
+ "no set large-community none",
+ NO_STR
+ SET_STR
+ "BGP large community attribute\n"
+ "No community attribute\n")
+{
+ return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index),
+ "large-community", NULL);
+}
+
+DEFUN (no_set_lcommunity1,
+ no_set_lcommunity1_cmd,
+ "no set large-community AA:BB:CC...",
+ NO_STR
+ SET_STR
+ "BGP large community attribute\n"
+ "Large community in AA:BB:CC... format or additive\n")
+{
+ return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index),
+ "large-community", NULL);
+}
+
+DEFUN (set_lcommunity_delete,
+ set_lcommunity_delete_cmd,
+ "set large-comm-list <(1-99)|(100-500)|WORD> delete",
+ SET_STR
+ "set BGP large community list (for deletion)\n"
+ "Large Community-list number (standard)\n"
+ "Large Communitly-list number (expanded)\n"
+ "Large Community-list name\n"
+ "Delete matching large communities\n")
+{
+ char *str;
+
+ str = XCALLOC (MTYPE_TMP, strlen (argv[2]->arg) + strlen (" delete") + 1);
+ strcpy (str, argv[2]->arg);
+ strcpy (str + strlen (argv[2]->arg), " delete");
+
+ generic_set_add (vty, VTY_GET_CONTEXT(route_map_index),
+ "large-comm-list", str);
+
+ XFREE (MTYPE_TMP, str);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_set_lcommunity_delete,
+ no_set_lcommunity_delete_cmd,
+ "no set large-comm-list <(1-99|(100-500)|WORD)> [delete]",
+ NO_STR
+ SET_STR
+ "set BGP large community list (for deletion)\n"
+ "Large Community-list number (standard)\n"
+ "Large Communitly-list number (expanded)\n"
+ "Large Community-list name\n"
+ "Delete matching large communities\n")
+{
+ return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index),
+ "large-comm-list", NULL);
+}
DEFUN (set_ecommunity_rt,
set_ecommunity_rt_cmd,
@@ -3992,7 +4399,7 @@ DEFUN (no_set_vpn_nexthop,
DEFUN (set_ipx_vpn_nexthop,
set_ipx_vpn_nexthop_cmd,
- "set <ipv4|ipv6> vpn next-hop [A.B.C.D|X:X::X:X]",
+ "set <ipv4|ipv6> vpn next-hop [<A.B.C.D|X:X::X:X>]",
SET_STR
"IPv4 information\n"
"IPv6 information\n"
@@ -4019,7 +4426,7 @@ DEFUN (set_ipx_vpn_nexthop,
DEFUN (no_set_ipx_vpn_nexthop,
no_set_ipx_vpn_nexthop_cmd,
- "no set <ipv4|ipv6> vpn next-hop [A.B.C.D|X:X::X:X]",
+ "no set <ipv4|ipv6> vpn next-hop [<A.B.C.D|X:X::X:X>]",
NO_STR
SET_STR
"IPv4 information\n"
@@ -4139,6 +4546,7 @@ bgp_route_map_init (void)
route_map_install_match (&route_match_ip_route_source_prefix_list_cmd);
route_map_install_match (&route_match_aspath_cmd);
route_map_install_match (&route_match_community_cmd);
+ route_map_install_match (&route_match_lcommunity_cmd);
route_map_install_match (&route_match_ecommunity_cmd);
route_map_install_match (&route_match_local_pref_cmd);
route_map_install_match (&route_match_metric_cmd);
@@ -4158,6 +4566,8 @@ bgp_route_map_init (void)
route_map_install_set (&route_set_aggregator_as_cmd);
route_map_install_set (&route_set_community_cmd);
route_map_install_set (&route_set_community_delete_cmd);
+ route_map_install_set (&route_set_lcommunity_cmd);
+ route_map_install_set (&route_set_lcommunity_delete_cmd);
route_map_install_set (&route_set_vpnv4_nexthop_cmd);
route_map_install_set (&route_set_vpnv6_nexthop_cmd);
route_map_install_set (&route_set_originator_id_cmd);
@@ -4180,6 +4590,8 @@ bgp_route_map_init (void)
install_element (RMAP_NODE, &match_community_cmd);
install_element (RMAP_NODE, &match_community_exact_cmd);
install_element (RMAP_NODE, &no_match_community_cmd);
+ install_element (RMAP_NODE, &match_lcommunity_cmd);
+ install_element (RMAP_NODE, &no_match_lcommunity_cmd);
install_element (RMAP_NODE, &match_ecommunity_cmd);
install_element (RMAP_NODE, &no_match_ecommunity_cmd);
install_element (RMAP_NODE, &match_origin_cmd);
@@ -4209,6 +4621,12 @@ bgp_route_map_init (void)
install_element (RMAP_NODE, &no_set_community_cmd);
install_element (RMAP_NODE, &set_community_delete_cmd);
install_element (RMAP_NODE, &no_set_community_delete_cmd);
+ install_element (RMAP_NODE, &set_lcommunity_cmd);
+ install_element (RMAP_NODE, &set_lcommunity_none_cmd);
+ install_element (RMAP_NODE, &no_set_lcommunity_cmd);
+ install_element (RMAP_NODE, &no_set_lcommunity1_cmd);
+ install_element (RMAP_NODE, &set_lcommunity_delete_cmd);
+ install_element (RMAP_NODE, &no_set_lcommunity_delete_cmd);
install_element (RMAP_NODE, &set_ecommunity_rt_cmd);
install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd);
install_element (RMAP_NODE, &set_ecommunity_soo_cmd);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 80efe5f591..94809d69f5 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -41,14 +41,15 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_damp.h"
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_fsm.h"
-#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_open.h"
#include "bgpd/bgp_regex.h"
#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_table.h"
#include "bgpd/bgp_vty.h"
@@ -167,17 +168,7 @@ bgp_vty_safi_from_arg(const char *safi_str)
}
int
-bgp_parse_safi(const char *str, safi_t *safi)
-{
- *safi = bgp_vty_safi_from_arg(str);
- if (*safi != SAFI_MAX)
- return 0;
- else
- return -1;
-}
-
-int
-argv_find_and_parse_safi(struct cmd_token **argv, int argc, int *index, safi_t *safi)
+argv_find_and_parse_safi (struct cmd_token **argv, int argc, int *index, safi_t *safi)
{
int ret = 0;
if (argv_find (argv, argc, "unicast", index))
@@ -207,6 +198,80 @@ argv_find_and_parse_safi(struct cmd_token **argv, int argc, int *index, safi_t *
return ret;
}
+/*
+ * bgp_vty_find_and_parse_afi_safi_vrf
+ *
+ * For a given 'show ...' command, correctly parse the afi/safi/vrf out from it
+ * This function *assumes* that the calling function pre-sets the afi/safi/vrf
+ * to appropriate values for the calling function. This is to allow the
+ * calling function to make decisions appropriate for the show command
+ * that is being parsed.
+ *
+ * The show commands are generally of the form:
+ * "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] ..."
+ *
+ * Since we use argv_find if the show command in particular doesn't have:
+ * [ip]
+ * [<view|vrf> WORD]
+ * [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]]
+ * The command parsing should still be ok.
+ *
+ * vty -> The vty for the command so we can output some useful data in
+ * the event of a parse error in the vrf.
+ * argv -> The command tokens
+ * argc -> How many command tokens we have
+ * idx -> The current place in the command, generally should be 0 for this function
+ * afi -> The parsed afi if it was included in the show command, returned here
+ * safi -> The parsed safi if it was included in the show command, returned here
+ * vrf -> The parsed vrf id if it was included in the show command, returned here
+ *
+ * The function returns the correct location in the parse tree for the
+ * last token found.
+ *
+ * Returns 0 for failure to parse correctly, else the idx position of where
+ * it found the last token.
+ */
+int
+bgp_vty_find_and_parse_afi_safi_vrf (struct vty *vty, struct cmd_token **argv, int argc, int *idx,
+ afi_t *afi, safi_t *safi, vrf_id_t *vrf)
+{
+ char *vrf_name = NULL;
+
+ assert (afi);
+ assert (safi);
+ assert (vrf && *vrf != VRF_UNKNOWN);
+
+ if (argv_find (argv, argc, "ip", idx))
+ *afi = AFI_IP;
+
+ if (argv_find (argv, argc, "view", idx) || argv_find (argv, argc, "vrf", idx))
+ {
+ vrf_name = argv[*idx + 1]->arg;
+ *idx += 2;
+ }
+
+ if (argv_find_and_parse_afi (argv, argc, idx, afi))
+ argv_find_and_parse_safi (argv, argc, idx, safi);
+
+ if (vrf_name)
+ {
+ if (strmatch(vrf_name, "all"))
+ *vrf = VRF_ALL;
+ else
+ *vrf = vrf_name_to_id (vrf_name);
+ }
+
+ if (*vrf == VRF_UNKNOWN)
+ {
+ vty_out (vty, "View/Vrf specified is unknown: %s", vrf_name);
+ *idx = 0;
+ return 0;
+ }
+
+ *idx += 1;
+ return *idx;
+}
+
static int
peer_address_self_check (struct bgp *bgp, union sockunion *su)
{
@@ -3748,13 +3813,15 @@ DEFUN (no_neighbor_send_community,
/* neighbor send-community extended. */
DEFUN (neighbor_send_community_type,
neighbor_send_community_type_cmd,
- "neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|extended|standard>",
+ "neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|all|extended|standard|large>",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Send Community attribute to this neighbor\n"
"Send Standard and Extended Community attributes\n"
+ "Send Standard, Large and Extended Community attributes\n"
"Send Extended Community attributes\n"
- "Send Standard Community attributes\n")
+ "Send Standard Community attributes\n"
+ "Send Large Community attributes\n")
{
int idx = 0;
u_int32_t flag = 0;
@@ -3765,25 +3832,35 @@ DEFUN (neighbor_send_community_type,
SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY);
else if (argv_find (argv, argc, "extended", &idx))
SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY);
+ else if (argv_find (argv, argc, "large", &idx))
+ SET_FLAG (flag, PEER_FLAG_SEND_LARGE_COMMUNITY);
+ else if (argv_find (argv, argc, "both", &idx))
+ {
+ SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY);
+ SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY);
+ }
else
- {
- SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY);
- SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY);
- }
+ {
+ SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY);
+ SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY);
+ SET_FLAG (flag, PEER_FLAG_SEND_LARGE_COMMUNITY);
+ }
return peer_af_flag_set_vty (vty, peer, bgp_node_afi (vty), bgp_node_safi (vty), flag);
}
DEFUN (no_neighbor_send_community_type,
no_neighbor_send_community_type_cmd,
- "no neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|extended|standard>",
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|all|extended|standard|large>",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Send Community attribute to this neighbor\n"
"Send Standard and Extended Community attributes\n"
+ "Send Standard, Large and Extended Community attributes\n"
"Send Extended Community attributes\n"
- "Send Standard Community attributes\n")
+ "Send Standard Community attributes\n"
+ "Send Large Community attributes\n")
{
int idx_peer = 2;
int idx_type = 4;
@@ -3795,11 +3872,21 @@ DEFUN (no_neighbor_send_community_type,
return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty),
bgp_node_safi (vty),
PEER_FLAG_SEND_EXT_COMMUNITY);
+ if (strncmp (argv[idx_type]->arg, "l", 1) == 0)
+ return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty),
+ bgp_node_safi (vty),
+ PEER_FLAG_SEND_LARGE_COMMUNITY);
+ if (strncmp (argv[idx_type]->arg, "b", 1) == 0)
+ return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty),
+ bgp_node_safi (vty),
+ PEER_FLAG_SEND_COMMUNITY |
+ PEER_FLAG_SEND_EXT_COMMUNITY);
return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty),
bgp_node_safi (vty),
(PEER_FLAG_SEND_COMMUNITY |
- PEER_FLAG_SEND_EXT_COMMUNITY));
+ PEER_FLAG_SEND_EXT_COMMUNITY|
+ PEER_FLAG_SEND_LARGE_COMMUNITY));
}
/* neighbor soft-reconfig. */
@@ -5586,7 +5673,7 @@ DEFUN (address_family_vpnv6,
vty->node = BGP_VPNV6_NODE;
return CMD_SUCCESS;
}
-#endif /* KEEP_OLD_VPN_COMMANDS */
+#endif
DEFUN (address_family_encap,
address_family_encap_cmd,
@@ -6134,6 +6221,12 @@ DEFUN (show_bgp_memory,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
count * sizeof (struct ecommunity)),
VTY_NEWLINE);
+ if ((count = mtype_stats_alloc (MTYPE_LCOMMUNITY)))
+ vty_out (vty, "%ld BGP large-community entries, using %s of memory%s",
+ count,
+ mtype_memstr (memstrbuf, sizeof (memstrbuf),
+ count * sizeof (struct lcommunity)),
+ VTY_NEWLINE);
if ((count = mtype_stats_alloc (MTYPE_CLUSTER)))
vty_out (vty, "%ld Cluster lists, using %s of memory%s", count,
@@ -7111,12 +7204,16 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi,
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED))
vty_out (vty, " MED is propagated unchanged to this neighbor%s", VTY_NEWLINE);
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
- || CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY))
+ || CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
+ || CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY))
{
vty_out (vty, " Community attribute sent to this neighbor");
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
- && CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY))
- vty_out (vty, "(both)%s", VTY_NEWLINE);
+ && CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
+ && CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY))
+ vty_out (vty, "(all)%s", VTY_NEWLINE);
+ else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY))
+ vty_out (vty, "(large)%s", VTY_NEWLINE);
else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY))
vty_out (vty, "(extended)%s", VTY_NEWLINE);
else
@@ -8559,7 +8656,7 @@ DEFUN (show_ip_bgp_neighbors,
SHOW_STR
IP_STR
BGP_STR
- BGP_INSTANCE_ALL_HELP_STR
+ BGP_INSTANCE_HELP_STR
"Address Family\n"
"Address Family\n"
"Address Family\n"
@@ -8644,6 +8741,36 @@ DEFUN (show_ip_bgp_community_info,
return CMD_SUCCESS;
}
+static void
+lcommunity_show_all_iterator (struct hash_backet *backet, struct vty *vty)
+{
+ struct lcommunity *lcom;
+
+ lcom = (struct lcommunity *) backet->data;
+ vty_out (vty, "[%p] (%ld) %s%s", (void *)backet, lcom->refcnt,
+ lcommunity_str (lcom), VTY_NEWLINE);
+}
+
+/* Show BGP's community internal data. */
+DEFUN (show_ip_bgp_lcommunity_info,
+ show_ip_bgp_lcommunity_info_cmd,
+ "show ip bgp large-community-info",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "List all bgp large-community information\n")
+{
+ vty_out (vty, "Address Refcnt Large-community%s", VTY_NEWLINE);
+
+ hash_iterate (lcommunity_hash (),
+ (void (*) (struct hash_backet *, void *))
+ lcommunity_show_all_iterator,
+ vty);
+
+ return CMD_SUCCESS;
+}
+
+
DEFUN (show_ip_bgp_attr_info,
show_ip_bgp_attr_info_cmd,
"show [ip] bgp attribute-info",
@@ -9195,7 +9322,7 @@ bgp_show_peer_group_vty (struct vty *vty, const char *name,
DEFUN (show_ip_bgp_peer_groups,
show_ip_bgp_peer_groups_cmd,
- "show [ip] bgp [<view|vrf> VRFNAME] peer-group [PGNAME]",
+ "show [ip] bgp [<view|vrf> WORD] peer-group [PGNAME]",
SHOW_STR
IP_STR
BGP_STR
@@ -9207,7 +9334,7 @@ DEFUN (show_ip_bgp_peer_groups,
vrf = pg = NULL;
int idx = 0;
- vrf = argv_find (argv, argc, "VRFNAME", &idx) ? argv[idx]->arg : NULL;
+ vrf = argv_find (argv, argc, "WORD", &idx) ? argv[idx]->arg : NULL;
pg = argv_find (argv, argc, "PGNAME", &idx) ? argv[idx]->arg : NULL;
return bgp_show_peer_group_vty (vty, vrf, show_all_groups, pg);
@@ -10695,6 +10822,7 @@ bgp_vty_init (void)
install_element (BGP_NODE, &address_family_vpnv4_cmd);
install_element (BGP_NODE, &address_family_vpnv6_cmd);
#endif /* KEEP_OLD_VPN_COMMANDS */
+
install_element (BGP_NODE, &address_family_encap_cmd);
install_element (BGP_NODE, &address_family_encapv6_cmd);
@@ -10745,6 +10873,8 @@ bgp_vty_init (void)
/* "show [ip] bgp community" commands. */
install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd);
+ /* "show ip bgp large-community" commands. */
+ install_element (VIEW_NODE, &show_ip_bgp_lcommunity_info_cmd);
/* "show [ip] bgp attribute-info" commands. */
install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd);
@@ -11077,6 +11207,350 @@ DEFUN (show_ip_community_list_arg,
return CMD_SUCCESS;
}
+/*
+ * Large Community code.
+ */
+static int
+lcommunity_list_set_vty (struct vty *vty, int argc, struct cmd_token **argv,
+ int style, int reject_all_digit_name)
+{
+ int ret;
+ int direct;
+ char *str;
+ int idx = 0;
+ char *cl_name;
+
+ direct = argv_find (argv, argc, "permit", &idx) ? COMMUNITY_PERMIT : COMMUNITY_DENY;
+
+ /* All digit name check. */
+ idx = 0;
+ argv_find (argv, argc, "WORD", &idx);
+ argv_find (argv, argc, "(1-99)", &idx);
+ argv_find (argv, argc, "(100-500)", &idx);
+ cl_name = argv[idx]->arg;
+ if (reject_all_digit_name && all_digit (cl_name))
+ {
+ vty_out (vty, "%% Community name cannot have all digits%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ argv_find (argv, argc, "AA:BB:CC", &idx);
+ argv_find (argv, argc, "LINE", &idx);
+ /* Concat community string argument. */
+ if (idx)
+ str = argv_concat (argv, argc, idx);
+ else
+ str = NULL;
+
+ ret = lcommunity_list_set (bgp_clist, cl_name, str, direct, style);
+
+ /* Free temporary community list string allocated by
+ argv_concat(). */
+ if (str)
+ XFREE (MTYPE_TMP, str);
+
+ if (ret < 0)
+ {
+ community_list_perror (vty, ret);
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
+static int
+lcommunity_list_unset_vty (struct vty *vty, int argc, struct cmd_token **argv,
+ int style)
+{
+ int ret;
+ int direct = 0;
+ char *str = NULL;
+ int idx = 0;
+
+ argv_find (argv, argc, "permit", &idx);
+ argv_find (argv, argc, "deny", &idx);
+
+ if (idx)
+ {
+ /* Check the list direct. */
+ if (strncmp (argv[idx]->arg, "p", 1) == 0)
+ direct = COMMUNITY_PERMIT;
+ else
+ direct = COMMUNITY_DENY;
+
+ idx = 0;
+ argv_find (argv, argc, "LINE", &idx);
+ argv_find (argv, argc, "AA:AA:NN", &idx);
+ /* Concat community string argument. */
+ str = argv_concat (argv, argc, idx);
+ }
+
+ idx = 0;
+ argv_find (argv, argc, "(1-99)", &idx);
+ argv_find (argv, argc, "(100-500)", &idx);
+ argv_find (argv, argc, "WORD", &idx);
+
+ /* Unset community list. */
+ ret = lcommunity_list_unset (bgp_clist, argv[idx]->arg, str, direct, style);
+
+ /* Free temporary community list string allocated by
+ argv_concat(). */
+ if (str)
+ XFREE (MTYPE_TMP, str);
+
+ if (ret < 0)
+ {
+ community_list_perror (vty, ret);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
+/* "large-community-list" keyword help string. */
+#define LCOMMUNITY_LIST_STR "Add a large community list entry\n"
+#define LCOMMUNITY_VAL_STR "large community in 'aa:bb:cc' format\n"
+
+DEFUN (ip_lcommunity_list_standard,
+ ip_lcommunity_list_standard_cmd,
+ "ip large-community-list (1-99) <deny|permit>",
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Large Community list number (standard)\n"
+ "Specify large community to reject\n"
+ "Specify large community to accept\n"
+ LCOMMUNITY_VAL_STR)
+{
+ return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 0);
+}
+
+DEFUN (ip_lcommunity_list_standard1,
+ ip_lcommunity_list_standard1_cmd,
+ "ip large-community-list (1-99) <deny|permit> AA:BB:CC...",
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Large Community list number (standard)\n"
+ "Specify large community to reject\n"
+ "Specify large community to accept\n"
+ LCOMMUNITY_VAL_STR)
+{
+ return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 0);
+}
+
+DEFUN (ip_lcommunity_list_expanded,
+ ip_lcommunity_list_expanded_cmd,
+ "ip large-community-list (100-500) <deny|permit> LINE...",
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Large Community list number (expanded)\n"
+ "Specify large community to reject\n"
+ "Specify large community to accept\n"
+ "An ordered list as a regular-expression\n")
+{
+ return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED, 0);
+}
+
+DEFUN (ip_lcommunity_list_name_standard,
+ ip_lcommunity_list_name_standard_cmd,
+ "ip large-community-list standard WORD <deny|permit>",
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Specify standard large-community-list\n"
+ "Large Community list name\n"
+ "Specify large community to reject\n"
+ "Specify large community to accept\n")
+{
+ return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 1);
+}
+
+DEFUN (ip_lcommunity_list_name_standard1,
+ ip_lcommunity_list_name_standard1_cmd,
+ "ip large-community-list standard WORD <deny|permit> AA:BB:CC...",
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Specify standard large-community-list\n"
+ "Large Community list name\n"
+ "Specify large community to reject\n"
+ "Specify large community to accept\n"
+ LCOMMUNITY_VAL_STR)
+{
+ return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 1);
+}
+
+DEFUN (ip_lcommunity_list_name_expanded,
+ ip_lcommunity_list_name_expanded_cmd,
+ "ip large-community-list expanded WORD <deny|permit> LINE...",
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Specify expanded large-community-list\n"
+ "Large Community list name\n"
+ "Specify large community to reject\n"
+ "Specify large community to accept\n"
+ "An ordered list as a regular-expression\n")
+{
+ return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED, 1);
+}
+
+DEFUN (no_ip_lcommunity_list_standard_all,
+ no_ip_lcommunity_list_standard_all_cmd,
+ "no ip large-community-list <(1-99)|(100-500)|WORD>",
+ NO_STR
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Large Community list number (standard)\n"
+ "Large Community list number (expanded)\n"
+ "Large Community list name\n")
+{
+ return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD);
+}
+
+DEFUN (no_ip_lcommunity_list_name_expanded_all,
+ no_ip_lcommunity_list_name_expanded_all_cmd,
+ "no ip large-community-list expanded WORD",
+ NO_STR
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Specify expanded large-community-list\n"
+ "Large Community list name\n")
+{
+ return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED);
+}
+
+DEFUN (no_ip_lcommunity_list_standard,
+ no_ip_lcommunity_list_standard_cmd,
+ "no ip large-community-list (1-99) <deny|permit> AA:AA:NN...",
+ NO_STR
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Large Community list number (standard)\n"
+ "Specify large community to reject\n"
+ "Specify large community to accept\n"
+ LCOMMUNITY_VAL_STR)
+{
+ return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD);
+}
+
+DEFUN (no_ip_lcommunity_list_expanded,
+ no_ip_lcommunity_list_expanded_cmd,
+ "no ip large-community-list (100-500) <deny|permit> LINE...",
+ NO_STR
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Large Community list number (expanded)\n"
+ "Specify large community to reject\n"
+ "Specify large community to accept\n"
+ "An ordered list as a regular-expression\n")
+{
+ return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED);
+}
+
+DEFUN (no_ip_lcommunity_list_name_standard,
+ no_ip_lcommunity_list_name_standard_cmd,
+ "no ip large-community-list standard WORD <deny|permit> AA:AA:NN...",
+ NO_STR
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Specify standard large-community-list\n"
+ "Large Community list name\n"
+ "Specify large community to reject\n"
+ "Specify large community to accept\n"
+ LCOMMUNITY_VAL_STR)
+{
+ return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD);
+}
+
+DEFUN (no_ip_lcommunity_list_name_expanded,
+ no_ip_lcommunity_list_name_expanded_cmd,
+ "no ip large-community-list expanded WORD <deny|permit> LINE...",
+ NO_STR
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Specify expanded large-community-list\n"
+ "Large community list name\n"
+ "Specify large community to reject\n"
+ "Specify large community to accept\n"
+ "An ordered list as a regular-expression\n")
+{
+ return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED);
+}
+
+static void
+lcommunity_list_show (struct vty *vty, struct community_list *list)
+{
+ struct community_entry *entry;
+
+ for (entry = list->head; entry; entry = entry->next)
+ {
+ if (entry == list->head)
+ {
+ if (all_digit (list->name))
+ vty_out (vty, "Large community %s list %s%s",
+ entry->style == EXTCOMMUNITY_LIST_STANDARD ?
+ "standard" : "(expanded) access",
+ list->name, VTY_NEWLINE);
+ else
+ vty_out (vty, "Named large community %s list %s%s",
+ entry->style == EXTCOMMUNITY_LIST_STANDARD ?
+ "standard" : "expanded",
+ list->name, VTY_NEWLINE);
+ }
+ if (entry->any)
+ vty_out (vty, " %s%s",
+ community_direct_str (entry->direct), VTY_NEWLINE);
+ else
+ vty_out (vty, " %s %s%s",
+ community_direct_str (entry->direct),
+ entry->style == EXTCOMMUNITY_LIST_STANDARD ?
+ entry->u.ecom->str : entry->config,
+ VTY_NEWLINE);
+ }
+}
+
+DEFUN (show_ip_lcommunity_list,
+ show_ip_lcommunity_list_cmd,
+ "show ip large-community-list",
+ SHOW_STR
+ IP_STR
+ "List large-community list\n")
+{
+ struct community_list *list;
+ struct community_list_master *cm;
+
+ cm = community_list_master_lookup (bgp_clist, LARGE_COMMUNITY_LIST_MASTER);
+ if (! cm)
+ return CMD_SUCCESS;
+
+ for (list = cm->num.head; list; list = list->next)
+ lcommunity_list_show (vty, list);
+
+ for (list = cm->str.head; list; list = list->next)
+ lcommunity_list_show (vty, list);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_lcommunity_list_arg,
+ show_ip_lcommunity_list_arg_cmd,
+ "show ip large-community-list <(1-500)|WORD>",
+ SHOW_STR
+ IP_STR
+ "List large-community list\n"
+ "large-community-list number\n"
+ "large-community-list name\n")
+{
+ struct community_list *list;
+
+ list = community_list_lookup (bgp_clist, argv[3]->arg, LARGE_COMMUNITY_LIST_MASTER);
+ if (! list)
+ {
+ vty_out (vty, "%% Can't find extcommunity-list%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ lcommunity_list_show (vty, list);
+
+ return CMD_SUCCESS;
+}
+
/* "extcommunity-list" keyword help string. */
#define EXTCOMMUNITY_LIST_STR "Add a extended community list entry\n"
#define EXTCOMMUNITY_VAL_STR "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n"
@@ -11386,6 +11860,30 @@ community_list_config_write (struct vty *vty)
community_list_config_str (entry), VTY_NEWLINE);
write++;
}
+
+
+ /* lcommunity-list. */
+ cm = community_list_master_lookup (bgp_clist, LARGE_COMMUNITY_LIST_MASTER);
+
+ for (list = cm->num.head; list; list = list->next)
+ for (entry = list->head; entry; entry = entry->next)
+ {
+ vty_out (vty, "ip large-community-list %s %s %s%s",
+ list->name, community_direct_str (entry->direct),
+ community_list_config_str (entry), VTY_NEWLINE);
+ write++;
+ }
+ for (list = cm->str.head; list; list = list->next)
+ for (entry = list->head; entry; entry = entry->next)
+ {
+ vty_out (vty, "ip large-community-list %s %s %s %s%s",
+ entry->style == LARGE_COMMUNITY_LIST_STANDARD
+ ? "standard" : "expanded",
+ list->name, community_direct_str (entry->direct),
+ community_list_config_str (entry), VTY_NEWLINE);
+ write++;
+ }
+
return write;
}
@@ -11416,4 +11914,20 @@ community_list_vty (void)
install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_all_cmd);
install_element (VIEW_NODE, &show_ip_extcommunity_list_cmd);
install_element (VIEW_NODE, &show_ip_extcommunity_list_arg_cmd);
+
+ /* Large Community List */
+ install_element (CONFIG_NODE, &ip_lcommunity_list_standard_cmd);
+ install_element (CONFIG_NODE, &ip_lcommunity_list_standard1_cmd);
+ install_element (CONFIG_NODE, &ip_lcommunity_list_expanded_cmd);
+ install_element (CONFIG_NODE, &ip_lcommunity_list_name_standard_cmd);
+ install_element (CONFIG_NODE, &ip_lcommunity_list_name_standard1_cmd);
+ install_element (CONFIG_NODE, &ip_lcommunity_list_name_expanded_cmd);
+ install_element (CONFIG_NODE, &no_ip_lcommunity_list_standard_all_cmd);
+ install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_all_cmd);
+ install_element (CONFIG_NODE, &no_ip_lcommunity_list_standard_cmd);
+ install_element (CONFIG_NODE, &no_ip_lcommunity_list_expanded_cmd);
+ install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_standard_cmd);
+ install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_cmd);
+ install_element (VIEW_NODE, &show_ip_lcommunity_list_cmd);
+ install_element (VIEW_NODE, &show_ip_lcommunity_list_arg_cmd);
}
diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h
index 40c1723218..13e67d112e 100644
--- a/bgpd/bgp_vty.h
+++ b/bgpd/bgp_vty.h
@@ -51,9 +51,6 @@ peer_and_group_lookup_vty (struct vty *vty, const char *peer_str);
extern int
bgp_parse_afi(const char *str, afi_t *afi);
-extern int
-bgp_parse_safi(const char *str, safi_t *safi);
-
extern afi_t
bgp_vty_afi_from_arg(const char *afi_str);
@@ -66,4 +63,7 @@ argv_find_and_parse_afi(struct cmd_token **argv, int argc, int *index, afi_t *af
extern int
argv_find_and_parse_safi(struct cmd_token **argv, int argc, int *index, safi_t *safi);
+extern int
+bgp_vty_find_and_parse_afi_safi_vrf (struct vty *vty, struct cmd_token **argv, int argc, int *idx,
+ afi_t *afi, safi_t *safi, vrf_id_t *vrf);
#endif /* _QUAGGA_BGP_VTY_H */
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index ec2223d3ed..b0c163f1e3 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -348,7 +348,7 @@ time_t bgp_clock (void)
{
struct timeval tv;
- quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv);
+ monotime(&tv);
return tv.tv_sec;
}
@@ -652,7 +652,7 @@ bgp_listen_limit_unset (struct bgp *bgp)
}
int
-bgp_map_afi_safi_iana2int (afi_t pkt_afi, safi_t pkt_safi,
+bgp_map_afi_safi_iana2int (iana_afi_t pkt_afi, safi_t pkt_safi,
afi_t *afi, safi_t *safi)
{
/* Map from IANA values to internal values, return error if
@@ -668,7 +668,7 @@ bgp_map_afi_safi_iana2int (afi_t pkt_afi, safi_t pkt_safi,
int
bgp_map_afi_safi_int2iana (afi_t afi, safi_t safi,
- afi_t *pkt_afi, safi_t *pkt_safi)
+ iana_afi_t *pkt_afi, safi_t *pkt_safi)
{
/* Map from internal values to IANA values, return error if
* internal values are bad (unexpected).
@@ -902,6 +902,7 @@ peer_af_flag_reset (struct peer *peer, afi_t afi, safi_t safi)
{
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY);
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY);
+ SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY);
}
/* Clear neighbor default_originate_rmap */
@@ -1206,6 +1207,7 @@ peer_new (struct bgp *bgp)
{
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY);
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY);
+ SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY);
}
peer->orf_plist[afi][safi] = NULL;
}
@@ -3702,6 +3704,7 @@ static const struct peer_flag_action peer_af_flag_action_list[] =
{
{ PEER_FLAG_SEND_COMMUNITY, 1, peer_change_reset_out },
{ PEER_FLAG_SEND_EXT_COMMUNITY, 1, peer_change_reset_out },
+ { PEER_FLAG_SEND_LARGE_COMMUNITY, 1, peer_change_reset_out },
{ PEER_FLAG_NEXTHOP_SELF, 1, peer_change_reset_out },
{ PEER_FLAG_REFLECTOR_CLIENT, 1, peer_change_reset },
{ PEER_FLAG_RSERVER_CLIENT, 1, peer_change_reset },
@@ -6982,10 +6985,17 @@ bgp_config_write_peer_af (struct vty *vty, struct bgp *bgp,
if (bgp_option_check (BGP_OPT_CONFIG_CISCO))
{
if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)
- && peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
+ && peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)
+ && peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY))
{
afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s send-community both%s",
+ " neighbor %s send-community all%s",
+ addr, VTY_NEWLINE);
+ }
+ else if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY))
+ {
+ afi_header_vty_out (vty, afi, safi, write,
+ " neighbor %s send-community large%s",
addr, VTY_NEWLINE);
}
else if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
@@ -7006,10 +7016,19 @@ bgp_config_write_peer_af (struct vty *vty, struct bgp *bgp,
if (!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY) &&
(!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)) &&
!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY) &&
- (!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)))
+ (!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) &&
+ !peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY) &&
+ (!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY)))
+ {
+ afi_header_vty_out (vty, afi, safi, write,
+ " no neighbor %s send-community all%s",
+ addr, VTY_NEWLINE);
+ }
+ else if (!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY) &&
+ (!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY)))
{
afi_header_vty_out (vty, afi, safi, write,
- " no neighbor %s send-community both%s",
+ " no neighbor %s send-community large%s",
addr, VTY_NEWLINE);
}
else if (!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY) &&
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 2718805130..2eef04e1d1 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -705,6 +705,7 @@ struct peer
#define PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS (1 << 23) /* addpath-tx-bestpath-per-AS */
#define PEER_FLAG_WEIGHT (1 << 24) /* weight */
#define PEER_FLAG_ALLOWAS_IN_ORIGIN (1 << 25) /* allowas-in origin */
+#define PEER_FLAG_SEND_LARGE_COMMUNITY (1 << 26) /* Send large Communities */
/* MD5 password */
char *password;
@@ -963,6 +964,7 @@ struct bgp_nlri
#define BGP_ATTR_AS4_AGGREGATOR 18
#define BGP_ATTR_AS_PATHLIMIT 21
#define BGP_ATTR_ENCAP 23
+#define BGP_ATTR_LARGE_COMMUNITIES 32
#if ENABLE_BGP_VNC
#define BGP_ATTR_VNC 255
#endif
@@ -1355,11 +1357,11 @@ extern void bgp_route_map_terminate(void);
extern int peer_cmp (struct peer *p1, struct peer *p2);
extern int
-bgp_map_afi_safi_iana2int (afi_t pkt_afi, safi_t pkt_safi,
+bgp_map_afi_safi_iana2int (iana_afi_t pkt_afi, safi_t pkt_safi,
afi_t *afi, safi_t *safi);
extern int
bgp_map_afi_safi_int2iana (afi_t afi, safi_t safi,
- afi_t *pkt_afi, safi_t *pkt_safi);
+ iana_afi_t *pkt_afi, safi_t *pkt_safi);
extern struct peer_af * peer_af_create (struct peer *, afi_t, safi_t);
extern struct peer_af * peer_af_find (struct peer *, afi_t, safi_t);
diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c
index ab9a24e831..8ff28a39d7 100644
--- a/bgpd/rfapi/bgp_rfapi_cfg.c
+++ b/bgpd/rfapi/bgp_rfapi_cfg.c
@@ -30,8 +30,8 @@
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"
-#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/rfapi/rfapi.h"
@@ -561,8 +561,9 @@ DEFUN (vnc_defaults_responselifetime,
return CMD_SUCCESS;
}
-static struct rfapi_nve_group_cfg *
-rfapi_group_lookup_byname (struct bgp *bgp, const char *name)
+struct rfapi_nve_group_cfg *
+bgp_rfapi_cfg_match_byname (struct bgp *bgp, const char *name,
+ rfapi_group_cfg_type_t type) /* _MAX = any */
{
struct rfapi_nve_group_cfg *rfg;
struct listnode *node, *nnode;
@@ -570,18 +571,29 @@ rfapi_group_lookup_byname (struct bgp *bgp, const char *name)
for (ALL_LIST_ELEMENTS
(bgp->rfapi_cfg->nve_groups_sequential, node, nnode, rfg))
{
- if (!strcmp (rfg->name, name))
+ if ((type == RFAPI_GROUP_CFG_MAX || type == rfg->type) &&
+ !strcmp (rfg->name, name))
return rfg;
}
return NULL;
}
static struct rfapi_nve_group_cfg *
-rfapi_group_new ()
+rfapi_group_new (struct bgp *bgp,
+ rfapi_group_cfg_type_t type,
+ const char *name)
{
struct rfapi_nve_group_cfg *rfg;
rfg = XCALLOC (MTYPE_RFAPI_GROUP_CFG, sizeof (struct rfapi_nve_group_cfg));
+ if (rfg)
+ {
+ rfg->type = type;
+ rfg->name = strdup (name);
+ /* add to tail of list */
+ listnode_add (bgp->rfapi_cfg->nve_groups_sequential, rfg);
+ }
+ rfg->label = MPLS_LABEL_ILLEGAL;
QOBJ_REG (rfg, rfapi_nve_group_cfg);
return rfg;
@@ -1033,7 +1045,8 @@ DEFUN (vnc_redistribute_nvegroup,
* OK if nve group doesn't exist yet; we'll set the pointer
* when the group is defined later
*/
- bgp->rfapi_cfg->rfg_redist = rfapi_group_lookup_byname (bgp, argv[3]->arg);
+ bgp->rfapi_cfg->rfg_redist = bgp_rfapi_cfg_match_byname (bgp, argv[3]->arg,
+ RFAPI_GROUP_CFG_NVE);
if (bgp->rfapi_cfg->rfg_redist_name)
free (bgp->rfapi_cfg->rfg_redist_name);
bgp->rfapi_cfg->rfg_redist_name = strdup (argv[3]->arg);
@@ -1622,7 +1635,7 @@ DEFUN (vnc_export_nvegroup,
return CMD_WARNING;
}
- rfg_new = rfapi_group_lookup_byname (bgp, argv[5]->arg);
+ rfg_new = bgp_rfapi_cfg_match_byname (bgp, argv[5]->arg, RFAPI_GROUP_CFG_NVE);
if (argv[2]->arg[0] == 'b')
{
@@ -2417,20 +2430,17 @@ DEFUN (vnc_nve_group,
struct rfapi_rfg_name *rfgn;
/* Search for name */
- rfg = rfapi_group_lookup_byname (bgp, argv[2]->arg);
+ rfg = bgp_rfapi_cfg_match_byname (bgp, argv[2]->arg, RFAPI_GROUP_CFG_NVE);
if (!rfg)
{
- rfg = rfapi_group_new ();
+ rfg = rfapi_group_new (bgp, RFAPI_GROUP_CFG_NVE, argv[2]->arg);
if (!rfg)
{
/* Error out of memory */
vty_out (vty, "Can't allocate memory for NVE group%s", VTY_NEWLINE);
return CMD_WARNING;
}
- rfg->name = strdup (argv[2]->arg);
- /* add to tail of list */
- listnode_add (bgp->rfapi_cfg->nve_groups_sequential, rfg);
/* Copy defaults from struct rfapi_cfg */
rfg->rd = bgp->rfapi_cfg->default_rd;
@@ -2453,7 +2463,7 @@ DEFUN (vnc_nve_group,
rfg->rt_import_list =
ecommunity_dup (bgp->rfapi_cfg->default_rt_import_list);
rfg->rfapi_import_table =
- rfapiImportTableRefAdd (bgp, rfg->rt_import_list);
+ rfapiImportTableRefAdd (bgp, rfg->rt_import_list, rfg);
}
/*
@@ -2629,7 +2639,8 @@ static int
bgp_rfapi_delete_named_nve_group (
struct vty *vty, /* NULL = no output */
struct bgp *bgp,
- const char *rfg_name) /* NULL = any */
+ const char *rfg_name, /* NULL = any */
+ rfapi_group_cfg_type_t type) /* _MAX = any */
{
struct rfapi_nve_group_cfg *rfg = NULL;
struct listnode *node, *nnode;
@@ -2638,7 +2649,7 @@ bgp_rfapi_delete_named_nve_group (
/* Search for name */
if (rfg_name)
{
- rfg = rfapi_group_lookup_byname (bgp, rfg_name);
+ rfg = bgp_rfapi_cfg_match_byname (bgp, rfg_name, type);
if (!rfg)
{
if (vty)
@@ -2665,7 +2676,8 @@ bgp_rfapi_delete_named_nve_group (
for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_direct_bgp_l,
node, rfgn))
{
- if (rfg_name == NULL || !strcmp (rfgn->name, rfg_name))
+ if (rfg_name == NULL ||
+ (type == RFAPI_GROUP_CFG_NVE && !strcmp (rfgn->name, rfg_name)))
{
rfgn->rfg = NULL;
/* remove exported routes from this group */
@@ -2680,7 +2692,8 @@ bgp_rfapi_delete_named_nve_group (
for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_zebra_l, node, rfgn))
{
- if (rfg_name == NULL || !strcmp (rfgn->name, rfg_name))
+ if (rfg_name == NULL ||
+ (type == RFAPI_GROUP_CFG_NVE && !strcmp (rfgn->name, rfg_name)))
{
rfgn->rfg = NULL;
/* remove exported routes from this group */
@@ -2707,7 +2720,7 @@ DEFUN (vnc_no_nve_group,
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
- return bgp_rfapi_delete_named_nve_group (vty, bgp, argv[3]->arg);
+ return bgp_rfapi_delete_named_nve_group (vty, bgp, argv[3]->arg, RFAPI_GROUP_CFG_NVE);
}
DEFUN (vnc_nve_group_prefix,
@@ -2890,7 +2903,7 @@ DEFUN (vnc_nve_group_rt_import,
*/
if (rfg->rfapi_import_table)
rfapiImportTableRefDelByIt (bgp, rfg->rfapi_import_table);
- rfg->rfapi_import_table = rfapiImportTableRefAdd (bgp, rfg->rt_import_list);
+ rfg->rfapi_import_table = rfapiImportTableRefAdd (bgp, rfg->rt_import_list, rfg);
if (is_export_bgp)
vnc_direct_bgp_add_group (bgp, rfg);
@@ -2997,7 +3010,7 @@ DEFUN (vnc_nve_group_rt_both,
*/
if (rfg->rfapi_import_table)
rfapiImportTableRefDelByIt (bgp, rfg->rfapi_import_table);
- rfg->rfapi_import_table = rfapiImportTableRefAdd (bgp, rfg->rt_import_list);
+ rfg->rfapi_import_table = rfapiImportTableRefAdd (bgp, rfg->rt_import_list, rfg);
if (is_export_bgp)
vnc_direct_bgp_add_group (bgp, rfg);
@@ -3238,6 +3251,492 @@ static struct cmd_node bgp_vnc_nve_group_node = {
};
/*-------------------------------------------------------------------------
+ * VNC nve-group
+ * Note there are two types of NVEs, one for VPNs one for RFP NVEs
+ *-----------------------------------------------------------------------*/
+
+DEFUN (vnc_vrf_policy,
+ vnc_vrf_policy_cmd,
+ "vrf-policy NAME",
+ "Configure a VRF policy group\n"
+ "VRF name\n")
+{
+ struct rfapi_nve_group_cfg *rfg;
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Search for name */
+ rfg = bgp_rfapi_cfg_match_byname (bgp, argv[1]->arg, RFAPI_GROUP_CFG_VRF);
+
+ if (!rfg)
+ {
+ rfg = rfapi_group_new (bgp, RFAPI_GROUP_CFG_VRF, argv[1]->arg);
+ if (!rfg)
+ {
+ /* Error out of memory */
+ vty_out (vty, "Can't allocate memory for NVE group%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ /*
+ * XXX subsequent calls will need to make sure this item is still
+ * in the linked list and has the same name
+ */
+ VTY_PUSH_CONTEXT_SUB (BGP_VRF_POLICY_NODE, rfg);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (vnc_no_vrf_policy,
+ vnc_no_vrf_policy_cmd,
+ "no vrf-policy NAME",
+ NO_STR
+ "Remove a VRF policy group\n"
+ "VRF name\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return bgp_rfapi_delete_named_nve_group (vty, bgp, argv[2]->arg, RFAPI_GROUP_CFG_VRF);
+}
+
+DEFUN (vnc_vrf_policy_label,
+ vnc_vrf_policy_label_cmd,
+ "label (0-1048575)",
+ "Default label value for VRF\n"
+ "Label Value <0-1048575>\n")
+{
+ VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
+
+ uint32_t label;
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* make sure it's still in list */
+ if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
+ {
+ /* Not in list anymore */
+ vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ VTY_GET_INTEGER_RANGE ("Label value", label, argv[1]->arg, 0, MPLS_LABEL_MAX);
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_prechange (bgp);
+ }
+
+ rfg->label = label;
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_postchange (bgp);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (vnc_vrf_policy_no_label,
+ vnc_vrf_policy_no_label_cmd,
+ "no label",
+ "Remove VRF default label\n")
+{
+ VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ /* make sure it's still in list */
+ if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
+ {
+ /* Not in list anymore */
+ vty_out (vty, "Current VRF group no longer exists%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_prechange (bgp);
+ }
+
+ rfg->label = MPLS_LABEL_ILLEGAL;
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_postchange (bgp);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (vnc_vrf_policy_nexthop,
+ vnc_vrf_policy_nexthop_cmd,
+ "nexthop <A.B.C.D|X:X::X:X|self>",
+ "Specify next hop to use for VRF advertised prefixes\n"
+ "IPv4 prefix\n"
+ "IPv6 prefix\n"
+ "Use configured router-id (default)")
+{
+ VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
+ struct prefix p;
+
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ /* make sure it's still in list */
+ if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
+ {
+ /* Not in list anymore */
+ vty_out (vty, "Current VRF no longer exists%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_prechange (bgp);
+ }
+
+ if (!str2prefix (argv[1]->arg, &p) && p.family)
+ {
+ //vty_out (vty, "Nexthop set to self%s", VTY_NEWLINE);
+ SET_FLAG (rfg->flags, RFAPI_RFG_VPN_NH_SELF);
+ memset(&rfg->vn_prefix, 0, sizeof(struct prefix));
+ }
+ else
+ {
+ UNSET_FLAG (rfg->flags, RFAPI_RFG_VPN_NH_SELF);
+ rfg->vn_prefix = p;
+ }
+
+ /* TBD handle router-id/ nexthop changes when have advertised prefixes */
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_postchange (bgp);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/* The RT code should be refactored/simplified with above... */
+DEFUN (vnc_vrf_policy_rt_import,
+ vnc_vrf_policy_rt_import_cmd,
+ "rt import RTLIST...",
+ "Specify route targets\n"
+ "Import filter\n"
+ "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")
+{
+ VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int rc;
+ struct listnode *node;
+ struct rfapi_rfg_name *rfgn;
+ int is_export_bgp = 0;
+ int is_export_zebra = 0;
+
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* make sure it's still in list */
+ if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
+ {
+ /* Not in list anymore */
+ vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_import_list);
+ if (rc != CMD_SUCCESS)
+ return rc;
+
+ for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_direct_bgp_l,
+ node, rfgn))
+ {
+
+ if (rfgn->rfg == rfg)
+ {
+ is_export_bgp = 1;
+ break;
+ }
+ }
+
+ if (is_export_bgp)
+ vnc_direct_bgp_del_group (bgp, rfg);
+
+ for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_zebra_l, node, rfgn))
+ {
+
+ if (rfgn->rfg == rfg)
+ {
+ is_export_zebra = 1;
+ break;
+ }
+ }
+
+ if (is_export_zebra)
+ vnc_zebra_del_group (bgp, rfg);
+
+ /*
+ * stop referencing old import table, now reference new one
+ */
+ if (rfg->rfapi_import_table)
+ rfapiImportTableRefDelByIt (bgp, rfg->rfapi_import_table);
+ rfg->rfapi_import_table = rfapiImportTableRefAdd (bgp, rfg->rt_import_list, rfg);
+
+ if (is_export_bgp)
+ vnc_direct_bgp_add_group (bgp, rfg);
+
+ if (is_export_zebra)
+ vnc_zebra_add_group (bgp, rfg);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (vnc_vrf_policy_rt_export,
+ vnc_vrf_policy_rt_export_cmd,
+ "rt export RTLIST...",
+ "Specify route targets\n"
+ "Export filter\n"
+ "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")
+{
+ VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int rc;
+
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* make sure it's still in list */
+ if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
+ {
+ /* Not in list anymore */
+ vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_prechange (bgp);
+ }
+
+ rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_export_list);
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_postchange (bgp);
+ }
+
+ return rc;
+}
+
+DEFUN (vnc_vrf_policy_rt_both,
+ vnc_vrf_policy_rt_both_cmd,
+ "rt both RTLIST...",
+ "Specify route targets\n"
+ "Export+import filters\n"
+ "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")
+{
+ VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int rc;
+ int is_export_bgp = 0;
+ int is_export_zebra = 0;
+ struct listnode *node;
+ struct rfapi_rfg_name *rfgn;
+
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* make sure it's still in list */
+ if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
+ {
+ /* Not in list anymore */
+ vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_import_list);
+ if (rc != CMD_SUCCESS)
+ return rc;
+
+ for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_direct_bgp_l,
+ node, rfgn))
+ {
+
+ if (rfgn->rfg == rfg)
+ {
+ is_export_bgp = 1;
+ break;
+ }
+ }
+
+ if (is_export_bgp)
+ vnc_direct_bgp_del_group (bgp, rfg);
+
+ for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_zebra_l, node, rfgn))
+ {
+
+ if (rfgn->rfg == rfg)
+ {
+ is_export_zebra = 1;
+ break;
+ }
+ }
+
+ if (is_export_zebra)
+ {
+ vnc_zlog_debug_verbose ("%s: is_export_zebra", __func__);
+ vnc_zebra_del_group (bgp, rfg);
+ }
+
+ /*
+ * stop referencing old import table, now reference new one
+ */
+ if (rfg->rfapi_import_table)
+ rfapiImportTableRefDelByIt (bgp, rfg->rfapi_import_table);
+ rfg->rfapi_import_table = rfapiImportTableRefAdd (bgp, rfg->rt_import_list, rfg);
+
+ if (is_export_bgp)
+ vnc_direct_bgp_add_group (bgp, rfg);
+
+ if (is_export_zebra)
+ vnc_zebra_add_group (bgp, rfg);
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_prechange (bgp);
+ }
+
+ rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_export_list);
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_postchange (bgp);
+ }
+
+ return rc;
+
+}
+
+DEFUN (vnc_vrf_policy_rd,
+ vnc_vrf_policy_rd_cmd,
+ "rd ASN:nn_or_IP-address:nn",
+ "Specify default VRF route distinguisher\n"
+ "Route Distinguisher (<as-number>:<number> | <ip-address>:<number> | auto:nh:<number> )\n")
+{
+ int ret;
+ struct prefix_rd prd;
+ VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* make sure it's still in list */
+ if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
+ {
+ /* Not in list anymore */
+ vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!strncmp (argv[1]->arg, "auto:nh:", 8))
+ {
+ /*
+ * use AF_UNIX to designate automatically-assigned RD
+ * auto:vn:nn where nn is a 2-octet quantity
+ */
+ char *end = NULL;
+ uint32_t value32 = strtoul (argv[1]->arg + 8, &end, 10);
+ uint16_t value = value32 & 0xffff;
+
+ if (!*(argv[1]->arg + 5) || *end)
+ {
+ vty_out (vty, "%% Malformed rd%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (value32 > 0xffff)
+ {
+ vty_out (vty, "%% Malformed rd (must be less than %u%s",
+ 0x0ffff, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ memset (&prd, 0, sizeof (prd));
+ prd.family = AF_UNIX;
+ prd.prefixlen = 64;
+ prd.val[0] = (RD_TYPE_IP >> 8) & 0x0ff;
+ prd.val[1] = RD_TYPE_IP & 0x0ff;
+ prd.val[6] = (value >> 8) & 0x0ff;
+ prd.val[7] = value & 0x0ff;
+
+ }
+ else
+ {
+
+ ret = str2prefix_rd (argv[1]->arg, &prd);
+ if (!ret)
+ {
+ vty_out (vty, "%% Malformed rd%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_prechange (bgp);
+ }
+
+ rfg->rd = prd;
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_postchange (bgp);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (exit_vrf_policy,
+ exit_vrf_policy_cmd,
+ "exit-vrf-policy",
+ "Exit VRF policy configuration mode\n")
+{
+ if (vty->node == BGP_VRF_POLICY_NODE)
+ {
+ vty->node = BGP_NODE;
+ }
+ return CMD_SUCCESS;
+}
+
+static struct cmd_node bgp_vrf_policy_node = {
+ BGP_VRF_POLICY_NODE,
+ "%s(config-router-vrf-policy)# ",
+ 1
+};
+
+/*-------------------------------------------------------------------------
* vnc-l2-group
*-----------------------------------------------------------------------*/
@@ -3247,11 +3746,17 @@ DEFUN (vnc_l2_group,
"vnc l2-group NAME",
VNC_CONFIG_STR "Configure a L2 group\n" "Group name\n")
{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
struct rfapi_l2_group_cfg *rfg;
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
/* Search for name */
- rfg = rfapi_l2_group_lookup_byname (bgp, argv[2]->arg);
+ rfg = rfapi_l2_group_lookup_byname (bgp, argv[1]->arg);
if (!rfg)
{
@@ -3262,7 +3767,7 @@ DEFUN (vnc_l2_group,
vty_out (vty, "Can't allocate memory for L2 group%s", VTY_NEWLINE);
return CMD_WARNING;
}
- rfg->name = strdup (argv[2]->arg);
+ rfg->name = strdup (argv[1]->arg);
/* add to tail of list */
listnode_add (bgp->rfapi_cfg->l2_groups, rfg);
}
@@ -3336,18 +3841,29 @@ DEFUN (vnc_no_l2_group,
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
return bgp_rfapi_delete_named_l2_group (vty, bgp, argv[3]->arg);
}
DEFUN (vnc_l2_group_lni,
vnc_l2_group_lni_cmd,
- "logical-network-id (0-4294967295)",
+ "logical-network-id <0-4294967295>",
"Specify Logical Network ID associated with group\n"
"value\n")
{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg);
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
/* make sure it's still in list */
if (!listnode_lookup (bgp->rfapi_cfg->l2_groups, rfg))
@@ -3364,14 +3880,20 @@ DEFUN (vnc_l2_group_lni,
DEFUN (vnc_l2_group_labels,
vnc_l2_group_labels_cmd,
- "labels LABELLIST...",
+ "labels .LABELLIST",
"Specify label values associated with group\n"
"Space separated list of label values <0-1048575>\n")
{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg);
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
struct list *ll;
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
/* make sure it's still in list */
if (!listnode_lookup (bgp->rfapi_cfg->l2_groups, rfg))
{
@@ -3386,13 +3908,12 @@ DEFUN (vnc_l2_group_labels,
ll = list_new ();
rfg->labels = ll;
}
-
- argc -= 1;
- argv += 1;
+ argc--;
+ argv++;
for (; argc; --argc, ++argv)
{
uint32_t label;
- VTY_GET_INTEGER_RANGE ("Label value", label, argv[0]->arg, 0, 1048575);
+ VTY_GET_INTEGER_RANGE ("Label value", label, argv[0]->arg, 0, MPLS_LABEL_MAX);
if (!listnode_lookup (ll, (void *) (uintptr_t) label))
listnode_add (ll, (void *) (uintptr_t) label);
}
@@ -3402,16 +3923,22 @@ DEFUN (vnc_l2_group_labels,
DEFUN (vnc_l2_group_no_labels,
vnc_l2_group_no_labels_cmd,
- "no labels LABELLIST...",
+ "no labels .LABELLIST",
NO_STR
"Remove label values associated with L2 group\n"
"Specify label values associated with L2 group\n"
"Space separated list of label values <0-1048575>\n")
{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg);
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
struct list *ll;
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
/* make sure it's still in list */
if (!listnode_lookup (bgp->rfapi_cfg->l2_groups, rfg))
{
@@ -3427,12 +3954,12 @@ DEFUN (vnc_l2_group_no_labels,
return CMD_WARNING;
}
- argc -= 2;
- argv += 2;
+ argc-=2;
+ argv+=2;
for (; argc; --argc, ++argv)
{
uint32_t label;
- VTY_GET_INTEGER_RANGE ("Label value", label, argv[0]->arg, 0, 1048575);
+ VTY_GET_INTEGER_RANGE ("Label value", label, argv[0]->arg, 0, MPLS_LABEL_MAX);
listnode_delete (ll, (void *) (uintptr_t) label);
}
@@ -3448,8 +3975,8 @@ DEFUN (vnc_l2_group_rt,
"Import filters\n"
"A route target\n")
{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg);
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
int rc = CMD_SUCCESS;
int do_import = 0;
int do_export = 0;
@@ -3467,10 +3994,8 @@ DEFUN (vnc_l2_group_rt,
default:
vty_out (vty, "Unknown option, %s%s", argv[1]->arg, VTY_NEWLINE);
return CMD_ERR_NO_MATCH;
- }
- if (argc < 3)
- return CMD_ERR_INCOMPLETE;
+ }
if (!bgp)
{
vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
@@ -3486,9 +4011,9 @@ DEFUN (vnc_l2_group_rt,
}
if (do_import)
- rc = set_ecom_list (vty, argc - 2, argv + 2, &rfg->rt_import_list);
+ rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_import_list);
if (rc == CMD_SUCCESS && do_export)
- rc = set_ecom_list (vty, argc - 2, argv + 2, &rfg->rt_export_list);
+ rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_export_list);
return rc;
}
@@ -3571,7 +4096,9 @@ bgp_rfapi_cfg_init (void)
install_node (&bgp_vnc_defaults_node, NULL);
install_node (&bgp_vnc_nve_group_node, NULL);
+ install_node (&bgp_vrf_policy_node, NULL);
install_node (&bgp_vnc_l2_group_node, NULL);
+ install_default (BGP_VRF_POLICY_NODE);
install_default (BGP_VNC_DEFAULTS_NODE);
install_default (BGP_VNC_NVE_GROUP_NODE);
install_default (BGP_VNC_L2_GROUP_NODE);
@@ -3582,6 +4109,8 @@ bgp_rfapi_cfg_init (void)
install_element (BGP_NODE, &vnc_defaults_cmd);
install_element (BGP_NODE, &vnc_nve_group_cmd);
install_element (BGP_NODE, &vnc_no_nve_group_cmd);
+ install_element (BGP_NODE, &vnc_vrf_policy_cmd);
+ install_element (BGP_NODE, &vnc_no_vrf_policy_cmd);
install_element (BGP_NODE, &vnc_l2_group_cmd);
install_element (BGP_NODE, &vnc_no_l2_group_cmd);
install_element (BGP_NODE, &vnc_advertise_un_method_cmd);
@@ -3645,6 +4174,16 @@ bgp_rfapi_cfg_init (void)
&vnc_nve_group_export_no_routemap_cmd);
install_element (BGP_VNC_NVE_GROUP_NODE, &exit_vnc_cmd);
+ install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_label_cmd);
+ install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_no_label_cmd);
+ //Hide per Jan 17 discussion
+ //install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_nexthop_cmd);
+ install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_rt_import_cmd);
+ install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_rt_export_cmd);
+ install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_rt_both_cmd);
+ install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_rd_cmd);
+ install_element (BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd);
+
install_element (BGP_VNC_L2_GROUP_NODE, &vnc_l2_group_lni_cmd);
install_element (BGP_VNC_L2_GROUP_NODE, &vnc_l2_group_labels_cmd);
install_element (BGP_VNC_L2_GROUP_NODE, &vnc_l2_group_no_labels_cmd);
@@ -3713,7 +4252,7 @@ bgp_rfapi_cfg_destroy (struct bgp *bgp, struct rfapi_cfg *h)
if (h == NULL)
return;
- bgp_rfapi_delete_named_nve_group (NULL, bgp, NULL);
+ bgp_rfapi_delete_named_nve_group (NULL, bgp, NULL, RFAPI_GROUP_CFG_MAX);
bgp_rfapi_delete_named_l2_group (NULL, bgp, NULL);
if (h->l2_groups != NULL)
list_delete (h->l2_groups);
@@ -3741,6 +4280,166 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
afi_t afi;
int type;
+ vty_out (vty, "!%s", VTY_NEWLINE);
+ for (ALL_LIST_ELEMENTS (hc->nve_groups_sequential, node, nnode, rfg))
+ if (rfg->type == RFAPI_GROUP_CFG_VRF)
+ {
+ ++write;
+ vty_out (vty, " vrf-policy %s%s", rfg->name, VTY_NEWLINE);
+ if (rfg->label <= MPLS_LABEL_MAX)
+ {
+ vty_out (vty, " label %u%s", rfg->label, VTY_NEWLINE);
+
+ }
+ if (CHECK_FLAG (rfg->flags, RFAPI_RFG_VPN_NH_SELF))
+ {
+ vty_out (vty, " nexthop self%s", VTY_NEWLINE);
+
+ }
+ else
+ {
+ if (rfg->vn_prefix.family)
+ {
+ char buf[BUFSIZ];
+ buf[0] = buf[BUFSIZ - 1] = 0;
+ inet_ntop(rfg->vn_prefix.family, &rfg->vn_prefix.u.prefix, buf, sizeof(buf));
+ if (!buf[0] || buf[BUFSIZ - 1])
+ {
+ //vty_out (vty, "nexthop self%s", VTY_NEWLINE);
+ }
+ else
+ {
+ vty_out (vty, " nexthop %s%s", buf, VTY_NEWLINE);
+ }
+ }
+ }
+
+ if (rfg->rd.prefixlen)
+ {
+ char buf[BUFSIZ];
+ buf[0] = buf[BUFSIZ - 1] = 0;
+
+ if (AF_UNIX == rfg->rd.family)
+ {
+
+ uint16_t value = 0;
+
+ value = ((rfg->rd.val[6] << 8) & 0x0ff00) |
+ (rfg->rd.val[7] & 0x0ff);
+
+ vty_out (vty, " rd auto:nh:%d%s", value, VTY_NEWLINE);
+
+ }
+ else
+ {
+
+ if (!prefix_rd2str (&rfg->rd, buf, BUFSIZ) ||
+ !buf[0] || buf[BUFSIZ - 1])
+ {
+
+ vty_out (vty, "!Error: Can't convert rd%s", VTY_NEWLINE);
+ }
+ else
+ {
+ vty_out (vty, " rd %s%s", buf, VTY_NEWLINE);
+ }
+ }
+ }
+
+ if (rfg->rt_import_list && rfg->rt_export_list &&
+ ecommunity_cmp (rfg->rt_import_list, rfg->rt_export_list))
+ {
+ char *b = ecommunity_ecom2str (rfg->rt_import_list,
+ ECOMMUNITY_FORMAT_ROUTE_MAP);
+ vty_out (vty, " rt both %s%s", b, VTY_NEWLINE);
+ XFREE (MTYPE_ECOMMUNITY_STR, b);
+ }
+ else
+ {
+ if (rfg->rt_import_list)
+ {
+ char *b = ecommunity_ecom2str (rfg->rt_import_list,
+ ECOMMUNITY_FORMAT_ROUTE_MAP);
+ vty_out (vty, " rt import %s%s", b, VTY_NEWLINE);
+ XFREE (MTYPE_ECOMMUNITY_STR, b);
+ }
+ if (rfg->rt_export_list)
+ {
+ char *b = ecommunity_ecom2str (rfg->rt_export_list,
+ ECOMMUNITY_FORMAT_ROUTE_MAP);
+ vty_out (vty, " rt export %s%s", b, VTY_NEWLINE);
+ XFREE (MTYPE_ECOMMUNITY_STR, b);
+ }
+ }
+
+ /*
+ * route filtering: prefix-lists and route-maps
+ */
+ for (afi = AFI_IP; afi < AFI_MAX; ++afi)
+ {
+
+ const char *afistr = (afi == AFI_IP) ? "ipv4" : "ipv6";
+
+ if (rfg->plist_export_bgp_name[afi])
+ {
+ vty_out (vty, " export bgp %s prefix-list %s%s",
+ afistr, rfg->plist_export_bgp_name[afi],
+ VTY_NEWLINE);
+ }
+ if (rfg->plist_export_zebra_name[afi])
+ {
+ vty_out (vty, " export zebra %s prefix-list %s%s",
+ afistr, rfg->plist_export_zebra_name[afi],
+ VTY_NEWLINE);
+ }
+ /*
+ * currently we only support redist plists for bgp-direct.
+ * If we later add plist support for redistributing other
+ * protocols, we'll need to loop over protocols here
+ */
+ if (rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi])
+ {
+ vty_out (vty, " redistribute bgp-direct %s prefix-list %s%s",
+ afistr,
+ rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi],
+ VTY_NEWLINE);
+ }
+ if (rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT_EXT][afi])
+ {
+ vty_out (vty,
+ " redistribute bgp-direct-to-nve-groups %s prefix-list %s%s",
+ afistr,
+ rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT_EXT]
+ [afi], VTY_NEWLINE);
+ }
+ }
+
+ if (rfg->routemap_export_bgp_name)
+ {
+ vty_out (vty, " export bgp route-map %s%s",
+ rfg->routemap_export_bgp_name, VTY_NEWLINE);
+ }
+ if (rfg->routemap_export_zebra_name)
+ {
+ vty_out (vty, " export zebra route-map %s%s",
+ rfg->routemap_export_zebra_name, VTY_NEWLINE);
+ }
+ if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT])
+ {
+ vty_out (vty, " redistribute bgp-direct route-map %s%s",
+ rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT],
+ VTY_NEWLINE);
+ }
+ if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT_EXT])
+ {
+ vty_out (vty,
+ " redistribute bgp-direct-to-nve-groups route-map %s%s",
+ rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT_EXT],
+ VTY_NEWLINE);
+ }
+ vty_out (vty, " exit-vrf-policy%s", VTY_NEWLINE);
+ vty_out (vty, "!%s", VTY_NEWLINE);
+ }
if (hc->flags & BGP_VNC_CONFIG_ADV_UN_METHOD_ENCAP)
{
vty_out (vty, " vnc advertise-un-method encap-safi%s", VTY_NEWLINE);
@@ -3902,6 +4601,7 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
}
for (ALL_LIST_ELEMENTS (hc->nve_groups_sequential, node, nnode, rfg))
+ if (rfg->type == RFAPI_GROUP_CFG_NVE)
{
++write;
vty_out (vty, " vnc nve-group %s%s", rfg->name, VTY_NEWLINE);
diff --git a/bgpd/rfapi/bgp_rfapi_cfg.h b/bgpd/rfapi/bgp_rfapi_cfg.h
index 897b4be764..8f93d69f6b 100644
--- a/bgpd/rfapi/bgp_rfapi_cfg.h
+++ b/bgpd/rfapi/bgp_rfapi_cfg.h
@@ -41,12 +41,21 @@ struct rfapi_l2_group_cfg
};
DECLARE_QOBJ_TYPE(rfapi_l2_group_cfg)
+typedef enum
+{
+ RFAPI_GROUP_CFG_NVE = 1,
+ RFAPI_GROUP_CFG_VRF,
+ RFAPI_GROUP_CFG_L2,
+ RFAPI_GROUP_CFG_MAX
+} rfapi_group_cfg_type_t;
+
struct rfapi_nve_group_cfg
{
struct route_node *vn_node; /* backref */
struct route_node *un_node; /* backref */
- char *name;
+ rfapi_group_cfg_type_t type; /* NVE|VPN */
+ char *name; /* unique by type! */
struct prefix vn_prefix;
struct prefix un_prefix;
@@ -54,8 +63,9 @@ struct rfapi_nve_group_cfg
uint8_t l2rd; /* 0 = VN addr LSB */
uint32_t response_lifetime;
uint32_t flags;
-#define RFAPI_RFG_RESPONSE_LIFETIME 0x1
+#define RFAPI_RFG_RESPONSE_LIFETIME 0x01 /* bits */
#define RFAPI_RFG_L2RD 0x02
+#define RFAPI_RFG_VPN_NH_SELF 0x04
struct ecommunity *rt_import_list;
struct ecommunity *rt_export_list;
struct rfapi_import_table *rfapi_import_table;
@@ -99,6 +109,9 @@ struct rfapi_nve_group_cfg
char *routemap_redist_name[ZEBRA_ROUTE_MAX];
struct route_map *routemap_redist[ZEBRA_ROUTE_MAX];
+ /* for VRF type groups */
+ uint32_t label;
+ struct rfapi_descriptor *rfd;
QOBJ_FIELDS
};
DECLARE_QOBJ_TYPE(rfapi_nve_group_cfg)
@@ -288,6 +301,12 @@ bgp_rfapi_cfg_match_group (
struct prefix *vn,
struct prefix *un);
+struct rfapi_nve_group_cfg *
+bgp_rfapi_cfg_match_byname (
+ struct bgp *bgp,
+ const char *name,
+ rfapi_group_cfg_type_t type); /* _MAX = any */
+
extern void
vnc_prefix_list_update (struct bgp *bgp);
diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c
index 61da18a308..cc6b555c9d 100644
--- a/bgpd/rfapi/rfapi.c
+++ b/bgpd/rfapi/rfapi.c
@@ -36,13 +36,13 @@
#include "bgpd/bgpd.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_attr.h"
-#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
#include "bgpd/rfapi/rfapi.h"
#include "bgpd/rfapi/rfapi_backend.h"
#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_advertise.h"
#include "bgpd/bgp_vnc_types.h"
@@ -335,6 +335,9 @@ is_valid_rfd (struct rfapi_descriptor *rfd)
if (!rfd || rfd->bgp == NULL)
return 0;
+ if (CHECK_FLAG(rfd->flags, RFAPI_HD_FLAG_IS_VRF)) /* assume VRF/internal are valid */
+ return 1;
+
if (rfapi_find_handle (rfd->bgp, &rfd->vn_addr, &rfd->un_addr, &hh))
return 0;
@@ -357,6 +360,9 @@ rfapi_check (void *handle)
if (!rfd || rfd->bgp == NULL)
return EINVAL;
+ if (CHECK_FLAG(rfd->flags, RFAPI_HD_FLAG_IS_VRF)) /* assume VRF/internal are valid */
+ return 0;
+
if ((rc = rfapi_find_handle (rfd->bgp, &rfd->vn_addr, &rfd->un_addr, &hh)))
return rc;
@@ -1347,7 +1353,6 @@ rfapi_rfp_set_cb_methods (void *rfp_start_val,
/***********************************************************************
* NVE Sessions
***********************************************************************/
-
/*
* Caller must supply an already-allocated rfd with the "caller"
* fields already set (vn_addr, un_addr, callback, cookie)
@@ -1474,6 +1479,57 @@ rfapi_open_inner (
return 0;
}
+/* moved from rfapi_register */
+int
+rfapi_init_and_open(
+ struct bgp *bgp,
+ struct rfapi_descriptor *rfd,
+ struct rfapi_nve_group_cfg *rfg)
+{
+ struct rfapi *h = bgp->rfapi;
+ char buf_vn[BUFSIZ];
+ char buf_un[BUFSIZ];
+ afi_t afi_vn, afi_un;
+ struct prefix pfx_un;
+ struct route_node *rn;
+
+
+ rfapi_time (&rfd->open_time);
+
+ if (rfg->type == RFAPI_GROUP_CFG_VRF)
+ SET_FLAG(rfd->flags, RFAPI_HD_FLAG_IS_VRF);
+
+ rfapiRfapiIpAddr2Str (&rfd->vn_addr, buf_vn, BUFSIZ);
+ rfapiRfapiIpAddr2Str (&rfd->un_addr, buf_un, BUFSIZ);
+
+ vnc_zlog_debug_verbose ("%s: new RFD with VN=%s UN=%s cookie=%p",
+ __func__, buf_vn, buf_un, rfd->cookie);
+
+ if (rfg->type != RFAPI_GROUP_CFG_VRF) /* unclear if needed for VRF */
+ {
+ listnode_add (&h->descriptors, rfd);
+ if (h->descriptors.count > h->stat.max_descriptors)
+ {
+ h->stat.max_descriptors = h->descriptors.count;
+ }
+
+ /*
+ * attach to UN radix tree
+ */
+ afi_vn = family2afi (rfd->vn_addr.addr_family);
+ afi_un = family2afi (rfd->un_addr.addr_family);
+ assert (afi_vn && afi_un);
+ assert (!rfapiRaddr2Qprefix (&rfd->un_addr, &pfx_un));
+
+ rn = route_node_get (&(h->un[afi_un]), &pfx_un);
+ assert (rn);
+ rfd->next = rn->info;
+ rn->info = rfd;
+ rfd->un_node = rn;
+ }
+ return rfapi_open_inner (rfd, bgp, h, rfg);
+}
+
struct rfapi_vn_option *
rfapiVnOptionsDup (struct rfapi_vn_option *orig)
{
@@ -1991,14 +2047,10 @@ rfapi_open (
struct prefix pfx_vn;
struct prefix pfx_un;
- struct route_node *rn;
int rc;
rfapi_handle hh = NULL;
int reusing_provisional = 0;
- afi_t afi_vn;
- afi_t afi_un;
-
{
char buf[2][INET_ADDRSTRLEN];
vnc_zlog_debug_verbose ("%s: VN=%s UN=%s", __func__,
@@ -2129,40 +2181,7 @@ rfapi_open (
if (!reusing_provisional)
{
- rfapi_time (&rfd->open_time);
-
- {
- char buf_vn[BUFSIZ];
- char buf_un[BUFSIZ];
-
- rfapiRfapiIpAddr2Str (vn, buf_vn, BUFSIZ);
- rfapiRfapiIpAddr2Str (un, buf_un, BUFSIZ);
-
- vnc_zlog_debug_verbose ("%s: new HD with VN=%s UN=%s cookie=%p",
- __func__, buf_vn, buf_un, userdata);
- }
-
- listnode_add (&h->descriptors, rfd);
- if (h->descriptors.count > h->stat.max_descriptors)
- {
- h->stat.max_descriptors = h->descriptors.count;
- }
-
- /*
- * attach to UN radix tree
- */
- afi_vn = family2afi (rfd->vn_addr.addr_family);
- afi_un = family2afi (rfd->un_addr.addr_family);
- assert (afi_vn && afi_un);
- assert (!rfapiRaddr2Qprefix (&rfd->un_addr, &pfx_un));
-
- rn = route_node_get (&(h->un[afi_un]), &pfx_un);
- assert (rn);
- rfd->next = rn->info;
- rn->info = rfd;
- rfd->un_node = rn;
-
- rc = rfapi_open_inner (rfd, bgp, h, rfg);
+ rc = rfapi_init_and_open(bgp, rfd, rfg);
/*
* This can fail only if the VN address is IPv6 and the group
* specified auto-assignment of RDs, which only works for v4,
@@ -2777,7 +2796,7 @@ rfapi_register (
NULL,
action == RFAPI_REGISTER_KILL);
- if (0 == rfapiApDelete (bgp, rfd, &p, pfx_mac, &adv_tunnel))
+ if (0 == rfapiApDelete (bgp, rfd, &p, pfx_mac, &prd, &adv_tunnel))
{
if (adv_tunnel)
rfapiTunnelRouteAnnounce (bgp, rfd, &rfd->max_prefix_lifetime);
diff --git a/bgpd/rfapi/rfapi_ap.c b/bgpd/rfapi/rfapi_ap.c
index 4b8eb9511b..5cc1dd7815 100644
--- a/bgpd/rfapi/rfapi_ap.c
+++ b/bgpd/rfapi/rfapi_ap.c
@@ -35,13 +35,13 @@
#include "bgpd/bgpd.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_attr.h"
-#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
#include "bgpd/rfapi/rfapi.h"
#include "bgpd/rfapi/rfapi_backend.h"
#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_advertise.h"
@@ -103,12 +103,11 @@ sl_adb_lifetime_cmp (void *adb1, void *adb2)
return 0;
}
-
void
rfapiApInit (struct rfapi_advertised_prefixes *ap)
{
- ap->ipN_by_prefix = skiplist_new (0, vnc_prefix_cmp, NULL);
- ap->ip0_by_ether = skiplist_new (0, vnc_prefix_cmp, NULL);
+ ap->ipN_by_prefix = skiplist_new (0, rfapi_rib_key_cmp, NULL);
+ ap->ip0_by_ether = skiplist_new (0, rfapi_rib_key_cmp, NULL);
ap->by_lifetime = skiplist_new (0, sl_adb_lifetime_cmp, NULL);
}
@@ -192,7 +191,7 @@ rfapiApReadvertiseAll (struct bgp *bgp, struct rfapi_descriptor *rfd)
* TBD this is not quite right. When pfx_ip is 0/32 or 0/128,
* we need to substitute the VN address as the prefix
*/
- add_vnc_route (rfd, bgp, SAFI_MPLS_VPN, &adb->prefix_ip, &prd, /* RD to use (0 for ENCAP) */
+ add_vnc_route (rfd, bgp, SAFI_MPLS_VPN, &adb->u.s.prefix_ip, &prd, /* RD to use (0 for ENCAP) */
&rfd->vn_addr, /* nexthop */
&local_pref, &adb->lifetime, NULL, NULL, /* struct rfapi_un_option */
NULL, /* struct rfapi_vn_option */
@@ -221,11 +220,11 @@ rfapiApWithdrawAll (struct bgp *bgp, struct rfapi_descriptor *rfd)
struct prefix pfx_vn_buf;
struct prefix *pfx_ip;
- if (!(RFAPI_0_PREFIX (&adb->prefix_ip) &&
- RFAPI_HOST_PREFIX (&adb->prefix_ip)))
+ if (!(RFAPI_0_PREFIX (&adb->u.s.prefix_ip) &&
+ RFAPI_HOST_PREFIX (&adb->u.s.prefix_ip)))
{
- pfx_ip = &adb->prefix_ip;
+ pfx_ip = &adb->u.s.prefix_ip;
}
else
@@ -247,7 +246,7 @@ rfapiApWithdrawAll (struct bgp *bgp, struct rfapi_descriptor *rfd)
}
}
- del_vnc_route (rfd, rfd->peer, bgp, SAFI_MPLS_VPN, pfx_ip ? pfx_ip : &pfx_vn_buf, &adb->prd, /* RD to use (0 for ENCAP) */
+ del_vnc_route (rfd, rfd->peer, bgp, SAFI_MPLS_VPN, pfx_ip ? pfx_ip : &pfx_vn_buf, &adb->u.s.prd, /* RD to use (0 for ENCAP) */
ZEBRA_ROUTE_BGP, BGP_ROUTE_RFP, NULL, 0);
}
}
@@ -404,19 +403,19 @@ rfapiApAdjustLifetimeStats (
{
void *cursor;
- struct prefix *prefix;
- struct rfapi_adb *adb;
+ struct rfapi_rib_key rk;
+ struct rfapi_adb *adb;
int rc;
vnc_zlog_debug_verbose ("%s: walking to find new min/max", __func__);
cursor = NULL;
for (rc = skiplist_next (rfd->advertised.ipN_by_prefix,
- (void **) &prefix, (void **) &adb,
+ (void **) &rk, (void **) &adb,
&cursor); !rc;
rc =
skiplist_next (rfd->advertised.ipN_by_prefix,
- (void **) &prefix, (void **) &adb, &cursor))
+ (void **) &rk, (void **) &adb, &cursor))
{
uint32_t lt = adb->lifetime;
@@ -428,10 +427,10 @@ rfapiApAdjustLifetimeStats (
}
cursor = NULL;
for (rc = skiplist_next (rfd->advertised.ip0_by_ether,
- (void **) &prefix, (void **) &adb,
+ (void **) &rk, (void **) &adb,
&cursor); !rc;
rc =
- skiplist_next (rfd->advertised.ip0_by_ether, (void **) &prefix,
+ skiplist_next (rfd->advertised.ip0_by_ether, (void **) &rk,
(void **) &adb, &cursor))
{
@@ -483,14 +482,15 @@ rfapiApAdd (
struct rfapi_adb *adb;
uint32_t old_lifetime = 0;
int use_ip0 = 0;
+ struct rfapi_rib_key rk;
+ rfapi_rib_key_init(pfx_ip, prd, pfx_eth, &rk);
if (RFAPI_0_PREFIX (pfx_ip) && RFAPI_HOST_PREFIX (pfx_ip))
{
use_ip0 = 1;
assert (pfx_eth);
-
rc =
- skiplist_search (rfd->advertised.ip0_by_ether, pfx_eth,
+ skiplist_search (rfd->advertised.ip0_by_ether, &rk,
(void **) &adb);
}
@@ -499,7 +499,7 @@ rfapiApAdd (
/* find prefix in advertised prefixes list */
rc =
- skiplist_search (rfd->advertised.ipN_by_prefix, pfx_ip,
+ skiplist_search (rfd->advertised.ipN_by_prefix, &rk,
(void **) &adb);
}
@@ -510,19 +510,17 @@ rfapiApAdd (
adb = XCALLOC (MTYPE_RFAPI_ADB, sizeof (struct rfapi_adb));
assert (adb);
adb->lifetime = lifetime;
- adb->prefix_ip = *pfx_ip;
- if (pfx_eth)
- adb->prefix_eth = *pfx_eth;
+ adb->u.key = rk;
if (use_ip0)
{
assert (pfx_eth);
- skiplist_insert (rfd->advertised.ip0_by_ether, &adb->prefix_eth,
+ skiplist_insert (rfd->advertised.ip0_by_ether, &adb->u.key,
adb);
}
else
{
- skiplist_insert (rfd->advertised.ipN_by_prefix, &adb->prefix_ip,
+ skiplist_insert (rfd->advertised.ipN_by_prefix, &adb->u.key,
adb);
}
@@ -537,19 +535,12 @@ rfapiApAdd (
adb->lifetime = lifetime;
assert (!skiplist_insert (rfd->advertised.by_lifetime, adb, adb));
}
-
- if (!use_ip0 && pfx_eth && prefix_cmp (&adb->prefix_eth, pfx_eth))
- {
- /* mac address changed */
- adb->prefix_eth = *pfx_eth;
- }
}
adb->cost = cost;
if (l2o)
adb->l2o = *l2o;
else
memset (&adb->l2o, 0, sizeof (struct rfapi_l2address_option));
- adb->prd = *prd;
if (rfapiApAdjustLifetimeStats
(rfd, (rc ? NULL : &old_lifetime), &lifetime))
@@ -568,16 +559,19 @@ rfapiApDelete (
struct rfapi_descriptor *rfd,
struct prefix *pfx_ip,
struct prefix *pfx_eth,
+ struct prefix_rd *prd,
int *advertise_tunnel) /* out */
{
int rc;
struct rfapi_adb *adb;
uint32_t old_lifetime;
int use_ip0 = 0;
+ struct rfapi_rib_key rk;
if (advertise_tunnel)
*advertise_tunnel = 0;
+ rfapi_rib_key_init(pfx_ip, prd, pfx_eth, &rk);
/* find prefix in advertised prefixes list */
if (RFAPI_0_PREFIX (pfx_ip) && RFAPI_HOST_PREFIX (pfx_ip))
{
@@ -585,7 +579,7 @@ rfapiApDelete (
assert (pfx_eth);
rc =
- skiplist_search (rfd->advertised.ip0_by_ether, pfx_eth,
+ skiplist_search (rfd->advertised.ip0_by_ether, &rk,
(void **) &adb);
}
@@ -594,7 +588,7 @@ rfapiApDelete (
/* find prefix in advertised prefixes list */
rc =
- skiplist_search (rfd->advertised.ipN_by_prefix, pfx_ip,
+ skiplist_search (rfd->advertised.ipN_by_prefix, &rk,
(void **) &adb);
}
@@ -607,11 +601,11 @@ rfapiApDelete (
if (use_ip0)
{
- rc = skiplist_delete (rfd->advertised.ip0_by_ether, pfx_eth, NULL);
+ rc = skiplist_delete (rfd->advertised.ip0_by_ether, &rk, NULL);
}
else
{
- rc = skiplist_delete (rfd->advertised.ipN_by_prefix, pfx_ip, NULL);
+ rc = skiplist_delete (rfd->advertised.ipN_by_prefix, &rk, NULL);
}
assert (!rc);
diff --git a/bgpd/rfapi/rfapi_ap.h b/bgpd/rfapi/rfapi_ap.h
index f2805f49cb..8a59f05274 100644
--- a/bgpd/rfapi/rfapi_ap.h
+++ b/bgpd/rfapi/rfapi_ap.h
@@ -93,6 +93,7 @@ rfapiApDelete (
struct rfapi_descriptor *rfd,
struct prefix *pfx_ip,
struct prefix *pfx_eth,
+ struct prefix_rd *prd,
int *advertise_tunnel); /* out */
diff --git a/bgpd/rfapi/rfapi_backend.h b/bgpd/rfapi/rfapi_backend.h
index 788ec73751..9e5b0dc5cb 100644
--- a/bgpd/rfapi/rfapi_backend.h
+++ b/bgpd/rfapi/rfapi_backend.h
@@ -36,15 +36,6 @@ extern void rfapi_delete (struct bgp *);
struct rfapi *bgp_rfapi_new (struct bgp *bgp);
void bgp_rfapi_destroy (struct bgp *bgp, struct rfapi *h);
-struct rfapi_import_table *rfapiImportTableRefAdd (struct bgp *bgp,
- struct ecommunity
- *rt_import_list);
-
-void
-rfapiImportTableRefDelByIt (struct bgp *bgp,
- struct rfapi_import_table *it_target);
-
-
extern void
rfapiProcessUpdate (struct peer *peer,
void *rfd,
diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c
index e6fdb7180e..1cd12ca0d2 100644
--- a/bgpd/rfapi/rfapi_import.c
+++ b/bgpd/rfapi/rfapi_import.c
@@ -4644,7 +4644,8 @@ bgp_rfapi_destroy (struct bgp *bgp, struct rfapi *h)
}
struct rfapi_import_table *
-rfapiImportTableRefAdd (struct bgp *bgp, struct ecommunity *rt_import_list)
+rfapiImportTableRefAdd (struct bgp *bgp, struct ecommunity *rt_import_list,
+ struct rfapi_nve_group_cfg *rfg)
{
struct rfapi *h;
struct rfapi_import_table *it;
@@ -4670,6 +4671,7 @@ rfapiImportTableRefAdd (struct bgp *bgp, struct ecommunity *rt_import_list)
h->imports = it;
it->rt_import_list = ecommunity_dup (rt_import_list);
+ it->rfg = rfg;
it->monitor_exterior_orphans =
skiplist_new (0, NULL, (void (*)(void *)) prefix_free);
@@ -4943,6 +4945,7 @@ rfapiDeleteRemotePrefixesIt (
* un if set, tunnel must match this prefix
* vn if set, nexthop prefix must match this prefix
* p if set, prefix must match this prefix
+ * it if set, only look in this import table
*
* output
* pARcount number of active routes deleted
@@ -4958,6 +4961,7 @@ rfapiDeleteRemotePrefixes (
struct prefix *un,
struct prefix *vn,
struct prefix *p,
+ struct rfapi_import_table *arg_it,
int delete_active,
int delete_holddown,
uint32_t *pARcount,
@@ -4995,7 +4999,11 @@ rfapiDeleteRemotePrefixes (
* for the afi/safi combination
*/
- for (it = h->imports; it; it = it->next)
+ if (arg_it)
+ it = arg_it;
+ else
+ it = h->imports;
+ for (; it; )
{
vnc_zlog_debug_verbose
@@ -5016,6 +5024,11 @@ rfapiDeleteRemotePrefixes (
&deleted_holddown_nve_count,
uniq_active_nves,
uniq_holddown_nves);
+
+ if (arg_it)
+ it = NULL;
+ else
+ it = it->next;
}
/*
diff --git a/bgpd/rfapi/rfapi_import.h b/bgpd/rfapi/rfapi_import.h
index 3cf55462a1..3ba76539dd 100644
--- a/bgpd/rfapi/rfapi_import.h
+++ b/bgpd/rfapi/rfapi_import.h
@@ -38,6 +38,7 @@
struct rfapi_import_table
{
struct rfapi_import_table *next;
+ struct rfapi_nve_group_cfg *rfg;
struct ecommunity *rt_import_list; /* copied from nve grp */
int refcount; /* nve grps and nves */
uint32_t l2_logical_net_id; /* L2 only: EVPN Eth Seg Id */
@@ -90,6 +91,11 @@ rfapiShowImportTable (
struct route_table *rt,
int isvpn);
+extern struct rfapi_import_table *
+rfapiImportTableRefAdd (
+ struct bgp *bgp,
+ struct ecommunity *rt_import_list,
+ struct rfapi_nve_group_cfg *rfg);
extern void
rfapiImportTableRefDelByIt (
@@ -223,6 +229,7 @@ extern int rfapiEcommunityGetEthernetTag (
* un if set, tunnel must match this prefix
* vn if set, nexthop prefix must match this prefix
* p if set, prefix must match this prefix
+ * it if set, only look in this import table
*
* output
* pARcount number of active routes deleted
@@ -238,6 +245,7 @@ rfapiDeleteRemotePrefixes (
struct prefix *un,
struct prefix *vn,
struct prefix *p,
+ struct rfapi_import_table *it,
int delete_active,
int delete_holddown,
uint32_t *pARcount, /* active routes */
diff --git a/bgpd/rfapi/rfapi_private.h b/bgpd/rfapi/rfapi_private.h
index 33390c4f55..ed83ef1e1f 100644
--- a/bgpd/rfapi/rfapi_private.h
+++ b/bgpd/rfapi/rfapi_private.h
@@ -35,21 +35,6 @@
#include "rfapi.h"
/*
- * RFAPI Advertisement Data Block
- *
- * Holds NVE prefix advertisement information
- */
-struct rfapi_adb
-{
- struct prefix prefix_ip;
- struct prefix prefix_eth; /* now redundant with l2o */
- struct prefix_rd prd;
- uint32_t lifetime;
- uint8_t cost;
- struct rfapi_l2address_option l2o;
-};
-
-/*
* Lists of rfapi_adb. Each rfapi_adb is referenced twice:
*
* 1. each is referenced in by_lifetime
@@ -62,7 +47,6 @@ struct rfapi_advertised_prefixes
struct skiplist *by_lifetime; /* all */
};
-
struct rfapi_descriptor
{
struct route_node *un_node; /* backref to un table */
@@ -151,6 +135,7 @@ struct rfapi_descriptor
#define RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_ETHER 0x00000004
#define RFAPI_HD_FLAG_PROVISIONAL 0x00000008
#define RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY 0x00000010
+#define RFAPI_HD_FLAG_IS_VRF 0x00000012
};
#define RFAPI_QUEUED_FLAG(afi) ( \
@@ -378,9 +363,6 @@ rfp_cost_to_localpref (uint8_t cost);
extern int
rfapi_set_autord_from_vn (struct prefix_rd *rd, struct rfapi_ip_addr *vn);
-extern void
-rfapiAdbFree (struct rfapi_adb *adb);
-
extern struct rfapi_nexthop *
rfapi_nexthop_new (struct rfapi_nexthop *copyme);
@@ -452,4 +434,17 @@ DECLARE_MTYPE(RFAPI_L2ADDR_OPT)
DECLARE_MTYPE(RFAPI_AP)
DECLARE_MTYPE(RFAPI_MONITOR_ETH)
+
+/*
+ * Caller must supply an already-allocated rfd with the "caller"
+ * fields already set (vn_addr, un_addr, callback, cookie)
+ * The advertised_prefixes[] array elements should be NULL to
+ * have this function set them to newly-allocated radix trees.
+ */
+extern int
+rfapi_init_and_open(
+ struct bgp *bgp,
+ struct rfapi_descriptor *rfd,
+ struct rfapi_nve_group_cfg *rfg);
+
#endif /* _QUAGGA_BGP_RFAPI_PRIVATE_H */
diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c
index 6aae35e635..8e5d47415f 100644
--- a/bgpd/rfapi/rfapi_rib.c
+++ b/bgpd/rfapi/rfapi_rib.c
@@ -405,10 +405,26 @@ rfapiRibStartTimer (
assert (ri->timer);
}
+extern void
+rfapi_rib_key_init (struct prefix *prefix, /* may be NULL */
+ struct prefix_rd *rd, /* may be NULL */
+ struct prefix *aux, /* may be NULL */
+ struct rfapi_rib_key *rk)
+
+{
+ memset((void *)rk, 0, sizeof(struct rfapi_rib_key));
+ if (prefix)
+ rk->vn = *prefix;
+ if (rd)
+ rk->rd = *rd;
+ if (aux)
+ rk->aux_prefix = *aux;
+}
+
/*
* Compares two <struct rfapi_rib_key>s
*/
-static int
+int
rfapi_rib_key_cmp (void *k1, void *k2)
{
struct rfapi_rib_key *a = (struct rfapi_rib_key *) k1;
@@ -498,9 +514,13 @@ rfapi_info_cmp (struct rfapi_info *a, struct rfapi_info *b)
void
rfapiRibClear (struct rfapi_descriptor *rfd)
{
- struct bgp *bgp = bgp_get_default ();
+ struct bgp *bgp;
afi_t afi;
+ if (rfd->bgp)
+ bgp = rfd->bgp;
+ else
+ bgp = bgp_get_default ();
#if DEBUG_L2_EXTRA
vnc_zlog_debug_verbose ("%s: rfd=%p", __func__, rfd);
#endif
diff --git a/bgpd/rfapi/rfapi_rib.h b/bgpd/rfapi/rfapi_rib.h
index 2a111946f7..74331a28d0 100644
--- a/bgpd/rfapi/rfapi_rib.h
+++ b/bgpd/rfapi/rfapi_rib.h
@@ -45,6 +45,27 @@ struct rfapi_rib_key
*/
struct prefix aux_prefix;
};
+#include "rfapi.h"
+
+/*
+ * RFAPI Advertisement Data Block
+ *
+ * Holds NVE prefix advertisement information
+ */
+struct rfapi_adb
+{
+ union {
+ struct {
+ struct prefix prefix_ip;
+ struct prefix_rd prd;
+ struct prefix prefix_eth;
+ } s; /* mainly for legacy use */
+ struct rfapi_rib_key key;
+ } u;
+ uint32_t lifetime;
+ uint8_t cost;
+ struct rfapi_l2address_option l2o;
+};
struct rfapi_info
{
@@ -151,4 +172,16 @@ rfapiRibCheckCounts (
#define RFAPI_RIB_CHECK_COUNTS(checkstats, offset)
#endif
+extern void
+rfapi_rib_key_init (struct prefix *prefix, /* may be NULL */
+ struct prefix_rd *rd, /* may be NULL */
+ struct prefix *aux, /* may be NULL */
+ struct rfapi_rib_key *rk);
+
+extern int
+rfapi_rib_key_cmp (void *k1, void *k2);
+
+extern void
+rfapiAdbFree (struct rfapi_adb *adb);
+
#endif /* QUAGGA_HGP_RFAPI_RIB_H */
diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c
index 1e7941a41d..1e92cbcbf1 100644
--- a/bgpd/rfapi/rfapi_vty.c
+++ b/bgpd/rfapi/rfapi_vty.c
@@ -1447,17 +1447,24 @@ rfapiShowRemoteRegistrationsIt (
if (pLni)
{
- fp (out, "%s[%s] L2VPN Network 0x%x (%u) RT={%s}%s",
- HVTY_NEWLINE, type, *pLni, (*pLni & 0xfff), s,
- HVTY_NEWLINE);
+ fp (out, "%s[%s] L2VPN Network 0x%x (%u) RT={%s}",
+ HVTY_NEWLINE, type, *pLni, (*pLni & 0xfff), s);
}
else
{
- fp (out, "%s[%s] Prefix RT={%s}%s",
- HVTY_NEWLINE, type, s, HVTY_NEWLINE);
+ fp (out, "%s[%s] Prefix RT={%s}",
+ HVTY_NEWLINE, type, s);
}
XFREE (MTYPE_ECOMMUNITY_STR, s);
+ if (it->rfg && it->rfg->name)
+ {
+ fp (out, " %s \"%s\"",
+ (it->rfg->type == RFAPI_GROUP_CFG_VRF ?
+ "VRF" : "NVE group"),
+ it->rfg->name);
+ }
+ fp (out, "%s", HVTY_NEWLINE);
if (show_expiring)
{
#if RFAPI_REGISTRATIONS_REPORT_AGE
@@ -1847,14 +1854,14 @@ rfapiPrintDescriptor (struct vty *vty, struct rfapi_descriptor *rfd)
{
/* group like family prefixes together in output */
- if (family != adb->prefix_ip.family)
+ if (family != adb->u.s.prefix_ip.family)
continue;
- prefix2str (&adb->prefix_ip, buf, BUFSIZ);
+ prefix2str (&adb->u.s.prefix_ip, buf, BUFSIZ);
buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
vty_out (vty, " Adv Pfx: %s%s", buf, HVTY_NEWLINE);
- rfapiPrintAdvertisedInfo (vty, rfd, SAFI_MPLS_VPN, &adb->prefix_ip);
+ rfapiPrintAdvertisedInfo (vty, rfd, SAFI_MPLS_VPN, &adb->u.s.prefix_ip);
}
}
for (rc =
@@ -1865,14 +1872,14 @@ rfapiPrintDescriptor (struct vty *vty, struct rfapi_descriptor *rfd)
&cursor))
{
- prefix2str (&adb->prefix_eth, buf, BUFSIZ);
+ prefix2str (&adb->u.s.prefix_eth, buf, BUFSIZ);
buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
vty_out (vty, " Adv Pfx: %s%s", buf, HVTY_NEWLINE);
/* TBD update the following function to print ethernet info */
/* Also need to pass/use rd */
- rfapiPrintAdvertisedInfo (vty, rfd, SAFI_MPLS_VPN, &adb->prefix_ip);
+ rfapiPrintAdvertisedInfo (vty, rfd, SAFI_MPLS_VPN, &adb->u.s.prefix_ip);
}
vty_out (vty, "%s", HVTY_NEWLINE);
}
@@ -3005,9 +3012,12 @@ struct rfapi_local_reg_delete_arg
/*
* match parameters
*/
+ struct bgp *bgp;
struct rfapi_ip_addr un_address; /* AF==0: wildcard */
struct rfapi_ip_addr vn_address; /* AF==0: wildcard */
struct prefix prefix; /* AF==0: wildcard */
+ struct prefix_rd rd; /* plen!=64: wildcard */
+ struct rfapi_nve_group_cfg *rfg; /* NULL: wildcard */
struct rfapi_l2address_option_match l2o;
@@ -3107,22 +3117,26 @@ nve_addr_cmp (void *k1, void *k2)
static int
parse_deleter_args (
- struct vty *vty,
- struct cmd_token *carg_prefix,
- struct cmd_token *carg_vn,
- struct cmd_token *carg_un,
- struct cmd_token *carg_l2addr,
- struct cmd_token *carg_vni,
- struct rfapi_local_reg_delete_arg *rcdarg)
+ struct vty *vty,
+ struct bgp *bgp,
+ const char *arg_prefix,
+ const char *arg_vn,
+ const char *arg_un,
+ const char *arg_l2addr,
+ const char *arg_vni,
+ const char *arg_rd,
+ struct rfapi_nve_group_cfg *arg_rfg,
+ struct rfapi_local_reg_delete_arg *rcdarg)
{
- const char *arg_prefix = carg_prefix ? carg_prefix->arg : NULL;
- const char *arg_vn = carg_vn ? carg_vn->arg : NULL;
- const char *arg_un = carg_un ? carg_un->arg : NULL;
- const char *arg_l2addr = carg_l2addr ? carg_l2addr->arg : NULL;
- const char *arg_vni = carg_vni ? carg_vni->arg : NULL;
int rc = CMD_WARNING;
- memset (rcdarg, 0, sizeof (struct rfapi_local_reg_delete_arg));
+ memset (rcdarg, 0, sizeof (struct rfapi_local_reg_delete_arg));
+
+ rcdarg->vty = vty;
+ if (bgp == NULL)
+ bgp = bgp_get_default();
+ rcdarg->bgp = bgp;
+ rcdarg->rfg = arg_rfg; /* may be NULL */
if (arg_vn && strcmp (arg_vn, "*"))
{
@@ -3168,7 +3182,41 @@ parse_deleter_args (
rcdarg->l2o.flags |= RFAPI_L2O_LNI;
}
}
- return 0;
+ if (arg_rd)
+ {
+ if (!str2prefix_rd (arg_rd, &rcdarg->rd))
+ {
+ vty_out (vty, "Malformed RD \"%s\"%s",
+ arg_rd, VTY_NEWLINE);
+ return rc;
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+static int
+parse_deleter_tokens (
+ struct vty *vty,
+ struct bgp *bgp,
+ struct cmd_token *carg_prefix,
+ struct cmd_token *carg_vn,
+ struct cmd_token *carg_un,
+ struct cmd_token *carg_l2addr,
+ struct cmd_token *carg_vni,
+ struct cmd_token *carg_rd,
+ struct rfapi_nve_group_cfg *arg_rfg,
+ struct rfapi_local_reg_delete_arg *rcdarg)
+{
+ const char *arg_prefix = carg_prefix ? carg_prefix->arg : NULL;
+ const char *arg_vn = carg_vn ? carg_vn->arg : NULL;
+ const char *arg_un = carg_un ? carg_un->arg : NULL;
+ const char *arg_l2addr = carg_l2addr ? carg_l2addr->arg : NULL;
+ const char *arg_vni = carg_vni ? carg_vni->arg : NULL;
+ const char *arg_rd = carg_rd ? carg_rd->arg : NULL;
+ return parse_deleter_args (vty, bgp,arg_prefix, arg_vn, arg_un,
+ arg_l2addr, arg_vni, arg_rd,
+ arg_rfg, rcdarg);
}
static void
@@ -3272,51 +3320,37 @@ clear_vnc_responses (struct rfapi_local_reg_delete_arg *cda)
* TBD need to count deleted prefixes and nves?
*
* ENXIO BGP or VNC not configured
- */
+ */
static int
-rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
+rfapiDeleteLocalPrefixesByRFD (struct rfapi_local_reg_delete_arg *cda,
+ struct rfapi_descriptor *rfd)
{
- struct rfapi_ip_addr *pUn; /* NULL = wildcard */
- struct rfapi_ip_addr *pVn; /* NULL = wildcard */
- struct prefix *pPrefix; /* NULL = wildcard */
+ struct rfapi_ip_addr *pUn; /* NULL = wildcard */
+ struct rfapi_ip_addr *pVn; /* NULL = wildcard */
+ struct prefix *pPrefix; /* NULL = wildcard */
+ struct prefix_rd *pPrd; /* NULL = wildcard */
- struct rfapi *h;
- struct listnode *node;
- struct rfapi_descriptor *rfd;
struct rfapi_ip_prefix rprefix;
- struct bgp *bgp_default = bgp_get_default ();
struct rfapi_next_hop_entry *head = NULL;
struct rfapi_next_hop_entry *tail = NULL;
- struct rfapi_cfg *rfapi_cfg;
#if DEBUG_L2_EXTRA
- vnc_zlog_debug_verbose ("%s: entry", __func__);
+ vnc_zlog_debug_verbose ("%s: entry", __func__);
#endif
- if (!bgp_default)
- return ENXIO;
-
- pUn = (cda->un_address.addr_family ? &cda->un_address : NULL);
- pVn = (cda->vn_address.addr_family ? &cda->vn_address : NULL);
- pPrefix = (cda->prefix.family ? &cda->prefix : NULL);
-
- h = bgp_default->rfapi;
- rfapi_cfg = bgp_default->rfapi_cfg;
-
- if (!h || !rfapi_cfg)
- return ENXIO;
+ pUn = (cda->un_address.addr_family ? &cda->un_address : NULL);
+ pVn = (cda->vn_address.addr_family ? &cda->vn_address : NULL);
+ pPrefix = (cda->prefix.family ? &cda->prefix : NULL);
+ pPrd = (cda->rd.prefixlen == 64 ? &cda->rd : NULL);
if (pPrefix)
{
rfapiQprefix2Rprefix (pPrefix, &rprefix);
}
-#if DEBUG_L2_EXTRA
- vnc_zlog_debug_verbose ("%s: starting descriptor loop", __func__);
-#endif
-
- for (ALL_LIST_ELEMENTS_RO (&h->descriptors, node, rfd))
+ do /* to preserve old code structure */
{
+ struct rfapi *h=cda->bgp->rfapi;;
struct rfapi_adb *adb;
int rc;
int deleted_from_this_nve;
@@ -3376,7 +3410,7 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
if (pPrefix)
{
- if (!prefix_same (pPrefix, &adb->prefix_ip))
+ if (!prefix_same (pPrefix, &adb->u.s.prefix_ip))
{
#if DEBUG_L2_EXTRA
vnc_zlog_debug_verbose ("%s: adb=%p, prefix doesn't match, skipping",
@@ -3385,11 +3419,22 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
continue;
}
}
+ if (pPrd)
+ {
+ if (memcmp(pPrd->val, adb->u.s.prd.val, 8) != 0)
+ {
+#if DEBUG_L2_EXTRA
+ vnc_zlog_debug_verbose ("%s: adb=%p, RD doesn't match, skipping",
+ __func__, adb);
+#endif
+ continue;
+ }
+ }
if (CHECK_FLAG (cda->l2o.flags, RFAPI_L2O_MACADDR))
{
if (memcmp
(cda->l2o.o.macaddr.octet,
- adb->prefix_eth.u.prefix_eth.octet, ETHER_ADDR_LEN))
+ adb->u.s.prefix_eth.u.prefix_eth.octet, ETHER_ADDR_LEN))
{
#if DEBUG_L2_EXTRA
vnc_zlog_debug_verbose ("%s: adb=%p, macaddr doesn't match, skipping",
@@ -3423,48 +3468,43 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
for (ALL_LIST_ELEMENTS_RO (adb_delete_list, node, adb))
{
-
- struct rfapi_vn_option vn1;
- struct rfapi_vn_option vn2;
- struct rfapi_vn_option *pVn;
int this_advertisement_prefix_count;
+ struct rfapi_vn_option optary[3];
+ struct rfapi_vn_option *opt = NULL;
+ int cur_opt = 0;
this_advertisement_prefix_count = 1;
- rfapiQprefix2Rprefix (&adb->prefix_ip, &rp);
+ rfapiQprefix2Rprefix (&adb->u.s.prefix_ip, &rp);
+
+ memset (optary, 0, sizeof (optary));
/* if mac addr present in advert, make l2o vn option */
- if (adb->prefix_eth.family == AF_ETHERNET)
+ if (adb->u.s.prefix_eth.family == AF_ETHERNET)
{
-
- memset (&vn1, 0, sizeof (vn1));
- memset (&vn2, 0, sizeof (vn2));
-
- vn1.type = RFAPI_VN_OPTION_TYPE_L2ADDR;
- vn1.v.l2addr.macaddr = adb->prefix_eth.u.prefix_eth;
-
- /*
- * use saved RD value instead of trying to invert
- * complex L2-style RD computation in rfapi_register()
- */
- vn2.type = RFAPI_VN_OPTION_TYPE_INTERNAL_RD;
- vn2.v.internal_rd = adb->prd;
-
- vn1.next = &vn2;
-
- pVn = &vn1;
+ if (opt != NULL)
+ opt->next = &optary[cur_opt];
+ opt = &optary[cur_opt++];
+ opt->type = RFAPI_VN_OPTION_TYPE_L2ADDR;
+ opt->v.l2addr.macaddr = adb->u.s.prefix_eth.u.prefix_eth;
++this_advertisement_prefix_count;
}
- else
- {
- pVn = NULL;
- }
+ /*
+ * use saved RD value instead of trying to invert
+ * complex RD computation in rfapi_register()
+ */
+ if (opt != NULL)
+ opt->next = &optary[cur_opt];
+ opt = &optary[cur_opt++];
+ opt->type = RFAPI_VN_OPTION_TYPE_INTERNAL_RD;
+ opt->v.internal_rd = adb->u.s.prd;
#if DEBUG_L2_EXTRA
vnc_zlog_debug_verbose ("%s: ipN killing reg from adb %p ", __func__, adb);
#endif
- rc = rfapi_register (rfd, &rp, 0, NULL, pVn, RFAPI_REGISTER_KILL);
+ rc = rfapi_register (rfd, &rp, 0, NULL,
+ (cur_opt ? optary : NULL), RFAPI_REGISTER_KILL);
if (!rc)
{
cda->pfx_count += this_advertisement_prefix_count;
@@ -3500,7 +3540,7 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
if (CHECK_FLAG (cda->l2o.flags, RFAPI_L2O_MACADDR))
{
if (memcmp (cda->l2o.o.macaddr.octet,
- adb->prefix_eth.u.prefix_eth.octet,
+ adb->u.s.prefix_eth.u.prefix_eth.octet,
ETHER_ADDR_LEN))
{
@@ -3527,7 +3567,7 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
struct rfapi_vn_option vn;
- rfapiQprefix2Rprefix (&adb->prefix_ip, &rp);
+ rfapiQprefix2Rprefix (&adb->u.s.prefix_ip, &rp);
memset (&vn, 0, sizeof (vn));
vn.type = RFAPI_VN_OPTION_TYPE_L2ADDR;
@@ -3590,11 +3630,44 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
skiplist_insert (cda->nves, hap, hap);
}
}
- }
+ } while (0); /* to preserve old code structure */
return 0;
}
+static int
+rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
+{
+ int rc = 0;
+
+ if (cda->rfg)
+ {
+ if (cda->rfg->rfd) /* if not open, nothing to delete */
+ rc = rfapiDeleteLocalPrefixesByRFD (cda, cda->rfg->rfd);
+ }
+ else
+ {
+ struct bgp *bgp = cda->bgp;
+ struct rfapi *h;
+ struct rfapi_cfg *rfapi_cfg;
+
+ struct listnode *node;
+ struct rfapi_descriptor *rfd;
+ if (!bgp)
+ return ENXIO;
+ h = bgp->rfapi;
+ rfapi_cfg = bgp->rfapi_cfg;
+ if (!h || !rfapi_cfg)
+ return ENXIO;
+ vnc_zlog_debug_verbose ("%s: starting descriptor loop", __func__);
+ for (ALL_LIST_ELEMENTS_RO (&h->descriptors, node, rfd))
+ {
+ rc = rfapiDeleteLocalPrefixesByRFD (cda, rfd);
+ }
+ }
+ return rc;
+}
+
/*
* clear_vnc_prefix
*
@@ -3610,6 +3683,8 @@ clear_vnc_prefix (struct rfapi_local_reg_delete_arg *cda)
struct prefix *pVN = NULL;
struct prefix *pPrefix = NULL;
+ struct rfapi_import_table *it = NULL;
+
/*
* Delete matching remote prefixes in holddown
*/
@@ -3627,7 +3702,11 @@ clear_vnc_prefix (struct rfapi_local_reg_delete_arg *cda)
{
pPrefix = &cda->prefix;
}
- rfapiDeleteRemotePrefixes (pUN, pVN, pPrefix,
+ if (cda->rfg)
+ {
+ it = cda->rfg->rfapi_import_table;
+ }
+ rfapiDeleteRemotePrefixes (pUN, pVN, pPrefix, it,
0, 1, &cda->remote_active_pfx_count,
&cda->remote_active_nve_count,
&cda->remote_holddown_pfx_count,
@@ -3712,7 +3791,7 @@ DEFUN (clear_vnc_nve_all,
struct rfapi_local_reg_delete_arg cda;
int rc;
- if ((rc = parse_deleter_args (vty, NULL, NULL, NULL, NULL, NULL, &cda)))
+ if ((rc = parse_deleter_args (vty, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &cda)))
return rc;
cda.vty = vty;
@@ -3745,7 +3824,7 @@ DEFUN (clear_vnc_nve_vn_un,
int rc;
if ((rc =
- parse_deleter_args (vty, NULL, argv[4], argv[6], NULL, NULL, &cda)))
+ parse_deleter_tokens (vty, NULL, NULL, argv[4], argv[6], NULL, NULL, NULL, NULL, &cda)))
return rc;
cda.vty = vty;
@@ -3778,7 +3857,7 @@ DEFUN (clear_vnc_nve_un_vn,
int rc;
if ((rc =
- parse_deleter_args (vty, NULL, argv[6], argv[4], NULL, NULL, &cda)))
+ parse_deleter_tokens (vty, NULL, NULL, argv[6], argv[4], NULL, NULL, NULL, NULL, &cda)))
return rc;
cda.vty = vty;
@@ -3806,7 +3885,7 @@ DEFUN (clear_vnc_nve_vn,
struct rfapi_local_reg_delete_arg cda;
int rc;
- if ((rc = parse_deleter_args (vty, NULL, argv[4], NULL, NULL, NULL, &cda)))
+ if ((rc = parse_deleter_tokens (vty, NULL, NULL, argv[4], NULL, NULL, NULL, NULL, NULL, &cda)))
return rc;
cda.vty = vty;
@@ -3833,7 +3912,7 @@ DEFUN (clear_vnc_nve_un,
struct rfapi_local_reg_delete_arg cda;
int rc;
- if ((rc = parse_deleter_args (vty, NULL, NULL, argv[6], NULL, NULL, &cda)))
+ if ((rc = parse_deleter_tokens (vty, NULL, NULL, NULL, argv[6], NULL, NULL, NULL, NULL, &cda)))
return rc;
cda.vty = vty;
@@ -3876,7 +3955,7 @@ DEFUN (clear_vnc_prefix_vn_un,
int rc;
if ((rc =
- parse_deleter_args (vty, argv[3], argv[5], argv[7], NULL, NULL, &cda)))
+ parse_deleter_tokens (vty, NULL, argv[3], argv[5], argv[7], NULL, NULL, NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -3906,7 +3985,7 @@ DEFUN (clear_vnc_prefix_un_vn,
int rc;
if ((rc =
- parse_deleter_args (vty, argv[3], argv[7], argv[5], NULL, NULL, &cda)))
+ parse_deleter_tokens (vty, NULL, argv[3], argv[7], argv[5], NULL, NULL, NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -3932,7 +4011,7 @@ DEFUN (clear_vnc_prefix_un,
int rc;
if ((rc =
- parse_deleter_args (vty, argv[3], NULL, argv[5], NULL, NULL, &cda)))
+ parse_deleter_tokens (vty, NULL, argv[3], NULL, argv[5], NULL, NULL, NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -3958,7 +4037,7 @@ DEFUN (clear_vnc_prefix_vn,
int rc;
if ((rc =
- parse_deleter_args (vty, argv[3], argv[5], NULL, NULL, NULL, &cda)))
+ parse_deleter_tokens (vty, NULL, argv[3], argv[5], NULL, NULL, NULL, NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -3980,7 +4059,7 @@ DEFUN (clear_vnc_prefix_all,
struct rfapi_local_reg_delete_arg cda;
int rc;
- if ((rc = parse_deleter_args (vty, argv[3], NULL, NULL, NULL, NULL, &cda)))
+ if ((rc = parse_deleter_tokens (vty, NULL, argv[3], NULL, NULL, NULL, NULL, NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4022,8 +4101,8 @@ DEFUN (clear_vnc_mac_vn_un,
/* pfx vn un L2 VNI */
if ((rc =
- parse_deleter_args (vty, NULL, argv[7], argv[9], argv[3], argv[5],
- &cda)))
+ parse_deleter_tokens (vty, NULL, NULL, argv[7], argv[9], argv[3], argv[5],
+ NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4056,8 +4135,8 @@ DEFUN (clear_vnc_mac_un_vn,
/* pfx vn un L2 VNI */
if ((rc =
- parse_deleter_args (vty, NULL, argv[9], argv[7], argv[3], argv[5],
- &cda)))
+ parse_deleter_tokens (vty, NULL, NULL, argv[9], argv[7], argv[3], argv[5],
+ NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4086,7 +4165,7 @@ DEFUN (clear_vnc_mac_un,
/* pfx vn un L2 VNI */
if ((rc =
- parse_deleter_args (vty, NULL, NULL, argv[7], argv[3], argv[5], &cda)))
+ parse_deleter_tokens (vty, NULL, NULL, NULL, argv[7], argv[3], argv[5], NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4115,7 +4194,7 @@ DEFUN (clear_vnc_mac_vn,
/* pfx vn un L2 VNI */
if ((rc =
- parse_deleter_args (vty, NULL, argv[7], NULL, argv[3], argv[5], &cda)))
+ parse_deleter_tokens (vty, NULL, NULL, argv[7], NULL, argv[3], argv[5], NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4141,7 +4220,7 @@ DEFUN (clear_vnc_mac_all,
/* pfx vn un L2 VNI */
if ((rc =
- parse_deleter_args (vty, NULL, NULL, NULL, argv[3], argv[5], &cda)))
+ parse_deleter_tokens (vty, NULL, NULL, NULL, NULL, argv[3], argv[5], NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4182,8 +4261,8 @@ DEFUN (clear_vnc_mac_vn_un_prefix,
/* pfx vn un L2 VNI */
if ((rc =
- parse_deleter_args (vty, argv[11], argv[7], argv[9], argv[3], argv[5],
- &cda)))
+ parse_deleter_tokens (vty, NULL, argv[11], argv[7], argv[9], argv[3], argv[5],
+ NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4224,8 +4303,8 @@ DEFUN (clear_vnc_mac_un_vn_prefix,
/* pfx vn un L2 VNI */
if ((rc =
- parse_deleter_args (vty, argv[11], argv[9], argv[7], argv[3], argv[5],
- &cda)))
+ parse_deleter_tokens (vty, NULL, argv[11], argv[9], argv[7], argv[3], argv[5],
+ NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4258,8 +4337,8 @@ DEFUN (clear_vnc_mac_un_prefix,
/* pfx vn un L2 VNI */
if ((rc =
- parse_deleter_args (vty, argv[9], NULL, argv[7], argv[3], argv[5],
- &cda)))
+ parse_deleter_tokens (vty, NULL, argv[9], NULL, argv[7], argv[3], argv[5],
+ NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4292,8 +4371,8 @@ DEFUN (clear_vnc_mac_vn_prefix,
/* pfx vn un L2 VNI */
if ((rc =
- parse_deleter_args (vty, argv[9], argv[7], NULL, argv[3], argv[5],
- &cda)))
+ parse_deleter_tokens (vty, NULL, argv[9], argv[7], NULL, argv[3], argv[5],
+ NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4322,7 +4401,7 @@ DEFUN (clear_vnc_mac_all_prefix,
/* pfx vn un L2 VNI */
if ((rc =
- parse_deleter_args (vty, argv[7], NULL, NULL, argv[3], argv[5], &cda)))
+ parse_deleter_tokens (vty, NULL, argv[7], NULL, NULL, argv[3], argv[5], NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4930,6 +5009,361 @@ notcfg:
return CMD_WARNING;
}
+/************************************************************************
+ * Add prefix with vrf
+ *
+ * add [vrf <vrf-name>] prefix <prefix>
+ * [rd <value>] [label <value>] [local-preference <0-4294967295>]
+ ************************************************************************/
+static int
+vnc_add_vrf_prefix (struct vty *vty,
+ const char *arg_vrf,
+ const char *arg_prefix,
+ const char *arg_rd, /* optional */
+ const char *arg_label, /* optional */
+ const char *arg_pref) /* optional */
+{
+ struct bgp *bgp;
+ struct rfapi_nve_group_cfg *rfg;
+ struct prefix pfx;
+ struct rfapi_ip_prefix rpfx;
+ uint32_t pref = 0;
+ struct rfapi_vn_option optary[3];
+ struct rfapi_vn_option *opt = NULL;
+ int cur_opt = 0;
+
+ bgp = bgp_get_default (); /* assume main instance for now */
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (!bgp->rfapi || !bgp->rfapi_cfg)
+ {
+ vty_out (vty, "VRF support not configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ rfg = bgp_rfapi_cfg_match_byname (bgp, arg_vrf, RFAPI_GROUP_CFG_VRF);
+ /* arg checks */
+ if (!rfg)
+ {
+ vty_out (vty, "VRF \"%s\" appears not to be configured.%s",
+ arg_vrf, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (!rfg->rt_export_list || !rfg->rfapi_import_table)
+ {
+ vty_out (vty, "VRF \"%s\" is missing RT import/export RT configuration.%s",
+ arg_vrf, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (!rfg->rd.family && !arg_rd)
+ {
+ vty_out (vty, "VRF \"%s\" isn't configured with an RD, so RD must be provided.%s",
+ arg_vrf, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (rfg->label > MPLS_LABEL_MAX && !arg_label)
+ {
+ vty_out (vty, "VRF \"%s\" isn't configured with a default labels, so a label must be provided.%s",
+ arg_vrf, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (!str2prefix (arg_prefix, &pfx))
+ {
+ vty_out (vty, "Malformed prefix \"%s\"%s",
+ arg_prefix, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ rfapiQprefix2Rprefix (&pfx, &rpfx);
+ memset (optary, 0, sizeof (optary));
+ if (arg_rd)
+ {
+ if (opt != NULL)
+ opt->next = &optary[cur_opt];
+ opt = &optary[cur_opt++];
+ opt->type = RFAPI_VN_OPTION_TYPE_INTERNAL_RD;
+ if (!str2prefix_rd (arg_rd, &opt->v.internal_rd))
+ {
+ vty_out (vty, "Malformed RD \"%s\"%s",
+ arg_rd, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ if (rfg->label <= MPLS_LABEL_MAX || arg_label)
+ {
+ struct rfapi_l2address_option *l2o;
+ if (opt != NULL)
+ opt->next = &optary[cur_opt];
+ opt = &optary[cur_opt++];
+ opt->type = RFAPI_VN_OPTION_TYPE_L2ADDR;
+ l2o = &opt->v.l2addr;
+ if (arg_label)
+ {
+ int32_t label;
+ VTY_GET_INTEGER_RANGE ("Label value", label, arg_label, 0, MPLS_LABEL_MAX);
+ l2o->label = label;
+ }
+ else
+ l2o->label = rfg->label;
+ }
+ if (arg_pref)
+ {
+ char *endptr = NULL;
+ pref = strtoul (arg_pref, &endptr, 10);
+ if (*endptr != '\0')
+ {
+ vty_out (vty, "%% Invalid local-preference value \"%s\"%s", arg_pref, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ rpfx.cost = 255 - (pref & 255) ;
+ if (rfg->rfd == NULL) /* need new rfapi_handle */
+ {
+ /* based on rfapi_open */
+ struct rfapi_descriptor *rfd;
+ rfd = XCALLOC (MTYPE_RFAPI_DESC, sizeof (struct rfapi_descriptor));
+ rfd->bgp = bgp;
+ rfg->rfd = rfd;
+ /* leave most fields empty as will get from (dynamic) config when needed */
+ rfd->default_tunneltype_option.type = BGP_ENCAP_TYPE_MPLS;
+ rfd->cookie = rfg;
+ if (rfg->vn_prefix.family &&
+ !CHECK_FLAG(rfg->flags, RFAPI_RFG_VPN_NH_SELF))
+ {
+ rfapiQprefix2Raddr(&rfg->vn_prefix, &rfd->vn_addr);
+ }
+ else
+ {
+ memset(&rfd->vn_addr, 0, sizeof(struct rfapi_ip_addr));
+ rfd->vn_addr.addr_family = AF_INET;
+ rfd->vn_addr.addr.v4 = bgp->router_id;
+ }
+ rfd->un_addr = rfd->vn_addr; /* sigh, need something in UN for lookups */
+ vnc_zlog_debug_verbose ("%s: Opening RFD for VRF %s",
+ __func__, rfg->name);
+ rfapi_init_and_open(bgp, rfd, rfg);
+ }
+
+ if (!rfapi_register (rfg->rfd, &rpfx, RFAPI_INFINITE_LIFETIME, NULL,
+ (cur_opt ? optary : NULL), RFAPI_REGISTER_ADD))
+ {
+ struct rfapi_next_hop_entry *head = NULL;
+ struct rfapi_next_hop_entry *tail = NULL;
+ struct rfapi_vn_option *vn_opt_new;
+
+ vnc_zlog_debug_verbose ("%s: rfapi_register succeeded", __func__);
+
+ if (bgp->rfapi->rfp_methods.local_cb)
+ {
+ struct rfapi_descriptor *r = (struct rfapi_descriptor *) rfg->rfd;
+ vn_opt_new = rfapi_vn_options_dup (opt);
+
+ rfapiAddDeleteLocalRfpPrefix (&r->un_addr, &r->vn_addr, &rpfx,
+ 1, RFAPI_INFINITE_LIFETIME,
+ vn_opt_new, &head, &tail);
+ if (head)
+ {
+ bgp->rfapi->flags |= RFAPI_INCALLBACK;
+ (*bgp->rfapi->rfp_methods.local_cb) (head, r->cookie);
+ bgp->rfapi->flags &= ~RFAPI_INCALLBACK;
+ }
+ head = tail = NULL;
+ }
+ vnc_zlog_debug_verbose ("%s completed, count=%d/%d", __func__,
+ rfg->rfapi_import_table->local_count[AFI_IP],
+ rfg->rfapi_import_table->local_count[AFI_IP6]);
+ return CMD_SUCCESS;
+ }
+
+ vnc_zlog_debug_verbose ("%s: rfapi_register failed", __func__);
+ vty_out (vty, "Add failed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+}
+
+DEFUN (add_vrf_prefix_rd_label_pref,
+ add_vrf_prefix_rd_label_pref_cmd,
+ "add vrf NAME prefix <A.B.C.D/M|X:X::X:X/M> [rd ASN:nn_or_IP-address] [label (0-1048575)] [preference (0-4294967295)]",
+ "Add\n"
+ "To a VRF\n"
+ "VRF name\n"
+ "Add/modify prefix related information\n"
+ "IPv4 prefix\n"
+ "IPv6 prefix\n"
+ "Override configured VRF Route Distinguisher\n"
+ "<as-number>:<number> or <ip-address>:<number>\n"
+ "Override configured VRF label"
+ "Label Value <0-1048575>\n"
+ "Set advertised local preference\n"
+ "local preference (higher=more preferred)\n")
+{
+ char *arg_vrf = argv[2]->arg;
+ char *arg_prefix = argv[4]->arg;
+ char *arg_rd = NULL; /* optional */
+ char *arg_label = NULL; /* optional */
+ char *arg_pref = NULL; /* optional */
+ int pargc = 5;
+ argc--; /* don't parse argument */
+ while (pargc < argc)
+ {
+ switch (argv[pargc++]->arg[0])
+ {
+ case 'r':
+ arg_rd = argv[pargc]->arg;
+ break;
+ case 'l':
+ arg_label = argv[pargc]->arg;
+ break;
+ case 'p':
+ arg_pref = argv[pargc]->arg;
+ break;
+ default:
+ break;
+ }
+ pargc ++;
+ }
+
+ return vnc_add_vrf_prefix (vty, arg_vrf, arg_prefix, arg_rd, arg_label, arg_pref);
+}
+
+/************************************************************************
+ * del prefix with vrf
+ *
+ * clear [vrf <vrf-name>] prefix <prefix> [rd <value>]
+ ************************************************************************/
+static int
+rfapi_cfg_group_it_count(struct rfapi_nve_group_cfg *rfg)
+{
+ int count = 0;
+ afi_t afi = AFI_MAX;
+ while (afi-- > 0)
+ {
+ count += rfg->rfapi_import_table->local_count[afi];
+ }
+ return count;
+}
+
+static void
+clear_vnc_vrf_closer (struct rfapi_nve_group_cfg *rfg)
+{
+ struct rfapi_descriptor *rfd = rfg->rfd;
+ afi_t afi;
+
+ if (rfd == NULL)
+ return;
+ /* check if IT is empty */
+ for (afi = 0;
+ afi < AFI_MAX && rfg->rfapi_import_table->local_count[afi] == 0;
+ afi++);
+
+ if (afi == AFI_MAX)
+ {
+ vnc_zlog_debug_verbose ("%s: closing RFD for VRF %s",
+ __func__, rfg->name);
+ rfg->rfd = NULL;
+ rfapi_close(rfd);
+ }
+ else
+ {
+ vnc_zlog_debug_verbose ("%s: VRF %s afi=%d count=%d",
+ __func__, rfg->name, afi,
+ rfg->rfapi_import_table->local_count[afi]);
+ }
+}
+
+static int
+vnc_clear_vrf (struct vty *vty,
+ struct bgp *bgp,
+ const char *arg_vrf,
+ const char *arg_prefix, /* NULL = all */
+ const char *arg_rd) /* optional */
+{
+ struct rfapi_nve_group_cfg *rfg;
+ struct rfapi_local_reg_delete_arg cda;
+ int rc;
+ int start_count;
+
+ if (bgp == NULL)
+ bgp = bgp_get_default (); /* assume main instance for now */
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (!bgp->rfapi || !bgp->rfapi_cfg)
+ {
+ vty_out (vty, "VRF support not configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ rfg = bgp_rfapi_cfg_match_byname (bgp, arg_vrf, RFAPI_GROUP_CFG_VRF);
+ /* arg checks */
+ if (!rfg)
+ {
+ vty_out (vty, "VRF \"%s\" appears not to be configured.%s",
+ arg_vrf, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ rc = parse_deleter_args (vty, bgp, arg_prefix, NULL, NULL, NULL, NULL,
+ arg_rd, rfg, &cda);
+ if (rc != CMD_SUCCESS) /* parse error */
+ return rc;
+
+ start_count = rfapi_cfg_group_it_count(rfg);
+ clear_vnc_prefix (&cda);
+ clear_vnc_vrf_closer (rfg);
+ vty_out (vty, "Cleared %u out of %d prefixes.%s",
+ cda.pfx_count, start_count, VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
+DEFUN (clear_vrf_prefix_rd,
+ clear_vrf_prefix_rd_cmd,
+ "clear vrf NAME [prefix <A.B.C.D/M|X:X::X:X/M>] [rd ASN:nn_or_IP-address]",
+ "Clear stored data\n"
+ "From a VRF\n"
+ "VRF name\n"
+ "Prefix related information\n"
+ "IPv4 prefix\n"
+ "IPv6 prefix\n"
+ "Specific VRF Route Distinguisher\n"
+ "<as-number>:<number> or <ip-address>:<number>\n")
+{
+ char *arg_vrf = argv[2]->arg;
+ char *arg_prefix = NULL; /* optional */
+ char *arg_rd = NULL; /* optional */
+ int pargc = 3;
+ argc--; /* don't check parameter */
+ while (pargc < argc)
+ {
+ switch (argv[pargc++]->arg[0])
+ {
+ case 'r':
+ arg_rd = argv[pargc]->arg;
+ break;
+ case 'p':
+ arg_prefix = argv[pargc]->arg;
+ break;
+ default:
+ break;
+ }
+ pargc ++;
+ }
+ return vnc_clear_vrf (vty, NULL, arg_vrf, arg_prefix, arg_rd);
+}
+
+DEFUN (clear_vrf_all,
+ clear_vrf_all_cmd,
+ "clear vrf NAME all",
+ "Clear stored data\n"
+ "From a VRF\n"
+ "VRF name\n"
+ "All prefixes\n")
+{
+ char *arg_vrf = argv[2]->arg;
+ return vnc_clear_vrf (vty, NULL, arg_vrf, NULL, NULL);
+}
+
void rfapi_vty_init ()
{
install_element (ENABLE_NODE, &add_vnc_prefix_cost_life_lnh_cmd);
@@ -4953,6 +5387,8 @@ void rfapi_vty_init ()
install_element (ENABLE_NODE, &add_vnc_mac_vni_life_cmd);
install_element (ENABLE_NODE, &add_vnc_mac_vni_cmd);
+ install_element (ENABLE_NODE, &add_vrf_prefix_rd_label_pref_cmd);
+
install_element (ENABLE_NODE, &clear_vnc_nve_all_cmd);
install_element (ENABLE_NODE, &clear_vnc_nve_vn_un_cmd);
install_element (ENABLE_NODE, &clear_vnc_nve_un_vn_cmd);
@@ -4977,6 +5413,9 @@ void rfapi_vty_init ()
install_element (ENABLE_NODE, &clear_vnc_mac_vn_prefix_cmd);
install_element (ENABLE_NODE, &clear_vnc_mac_all_prefix_cmd);
+ install_element (ENABLE_NODE, &clear_vrf_prefix_rd_cmd);
+ install_element (ENABLE_NODE, &clear_vrf_all_cmd);
+
install_element (ENABLE_NODE, &vnc_clear_counters_cmd);
install_element (VIEW_NODE, &vnc_show_summary_cmd);
diff --git a/configure.ac b/configure.ac
index 6ce5d0cc2c..550ac4f926 100755
--- a/configure.ac
+++ b/configure.ac
@@ -1459,6 +1459,7 @@ case "x${quagga_ac_bison_version}" in
x2.7*)
BISON_OPENBRACE='"'
BISON_CLOSEBRACE='"'
+ BISON_VERBOSE=''
AC_MSG_RESULT([$quagga_ac_bison_version - 2.7 or older])
;;
x2.*|x1.*)
@@ -1474,11 +1475,13 @@ case "x${quagga_ac_bison_version}" in
*)
BISON_OPENBRACE='{'
BISON_CLOSEBRACE='}'
+ BISON_VERBOSE='-Dparse.error=verbose'
AC_MSG_RESULT([$quagga_ac_bison_version - 3.0 or newer])
;;
esac
AC_SUBST(BISON_OPENBRACE)
AC_SUBST(BISON_CLOSEBRACE)
+AC_SUBST(BISON_VERBOSE)
if $quagga_ac_bison_missing; then
YACC="$SHELL $missing_dir/missing bison -y"
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index 086f5b23da..c1fb062e55 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -1149,7 +1149,7 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid)
unsigned long long start_time, end_time;
/* Get time that can't roll backwards. */
- quagga_gettime(QUAGGA_CLK_MONOTONIC, &time_now);
+ monotime(&time_now);
start_time = time_now.tv_sec;
start_time = (start_time * 1000000) + time_now.tv_usec;
@@ -1243,7 +1243,7 @@ out:
spftree->pending = 0;
spftree->runcount++;
spftree->last_run_timestamp = time (NULL);
- quagga_gettime(QUAGGA_CLK_MONOTONIC, &time_now);
+ monotime(&time_now);
end_time = time_now.tv_sec;
end_time = (end_time * 1000000) + time_now.tv_usec;
spftree->last_run_duration = end_time - start_time;
diff --git a/lib/Makefile.am b/lib/Makefile.am
index f2c076c475..ac1935d731 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -3,7 +3,7 @@
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@
+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
@@ -26,6 +26,7 @@ libzebra_la_SOURCES = \
imsg-buffer.c imsg.c skiplist.c \
qobj.c wheel.c \
event_counter.c \
+ grammar_sandbox.c \
strlcpy.c \
strlcat.c
@@ -46,14 +47,15 @@ pkginclude_HEADERS = \
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
+ event_counter.h \
+ monotime.h
noinst_HEADERS = \
plist_int.h
noinst_PROGRAMS = grammar_sandbox
-grammar_sandbox_SOURCES = grammar_sandbox.c
+grammar_sandbox_SOURCES = grammar_sandbox_main.c
grammar_sandbox_LDADD = libzebra.la
EXTRA_DIST = \
diff --git a/lib/bfd.c b/lib/bfd.c
index 5db08fea60..a5edaea217 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -362,7 +362,7 @@ bfd_last_update (time_t last_update, char *buf, size_t len)
}
/* Get current time. */
- quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv);
+ monotime(&tv);
curr = tv.tv_sec;
diff = curr - last_update;
tm = gmtime (&diff);
diff --git a/lib/command.c b/lib/command.c
index b5dae5f28e..9485beddd9 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -43,7 +43,10 @@
DEFINE_MTYPE( LIB, HOST, "Host config")
DEFINE_MTYPE( LIB, STRVEC, "String vector")
-DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command desc")
+DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command Tokens")
+DEFINE_MTYPE_STATIC(LIB, CMD_DESC, "Command Token Text")
+DEFINE_MTYPE_STATIC(LIB, CMD_TEXT, "Command Token Help")
+DEFINE_MTYPE( LIB, CMD_ARG, "Command Argument")
/* Command vector which includes some level of command lists. Normally
each daemon maintains each own cmdvec. */
@@ -523,7 +526,7 @@ compare_completions (const void *fst, const void *snd)
* @param completions linked list of cmd_token
* @return deduplicated and sorted vector with
*/
-static vector
+vector
completions_to_vec (struct list *completions)
{
vector comps = vector_init (VECTOR_MIN_SIZE);
@@ -745,6 +748,7 @@ node_parent ( enum node_type node )
case BGP_VPNV6_NODE:
case BGP_ENCAP_NODE:
case BGP_ENCAPV6_NODE:
+ case BGP_VRF_POLICY_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
case BGP_VNC_L2_GROUP_NODE:
@@ -1110,6 +1114,7 @@ cmd_exit (struct vty *vty)
case BGP_VPNV6_NODE:
case BGP_ENCAP_NODE:
case BGP_ENCAPV6_NODE:
+ case BGP_VRF_POLICY_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
case BGP_VNC_L2_GROUP_NODE:
@@ -1173,6 +1178,7 @@ DEFUN (config_end,
case BGP_NODE:
case BGP_ENCAP_NODE:
case BGP_ENCAPV6_NODE:
+ case BGP_VRF_POLICY_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
case BGP_VNC_L2_GROUP_NODE:
@@ -1272,7 +1278,7 @@ permute (struct graph_node *start, struct vty *vty)
for (ALL_LIST_ELEMENTS_RO (position,ln,gnn))
{
struct cmd_token *tt = gnn->data;
- if (tt->type < SELECTOR_TKN)
+ if (tt->type < SPECIAL_TKN)
vty_out (vty, " %s", tt->text);
}
if (gn == start)
@@ -2402,16 +2408,21 @@ cmd_init (int terminal)
vrf_install_commands ();
}
srandom(time(NULL));
+
+#ifdef DEV_BUILD
+ grammar_sandbox_init();
+#endif
}
struct cmd_token *
-new_cmd_token (enum cmd_token_type type, u_char attr, char *text, char *desc)
+new_cmd_token (enum cmd_token_type type, u_char attr,
+ const char *text, const char *desc)
{
struct cmd_token *token = XCALLOC (MTYPE_CMD_TOKENS, sizeof (struct cmd_token));
token->type = type;
token->attr = attr;
- token->text = text;
- token->desc = desc;
+ token->text = text ? XSTRDUP (MTYPE_CMD_TEXT, text) : NULL;
+ token->desc = desc ? XSTRDUP (MTYPE_CMD_DESC, desc) : NULL;
token->arg = NULL;
token->allowrepeat = false;
@@ -2424,11 +2435,11 @@ del_cmd_token (struct cmd_token *token)
if (!token) return;
if (token->text)
- XFREE (MTYPE_CMD_TOKENS, token->text);
+ XFREE (MTYPE_CMD_TEXT, token->text);
if (token->desc)
- XFREE (MTYPE_CMD_TOKENS, token->desc);
+ XFREE (MTYPE_CMD_DESC, token->desc);
if (token->arg)
- XFREE (MTYPE_CMD_TOKENS, token->arg);
+ XFREE (MTYPE_CMD_ARG, token->arg);
XFREE (MTYPE_CMD_TOKENS, token);
}
@@ -2439,9 +2450,9 @@ copy_cmd_token (struct cmd_token *token)
struct cmd_token *copy = new_cmd_token (token->type, token->attr, NULL, NULL);
copy->max = token->max;
copy->min = token->min;
- copy->text = token->text ? XSTRDUP (MTYPE_CMD_TOKENS, token->text) : NULL;
- copy->desc = token->desc ? XSTRDUP (MTYPE_CMD_TOKENS, token->desc) : NULL;
- copy->arg = token->arg ? XSTRDUP (MTYPE_CMD_TOKENS, token->arg) : NULL;
+ copy->text = token->text ? XSTRDUP (MTYPE_CMD_TEXT, token->text) : NULL;
+ copy->desc = token->desc ? XSTRDUP (MTYPE_CMD_DESC, token->desc) : NULL;
+ copy->arg = token->arg ? XSTRDUP (MTYPE_CMD_ARG, token->arg) : NULL;
return copy;
}
diff --git a/lib/command.h b/lib/command.h
index 1e1698fc7d..3c3c3ae370 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -31,6 +31,7 @@
#include "hash.h"
DECLARE_MTYPE(HOST)
+DECLARE_MTYPE(CMD_ARG)
/* for test-commands.c */
DECLARE_MTYPE(STRVEC)
@@ -99,6 +100,7 @@ enum node_type
BGP_IPV6M_NODE, /* BGP IPv6 multicast address family. */
BGP_ENCAP_NODE, /* BGP ENCAP SAFI */
BGP_ENCAPV6_NODE, /* BGP ENCAP SAFI */
+ BGP_VRF_POLICY_NODE, /* BGP VRF policy */
BGP_VNC_DEFAULTS_NODE, /* BGP VNC nve defaults */
BGP_VNC_NVE_GROUP_NODE, /* BGP VNC nve group */
BGP_VNC_L2_GROUP_NODE, /* BGP VNC L2 group */
@@ -176,11 +178,12 @@ enum cmd_token_type
IPV6_PREFIX_TKN, // IPV6 network prefixes
/* plumbing types */
- SELECTOR_TKN, // marks beginning of selector
- OPTION_TKN, // marks beginning of option
- NUL_TKN, // dummy token
+ FORK_TKN, // marks subgraph beginning
+ JOIN_TKN, // marks subgraph end
START_TKN, // first token in line
END_TKN, // last token in line
+
+ SPECIAL_TKN = FORK_TKN,
};
/* Command attributes */
@@ -202,6 +205,8 @@ struct cmd_token
char *desc; // token description
long long min, max; // for ranges
char *arg; // user input that matches this token
+
+ struct graph_node *forkjoin; // paired FORK/JOIN for JOIN/FORK
};
/* Structure of command element. */
@@ -419,14 +424,16 @@ extern void cmd_terminate (void);
extern void cmd_exit (struct vty *vty);
extern int cmd_list_cmds (struct vty *vty, int do_permute);
+/* NOT safe for general use; call this only if DEV_BUILD! */
+extern void grammar_sandbox_init (void);
+
/* memory management for cmd_token */
-struct cmd_token *
-new_cmd_token (enum cmd_token_type, u_char attr, char *, char *);
-void
-del_cmd_token (struct cmd_token *);
-struct cmd_token *
-copy_cmd_token (struct cmd_token *);
+extern struct cmd_token *new_cmd_token (enum cmd_token_type, u_char attr,
+ const char *text, const char *desc);
+extern void del_cmd_token (struct cmd_token *);
+extern struct cmd_token *copy_cmd_token (struct cmd_token *);
+extern vector completions_to_vec (struct list *completions);
extern void command_parse_format (struct graph *graph, struct cmd_element *cmd);
/* Export typical functions. */
diff --git a/lib/command_lex.l b/lib/command_lex.l
index d767926263..2a241abbec 100644
--- a/lib/command_lex.l
+++ b/lib/command_lex.l
@@ -24,6 +24,12 @@
%{
#include "command_parse.h"
+
+#define YY_USER_ACTION yylloc->last_column += yyleng;
+#define LOC_STEP do { if (yylloc) { \
+ yylloc->first_column = yylloc->last_column; \
+ yylloc->first_line = yylloc->last_line; \
+ } } while(0)
%}
WORD (\-|\+)?[a-z0-9\*][-+_a-zA-Z0-9\*]*
@@ -45,9 +51,14 @@ RANGE \({NUMBER}[ ]?\-[ ]?{NUMBER}\)
%option prefix="cmd_yy"
%option reentrant
%option bison-bridge
+%option bison-locations
%%
-[ /t] /* ignore whitespace */;
+%{
+ LOC_STEP;
+%}
+
+[ \t]+ LOC_STEP /* ignore whitespace */;
{WORD} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return WORD;}
{IPV4} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return IPV4;}
{IPV4_PREFIX} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return IPV4_PREFIX;}
diff --git a/lib/command_match.c b/lib/command_match.c
index d228563240..bbd9cd091d 100644
--- a/lib/command_match.c
+++ b/lib/command_match.c
@@ -27,7 +27,6 @@
#include "command_match.h"
#include "memory.h"
-DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command Tokens")
DEFINE_MTYPE_STATIC(LIB, CMD_MATCHSTACK, "Command Match Stack")
#define MAXDEPTH 64
@@ -322,7 +321,7 @@ command_match_r (struct graph_node *start, vector vline, unsigned int n,
// copy token, set arg and prepend to currbest
struct cmd_token *token = start->data;
struct cmd_token *copy = copy_cmd_token (token);
- copy->arg = XSTRDUP (MTYPE_CMD_TOKENS, input_token);
+ copy->arg = XSTRDUP (MTYPE_CMD_ARG, input_token);
listnode_add_before (currbest, currbest->head, copy);
matcher_rv = MATCHER_OK;
}
@@ -459,7 +458,7 @@ command_complete (struct graph *graph,
/**
* Adds all children that are reachable by one parser hop to the given list.
- * NUL_TKN, SELECTOR_TKN, and OPTION_TKN nodes are treated as transparent.
+ * special tokens except END_TKN are treated as transparent.
*
* @param[in] list to add the nexthops to
* @param[in] node to start calculating nexthops from
@@ -490,26 +489,24 @@ add_nexthops (struct list *list, struct graph_node *node,
if (j != stackpos)
continue;
}
- switch (token->type)
+ if (token->type >= SPECIAL_TKN && token->type != END_TKN)
{
- case OPTION_TKN:
- case SELECTOR_TKN:
- case NUL_TKN:
- added += add_nexthops (list, child, stack, stackpos);
- break;
- default:
- if (stack)
- {
- nextstack = XMALLOC (MTYPE_CMD_MATCHSTACK,
- (stackpos + 1) * sizeof(struct graph_node *));
- nextstack[0] = child;
- memcpy(nextstack + 1, stack, stackpos * sizeof(struct graph_node *));
+ added += add_nexthops (list, child, stack, stackpos);
+ }
+ else
+ {
+ if (stack)
+ {
+ nextstack = XMALLOC (MTYPE_CMD_MATCHSTACK,
+ (stackpos + 1) * sizeof(struct graph_node *));
+ nextstack[0] = child;
+ memcpy(nextstack + 1, stack, stackpos * sizeof(struct graph_node *));
- listnode_add (list, nextstack);
- }
- else
- listnode_add (list, child);
- added++;
+ listnode_add (list, nextstack);
+ }
+ else
+ listnode_add (list, child);
+ added++;
}
}
diff --git a/lib/command_parse.y b/lib/command_parse.y
index c920e11380..e9d36ca41c 100644
--- a/lib/command_parse.y
+++ b/lib/command_parse.y
@@ -27,6 +27,8 @@
#define YYDEBUG 1
%}
+%locations
+/* define parse.error verbose */
%define api.pure full
/* define api.prefix {cmd_yy} */
@@ -49,14 +51,20 @@
#include "graph.h"
#define YYSTYPE CMD_YYSTYPE
+ #define YYLTYPE CMD_YYLTYPE
struct parser_ctx;
+
+ /* subgraph semantic value */
+ struct subgraph {
+ struct graph_node *start, *end;
+ };
}
%union {
long long number;
char *string;
struct graph_node *node;
- struct subgraph *subgraph;
+ struct subgraph subgraph;
}
%code provides {
@@ -94,28 +102,19 @@
%type <node> literal_token
%type <node> placeholder_token
%type <node> simple_token
-%type <subgraph> option
-%type <subgraph> option_token
-%type <subgraph> option_token_seq
%type <subgraph> selector
%type <subgraph> selector_token
%type <subgraph> selector_token_seq
%type <subgraph> selector_seq_seq
-%type <subgraph> compound_token
%code {
/* bison declarations */
void
- cmd_yyerror (struct parser_ctx *ctx, char const *msg);
-
- /* subgraph semantic value */
- struct subgraph {
- struct graph_node *start, *end;
- };
+ cmd_yyerror (CMD_YYLTYPE *locp, struct parser_ctx *ctx, char const *msg);
/* helper functions for parser */
- static char *
+ static const char *
doc_next (struct parser_ctx *ctx);
static struct graph_node *
@@ -130,11 +129,11 @@
static struct graph_node *
new_token_node (struct parser_ctx *,
enum cmd_token_type type,
- char *text,
- char *doc);
+ const char *text,
+ const char *doc);
static void
- terminate_graph (struct parser_ctx *ctx,
+ terminate_graph (CMD_YYLTYPE *locp, struct parser_ctx *ctx,
struct graph_node *);
static void
@@ -173,7 +172,7 @@ start:
cmd_token_seq
{
// tack on the command element
- terminate_graph (ctx, ctx->currnode);
+ terminate_graph (&@1, ctx, ctx->currnode);
}
| cmd_token_seq placeholder_token '.' '.' '.'
{
@@ -187,7 +186,7 @@ start:
add_edge_dedup (ctx->currnode, ctx->currnode);
// tack on the command element
- terminate_graph (ctx, ctx->currnode);
+ terminate_graph (&@1, ctx, ctx->currnode);
}
;
@@ -202,11 +201,10 @@ cmd_token:
if ((ctx->currnode = add_edge_dedup (ctx->currnode, $1)) != $1)
graph_delete_node (ctx->graph, $1);
}
-| compound_token
+| selector
{
- graph_add_edge (ctx->currnode, $1->start);
- ctx->currnode = $1->end;
- free ($1);
+ graph_add_edge (ctx->currnode, $1.start);
+ ctx->currnode = $1.end;
}
;
@@ -215,14 +213,9 @@ simple_token:
| placeholder_token
;
-compound_token:
- selector
-| option
-;
-
literal_token: WORD
{
- $$ = new_token_node (ctx, WORD_TKN, strdup($1), doc_next(ctx));
+ $$ = new_token_node (ctx, WORD_TKN, $1, doc_next(ctx));
free ($1);
}
;
@@ -230,32 +223,32 @@ literal_token: WORD
placeholder_token:
IPV4
{
- $$ = new_token_node (ctx, IPV4_TKN, strdup($1), doc_next(ctx));
+ $$ = new_token_node (ctx, IPV4_TKN, $1, doc_next(ctx));
free ($1);
}
| IPV4_PREFIX
{
- $$ = new_token_node (ctx, IPV4_PREFIX_TKN, strdup($1), doc_next(ctx));
+ $$ = new_token_node (ctx, IPV4_PREFIX_TKN, $1, doc_next(ctx));
free ($1);
}
| IPV6
{
- $$ = new_token_node (ctx, IPV6_TKN, strdup($1), doc_next(ctx));
+ $$ = new_token_node (ctx, IPV6_TKN, $1, doc_next(ctx));
free ($1);
}
| IPV6_PREFIX
{
- $$ = new_token_node (ctx, IPV6_PREFIX_TKN, strdup($1), doc_next(ctx));
+ $$ = new_token_node (ctx, IPV6_PREFIX_TKN, $1, doc_next(ctx));
free ($1);
}
| VARIABLE
{
- $$ = new_token_node (ctx, VARIABLE_TKN, strdup($1), doc_next(ctx));
+ $$ = new_token_node (ctx, VARIABLE_TKN, $1, doc_next(ctx));
free ($1);
}
| RANGE
{
- $$ = new_token_node (ctx, RANGE_TKN, strdup($1), doc_next(ctx));
+ $$ = new_token_node (ctx, RANGE_TKN, $1, doc_next(ctx));
struct cmd_token *token = $$->data;
// get the numbers out
@@ -265,7 +258,7 @@ placeholder_token:
token->max = strtoll (yylval.string, &yylval.string, 10);
// validate range
- if (token->min > token->max) cmd_yyerror (ctx, "Invalid range.");
+ if (token->min > token->max) cmd_yyerror (&@1, ctx, "Invalid range.");
free ($1);
}
@@ -273,141 +266,66 @@ placeholder_token:
/* <selector|set> productions */
selector: '<' selector_seq_seq '>'
{
- $$ = malloc (sizeof (struct subgraph));
- $$->start = new_token_node (ctx, SELECTOR_TKN, NULL, NULL);
- $$->end = new_token_node (ctx, NUL_TKN, NULL, NULL);
- for (unsigned int i = 0; i < vector_active ($2->start->to); i++)
- {
- struct graph_node *sn = vector_slot ($2->start->to, i),
- *en = vector_slot ($2->end->from, i);
- graph_add_edge ($$->start, sn);
- graph_add_edge (en, $$->end);
- }
- graph_delete_node (ctx->graph, $2->start);
- graph_delete_node (ctx->graph, $2->end);
- free ($2);
+ $$ = $2;
};
selector_seq_seq:
selector_seq_seq '|' selector_token_seq
{
- $$ = malloc (sizeof (struct subgraph));
- $$->start = graph_new_node (ctx->graph, NULL, NULL);
- $$->end = graph_new_node (ctx->graph, NULL, NULL);
-
- // link in last sequence
- graph_add_edge ($$->start, $3->start);
- graph_add_edge ($3->end, $$->end);
-
- for (unsigned int i = 0; i < vector_active ($1->start->to); i++)
- {
- struct graph_node *sn = vector_slot ($1->start->to, i),
- *en = vector_slot ($1->end->from, i);
- graph_add_edge ($$->start, sn);
- graph_add_edge (en, $$->end);
- }
- graph_delete_node (ctx->graph, $1->start);
- graph_delete_node (ctx->graph, $1->end);
- free ($1);
- free ($3);
+ $$ = $1;
+ graph_add_edge ($$.start, $3.start);
+ graph_add_edge ($3.end, $$.end);
}
-| selector_token_seq '|' selector_token_seq
+| selector_token_seq
{
- $$ = malloc (sizeof (struct subgraph));
- $$->start = graph_new_node (ctx->graph, NULL, NULL);
- $$->end = graph_new_node (ctx->graph, NULL, NULL);
- graph_add_edge ($$->start, $1->start);
- graph_add_edge ($1->end, $$->end);
- graph_add_edge ($$->start, $3->start);
- graph_add_edge ($3->end, $$->end);
- free ($1);
- free ($3);
+ $$.start = new_token_node (ctx, FORK_TKN, NULL, NULL);
+ $$.end = new_token_node (ctx, JOIN_TKN, NULL, NULL);
+ ((struct cmd_token *)$$.start->data)->forkjoin = $$.end;
+ ((struct cmd_token *)$$.end->data)->forkjoin = $$.start;
+
+ graph_add_edge ($$.start, $1.start);
+ graph_add_edge ($1.end, $$.end);
}
;
/* {keyword} productions */
selector: '{' selector_seq_seq '}'
{
- $$ = malloc (sizeof (struct subgraph));
- $$->start = new_token_node (ctx, SELECTOR_TKN, NULL, NULL);
- $$->end = new_token_node (ctx, NUL_TKN, NULL, NULL);
- graph_add_edge ($$->start, $$->end);
- for (unsigned int i = 0; i < vector_active ($2->start->to); i++)
- {
- struct graph_node *sn = vector_slot ($2->start->to, i),
- *en = vector_slot ($2->end->from, i);
- graph_add_edge ($$->start, sn);
- graph_add_edge (en, $$->start);
- }
- graph_delete_node (ctx->graph, $2->start);
- graph_delete_node (ctx->graph, $2->end);
- free ($2);
+ $$ = $2;
+ graph_add_edge ($$.end, $$.start);
+ /* there is intentionally no start->end link, for two reasons:
+ * 1) this allows "at least 1 of" semantics, which are otherwise impossible
+ * 2) this would add a start->end->start loop in the graph that the current
+ * loop-avoidal fails to handle
+ * just use [{a|b}] if neccessary, that will work perfectly fine, and reason
+ * #1 is good enough to keep it this way. */
};
-selector_token_seq:
- simple_token
-{
- $$ = malloc (sizeof (struct subgraph));
- $$->start = $$->end = $1;
-}
-| selector_token_seq selector_token
-{
- $$ = malloc (sizeof (struct subgraph));
- graph_add_edge ($1->end, $2->start);
- $$->start = $1->start;
- $$->end = $2->end;
- free ($1);
- free ($2);
-}
-;
-
selector_token:
simple_token
{
- $$ = malloc (sizeof (struct subgraph));
- $$->start = $$->end = $1;
+ $$.start = $$.end = $1;
}
-| option
| selector
;
-/* [option] productions */
-option: '[' option_token_seq ']'
+selector_token_seq:
+ selector_token_seq selector_token
{
- // make a new option
- $$ = malloc (sizeof (struct subgraph));
- $$->start = new_token_node (ctx, OPTION_TKN, NULL, NULL);
- $$->end = new_token_node (ctx, NUL_TKN, NULL, NULL);
- // add a path through the sequence to the end
- graph_add_edge ($$->start, $2->start);
- graph_add_edge ($2->end, $$->end);
- // add a path directly from the start to the end
- graph_add_edge ($$->start, $$->end);
- free ($2);
+ graph_add_edge ($1.end, $2.start);
+ $$.start = $1.start;
+ $$.end = $2.end;
}
+| selector_token
;
-option_token_seq:
- option_token
-| option_token_seq option_token
-{
- $$ = malloc (sizeof (struct subgraph));
- graph_add_edge ($1->end, $2->start);
- $$->start = $1->start;
- $$->end = $2->end;
- free ($1);
- free ($2);
-}
-;
-
-option_token:
- simple_token
+/* [option] productions */
+selector: '[' selector_seq_seq ']'
{
- $$ = malloc (sizeof (struct subgraph));
- $$->start = $$->end = $1;
+ $$ = $2;
+ graph_add_edge ($$.start, $$.end);
}
-| compound_token
;
%%
@@ -437,11 +355,39 @@ command_parse_format (struct graph *graph, struct cmd_element *cmd)
/* parser helper functions */
void
-yyerror (struct parser_ctx *ctx, char const *msg)
+yyerror (CMD_YYLTYPE *loc, struct parser_ctx *ctx, char const *msg)
{
+ char *tmpstr = strdup(ctx->el->string);
+ char *line, *eol;
+ char spacing[256];
+ int lineno = 0;
+
zlog_err ("%s: FATAL parse error: %s", __func__, msg);
- zlog_err ("while parsing this command definition: \n\t%s\n", ctx->el->string);
- //exit(EXIT_FAILURE);
+ zlog_err ("%s: %d:%d-%d of this command definition:", __func__, loc->first_line, loc->first_column, loc->last_column);
+
+ line = tmpstr;
+ do {
+ lineno++;
+ eol = strchr(line, '\n');
+ if (eol)
+ *eol++ = '\0';
+
+ zlog_err ("%s: | %s", __func__, line);
+ if (lineno == loc->first_line && lineno == loc->last_line
+ && loc->first_column < (int)sizeof(spacing) - 1
+ && loc->last_column < (int)sizeof(spacing) - 1) {
+
+ int len = loc->last_column - loc->first_column;
+ if (len == 0)
+ len = 1;
+
+ memset(spacing, ' ', loc->first_column - 1);
+ memset(spacing + loc->first_column - 1, '^', len);
+ spacing[loc->first_column - 1 + len] = '\0';
+ zlog_err ("%s: | %s", __func__, spacing);
+ }
+ } while ((line = eol));
+ free(tmpstr);
}
static void
@@ -456,27 +402,25 @@ cleanup (struct parser_ctx *ctx)
}
static void
-terminate_graph (struct parser_ctx *ctx, struct graph_node *finalnode)
+terminate_graph (CMD_YYLTYPE *locp, struct parser_ctx *ctx,
+ struct graph_node *finalnode)
{
// end of graph should look like this
// * -> finalnode -> END_TKN -> cmd_element
struct cmd_element *element = ctx->el;
struct graph_node *end_token_node =
- new_token_node (ctx,
- END_TKN,
- strdup (CMD_CR_TEXT),
- strdup (""));
+ new_token_node (ctx, END_TKN, CMD_CR_TEXT, "");
struct graph_node *end_element_node =
graph_new_node (ctx->graph, element, NULL);
if (node_adjacent (finalnode, end_token_node))
- cmd_yyerror (ctx, "Duplicate command.");
+ cmd_yyerror (locp, ctx, "Duplicate command.");
graph_add_edge (finalnode, end_token_node);
graph_add_edge (end_token_node, end_element_node);
}
-static char *
+static const char *
doc_next (struct parser_ctx *ctx)
{
const char *piece = ctx->docstr ? strsep (&ctx->docstr, "\n") : "";
@@ -486,12 +430,12 @@ doc_next (struct parser_ctx *ctx)
piece = "";
}
- return strdup (piece);
+ return piece;
}
static struct graph_node *
new_token_node (struct parser_ctx *ctx, enum cmd_token_type type,
- char *text, char *doc)
+ const char *text, const char *doc)
{
struct cmd_token *token = new_cmd_token (type, ctx->el->attr, text, doc);
return graph_new_node (ctx->graph, token, (void (*)(void *)) &del_cmd_token);
@@ -575,8 +519,7 @@ cmp_token (struct cmd_token *first, struct cmd_token *second)
* cases; ultimately this forks the graph, but the matcher can handle
* this regardless
*/
- case SELECTOR_TKN:
- case OPTION_TKN:
+ case FORK_TKN:
return 0;
/* end nodes are always considered equal, since each node may only
@@ -584,7 +527,7 @@ cmp_token (struct cmd_token *first, struct cmd_token *second)
*/
case START_TKN:
case END_TKN:
- case NUL_TKN:
+ case JOIN_TKN:
default:
break;
}
diff --git a/lib/grammar_sandbox.c b/lib/grammar_sandbox.c
index 0239ca44ac..315bd4d59c 100644
--- a/lib/grammar_sandbox.c
+++ b/lib/grammar_sandbox.c
@@ -3,11 +3,6 @@
*
* This unit defines a number of commands in the old engine that can
* be used to test and interact with the new engine.
- *
- * This shim should be removed upon integration. It is currently hooked in
- * vtysh/vtysh.c. It has no header, vtysh.c merely includes this entire unit
- * since it clutters up the makefiles less and this is only a temporary shim.
- *
* --
* Copyright (C) 2016 Cumulus Networks, Inc.
*
@@ -45,15 +40,15 @@ void
grammar_sandbox_init (void);
void
pretty_print_graph (struct vty *vty, struct graph_node *, int, int, struct graph_node **, size_t);
+static void
+pretty_print_dot (FILE *ofd, unsigned opts, struct graph_node *start,
+ struct graph_node **stack, size_t stackpos,
+ struct graph_node **visited, size_t *visitpos);
void
init_cmdgraph (struct vty *, struct graph **);
-vector
-completions_to_vec (struct list *);
-int
-compare_completions (const void *, const void *);
/** shim interface commands **/
-struct graph *nodegraph;
+struct graph *nodegraph = NULL, *nodegraph_free = NULL;
DEFUN (grammar_test,
grammar_test_cmd,
@@ -240,17 +235,77 @@ DEFUN (grammar_test_show,
return CMD_SUCCESS;
}
+DEFUN (grammar_test_dot,
+ grammar_test_dot_cmd,
+ "grammar dotfile OUTNAME",
+ GRAMMAR_STR
+ "print current graph for dot\n"
+ ".dot filename\n")
+{
+ struct graph_node *stack[MAXDEPTH];
+ struct graph_node *visited[MAXDEPTH*MAXDEPTH];
+ size_t vpos = 0;
+
+ if (!nodegraph) {
+ vty_out(vty, "nodegraph uninitialized\r\n");
+ return CMD_SUCCESS;
+ }
+ FILE *ofd = fopen(argv[2]->arg, "w");
+ if (!ofd) {
+ vty_out(vty, "%s: %s\r\n", argv[2]->arg, strerror(errno));
+ return CMD_SUCCESS;
+ }
+
+ fprintf(ofd, "digraph {\n graph [ rankdir = LR ];\n node [ fontname = \"Fira Mono\", fontsize = 9 ];\n\n");
+ pretty_print_dot (ofd, 0,
+ vector_slot (nodegraph->nodes, 0),
+ stack, 0, visited, &vpos);
+ fprintf(ofd, "}\n");
+ fclose(ofd);
+ return CMD_SUCCESS;
+}
+
DEFUN (grammar_init_graph,
grammar_init_graph_cmd,
"grammar init",
GRAMMAR_STR
"(re)initialize graph\n")
{
- graph_delete_graph (nodegraph);
+ if (nodegraph_free)
+ graph_delete_graph (nodegraph_free);
+ nodegraph_free = NULL;
+
init_cmdgraph (vty, &nodegraph);
return CMD_SUCCESS;
}
+extern vector cmdvec;
+
+DEFUN (grammar_access,
+ grammar_access_cmd,
+ "grammar access (0-65535)",
+ GRAMMAR_STR
+ "access node graph\n"
+ "node number\n")
+{
+ if (nodegraph_free)
+ graph_delete_graph (nodegraph_free);
+ nodegraph_free = NULL;
+
+ struct cmd_node *cnode;
+
+ cnode = vector_slot (cmdvec, atoi (argv[2]->arg));
+ if (!cnode)
+ {
+ vty_out (vty, "%% no such node%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ vty_out (vty, "node %d%s", (int)cnode->node, VTY_NEWLINE);
+ nodegraph = cnode->cmdgraph;
+ return CMD_SUCCESS;
+}
+
/* this is called in vtysh.c to set up the testing shim */
void grammar_sandbox_init(void) {
init_cmdgraph (NULL, &nodegraph);
@@ -258,10 +313,12 @@ void grammar_sandbox_init(void) {
// install all enable elements
install_element (ENABLE_NODE, &grammar_test_cmd);
install_element (ENABLE_NODE, &grammar_test_show_cmd);
+ install_element (ENABLE_NODE, &grammar_test_dot_cmd);
install_element (ENABLE_NODE, &grammar_test_match_cmd);
install_element (ENABLE_NODE, &grammar_test_complete_cmd);
install_element (ENABLE_NODE, &grammar_test_doc_cmd);
install_element (ENABLE_NODE, &grammar_init_graph_cmd);
+ install_element (ENABLE_NODE, &grammar_access_cmd);
}
#define item(x) { x, #x }
@@ -275,9 +332,8 @@ struct message tokennames[] = {
item(IPV6_PREFIX_TKN), // IPV6 network prefixes
/* plumbing types */
- item(SELECTOR_TKN), // marks beginning of selector
- item(OPTION_TKN), // marks beginning of option
- item(NUL_TKN), // dummy token
+ item(FORK_TKN),
+ item(JOIN_TKN),
item(START_TKN), // first token in line
item(END_TKN), // last token in line
{ 0, NULL }
@@ -292,7 +348,7 @@ size_t tokennames_max = array_size(tokennames);
*/
void
pretty_print_graph (struct vty *vty, struct graph_node *start, int level,
- int desc, struct graph_node **stack, size_t stackpos)
+ int desc, struct graph_node **stack, size_t stackpos)
{
// print this node
char tokennum[32];
@@ -346,92 +402,92 @@ pretty_print_graph (struct vty *vty, struct graph_node *start, int level,
vty_out(vty, "%s", VTY_NEWLINE);
}
-/** stuff that should go in command.c + command.h */
-void
-init_cmdgraph (struct vty *vty, struct graph **graph)
-{
- // initialize graph, add start noe
- *graph = graph_new ();
- struct cmd_token *token = new_cmd_token (START_TKN, 0, NULL, NULL);
- graph_new_node (*graph, token, (void (*)(void *)) &del_cmd_token);
- if (vty)
- vty_out (vty, "initialized graph%s", VTY_NEWLINE);
-}
-
-int
-compare_completions (const void *fst, const void *snd)
+static void
+pretty_print_dot (FILE *ofd, unsigned opts, struct graph_node *start,
+ struct graph_node **stack, size_t stackpos,
+ struct graph_node **visited, size_t *visitpos)
{
- struct cmd_token *first = *(struct cmd_token **) fst,
- *secnd = *(struct cmd_token **) snd;
- return strcmp (first->text, secnd->text);
-}
+ // print this node
+ char tokennum[32];
+ struct cmd_token *tok = start->data;
+ const char *color;
-vector
-completions_to_vec (struct list *completions)
-{
- vector comps = vector_init (VECTOR_MIN_SIZE);
-
- struct listnode *ln;
- struct cmd_token *token;
- unsigned int i, exists;
- for (ALL_LIST_ELEMENTS_RO(completions,ln,token))
- {
- // linear search for token in completions vector
- exists = 0;
- for (i = 0; i < vector_active (comps) && !exists; i++)
- {
- struct cmd_token *curr = vector_slot (comps, i);
- exists = !strcmp (curr->text, token->text) &&
- !strcmp (curr->desc, token->desc);
- }
+ for (size_t i = 0; i < (*visitpos); i++)
+ if (visited[i] == start)
+ return;
+ visited[(*visitpos)++] = start;
+ if ((*visitpos) == MAXDEPTH*MAXDEPTH)
+ return;
- if (!exists)
- vector_set (comps, copy_cmd_token (token));
+ snprintf(tokennum, sizeof(tokennum), "%d?", tok->type);
+ fprintf(ofd, " n%016llx [ shape=box, label=<", (unsigned long long)start);
+
+ fprintf(ofd, "<b>%s</b>", LOOKUP_DEF(tokennames, tok->type, tokennum));
+ if (tok->attr == CMD_ATTR_DEPRECATED)
+ fprintf(ofd, " (d)");
+ else if (tok->attr == CMD_ATTR_HIDDEN)
+ fprintf(ofd, " (h)");
+ if (tok->text) {
+ if (tok->type == WORD_TKN)
+ fprintf(ofd, "<br/>\"<font color=\"#0055ff\" point-size=\"11\"><b>%s</b></font>\"", tok->text);
+ else
+ fprintf(ofd, "<br/>%s", tok->text);
}
+/* if (desc)
+ fprintf(ofd, " ?'%s'", tok->desc); */
+ switch (tok->type) {
+ case START_TKN: color = "#ccffcc"; break;
+ case FORK_TKN: color = "#aaddff"; break;
+ case JOIN_TKN: color = "#ddaaff"; break;
+ case WORD_TKN: color = "#ffffff"; break;
+ default: color = "#ffffff"; break;
+ }
+ fprintf(ofd, ">, style = filled, fillcolor = \"%s\" ];\n", color);
- // sort completions
- qsort (comps->index,
- vector_active (comps),
- sizeof (void *),
- &compare_completions);
-
- return comps;
-}
+ if (stackpos == MAXDEPTH)
+ return;
+ stack[stackpos++] = start;
-static void vty_do_exit(void)
-{
- printf ("\nend.\n");
- exit (0);
+ for (unsigned int i = 0; i < vector_active (start->to); i++)
+ {
+ struct graph_node *adj = vector_slot (start->to, i);
+ // if this node is a vararg, just print *
+ if (adj == start) {
+ fprintf(ofd, " n%016llx -> n%016llx;\n",
+ (unsigned long long)start,
+ (unsigned long long)start);
+ } else if (((struct cmd_token *)adj->data)->type == END_TKN) {
+ //struct cmd_token *et = adj->data;
+ fprintf(ofd, " n%016llx -> end%016llx;\n",
+ (unsigned long long)start,
+ (unsigned long long)adj);
+ fprintf(ofd, " end%016llx [ shape=box, label=<end>, style = filled, fillcolor = \"#ffddaa\" ];\n",
+ (unsigned long long)adj);
+ } else {
+ fprintf(ofd, " n%016llx -> n%016llx;\n",
+ (unsigned long long)start,
+ (unsigned long long)adj);
+ size_t k;
+ for (k = 0; k < stackpos; k++)
+ if (stack[k] == adj)
+ break;
+ if (k == stackpos) {
+ pretty_print_dot (ofd, opts, adj, stack, stackpos, visited, visitpos);
+ }
+ }
+ }
}
-struct thread_master *master;
-int main(int argc, char **argv)
+/** stuff that should go in command.c + command.h */
+void
+init_cmdgraph (struct vty *vty, struct graph **graph)
{
- struct thread thread;
-
- master = thread_master_create ();
-
- zlog_default = openzlog ("grammar_sandbox", ZLOG_NONE, 0,
- LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
- zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
- zlog_set_level (NULL, ZLOG_DEST_STDOUT, LOG_DEBUG);
- zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
-
- /* Library inits. */
- cmd_init (1);
- host.name = strdup ("test");
-
- vty_init (master);
- memory_init ();
- grammar_sandbox_init();
-
- vty_stdio (vty_do_exit);
-
- /* Fetch next active thread. */
- while (thread_fetch (master, &thread))
- thread_call (&thread);
-
- /* Not reached. */
- exit (0);
+ // initialize graph, add start noe
+ *graph = graph_new ();
+ nodegraph_free = *graph;
+ struct cmd_token *token = new_cmd_token (START_TKN, 0, NULL, NULL);
+ graph_new_node (*graph, token, (void (*)(void *)) &del_cmd_token);
+ if (vty)
+ vty_out (vty, "initialized graph%s", VTY_NEWLINE);
}
diff --git a/lib/grammar_sandbox.h b/lib/grammar_sandbox.h
deleted file mode 100644
index 5da0b05d09..0000000000
--- a/lib/grammar_sandbox.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef _GRAMMAR_SANDBOX_H
-#define _GRAMMAR_SANDBOX_H
-
-/**
- * Houses functionality for testing shim as well as code that should go into
- * command.h and command.c during integration.
- */
-#include "memory.h"
-
-#define CMD_CR_TEXT "<cr>"
-
-void
-grammar_sandbox_init (void);
-
-/**
- * Types for tokens.
- *
- * The type determines what kind of data the token can match (in the
- * matching use case) or hold (in the argv use case).
- */
-enum cmd_token_type_t
-{
- WORD_TKN, // words
- NUMBER_TKN, // integral numbers
- VARIABLE_TKN, // almost anything
- RANGE_TKN, // integer range
- IPV4_TKN, // IPV4 addresses
- IPV4_PREFIX_TKN, // IPV4 network prefixes
- IPV6_TKN, // IPV6 prefixes
- IPV6_PREFIX_TKN, // IPV6 network prefixes
-
- /* plumbing types */
- SELECTOR_TKN, // marks beginning of selector
- OPTION_TKN, // marks beginning of option
- NUL_TKN, // dummy token
- START_TKN, // first token in line
- END_TKN, // last token in line
-};
-
-/**
- * Token struct.
- */
-struct cmd_token_t
-{
- enum cmd_token_type_t type; // token type
-
- char *text; // token text
- char *desc; // token description
-
- long long value; // for numeric types
- long long min, max; // for ranges
-
- char *arg; // user input that matches this token
-};
-
-#endif /* _GRAMMAR_SANDBOX_H */
diff --git a/lib/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c
new file mode 100644
index 0000000000..5deef406c1
--- /dev/null
+++ b/lib/grammar_sandbox_main.c
@@ -0,0 +1,64 @@
+/*
+ * Testing shim and API examples for the new CLI backend.
+ *
+ * Minimal main() to run grammar_sandbox standalone.
+ * [split off grammar_sandbox.c 2017-01-23]
+ * --
+ * Copyright (C) 2016 Cumulus Networks, Inc.
+ * Copyright (C) 2017 David Lamparter for NetDEF, Inc.
+ *
+ * This file is part of FreeRangeRouting (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 "command.h"
+#include "memory_vty.h"
+
+static void vty_do_exit(void)
+{
+ printf ("\nend.\n");
+ exit (0);
+}
+
+struct thread_master *master;
+
+int main(int argc, char **argv)
+{
+ struct thread thread;
+
+ master = thread_master_create ();
+
+ zlog_default = openzlog ("grammar_sandbox", ZLOG_NONE, 0,
+ LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
+ zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
+ zlog_set_level (NULL, ZLOG_DEST_STDOUT, LOG_DEBUG);
+ zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
+
+ /* Library inits. */
+ cmd_init (1);
+ host.name = strdup ("test");
+
+ vty_init (master);
+ memory_init ();
+
+ vty_stdio (vty_do_exit);
+
+ /* Fetch next active thread. */
+ while (thread_fetch (master, &thread))
+ thread_call (&thread);
+
+ /* Not reached. */
+ exit (0);
+}
diff --git a/lib/graph.c b/lib/graph.c
index 891ecc33c0..0992059ef1 100644
--- a/lib/graph.c
+++ b/lib/graph.c
@@ -55,11 +55,16 @@ graph_new_node (struct graph *graph, void *data, void (*del) (void*))
static void
vector_remove (vector v, unsigned int ix)
{
- vector_unset (v, ix);
- if (ix == vector_active (v)) return;
- for (; ix < vector_active (v) - 1; ix++)
- v->index[ix] = v->index[ix+1];
+ if (ix >= v->active)
+ return;
+
+ /* v->active is guaranteed >= 1 because ix can't be lower than 0
+ * and v->active is > ix. */
v->active--;
+ /* if ix == v->active--, we set the item to itself, then to NULL...
+ * still correct, no check neccessary. */
+ v->index[ix] = v->index[v->active];
+ v->index[v->active] = NULL;
}
void
@@ -71,22 +76,18 @@ graph_delete_node (struct graph *graph, struct graph_node *node)
struct graph_node *adj;
// remove all edges from other nodes to us
- vector edges = vector_copy (node->from);
- for (unsigned int i = 0; i < vector_active (edges); i++)
+ for (unsigned int i = vector_active (node->from); i--; /**/)
{
- adj = vector_slot (edges, i);
+ adj = vector_slot (node->from, i);
graph_remove_edge (adj, node);
}
- vector_free (edges);
// remove all edges from us to other nodes
- edges = vector_copy (node->to);
- for (unsigned int i = 0; i < vector_active (edges); i++)
+ for (unsigned int i = vector_active (node->to); i--; /**/)
{
- adj = vector_slot (edges, i);
+ adj = vector_slot (node->to, i);
graph_remove_edge (node, adj);
}
- vector_free (edges);
// if there is a deletion callback, call it
if (node->del && node->data)
@@ -97,9 +98,12 @@ graph_delete_node (struct graph *graph, struct graph_node *node)
vector_free (node->from);
// remove node from graph->nodes
- for (unsigned int i = 0; i < vector_active (graph->nodes); i++)
+ for (unsigned int i = vector_active (graph->nodes); i--; /**/)
if (vector_slot (graph->nodes, i) == node)
- vector_remove (graph->nodes, i);
+ {
+ vector_remove (graph->nodes, i);
+ break;
+ }
// free the node itself
XFREE (MTYPE_GRAPH_NODE, node);
@@ -117,20 +121,26 @@ void
graph_remove_edge (struct graph_node *from, struct graph_node *to)
{
// remove from from to->from
- for (unsigned int i = 0; i < vector_active (to->from); i++)
+ for (unsigned int i = vector_active (to->from); i--; /**/)
if (vector_slot (to->from, i) == from)
- vector_remove (to->from, i);
+ {
+ vector_remove (to->from, i);
+ break;
+ }
// remove to from from->to
- for (unsigned int i = 0; i < vector_active (from->to); i++)
+ for (unsigned int i = vector_active (from->to); i--; /**/)
if (vector_slot (from->to, i) == to)
- vector_remove (from->to, i);
+ {
+ vector_remove (from->to, i);
+ break;
+ }
}
void
graph_delete_graph (struct graph *graph)
{
// delete each node in the graph
- for (unsigned int i = 0; i < vector_active (graph->nodes); i++)
+ for (unsigned int i = vector_active (graph->nodes); i--; /**/)
graph_delete_node (graph, vector_slot (graph->nodes, i));
vector_free (graph->nodes);
diff --git a/lib/log.c b/lib/log.c
index d48534dc18..b8e505f347 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -118,7 +118,6 @@ quagga_timestamp(int timestamp_precision, char *buf, size_t buflen)
} cache;
struct timeval clock;
- /* would it be sufficient to use global 'recent_time' here? I fear not... */
gettimeofday(&clock, NULL);
/* first, we update the cache if the time has changed */
@@ -989,6 +988,7 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY (ZEBRA_IPV4_NEXTHOP_DELETE),
DESC_ENTRY (ZEBRA_IPV6_NEXTHOP_ADD),
DESC_ENTRY (ZEBRA_IPV6_NEXTHOP_DELETE),
+ DESC_ENTRY (ZEBRA_IPMR_ROUTE_STATS),
};
#undef DESC_ENTRY
diff --git a/lib/monotime.h b/lib/monotime.h
new file mode 100644
index 0000000000..0fd4940431
--- /dev/null
+++ b/lib/monotime.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2017 David Lamparter, for NetDEF, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FRR_MONOTIME_H
+#define _FRR_MONOTIME_H
+
+#include <stdint.h>
+#include <time.h>
+#include <sys/time.h>
+
+#ifndef TIMESPEC_TO_TIMEVAL
+/* should be in sys/time.h on BSD & Linux libcs */
+#define TIMESPEC_TO_TIMEVAL(tv, ts) do { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+ } while (0)
+#endif
+#ifndef TIMEVAL_TO_TIMESPEC
+/* should be in sys/time.h on BSD & Linux libcs */
+#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+ } while (0)
+#endif
+
+static inline time_t monotime(struct timeval *tvo)
+{
+ struct timespec ts;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (tvo) {
+ TIMESPEC_TO_TIMEVAL(tvo, &ts);
+ }
+ return ts.tv_sec;
+}
+
+/* the following two return microseconds, not time_t!
+ *
+ * also, they're negative forms of each other, but having both makes the
+ * code more readable
+ */
+static inline int64_t monotime_since(const struct timeval *ref,
+ struct timeval *out)
+{
+ struct timeval tv;
+ monotime(&tv);
+ timersub(&tv, ref, &tv);
+ if (out)
+ *out = tv;
+ return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
+}
+
+static inline int64_t monotime_until(const struct timeval *ref,
+ struct timeval *out)
+{
+ struct timeval tv;
+ monotime(&tv);
+ timersub(ref, &tv, &tv);
+ if (out)
+ *out = tv;
+ return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
+}
+
+#endif /* _FRR_MONOTIME_H */
diff --git a/lib/network.c b/lib/network.c
index 506e019136..2b6f2fbab5 100644
--- a/lib/network.c
+++ b/lib/network.c
@@ -62,8 +62,13 @@ writen(int fd, const u_char *ptr, int nbytes)
while (nleft > 0)
{
nwritten = write(fd, ptr, nleft);
-
- if (nwritten <= 0)
+
+ if (nwritten < 0)
+ {
+ if (!ERRNO_IO_RETRY(errno))
+ return nwritten;
+ }
+ if (nwritten == 0)
return (nwritten);
nleft -= nwritten;
diff --git a/lib/routemap.c b/lib/routemap.c
index 74bae1fd76..70f3069a36 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -710,6 +710,7 @@ enum route_map_dep_type
ROUTE_MAP_DEP_RMAP = 1,
ROUTE_MAP_DEP_CLIST,
ROUTE_MAP_DEP_ECLIST,
+ ROUTE_MAP_DEP_LCLIST,
ROUTE_MAP_DEP_PLIST,
ROUTE_MAP_DEP_ASPATH,
ROUTE_MAP_DEP_FILTER,
@@ -1819,6 +1820,7 @@ route_map_dep_update (struct hash *dephash, const char *dep_name,
case RMAP_EVENT_CLIST_ADDED:
case RMAP_EVENT_ECLIST_ADDED:
case RMAP_EVENT_ASLIST_ADDED:
+ case RMAP_EVENT_LLIST_ADDED:
case RMAP_EVENT_CALL_ADDED:
case RMAP_EVENT_FILTER_ADDED:
if (rmap_debug)
@@ -1840,6 +1842,7 @@ route_map_dep_update (struct hash *dephash, const char *dep_name,
case RMAP_EVENT_CLIST_DELETED:
case RMAP_EVENT_ECLIST_DELETED:
case RMAP_EVENT_ASLIST_DELETED:
+ case RMAP_EVENT_LLIST_DELETED:
case RMAP_EVENT_CALL_DELETED:
case RMAP_EVENT_FILTER_DELETED:
if (rmap_debug)
@@ -1902,6 +1905,10 @@ route_map_get_dep_hash (route_map_event_t event)
case RMAP_EVENT_ASLIST_DELETED:
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
break;
+ case RMAP_EVENT_LLIST_ADDED:
+ case RMAP_EVENT_LLIST_DELETED:
+ upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
+ break;
case RMAP_EVENT_CALL_ADDED:
case RMAP_EVENT_CALL_DELETED:
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
diff --git a/lib/routemap.h b/lib/routemap.h
index b52f7289b0..b378c64eae 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -84,6 +84,8 @@ typedef enum
RMAP_EVENT_CLIST_DELETED,
RMAP_EVENT_ECLIST_ADDED,
RMAP_EVENT_ECLIST_DELETED,
+ RMAP_EVENT_LLIST_ADDED,
+ RMAP_EVENT_LLIST_DELETED,
RMAP_EVENT_ASLIST_ADDED,
RMAP_EVENT_ASLIST_DELETED,
RMAP_EVENT_FILTER_ADDED,
diff --git a/lib/thread.c b/lib/thread.c
index 64eaae45b9..de7066bb82 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -41,151 +41,16 @@ DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats")
#include <mach/mach_time.h>
#endif
-/* Recent absolute time of day */
-struct timeval recent_time;
/* Relative time, since startup */
-static struct timeval relative_time;
-
static struct hash *cpu_record = NULL;
-/* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
- And change negative values to 0. */
-static struct timeval
-timeval_adjust (struct timeval a)
-{
- while (a.tv_usec >= TIMER_SECOND_MICRO)
- {
- a.tv_usec -= TIMER_SECOND_MICRO;
- a.tv_sec++;
- }
-
- while (a.tv_usec < 0)
- {
- a.tv_usec += TIMER_SECOND_MICRO;
- a.tv_sec--;
- }
-
- if (a.tv_sec < 0)
- /* Change negative timeouts to 0. */
- a.tv_sec = a.tv_usec = 0;
-
- return a;
-}
-
-static struct timeval
-timeval_subtract (struct timeval a, struct timeval b)
-{
- struct timeval ret;
-
- ret.tv_usec = a.tv_usec - b.tv_usec;
- ret.tv_sec = a.tv_sec - b.tv_sec;
-
- return timeval_adjust (ret);
-}
-
-static long
-timeval_cmp (struct timeval a, struct timeval b)
-{
- return (a.tv_sec == b.tv_sec
- ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
-}
-
-unsigned long
+static unsigned long
timeval_elapsed (struct timeval a, struct timeval b)
{
return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
+ (a.tv_usec - b.tv_usec));
}
-/* gettimeofday wrapper, to keep recent_time updated */
-static int
-quagga_gettimeofday (struct timeval *tv)
-{
- int ret;
-
- assert (tv);
-
- if (!(ret = gettimeofday (&recent_time, NULL)))
- {
- /* avoid copy if user passed recent_time pointer.. */
- if (tv != &recent_time)
- *tv = recent_time;
- return 0;
- }
- return ret;
-}
-
-static int
-quagga_get_relative (struct timeval *tv)
-{
- int ret;
-
-#ifdef HAVE_CLOCK_MONOTONIC
- {
- struct timespec tp;
- if (!(ret = clock_gettime (CLOCK_MONOTONIC, &tp)))
- {
- relative_time.tv_sec = tp.tv_sec;
- relative_time.tv_usec = tp.tv_nsec / 1000;
- }
- }
-#elif defined(__APPLE__)
- {
- uint64_t ticks;
- uint64_t useconds;
- static mach_timebase_info_data_t timebase_info;
-
- ticks = mach_absolute_time();
- if (timebase_info.denom == 0)
- mach_timebase_info(&timebase_info);
-
- useconds = ticks * timebase_info.numer / timebase_info.denom / 1000;
- relative_time.tv_sec = useconds / 1000000;
- relative_time.tv_usec = useconds % 1000000;
-
- return 0;
- }
-#else /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */
-#error no monotonic clock on this system
-#endif /* HAVE_CLOCK_MONOTONIC */
-
- if (tv)
- *tv = relative_time;
-
- return ret;
-}
-
-/* Exported Quagga timestamp function.
- * Modelled on POSIX clock_gettime.
- */
-int
-quagga_gettime (enum quagga_clkid clkid, struct timeval *tv)
-{
- switch (clkid)
- {
- case QUAGGA_CLK_MONOTONIC:
- return quagga_get_relative (tv);
- default:
- errno = EINVAL;
- return -1;
- }
-}
-
-time_t
-quagga_monotime (void)
-{
- struct timeval tv;
- quagga_get_relative(&tv);
- return tv.tv_sec;
-}
-
-/* Public export of recent_relative_time by value */
-struct timeval
-recent_relative_time (void)
-{
- return relative_time;
-}
-
static unsigned int
cpu_record_hash_key (struct cpu_thread_history *a)
{
@@ -437,11 +302,9 @@ thread_timer_cmp(void *a, void *b)
struct thread *thread_a = a;
struct thread *thread_b = b;
- long cmp = timeval_cmp(thread_a->u.sands, thread_b->u.sands);
-
- if (cmp < 0)
+ if (timercmp (&thread_a->u.sands, &thread_b->u.sands, <))
return -1;
- if (cmp > 0)
+ if (timercmp (&thread_a->u.sands, &thread_b->u.sands, >))
return 1;
return 0;
}
@@ -671,12 +534,8 @@ thread_master_free (struct thread_master *m)
unsigned long
thread_timer_remain_second (struct thread *thread)
{
- quagga_get_relative (NULL);
-
- if (thread->u.sands.tv_sec - relative_time.tv_sec > 0)
- return thread->u.sands.tv_sec - relative_time.tv_sec;
- else
- return 0;
+ int64_t remain = monotime_until(&thread->u.sands, NULL) / 1000000LL;
+ return remain < 0 ? 0 : remain;
}
#define debugargdef const char *funcname, const char *schedfrom, int fromln
@@ -685,9 +544,9 @@ thread_timer_remain_second (struct thread *thread)
struct timeval
thread_timer_remain(struct thread *thread)
{
- quagga_get_relative(NULL);
-
- return timeval_subtract(thread->u.sands, relative_time);
+ struct timeval remain;
+ monotime_until(&thread->u.sands, &remain);
+ return remain;
}
/* Get new thread. */
@@ -887,7 +746,6 @@ funcname_thread_add_timer_timeval (struct thread_master *m,
{
struct thread *thread;
struct pqueue *queue;
- struct timeval alarm_time;
assert (m != NULL);
@@ -897,11 +755,8 @@ funcname_thread_add_timer_timeval (struct thread_master *m,
queue = ((type == THREAD_TIMER) ? m->timer : m->background);
thread = thread_get (m, type, func, arg, debugargpass);
- /* Do we need jitter here? */
- quagga_get_relative (NULL);
- alarm_time.tv_sec = relative_time.tv_sec + time_relative->tv_sec;
- alarm_time.tv_usec = relative_time.tv_usec + time_relative->tv_usec;
- thread->u.sands = timeval_adjust(alarm_time);
+ monotime(&thread->u.sands);
+ timeradd(&thread->u.sands, time_relative, &thread->u.sands);
pqueue_enqueue(thread, queue);
return thread;
@@ -1137,7 +992,7 @@ thread_timer_wait (struct pqueue *queue, struct timeval *timer_val)
if (queue->size)
{
struct thread *next_timer = queue->array[0];
- *timer_val = timeval_subtract (next_timer->u.sands, relative_time);
+ monotime_until(&next_timer->u.sands, timer_val);
return timer_val;
}
return NULL;
@@ -1265,7 +1120,7 @@ thread_timer_process (struct pqueue *queue, struct timeval *timenow)
while (queue->size)
{
thread = queue->array[0];
- if (timeval_cmp (*timenow, thread->u.sands) < 0)
+ if (timercmp (timenow, &thread->u.sands, <))
return ready;
pqueue_dequeue(queue);
thread->type = THREAD_READY;
@@ -1303,6 +1158,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
thread_fd_set readfd;
thread_fd_set writefd;
thread_fd_set exceptfd;
+ struct timeval now;
struct timeval timer_val = { .tv_sec = 0, .tv_usec = 0 };
struct timeval timer_val_bg;
struct timeval *timer_wait = &timer_val;
@@ -1339,15 +1195,20 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
/* Calculate select wait timer if nothing else to do */
if (m->ready.count == 0)
{
- quagga_get_relative (NULL);
timer_wait = thread_timer_wait (m->timer, &timer_val);
timer_wait_bg = thread_timer_wait (m->background, &timer_val_bg);
if (timer_wait_bg &&
- (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
+ (!timer_wait || (timercmp (timer_wait, timer_wait_bg, >))))
timer_wait = timer_wait_bg;
}
+ if (timer_wait && timer_wait->tv_sec < 0)
+ {
+ timerclear(&timer_val);
+ timer_wait = &timer_val;
+ }
+
num = fd_select (m, FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
/* Signals should get quick treatment */
@@ -1362,8 +1223,8 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
/* Check foreground timers. Historically, they have had higher
priority than I/O threads, so let's push them onto the ready
list in front of the I/O threads. */
- quagga_get_relative (NULL);
- thread_timer_process (m->timer, &relative_time);
+ monotime(&now);
+ thread_timer_process (m->timer, &now);
/* Got IO, process it */
if (num > 0)
@@ -1379,7 +1240,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
#endif
/* Background timer/events, lowest priority */
- thread_timer_process (m->background, &relative_time);
+ thread_timer_process (m->background, &now);
if ((thread = thread_trim_head (&m->ready)) != NULL)
return thread_run (m, thread, fetch);
@@ -1408,9 +1269,7 @@ thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
int
thread_should_yield (struct thread *thread)
{
- quagga_get_relative (NULL);
- return (timeval_elapsed(relative_time, thread->real) >
- thread->yield);
+ return monotime_since(&thread->real, NULL) > (int64_t)thread->yield;
}
void
@@ -1422,17 +1281,8 @@ thread_set_yield_time (struct thread *thread, unsigned long yield_time)
void
thread_getrusage (RUSAGE_T *r)
{
- quagga_get_relative (NULL);
+ monotime(&r->real);
getrusage(RUSAGE_SELF, &(r->cpu));
- r->real = relative_time;
-
-#ifdef HAVE_CLOCK_MONOTONIC
- /* quagga_get_relative() only updates recent_time if gettimeofday
- * based, not when using CLOCK_MONOTONIC. As we export recent_time
- * and guarantee to update it before threads are run...
- */
- quagga_gettimeofday(&recent_time);
-#endif /* HAVE_CLOCK_MONOTONIC */
}
struct thread *thread_current = NULL;
diff --git a/lib/thread.h b/lib/thread.h
index c22bb4828d..a0801e1ecd 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -23,6 +23,7 @@
#define _ZEBRA_THREAD_H
#include <zebra.h>
+#include "monotime.h"
struct rusage_t
{
@@ -239,7 +240,6 @@ extern void thread_call (struct thread *);
extern unsigned long thread_timer_remain_second (struct thread *);
extern struct timeval thread_timer_remain(struct thread*);
extern int thread_should_yield (struct thread *);
-extern unsigned long timeval_elapsed (struct timeval a, struct timeval b);
/* set yield time for thread */
extern void thread_set_yield_time (struct thread *, unsigned long);
@@ -247,13 +247,6 @@ extern void thread_set_yield_time (struct thread *, unsigned long);
extern void thread_getrusage (RUSAGE_T *);
extern void thread_cmd_init (void);
-/* replacements for the system gettimeofday(), clock_gettime() and
- * time() functions, providing support for non-decrementing clock on
- * all systems, and fully monotonic on /some/ systems.
- */
-extern int quagga_gettime (enum quagga_clkid, struct timeval *);
-extern time_t quagga_monotime (void);
-
/* Returns elapsed real (wall clock) time. */
extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before,
unsigned long *cpu_time_elapsed);
@@ -262,8 +255,6 @@ extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before,
be used instead of calling gettimeofday if a recent value is sufficient.
This is guaranteed to be refreshed before a thread is called. */
extern struct timeval recent_time;
-/* Similar to recent_time, but a monotonically increasing time value */
-extern struct timeval recent_relative_time (void);
/* only for use in logging functions! */
extern struct thread *thread_current;
diff --git a/lib/vrf.h b/lib/vrf.h
index 96c716a7b8..f8bb07ef48 100644
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -34,6 +34,7 @@
/* The default VRF ID */
#define VRF_DEFAULT 0
#define VRF_UNKNOWN UINT16_MAX
+#define VRF_ALL UINT16_MAX - 1
/* Pending: May need to refine this. */
#ifndef IFLA_VRF_MAX
diff --git a/lib/vty.c b/lib/vty.c
index a435706d1f..9413d003ef 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -742,6 +742,7 @@ vty_end_config (struct vty *vty)
case BGP_VPNV6_NODE:
case BGP_ENCAP_NODE:
case BGP_ENCAPV6_NODE:
+ case BGP_VRF_POLICY_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
case BGP_VNC_L2_GROUP_NODE:
diff --git a/lib/zclient.c b/lib/zclient.c
index a4c5fa4afb..42fa41c9c8 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -1626,6 +1626,7 @@ zclient_read (struct thread *thread)
case ZEBRA_REDISTRIBUTE_IPV6_DEL:
if (zclient->redistribute_route_ipv6_del)
(*zclient->redistribute_route_ipv6_del) (command, zclient, length, vrf_id);
+ break;
case ZEBRA_INTERFACE_LINK_PARAMS:
if (zclient->interface_link_params)
(*zclient->interface_link_params) (command, zclient, length);
diff --git a/lib/zebra.h b/lib/zebra.h
index c9be1892e4..bb43d062bc 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -405,6 +405,7 @@ typedef enum {
ZEBRA_IPV4_NEXTHOP_DELETE,
ZEBRA_IPV6_NEXTHOP_ADD,
ZEBRA_IPV6_NEXTHOP_DELETE,
+ ZEBRA_IPMR_ROUTE_STATS,
} zebra_message_types_t;
/* Marker value used in new Zserv, in the byte location corresponding
@@ -477,6 +478,12 @@ typedef enum {
#define SAFI_RESERVED_5 5
#define SAFI_MAX 6
+#define IANA_SAFI_RESERVED 0
+#define IANA_SAFI_UNICAST 1
+#define IANA_SAFI_MULTICAST 2
+#define IANA_SAFI_ENCAP 7
+#define IANA_SAFI_MPLS_VPN 128
+
/*
* The above AFI and SAFI definitions are for internal use. The protocol
* definitions (IANA values) as for example used in BGP protocol packets
@@ -486,12 +493,14 @@ typedef enum {
* not optimal for use in data-structure sizing.
* Note: Only useful (i.e., supported) values are defined below.
*/
-#define IANA_AFI_RESERVED 0
-#define IANA_AFI_IPV4 1
-#define IANA_AFI_IPV6 2
-#define IANA_AFI_L2VPN 25
-#define IANA_AFI_IPMR 128
-#define IANA_AFI_IP6MR 129
+typedef enum {
+ IANA_AFI_RESERVED = 0,
+ IANA_AFI_IPV4 = 1,
+ IANA_AFI_IPV6 = 2,
+ IANA_AFI_L2VPN = 25,
+ IANA_AFI_IPMR = 128,
+ IANA_AFI_IP6MR = 129
+} iana_afi_t;
#define IANA_SAFI_RESERVED 0
#define IANA_SAFI_UNICAST 1
@@ -531,7 +540,7 @@ typedef uint32_t route_tag_t;
#define ROUTE_TAG_MAX UINT32_MAX
#define ROUTE_TAG_PRI PRIu32
-static inline afi_t afi_iana2int (afi_t afi)
+static inline afi_t afi_iana2int (iana_afi_t afi)
{
if (afi == IANA_AFI_IPV4)
return AFI_IP;
@@ -540,7 +549,7 @@ static inline afi_t afi_iana2int (afi_t afi)
return AFI_MAX;
}
-static inline afi_t afi_int2iana (afi_t afi)
+static inline iana_afi_t afi_int2iana (afi_t afi)
{
if (afi == AFI_IP)
return IANA_AFI_IPV4;
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
index f75a35fa50..2e31535d24 100644
--- a/ospf6d/ospf6_abr.c
+++ b/ospf6d/ospf6_abr.c
@@ -433,7 +433,7 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
else
{
summary->type = route->type;
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &summary->changed);
+ monotime(&summary->changed);
}
summary->path.router_bits = route->path.router_bits;
diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c
index d9cf97a713..198526a0eb 100644
--- a/ospf6d/ospf6_area.c
+++ b/ospf6d/ospf6_area.c
@@ -388,7 +388,7 @@ ospf6_area_show (struct vty *vty, struct ospf6_area *oa)
if (oa->ts_spf.tv_sec || oa->ts_spf.tv_usec)
{
- result = timeval_elapsed (recent_relative_time (), oa->ts_spf);
+ result = monotime_since(&oa->ts_spf, NULL);
if (result/TIMER_SECOND_MICRO > 0)
{
vty_out (vty, "SPF last executed %ld.%lds ago%s",
diff --git a/ospf6d/ospf6_bfd.c b/ospf6d/ospf6_bfd.c
index 28126918b5..fed5021208 100644
--- a/ospf6d/ospf6_bfd.c
+++ b/ospf6d/ospf6_bfd.c
@@ -245,7 +245,7 @@ ospf6_bfd_interface_dest_update (int command, struct zclient *zclient,
old_status = bfd_info->status;
bfd_info->status = status;
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &tv);
+ monotime(&tv);
bfd_info->last_update = tv.tv_sec;
if ((status == BFD_STATUS_DOWN) && (old_status == BFD_STATUS_UP))
diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c
index 14c16c0241..6ac93d8984 100644
--- a/ospf6d/ospf6_flood.c
+++ b/ospf6d/ospf6_flood.c
@@ -224,7 +224,7 @@ ospf6_install_lsa (struct ospf6_lsa *lsa)
ospf6_flood_clear (old);
}
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
+ monotime(&now);
if (! OSPF6_LSA_IS_MAXAGE (lsa))
lsa->expire = thread_add_timer (master, ospf6_lsa_expire, lsa,
OSPF_LSA_MAXAGE + lsa->birth.tv_sec - now.tv_sec);
@@ -862,7 +862,7 @@ ospf6_receive_lsa (struct ospf6_neighbor *from,
if (old)
{
struct timeval now, res;
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
+ monotime(&now);
timersub (&now, &old->installed, &res);
time_delta_ms = (res.tv_sec * 1000) + (int)(res.tv_usec/1000);
if (time_delta_ms < from->ospf6_if->area->ospf6->lsa_minarrival)
@@ -875,7 +875,7 @@ ospf6_receive_lsa (struct ospf6_neighbor *from,
}
}
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &new->received);
+ monotime(&new->received);
if (is_debug)
zlog_debug ("Install, Flood, Possibly acknowledge the received LSA");
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index 0ed8d30a8b..c458098099 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -961,7 +961,7 @@ ospf6_interface_show (struct vty *vty, struct interface *ifp)
vty_out (vty, " Number of I/F scoped LSAs is %u%s",
oi->lsdb->count, VNL);
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
+ monotime(&now);
timerclear (&res);
if (oi->thread_send_lsupdate)
diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c
index 586bd77f75..d93406fb68 100644
--- a/ospf6d/ospf6_intra.c
+++ b/ospf6d/ospf6_intra.c
@@ -1485,11 +1485,11 @@ ospf6_brouter_debug_print (struct ospf6_route *brouter)
ospf6_linkstate_prefix2str (&brouter->prefix, destination,
sizeof (destination));
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
+ monotime(&now);
timersub (&now, &brouter->installed, &res);
timerstring (&res, installed, sizeof (installed));
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
+ monotime(&now);
timersub (&now, &brouter->changed, &res);
timerstring (&res, changed, sizeof (changed));
diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c
index 06962ec069..bea153c928 100644
--- a/ospf6d/ospf6_lsa.c
+++ b/ospf6d/ospf6_lsa.c
@@ -207,9 +207,7 @@ ospf6_lsa_age_set (struct ospf6_lsa *lsa)
assert (lsa && lsa->header);
- if (quagga_gettime (QUAGGA_CLK_MONOTONIC, &now) < 0)
- zlog_warn ("LSA: quagga_gettime failed, may fail LSA AGEs: %s",
- safe_strerror (errno));
+ monotime(&now);
lsa->birth.tv_sec = now.tv_sec - ntohs (lsa->header->age);
lsa->birth.tv_usec = now.tv_usec;
@@ -230,9 +228,7 @@ ospf6_lsa_age_current (struct ospf6_lsa *lsa)
assert (lsa->header);
/* current time */
- if (quagga_gettime (QUAGGA_CLK_MONOTONIC, &now) < 0)
- zlog_warn ("LSA: quagga_gettime failed, may fail LSA AGEs: %s",
- safe_strerror (errno));
+ monotime(&now);
if (ntohs (lsa->header->age) >= OSPF_LSA_MAXAGE)
{
@@ -513,7 +509,7 @@ ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
inet_ntop (AF_INET, &lsa->header->adv_router,
adv_router, sizeof (adv_router));
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
+ monotime(&now);
timersub (&now, &lsa->installed, &res);
timerstring (&res, duration, sizeof (duration));
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index e9a25d37e5..578b39a641 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -1817,10 +1817,7 @@ ospf6_dbdesc_send (struct thread *thread)
if (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT) &&
(on->dbdesc_seqnum == 0))
{
- struct timeval tv;
- if (quagga_gettime (QUAGGA_CLK_MONOTONIC, &tv) < 0)
- tv.tv_sec = 1;
- on->dbdesc_seqnum = tv.tv_sec;
+ on->dbdesc_seqnum = monotime(NULL);
}
dbdesc->options[0] = on->ospf6_if->area->options[0];
diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c
index e9bb2493ff..ec79a1552b 100644
--- a/ospf6d/ospf6_neighbor.c
+++ b/ospf6d/ospf6_neighbor.c
@@ -97,7 +97,7 @@ ospf6_neighbor_create (u_int32_t router_id, struct ospf6_interface *oi)
on->ospf6_if = oi;
on->state = OSPF6_NEIGHBOR_DOWN;
on->state_change = 0;
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &on->last_changed);
+ monotime(&on->last_changed);
on->router_id = router_id;
on->summary_list = ospf6_lsdb_create (on);
@@ -163,7 +163,7 @@ ospf6_neighbor_state_change (u_char next_state, struct ospf6_neighbor *on, int e
return;
on->state_change++;
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &on->last_changed);
+ monotime(&on->last_changed);
/* log */
if (IS_OSPF6_DEBUG_NEIGHBOR (STATE))
@@ -633,7 +633,7 @@ ospf6_neighbor_show (struct vty *vty, struct ospf6_neighbor *on)
{
char router_id[16];
char duration[16];
- struct timeval now, res;
+ struct timeval res;
char nstate[16];
char deadtime[16];
long h, m, s;
@@ -645,13 +645,11 @@ ospf6_neighbor_show (struct vty *vty, struct ospf6_neighbor *on)
}
#endif /*HAVE_GETNAMEINFO*/
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
-
/* Dead time */
h = m = s = 0;
if (on->inactivity_timer)
{
- s = on->inactivity_timer->u.sands.tv_sec - recent_relative_time().tv_sec;
+ s = monotime_until(&on->inactivity_timer->u.sands, NULL) / 1000000LL;
h = s / 3600;
s -= h * 3600;
m = s / 60;
@@ -673,7 +671,7 @@ ospf6_neighbor_show (struct vty *vty, struct ospf6_neighbor *on)
}
/* Duration */
- timersub (&now, &on->last_changed, &res);
+ monotime_since(&on->last_changed, &res);
timerstring (&res, duration, sizeof (duration));
/*
@@ -707,7 +705,7 @@ ospf6_neighbor_show_drchoice (struct vty *vty, struct ospf6_neighbor *on)
inet_ntop (AF_INET, &on->drouter, drouter, sizeof (drouter));
inet_ntop (AF_INET, &on->bdrouter, bdrouter, sizeof (bdrouter));
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
+ monotime(&now);
timersub (&now, &on->last_changed, &res);
timerstring (&res, duration, sizeof (duration));
@@ -731,7 +729,7 @@ ospf6_neighbor_show_detail (struct vty *vty, struct ospf6_neighbor *on)
inet_ntop (AF_INET, &on->drouter, drouter, sizeof (drouter));
inet_ntop (AF_INET, &on->bdrouter, bdrouter, sizeof (bdrouter));
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
+ monotime(&now);
timersub (&now, &on->last_changed, &res);
timerstring (&res, duration, sizeof (duration));
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c
index 2f416e2689..29956c61a0 100644
--- a/ospf6d/ospf6_route.c
+++ b/ospf6d/ospf6_route.c
@@ -600,7 +600,7 @@ ospf6_route_add (struct ospf6_route *route,
else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
zlog_debug ("%s: route add: %s", ospf6_route_table_name (table), buf);
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
+ monotime(&now);
node = route_node_get (table->table, &route->prefix);
route->rnode = node;
@@ -1020,7 +1020,7 @@ ospf6_route_show (struct vty *vty, struct ospf6_route *route)
struct listnode *node;
struct ospf6_nexthop *nh;
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
+ monotime(&now);
timersub (&now, &route->changed, &res);
timerstring (&res, duration, sizeof (duration));
@@ -1068,7 +1068,7 @@ ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route)
struct listnode *node;
struct ospf6_nexthop *nh;
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
+ monotime(&now);
/* destination */
if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c
index 04519e7d46..333ce5588e 100644
--- a/ospf6d/ospf6_spf.c
+++ b/ospf6d/ospf6_spf.c
@@ -603,7 +603,7 @@ ospf6_spf_calculation_thread (struct thread *t)
ospf6->t_spf_calc = NULL;
/* execute SPF calculation */
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &start);
+ monotime(&start);
if (ospf6_is_router_abr (ospf6))
ospf6_abr_range_reset_cost (ospf6);
@@ -644,7 +644,7 @@ ospf6_spf_calculation_thread (struct thread *t)
if (ospf6_is_router_abr (ospf6))
ospf6_abr_defaults_to_stub (ospf6);
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &end);
+ monotime(&end);
timersub (&end, &start, &runtime);
ospf6->ts_spf_duration = runtime;
@@ -670,7 +670,6 @@ void
ospf6_spf_schedule (struct ospf6 *ospf6, unsigned int reason)
{
unsigned long delay, elapsed, ht;
- struct timeval now, result;
ospf6_set_spf_reason(ospf6, reason);
@@ -694,11 +693,7 @@ ospf6_spf_schedule (struct ospf6 *ospf6, unsigned int reason)
return;
}
- /* XXX Monotic timers: we only care about relative time here. */
- now = recent_relative_time ();
- timersub (&now, &ospf6->ts_spf, &result);
-
- elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000);
+ elapsed = monotime_since(&ospf6->ts_spf, NULL) / 1000LL;
ht = ospf6->spf_holdtime * ospf6->spf_hold_multiplier;
if (ht > ospf6->spf_max_holdtime)
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index 6da9680fe2..92111c73fc 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -124,7 +124,7 @@ ospf6_create (void)
o = XCALLOC (MTYPE_OSPF6_TOP, sizeof (struct ospf6));
/* initialize */
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &o->starttime);
+ monotime(&o->starttime);
o->area_list = list_new ();
o->area_list->cmp = ospf6_area_cmp;
o->lsdb = ospf6_lsdb_create (o);
@@ -891,7 +891,7 @@ ospf6_show (struct vty *vty, struct ospf6 *o)
router_id, VNL);
/* running time */
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
+ monotime(&now);
timersub (&now, &o->starttime, &running);
timerstring (&running, duration, sizeof (duration));
vty_out (vty, " Running %s%s", duration, VNL);
diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h
index b41e8ff001..f0bc022749 100644
--- a/ospf6d/ospf6d.h
+++ b/ospf6d/ospf6d.h
@@ -58,21 +58,6 @@ extern struct thread_master *master;
#define OSPF6_NEIGHBOR(x) ((struct ospf6_neighbor *) (x))
/* operation on timeval structure */
-#ifndef timerclear
-#define timerclear(a) (a)->tv_sec = (tvp)->tv_usec = 0
-#endif /*timerclear*/
-#ifndef timersub
-#define timersub(a, b, res) \
- do { \
- (res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
- (res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
- if ((res)->tv_usec < 0) \
- { \
- (res)->tv_sec--; \
- (res)->tv_usec += 1000000; \
- } \
- } while (0)
-#endif /*timersub*/
#define timerstring(tv, buf, size) \
do { \
if ((tv)->tv_sec / 60 / 60 / 24) \
@@ -87,15 +72,6 @@ extern struct thread_master *master;
(tv)->tv_sec / 60LL % 60, \
(tv)->tv_sec % 60LL); \
} while (0)
-#define timerstring_local(tv, buf, size) \
- do { \
- int ret; \
- struct tm *tm; \
- tm = localtime (&(tv)->tv_sec); \
- ret = strftime (buf, size, "%Y/%m/%d %H:%M:%S", tm); \
- if (ret == 0) \
- zlog_warn ("strftime error"); \
- } while (0)
#define threadtimer_string(now, t, buf, size) \
do { \
diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c
index fe40b10171..b063f317e2 100644
--- a/ospfd/ospf_ase.c
+++ b/ospfd/ospf_ase.c
@@ -649,7 +649,7 @@ ospf_ase_calculate_timer (struct thread *t)
{
ospf->ase_calc = 0;
- quagga_gettime(QUAGGA_CLK_MONOTONIC, &start_time);
+ monotime(&start_time);
/* Calculate external route for each AS-external-LSA */
LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa)
@@ -681,7 +681,7 @@ ospf_ase_calculate_timer (struct thread *t)
ospf->old_external_route = ospf->new_external_route;
ospf->new_external_route = route_table_init ();
- quagga_gettime(QUAGGA_CLK_MONOTONIC, &stop_time);
+ monotime(&stop_time);
zlog_info ("SPF Processing Time(usecs): External Routes: %lld\n",
(stop_time.tv_sec - start_time.tv_sec)*1000000LL+
diff --git a/ospfd/ospf_bfd.c b/ospfd/ospf_bfd.c
index b4d50a6b9f..74bc38220b 100644
--- a/ospfd/ospf_bfd.c
+++ b/ospfd/ospf_bfd.c
@@ -249,7 +249,7 @@ ospf_bfd_interface_dest_update (int command, struct zclient *zclient,
old_status = bfd_info->status;
bfd_info->status = status;
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &tv);
+ monotime(&tv);
bfd_info->last_update = tv.tv_sec;
if ((status == BFD_STATUS_DOWN) && (old_status == BFD_STATUS_UP))
diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c
index 4e9797184d..6e9e59f9b7 100644
--- a/ospfd/ospf_dump.c
+++ b/ospfd/ospf_dump.c
@@ -22,6 +22,7 @@
#include <zebra.h>
+#include "monotime.h"
#include "linklist.h"
#include "thread.h"
#include "prefix.h"
@@ -317,8 +318,8 @@ ospf_timer_dump (struct thread *t, char *buf, size_t size)
struct timeval result;
if (!t)
return "inactive";
-
- result = tv_sub (t->u.sands, recent_relative_time());
+
+ monotime_until (&t->u.sands, &result);
return ospf_timeval_dump (&result, buf, size);
}
diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c
index 7f83ddeaae..417a7aa8d2 100644
--- a/ospfd/ospf_flood.c
+++ b/ospfd/ospf_flood.c
@@ -22,6 +22,7 @@
#include <zebra.h>
+#include "monotime.h"
#include "linklist.h"
#include "prefix.h"
#include "if.h"
@@ -277,8 +278,8 @@ ospf_flood (struct ospf *ospf, struct ospf_neighbor *nbr,
"while local one is initial instance.");
; /* Accept this LSA for quick LSDB resynchronization. */
}
- else if (tv_cmp (tv_sub (recent_relative_time (), current->tv_recv),
- msec2tv (ospf->min_ls_arrival)) < 0)
+ else if (monotime_since (&current->tv_recv, NULL)
+ < ospf->min_ls_arrival * 1000LL)
{
if (IS_DEBUG_OSPF_EVENT)
zlog_debug ("LSA[Flooding]: LSA is received recently.");
@@ -969,7 +970,7 @@ ospf_lsa_flush_area (struct ospf_lsa *lsa, struct ospf_area *area)
more time for the ACK to be received and avoid
retransmissions */
lsa->data->ls_age = htons (OSPF_LSA_MAXAGE);
- lsa->tv_recv = recent_relative_time ();
+ monotime(&lsa->tv_recv);
lsa->tv_orig = lsa->tv_recv;
ospf_flood_through_area (area, NULL, lsa);
ospf_lsa_maxage (area->ospf, lsa);
@@ -982,7 +983,7 @@ ospf_lsa_flush_as (struct ospf *ospf, struct ospf_lsa *lsa)
more time for the ACK to be received and avoid
retransmissions */
lsa->data->ls_age = htons (OSPF_LSA_MAXAGE);
- lsa->tv_recv = recent_relative_time ();
+ monotime(&lsa->tv_recv);
lsa->tv_orig = lsa->tv_recv;
ospf_flood_through_as (ospf, NULL, lsa);
ospf_lsa_maxage (ospf, lsa);
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index 916d4d01c9..cf9943893a 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -22,6 +22,7 @@
#include <zebra.h>
+#include "monotime.h"
#include "linklist.h"
#include "prefix.h"
#include "if.h"
@@ -63,40 +64,6 @@ get_metric (u_char *metric)
struct timeval
-tv_adjust (struct timeval a)
-{
- while (a.tv_usec >= 1000000)
- {
- a.tv_usec -= 1000000;
- a.tv_sec++;
- }
-
- while (a.tv_usec < 0)
- {
- a.tv_usec += 1000000;
- a.tv_sec--;
- }
-
- return a;
-}
-
-int
-tv_ceil (struct timeval a)
-{
- a = tv_adjust (a);
-
- return (a.tv_usec ? a.tv_sec + 1 : a.tv_sec);
-}
-
-int
-tv_floor (struct timeval a)
-{
- a = tv_adjust (a);
-
- return a.tv_sec;
-}
-
-struct timeval
int2tv (int a)
{
struct timeval ret;
@@ -115,50 +82,22 @@ msec2tv (int a)
ret.tv_sec = a/1000;
ret.tv_usec = (a%1000) * 1000;
- return tv_adjust (ret);
-}
-
-struct timeval
-tv_add (struct timeval a, struct timeval b)
-{
- struct timeval ret;
-
- ret.tv_sec = a.tv_sec + b.tv_sec;
- ret.tv_usec = a.tv_usec + b.tv_usec;
-
- return tv_adjust (ret);
-}
-
-struct timeval
-tv_sub (struct timeval a, struct timeval b)
-{
- struct timeval ret;
-
- ret.tv_sec = a.tv_sec - b.tv_sec;
- ret.tv_usec = a.tv_usec - b.tv_usec;
-
- return tv_adjust (ret);
-}
-
-int
-tv_cmp (struct timeval a, struct timeval b)
-{
- return (a.tv_sec == b.tv_sec ?
- a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
+ return ret;
}
int
ospf_lsa_refresh_delay (struct ospf_lsa *lsa)
{
- struct timeval delta, now;
+ struct timeval delta;
int delay = 0;
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
- delta = tv_sub (now, lsa->tv_orig);
-
- if (tv_cmp (delta, msec2tv (OSPF_MIN_LS_INTERVAL)) < 0)
+ if (monotime_since (&lsa->tv_orig, &delta) < OSPF_MIN_LS_INTERVAL * 1000LL)
{
- delay = tv_ceil (tv_sub (msec2tv (OSPF_MIN_LS_INTERVAL), delta));
+ struct timeval minv = msec2tv (OSPF_MIN_LS_INTERVAL);
+ timersub (&minv, &delta, &minv);
+
+ /* TBD: remove padding to full sec, return timeval instead */
+ delay = minv.tv_sec + !!minv.tv_usec;
if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
zlog_debug ("LSA[Type%d:%s]: Refresh timer delay %d seconds",
@@ -174,12 +113,10 @@ ospf_lsa_refresh_delay (struct ospf_lsa *lsa)
int
get_age (struct ospf_lsa *lsa)
{
- int age;
-
- age = ntohs (lsa->data->ls_age)
- + tv_floor (tv_sub (recent_relative_time (), lsa->tv_recv));
+ struct timeval rel;
- return age;
+ monotime_since (&lsa->tv_recv, &rel);
+ return ntohs (lsa->data->ls_age) + rel.tv_sec;
}
@@ -228,7 +165,7 @@ ospf_lsa_new ()
new->flags = 0;
new->lock = 1;
new->retransmit_counter = 0;
- new->tv_recv = recent_relative_time ();
+ monotime(&new->tv_recv);
new->tv_orig = new->tv_recv;
new->refresh_list = -1;
@@ -3701,8 +3638,8 @@ ospf_refresher_register_lsa (struct ospf *ospf, struct ospf_lsa *lsa)
*/
delay = (random() % (max_delay - min_delay)) + min_delay;
- current_index = ospf->lsa_refresh_queue.index + (quagga_monotime ()
- - ospf->lsa_refresher_started)/OSPF_LSA_REFRESHER_GRANULARITY;
+ current_index = ospf->lsa_refresh_queue.index + (monotime(NULL)
+ - ospf->lsa_refresher_started)/OSPF_LSA_REFRESHER_GRANULARITY;
index = (current_index + delay/OSPF_LSA_REFRESHER_GRANULARITY)
% (OSPF_LSA_REFRESHER_SLOTS);
@@ -3765,7 +3702,7 @@ ospf_lsa_refresh_walker (struct thread *t)
modulus. */
ospf->lsa_refresh_queue.index =
((unsigned long)(ospf->lsa_refresh_queue.index +
- (quagga_monotime () - ospf->lsa_refresher_started)
+ (monotime(NULL) - ospf->lsa_refresher_started)
/ OSPF_LSA_REFRESHER_GRANULARITY))
% OSPF_LSA_REFRESHER_SLOTS;
@@ -3806,7 +3743,7 @@ ospf_lsa_refresh_walker (struct thread *t)
ospf->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker,
ospf, ospf->lsa_refresh_interval);
- ospf->lsa_refresher_started = quagga_monotime ();
+ ospf->lsa_refresher_started = monotime(NULL);
for (ALL_LIST_ELEMENTS (lsa_to_refresh, node, nnode, lsa))
{
diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h
index 28ecc9d4d6..8b9a0d4c49 100644
--- a/ospfd/ospf_lsa.h
+++ b/ospfd/ospf_lsa.h
@@ -227,14 +227,8 @@ struct as_external_lsa
/* Prototypes. */
/* XXX: Eek, time functions, similar are in lib/thread.c */
-extern struct timeval tv_adjust (struct timeval);
-extern int tv_ceil (struct timeval);
-extern int tv_floor (struct timeval);
extern struct timeval int2tv (int);
extern struct timeval msec2tv (int);
-extern struct timeval tv_add (struct timeval, struct timeval);
-extern struct timeval tv_sub (struct timeval, struct timeval);
-extern int tv_cmp (struct timeval, struct timeval);
extern int get_age (struct ospf_lsa *);
extern u_int16_t ospf_lsa_checksum (struct lsa_header *);
diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c
index 17cc1f66c2..ccb82bf8fe 100644
--- a/ospfd/ospf_nsm.c
+++ b/ospfd/ospf_nsm.c
@@ -630,10 +630,10 @@ nsm_notice_state_change (struct ospf_neighbor *nbr, int next_state, int event)
/* Advance in NSM */
if (next_state > nbr->state)
- nbr->ts_last_progress = recent_relative_time ();
+ monotime(&nbr->ts_last_progress);
else /* regression in NSM */
{
- nbr->ts_last_regress = recent_relative_time ();
+ monotime(&nbr->ts_last_regress);
nbr->last_regress_str = ospf_nsm_event_str [event];
}
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index f7d1d0fa7d..bf78336ad5 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -22,6 +22,7 @@
#include <zebra.h>
+#include "monotime.h"
#include "thread.h"
#include "memory.h"
#include "linklist.h"
@@ -521,16 +522,18 @@ ospf_ls_upd_timer (struct thread *thread)
struct ospf_lsa *lsa;
if ((lsa = rn->info) != NULL)
- /* Don't retransmit an LSA if we received it within
- the last RxmtInterval seconds - this is to allow the
- neighbour a chance to acknowledge the LSA as it may
- have ben just received before the retransmit timer
- fired. This is a small tweak to what is in the RFC,
- but it will cut out out a lot of retransmit traffic
- - MAG */
- if (tv_cmp (tv_sub (recent_relative_time (), lsa->tv_recv),
- int2tv (retransmit_interval)) >= 0)
- listnode_add (update, rn->info);
+ {
+ /* Don't retransmit an LSA if we received it within
+ the last RxmtInterval seconds - this is to allow the
+ neighbour a chance to acknowledge the LSA as it may
+ have ben just received before the retransmit timer
+ fired. This is a small tweak to what is in the RFC,
+ but it will cut out out a lot of retransmit traffic
+ - MAG */
+ if (monotime_since (&lsa->tv_recv, NULL)
+ >= retransmit_interval * 1000000LL)
+ listnode_add (update, rn->info);
+ }
}
}
@@ -1469,10 +1472,8 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
}
else
{
- struct timeval t, now;
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
- t = tv_sub (now, nbr->last_send_ts);
- if (tv_cmp (t, int2tv (nbr->v_inactivity)) < 0)
+ if (monotime_since (&nbr->last_send_ts, NULL)
+ < nbr->v_inactivity * 1000000LL)
{
/* In states Loading and Full the slave must resend
its last Database Description packet in response to
@@ -2074,12 +2075,8 @@ ospf_ls_upd (struct ospf *ospf, struct ip *iph, struct ospf_header *ospfh,
recent) LSA instance. */
else
{
- struct timeval now;
-
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
-
- if (tv_cmp (tv_sub (now, current->tv_orig),
- msec2tv (ospf->min_ls_arrival)) >= 0)
+ if (monotime_since (&current->tv_orig, NULL)
+ >= ospf->min_ls_arrival * 1000LL)
/* Trap NSSA type later.*/
ospf_ls_upd_send_lsa (nbr, current, OSPF_SEND_PACKET_DIRECT);
DISCARD_LSA (lsa, 8);
@@ -3577,7 +3574,7 @@ ospf_db_desc_send (struct ospf_neighbor *nbr)
if (nbr->last_send)
ospf_packet_free (nbr->last_send);
nbr->last_send = ospf_packet_dup (op);
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &nbr->last_send_ts);
+ monotime(&nbr->last_send_ts);
}
/* Re-send Database Description. */
diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c
index 5dfd41dd1e..077d0e68ad 100644
--- a/ospfd/ospf_spf.c
+++ b/ospfd/ospf_spf.c
@@ -20,6 +20,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include <zebra.h>
+#include "monotime.h"
#include "thread.h"
#include "memory.h"
#include "hash.h"
@@ -1279,7 +1280,7 @@ ospf_spf_calculate (struct ospf_area *area, struct route_table *new_table,
/* Increment SPF Calculation Counter. */
area->spf_calculation++;
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &area->ospf->ts_spf);
+ monotime(&area->ospf->ts_spf);
area->ts_spf = area->ospf->ts_spf;
if (IS_DEBUG_OSPF_EVENT)
@@ -1300,7 +1301,7 @@ ospf_spf_calculate_timer (struct thread *thread)
struct route_table *new_table, *new_rtrs;
struct ospf_area *area;
struct listnode *node, *nnode;
- struct timeval start_time, stop_time, spf_start_time;
+ struct timeval start_time, spf_start_time;
int areas_processed = 0;
unsigned long ia_time, prune_time, rt_time;
unsigned long abr_time, total_spf_time, spf_time;
@@ -1311,7 +1312,7 @@ ospf_spf_calculate_timer (struct thread *thread)
ospf->t_spf_calc = NULL;
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &spf_start_time);
+ monotime(&spf_start_time);
/* Allocate new table tree. */
new_table = route_table_init ();
new_rtrs = route_table_init ();
@@ -1338,24 +1339,19 @@ ospf_spf_calculate_timer (struct thread *thread)
areas_processed++;
}
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time);
- spf_time = timeval_elapsed (stop_time, spf_start_time);
+ spf_time = monotime_since(&spf_start_time, NULL);
ospf_vl_shut_unapproved (ospf);
- start_time = stop_time; /* saving a call */
-
+ monotime(&start_time);
ospf_ia_routing (ospf, new_table, new_rtrs);
+ ia_time = monotime_since(&start_time, NULL);
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time);
- ia_time = timeval_elapsed (stop_time, start_time);
-
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time);
+ monotime(&start_time);
ospf_prune_unreachable_networks (new_table);
ospf_prune_unreachable_routers (new_rtrs);
+ prune_time = monotime_since(&start_time, NULL);
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time);
- prune_time = timeval_elapsed (stop_time, start_time);
/* AS-external-LSA calculation should not be performed here. */
/* If new Router Route is installed,
@@ -1365,13 +1361,11 @@ ospf_spf_calculate_timer (struct thread *thread)
ospf_ase_calculate_timer_add (ospf);
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time);
-
/* Update routing table. */
+ monotime(&start_time);
ospf_route_install (ospf, new_table);
+ rt_time = monotime_since(&start_time, NULL);
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time);
- rt_time = timeval_elapsed (stop_time, start_time);
/* Update ABR/ASBR routing table */
if (ospf->old_rtrs)
{
@@ -1383,17 +1377,12 @@ ospf_spf_calculate_timer (struct thread *thread)
ospf->old_rtrs = ospf->new_rtrs;
ospf->new_rtrs = new_rtrs;
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time);
+ monotime(&start_time);
if (IS_OSPF_ABR (ospf))
ospf_abr_task (ospf);
+ abr_time = monotime_since(&start_time, NULL);
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time);
- abr_time = timeval_elapsed (stop_time, start_time);
-
- quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time);
- total_spf_time = timeval_elapsed (stop_time, spf_start_time);
- ospf->ts_spf_duration.tv_sec = total_spf_time/1000000;
- ospf->ts_spf_duration.tv_usec = total_spf_time % 1000000;
+ total_spf_time = monotime_since(&spf_start_time, &ospf->ts_spf_duration);
ospf_get_spf_reason_str (rbuf);
@@ -1421,7 +1410,6 @@ void
ospf_spf_calculate_schedule (struct ospf *ospf, ospf_spf_reason_t reason)
{
unsigned long delay, elapsed, ht;
- struct timeval result;
if (IS_DEBUG_OSPF_EVENT)
zlog_debug ("SPF: calculation timer scheduled");
@@ -1440,11 +1428,9 @@ ospf_spf_calculate_schedule (struct ospf *ospf, ospf_spf_reason_t reason)
(void *)ospf->t_spf_calc);
return;
}
-
- /* XXX Monotic timers: we only care about relative time here. */
- result = tv_sub (recent_relative_time (), ospf->ts_spf);
-
- elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000);
+
+ elapsed = monotime_since (&ospf->ts_spf, NULL) / 1000;
+
ht = ospf->spf_holdtime * ospf->spf_hold_multiplier;
if (ht > ospf->spf_max_holdtime)
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index ce12974d40..2a627f9221 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -23,6 +23,7 @@
#include <zebra.h>
#include <string.h>
+#include "monotime.h"
#include "memory.h"
#include "thread.h"
#include "prefix.h"
@@ -2809,10 +2810,8 @@ show_ip_ospf_area (struct vty *vty, struct ospf_area *area, json_object *json_ar
json_object_boolean_true_add(json_area, "indefiniteActiveAdmin");
if (area->t_stub_router)
{
- struct timeval result;
- unsigned long time_store = 0;
- result = tv_sub (area->t_stub_router->u.sands, recent_relative_time());
- time_store = (1000 * result.tv_sec) + (result.tv_usec / 1000);
+ long time_store;
+ time_store = monotime_until(&area->t_stub_router->u.sands, NULL) / 1000LL;
json_object_int_add(json_area, "activeStartupRemainderMsecs", time_store);
}
}
@@ -2971,9 +2970,8 @@ show_ip_ospf_common (struct vty *vty, struct ospf *ospf, u_char use_json)
{
if (use_json)
{
- unsigned long time_store = 0;
- result = tv_sub (ospf->t_deferred_shutdown->u.sands, recent_relative_time());
- time_store = (1000 * result.tv_sec) + (result.tv_usec / 1000);
+ long time_store;
+ time_store = monotime_until(&ospf->t_deferred_shutdown->u.sands, NULL) / 1000LL;
json_object_int_add(json, "deferredShutdownMsecs", time_store);
}
else
@@ -3066,11 +3064,9 @@ show_ip_ospf_common (struct vty *vty, struct ospf *ospf, u_char use_json)
{
if (ospf->ts_spf.tv_sec || ospf->ts_spf.tv_usec)
{
- unsigned long time_store = 0;
+ long time_store = 0;
- result = tv_sub (recent_relative_time(), ospf->ts_spf);
- result = tv_sub (result, recent_relative_time());
- time_store = (1000 * result.tv_sec) + (result.tv_usec / 1000);
+ time_store = monotime_since(&ospf->ts_spf, NULL) / 1000LL;
json_object_int_add(json, "spfLastExecutedMsecs", time_store);
time_store = (1000 * ospf->ts_spf_duration.tv_sec) + (ospf->ts_spf_duration.tv_usec / 1000);
@@ -3084,7 +3080,7 @@ show_ip_ospf_common (struct vty *vty, struct ospf *ospf, u_char use_json)
vty_out (vty, " SPF algorithm ");
if (ospf->ts_spf.tv_sec || ospf->ts_spf.tv_usec)
{
- result = tv_sub (recent_relative_time(), ospf->ts_spf);
+ monotime_since(&ospf->ts_spf, &result);
vty_out (vty, "last executed %s ago%s",
ospf_timeval_dump (&result, timebuf, sizeof (timebuf)),
VTY_NEWLINE);
@@ -3098,13 +3094,10 @@ show_ip_ospf_common (struct vty *vty, struct ospf *ospf, u_char use_json)
if (use_json)
{
- struct timeval temp_time;
- unsigned long time_store = 0;
-
if (ospf->t_spf_calc)
{
- temp_time = tv_sub (ospf->t_spf_calc->u.sands, recent_relative_time());
- time_store = (1000 * temp_time.tv_sec) + (temp_time.tv_usec / 1000);
+ long time_store;
+ time_store = monotime_until(&ospf->t_spf_calc->u.sands, NULL) / 1000LL;
json_object_int_add(json, "spfTimerDueInMsecs", time_store);
}
@@ -3509,16 +3502,9 @@ show_ip_ospf_interface_sub (struct vty *vty, struct ospf *ospf, struct interface
char timebuf[OSPF_TIME_DUMP_SIZE];
if (use_json)
{
- struct timeval result;
- unsigned long time_store = 0;
- if (oi->t_hello)
- result = tv_sub (oi->t_hello->u.sands, recent_relative_time());
- else
- {
- result.tv_sec = 0;
- result.tv_usec = 0;
- }
- time_store = (1000 * result.tv_sec) + (result.tv_usec / 1000);
+ long time_store = 0;
+ if (oi->t_hello)
+ time_store = monotime_until(&oi->t_hello->u.sands, NULL) / 1000LL;
json_object_int_add(json_interface_sub, "timerHelloInMsecs", time_store);
}
else
@@ -3708,11 +3694,9 @@ show_ip_ospf_neighbor_sub (struct vty *vty, struct ospf_interface *oi, json_obje
json_neighbor = json_object_new_object();
ospf_nbr_state_message (nbr, msgbuf, 16);
- struct timeval result;
- unsigned long time_store = 0;
+ long time_store;
- result = tv_sub (nbr->t_inactivity->u.sands, recent_relative_time());
- time_store = (1000 * result.tv_sec) + (result.tv_usec / 1000);
+ time_store = monotime_until(&nbr->t_inactivity->u.sands, NULL) / 1000LL;
json_object_int_add (json_neighbor, "priority", nbr->priority);
json_object_string_add (json_neighbor, "state", msgbuf);
@@ -4093,9 +4077,8 @@ show_ip_ospf_nbr_nbma_detail_sub (struct vty *vty, struct ospf_interface *oi, st
/* Show poll-interval timer. */
if (use_json)
{
- struct timeval res = tv_sub (nbr_nbma->t_poll->u.sands, recent_relative_time ());
- unsigned long time_store = 0;
- time_store = (1000 * res.tv_sec) + (res.tv_usec / 1000);
+ long time_store;
+ time_store = monotime_until(&nbr_nbma->t_poll->u.sands, NULL) / 1000LL;
json_object_int_add(json_sub, "pollIntervalTimerDueMsec", time_store);
}
else
@@ -4170,11 +4153,12 @@ show_ip_ospf_neighbor_detail_sub (struct vty *vty, struct ospf_interface *oi,
if (nbr->ts_last_progress.tv_sec || nbr->ts_last_progress.tv_usec)
{
- struct timeval res = tv_sub (recent_relative_time (), nbr->ts_last_progress);
+ struct timeval res;
+ long time_store;
+
+ time_store = monotime_since(&nbr->ts_last_progress, &res) / 1000LL;
if (use_json)
{
- unsigned long time_store = 0;
- time_store = (1000 * res.tv_sec) + (res.tv_usec / 1000);
json_object_int_add(json_sub, "lastPrgrsvChangeMsec", time_store);
}
else
@@ -4189,11 +4173,12 @@ show_ip_ospf_neighbor_detail_sub (struct vty *vty, struct ospf_interface *oi,
if (nbr->ts_last_regress.tv_sec || nbr->ts_last_regress.tv_usec)
{
- struct timeval res = tv_sub (recent_relative_time (), nbr->ts_last_regress);
+ struct timeval res;
+ long time_store;
+
+ time_store = monotime_since(&nbr->ts_last_regress, &res) / 1000LL;
if (use_json)
{
- unsigned long time_store = 0;
- time_store = (1000 * res.tv_sec) + (res.tv_usec / 1000);
json_object_int_add(json_sub, "lastRegressiveChangeMsec", time_store);
if (nbr->last_regress_str)
json_object_string_add(json_sub, "lastRegressiveChangeReason", nbr->last_regress_str);
@@ -4234,9 +4219,8 @@ show_ip_ospf_neighbor_detail_sub (struct vty *vty, struct ospf_interface *oi,
{
if (nbr->t_inactivity)
{
- struct timeval res = tv_sub (nbr->t_inactivity->u.sands, recent_relative_time ());
- unsigned long time_store = 0;
- time_store = (1000 * res.tv_sec) + (res.tv_usec / 1000);
+ long time_store;
+ time_store = monotime_until(&nbr->t_inactivity->u.sands, NULL) / 1000LL;
json_object_int_add(json_sub, "routerDeadIntervalTimerDueMsec", time_store);
}
else
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index b7542c2a8b..0398bc21b8 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -273,7 +273,7 @@ ospf_new (u_short instance)
new->lsa_refresh_interval = OSPF_LSA_REFRESH_INTERVAL_DEFAULT;
new->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker,
new, new->lsa_refresh_interval);
- new->lsa_refresher_started = quagga_monotime ();
+ new->lsa_refresher_started = monotime(NULL);
if ((new->fd = ospf_sock_init()) < 0)
{
@@ -1583,7 +1583,7 @@ ospf_timers_refresh_set (struct ospf *ospf, int interval)
return 1;
time_left = ospf->lsa_refresh_interval -
- (quagga_monotime () - ospf->lsa_refresher_started);
+ (monotime(NULL) - ospf->lsa_refresher_started);
if (time_left > interval)
{
@@ -1602,7 +1602,7 @@ ospf_timers_refresh_unset (struct ospf *ospf)
int time_left;
time_left = ospf->lsa_refresh_interval -
- (quagga_monotime () - ospf->lsa_refresher_started);
+ (monotime(NULL) - ospf->lsa_refresher_started);
if (time_left > OSPF_LSA_REFRESH_INTERVAL_DEFAULT)
{
diff --git a/pimd/Makefile.am b/pimd/Makefile.am
index bc28aa1e92..314a744339 100644
--- a/pimd/Makefile.am
+++ b/pimd/Makefile.am
@@ -19,7 +19,6 @@
# 330, Boston, MA 02111-1307, USA.
# PIM_DEBUG_BYDEFAULT: Automatically enables all pimd "debug ..." commands
-# PIM_ZCLIENT_DEBUG: Support for internal ZEBRA client debugging
# PIM_CHECK_RECV_IFINDEX_SANITY: Compare socket ifindex with recv ifindex
# PIM_REPORT_RECV_IFINDEX_MISMATCH: Report sock/recv ifindex mismatch
# PIM_ENFORCE_LOOPFREE_MFC: Refuse adding looping MFC entries
@@ -27,9 +26,8 @@
PIM_DEFS =
#PIM_DEFS += -DPIM_DEBUG_BYDEFAULT
-PIM_DEFS += -DPIM_CHECK_RECV_IFINDEX_SANITY
+#PIM_DEFS += -DPIM_CHECK_RECV_IFINDEX_SANITY
#PIM_DEFS += -DPIM_REPORT_RECV_IFINDEX_MISMATCH
-PIM_DEFS += -DPIM_ZCLIENT_DEBUG
PIM_DEFS += -DPIM_ENFORCE_LOOPFREE_MFC
#PIM_DEFS += -DPIM_UNEXPECTED_KERNEL_UPCALL
@@ -47,24 +45,26 @@ noinst_PROGRAMS = test_igmpv3_join
libpim_a_SOURCES = \
pim_memory.c \
pimd.c pim_version.c pim_cmd.c pim_signals.c pim_iface.c \
- pim_vty.c pim_igmp.c pim_sock.c pim_zebra.c \
+ pim_vty.c pim_igmp.c pim_sock.c pim_zebra.c pim_igmpv2.c \
pim_igmpv3.c pim_str.c pim_mroute.c pim_util.c pim_time.c \
pim_oil.c pim_zlookup.c pim_pim.c pim_tlv.c pim_neighbor.c \
pim_hello.c pim_ifchannel.c pim_join.c pim_assert.c \
pim_msg.c pim_upstream.c pim_rpf.c pim_macro.c \
pim_ssmpingd.c pim_int.c pim_rp.c \
- pim_static.c pim_br.c pim_register.c pim_routemap.c
+ pim_static.c pim_br.c pim_register.c pim_routemap.c \
+ pim_msdp.c pim_msdp_socket.c pim_msdp_packet.c
noinst_HEADERS = \
pim_memory.h \
pimd.h pim_version.h pim_cmd.h pim_signals.h pim_iface.h \
- pim_vty.h pim_igmp.h pim_sock.h pim_zebra.h \
+ pim_vty.h pim_igmp.h pim_sock.h pim_zebra.h pim_igmpv2.h \
pim_igmpv3.h pim_str.h pim_mroute.h pim_util.h pim_time.h \
pim_oil.h pim_zlookup.h pim_pim.h pim_tlv.h pim_neighbor.h \
pim_hello.h pim_ifchannel.h pim_join.h pim_assert.h \
pim_msg.h pim_upstream.h pim_rpf.h pim_macro.h \
pim_igmp_join.h pim_ssmpingd.h pim_int.h pim_rp.h \
- pim_static.h pim_br.h pim_register.h
+ pim_static.h pim_br.h pim_register.h \
+ pim_msdp.h pim_msdp_socket.h pim_msdp_packet.h
pimd_SOURCES = \
pim_main.c $(libpim_a_SOURCES)
diff --git a/pimd/README b/pimd/README
index c8997808b6..3d03979a9a 100644
--- a/pimd/README
+++ b/pimd/README
@@ -1,18 +1,17 @@
INTRODUCTION
qpimd aims to implement a PIM (Protocol Independent Multicast)
- daemon for the Quagga Routing Suite.
+ daemon for the FRR Routing Suite.
- Initially qpimd targets only PIM SSM (Source-Specific
- Multicast) mode as defined in section 4.8.2 (PIM-SSM-Only
- Routers) of RFC 4601.
+ qpimd implements PIM-SM (Sparse Mode) of RFC 4601.
+ Additionally MSDP has been implemented.
In order to deliver end-to-end multicast routing control
- plane, qpimd includes the router-side of IGMPv3 (RFC 3376).
+ plane, qpimd includes the router-side of IGMPv[2|3] (RFC 3376).
LICENSE
- qpimd - pimd for quagga
+ qpimd - pimd for FRR
Copyright (C) 2008 Everton da Silva Marques
qpimd is free software; you can redistribute it and/or modify
@@ -34,78 +33,16 @@ HOME SITE
qpimd lives at:
- https://github.com/udhos/qpimd
+ https://github.com/freerangerouting/frr
PLATFORMS
- qpimd has been tested with Debian Lenny under Linux 2.6.
+ qpimd has been tested with Debian Jessie.
REQUIREMENTS
- qpimd requires Quagga (0.99.11 or higher from http://www.quagga.net)
+ qpimd requires FRR (2.0 or higher)
- The GNU Build System (Autotools) is required to build from
- source code repository.
-
- gawk is also needed to build with Autotools. Any other awk
- usually won't work.
-
-BUILDING FROM QUAGGA GIT REPOSITORY
-
- 1) Get the latest quagga source tree
-
- # git clone git://code.quagga.net/quagga.git quagga
-
- 2) Apply qpimd patch into quagga source tree
-
- # patch -p1 -d quagga < pimd-0.153-quagga-git20090623.patch
-
- 3) Compile and install quagga
-
- # cd quagga
- # ./bootstrap.sh
- # ./configure --prefix=/usr/local/quagga --enable-pimd
- # make
- # make install
-
-BUILDING FROM QUAGGA TARBALL
-
- 1) Get the latest quagga tarball
-
- # wget http://www.quagga.net/download/quagga-0.99.13.tar.gz
-
- 2) Unpack the quagga tarball
-
- # tar xzf quagga-0.99.13.tar.gz
-
- 3) Apply qpimd patch into quagga source tree
-
- # patch -p1 -d quagga-0.99.13 < pimd-0.153-quagga-0.99.13.patch
-
- 4) Compile and install quagga
-
- # cd quagga-0.99.13
- # ./configure --prefix=/usr/local/quagga --enable-pimd
- # make
- # make install
-
-USAGE
-
- 1) Configure and start the zebra daemon
-
- # cp /usr/local/quagga/etc/zebra.conf.sample /usr/local/quagga/etc/zebra.conf
- # vi /usr/local/quagga/etc/zebra.conf
- # /usr/local/quagga/sbin/zebra
-
- 2) Configure and start the pimd daemon
-
- # cp /usr/local/quagga/etc/pimd.conf.sample /usr/local/quagga/etc/pimd.conf
- # vi /usr/local/quagga/etc/pimd.conf
- # /usr/local/quagga/sbin/pimd
-
- 3) Access pimd vty interface at port TCP 2611
-
- # telnet localhost 2611
CONFIGURATION COMMANDS
@@ -120,7 +57,7 @@ SUPPORT
Please post comments, questions, patches, bug reports at the
support site:
- https://github.com/udhos/qpimd
+ https://freerangerouting/frr
RELATED WORK
diff --git a/pimd/pim_assert.c b/pimd/pim_assert.c
index f09540ea00..d6f372cc44 100644
--- a/pimd/pim_assert.c
+++ b/pimd/pim_assert.c
@@ -54,31 +54,23 @@ void pim_ifassert_winner_set(struct pim_ifchannel *ch,
if (PIM_DEBUG_PIM_EVENTS) {
if (ch->ifassert_state != new_state) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- zlog_debug("%s: (S,G)=(%s,%s) assert state changed from %s to %s on interface %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str,
- pim_ifchannel_ifassert_name(ch->ifassert_state),
- pim_ifchannel_ifassert_name(new_state),
- ch->interface->name);
+ zlog_debug("%s: (S,G)=%s assert state changed from %s to %s on interface %s",
+ __PRETTY_FUNCTION__,
+ ch->sg_str,
+ pim_ifchannel_ifassert_name(ch->ifassert_state),
+ pim_ifchannel_ifassert_name(new_state),
+ ch->interface->name);
}
if (winner_changed) {
- char src_str[100];
- char grp_str[100];
- char was_str[100];
- char winner_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
+ char was_str[INET_ADDRSTRLEN];
+ char winner_str[INET_ADDRSTRLEN];
pim_inet4_dump("<was?>", ch->ifassert_winner, was_str, sizeof(was_str));
pim_inet4_dump("<winner?>", winner, winner_str, sizeof(winner_str));
- zlog_debug("%s: (S,G)=(%s,%s) assert winner changed from %s to %s on interface %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str,
- was_str, winner_str, ch->interface->name);
+ zlog_debug("%s: (S,G)=%s assert winner changed from %s to %s on interface %s",
+ __PRETTY_FUNCTION__,
+ ch->sg_str,
+ was_str, winner_str, ch->interface->name);
}
} /* PIM_DEBUG_PIM_EVENTS */
@@ -98,7 +90,7 @@ static void on_trace(const char *label,
struct interface *ifp, struct in_addr src)
{
if (PIM_DEBUG_PIM_TRACE) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
zlog_debug("%s: from %s on %s",
label, src_str, ifp->name);
@@ -138,13 +130,9 @@ static void if_could_assert_do_a1(const char *caller,
{
if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
if (assert_action_a1(ch)) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- zlog_warn("%s: %s: (S,G)=(%s,%s) assert_action_a1 failure on interface %s",
+ zlog_warn("%s: %s: (S,G)=%s assert_action_a1 failure on interface %s",
__PRETTY_FUNCTION__, caller,
- src_str, grp_str, ch->interface->name);
+ ch->sg_str, ch->interface->name);
/* log warning only */
}
}
@@ -156,16 +144,16 @@ static int dispatch_assert(struct interface *ifp,
struct pim_assert_metric recv_metric)
{
struct pim_ifchannel *ch;
+ struct prefix_sg sg;
- ch = pim_ifchannel_add(ifp, source_addr, group_addr);
+ memset (&sg, 0, sizeof (struct prefix_sg));
+ sg.src = source_addr;
+ sg.grp = group_addr;
+ ch = pim_ifchannel_add(ifp, &sg, 0);
if (!ch) {
- char source_str[100];
- char group_str[100];
- pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
- pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
- zlog_warn("%s: (S,G)=(%s,%s) failure creating channel on interface %s",
+ zlog_warn("%s: (S,G)=%s failure creating channel on interface %s",
__PRETTY_FUNCTION__,
- source_str, group_str, ifp->name);
+ pim_str_sg_dump (&sg), ifp->name);
return -1;
}
@@ -193,7 +181,6 @@ static int dispatch_assert(struct interface *ifp,
}
else {
if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
- zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
assert_action_a3(ch);
}
}
@@ -222,13 +209,9 @@ static int dispatch_assert(struct interface *ifp,
break;
default:
{
- char source_str[100];
- char group_str[100];
- pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
- pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
- zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s",
+ zlog_warn("%s: (S,G)=%s invalid assert state %d on interface %s",
__PRETTY_FUNCTION__,
- source_str, group_str, ch->ifassert_state, ifp->name);
+ ch->sg_str, ch->ifassert_state, ifp->name);
}
return -2;
}
@@ -241,7 +224,7 @@ int pim_assert_recv(struct interface *ifp,
struct in_addr src_addr,
uint8_t *buf, int buf_size)
{
- struct prefix msg_group_addr;
+ struct prefix_sg sg;
struct prefix msg_source_addr;
struct pim_assert_metric msg_metric;
int offset;
@@ -256,9 +239,10 @@ int pim_assert_recv(struct interface *ifp,
/*
Parse assert group addr
*/
- offset = pim_parse_addr_group (&msg_group_addr, curr, curr_size);
+ memset (&sg, 0, sizeof (struct prefix_sg));
+ offset = pim_parse_addr_group (&sg, curr, curr_size);
if (offset < 1) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: pim_parse_addr_group() failure: from %s on %s",
__PRETTY_FUNCTION__,
@@ -273,7 +257,7 @@ int pim_assert_recv(struct interface *ifp,
*/
offset = pim_parse_addr_ucast (&msg_source_addr, curr, curr_size);
if (offset < 1) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
__PRETTY_FUNCTION__,
@@ -284,7 +268,7 @@ int pim_assert_recv(struct interface *ifp,
curr_size -= offset;
if (curr_size != 8) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: preference/metric size is not 8: size=%d from %s on interface %s",
__PRETTY_FUNCTION__,
@@ -311,12 +295,12 @@ int pim_assert_recv(struct interface *ifp,
msg_metric.route_metric = pim_read_uint32_host(curr);
if (PIM_DEBUG_PIM_TRACE) {
- char neigh_str[100];
- char source_str[100];
- char group_str[100];
+ char neigh_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<neigh?>", src_addr, neigh_str, sizeof(neigh_str));
pim_inet4_dump("<src?>", msg_source_addr.u.prefix4, source_str, sizeof(source_str));
- pim_inet4_dump("<grp?>", msg_group_addr.u.prefix4, group_str, sizeof(group_str));
+ pim_inet4_dump("<grp?>", sg.grp, group_str, sizeof(group_str));
zlog_debug("%s: from %s on %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
__PRETTY_FUNCTION__, neigh_str, ifp->name,
source_str, group_str,
@@ -329,7 +313,7 @@ int pim_assert_recv(struct interface *ifp,
return dispatch_assert(ifp,
msg_source_addr.u.prefix4,
- msg_group_addr.u.prefix4,
+ sg.grp,
msg_metric);
}
@@ -399,7 +383,7 @@ int pim_assert_build_msg(uint8_t *pim_msg, int buf_size,
remain,
group_addr);
if (!pim_msg_curr) {
- char group_str[100];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
zlog_warn("%s: failure encoding group address %s: space left=%d",
__PRETTY_FUNCTION__, group_str, remain);
@@ -412,7 +396,7 @@ int pim_assert_build_msg(uint8_t *pim_msg, int buf_size,
remain,
source_addr);
if (!pim_msg_curr) {
- char source_str[100];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: failure encoding source address %s: space left=%d",
__PRETTY_FUNCTION__, source_str, remain);
@@ -448,17 +432,23 @@ static int pim_assert_do(struct pim_ifchannel *ch,
int pim_msg_size;
ifp = ch->interface;
- zassert(ifp);
-
+ if (!ifp)
+ {
+ if (PIM_DEBUG_PIM_TRACE)
+ zlog_debug("%s: channel%s has no associated interface!",
+ __PRETTY_FUNCTION__, ch->sg_str);
+ return -1;
+ }
pim_ifp = ifp->info;
if (!pim_ifp) {
- zlog_warn("%s: pim not enabled on interface: %s",
- __PRETTY_FUNCTION__, ifp->name);
+ if (PIM_DEBUG_PIM_TRACE)
+ zlog_debug("%s: channel %s pim not enabled on interface: %s",
+ __PRETTY_FUNCTION__, ch->sg_str, ifp->name);
return -1;
}
pim_msg_size = pim_assert_build_msg(pim_msg, sizeof(pim_msg), ifp,
- ch->group_addr, ch->source_addr,
+ ch->sg.grp, ch->sg.src,
metric.metric_preference,
metric.route_metric,
metric.rpt_bit_flag);
@@ -480,19 +470,16 @@ static int pim_assert_do(struct pim_ifchannel *ch,
pim_hello_require(ifp);
if (PIM_DEBUG_PIM_TRACE) {
- char source_str[100];
- char group_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, source_str, sizeof(source_str));
- pim_inet4_dump("<grp?>", ch->group_addr, group_str, sizeof(group_str));
- zlog_debug("%s: to %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
+ zlog_debug("%s: to %s: (S,G)=%s pref=%u metric=%u rpt_bit=%u",
__PRETTY_FUNCTION__,
- ifp->name, source_str, group_str,
+ ifp->name, ch->sg_str,
metric.metric_preference,
metric.route_metric,
PIM_FORCE_BOOLEAN(metric.rpt_bit_flag));
}
if (pim_msg_send(pim_ifp->pim_sock_fd,
+ pim_ifp->primary_address,
qpim_all_pim_routers_addr,
pim_msg,
pim_msg_size,
@@ -523,7 +510,7 @@ static int pim_assert_cancel(struct pim_ifchannel *ch)
metric.rpt_bit_flag = 0;
metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX;
metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX;
- metric.ip_address = ch->source_addr;
+ metric.ip_address = ch->sg.src;
return pim_assert_do(ch, metric);
}
@@ -533,28 +520,20 @@ static int on_assert_timer(struct thread *t)
struct pim_ifchannel *ch;
struct interface *ifp;
- zassert(t);
ch = THREAD_ARG(t);
- zassert(ch);
ifp = ch->interface;
- zassert(ifp);
if (PIM_DEBUG_PIM_TRACE) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- zlog_debug("%s: (S,G)=(%s,%s) timer expired on interface %s",
+ zlog_debug("%s: (S,G)=%s timer expired on interface %s",
__PRETTY_FUNCTION__,
- src_str, grp_str, ifp->name);
+ ch->sg_str, ifp->name);
}
- ch->t_ifassert_timer = 0;
+ ch->t_ifassert_timer = NULL;
switch (ch->ifassert_state) {
case PIM_IFASSERT_I_AM_WINNER:
- zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
assert_action_a3(ch);
break;
case PIM_IFASSERT_I_AM_LOSER:
@@ -562,13 +541,10 @@ static int on_assert_timer(struct thread *t)
break;
default:
{
- char source_str[100];
- char group_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, source_str, sizeof(source_str));
- pim_inet4_dump("<grp?>", ch->group_addr, group_str, sizeof(group_str));
- zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s",
- __PRETTY_FUNCTION__,
- source_str, group_str, ch->ifassert_state, ifp->name);
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_warn("%s: (S,G)=%s invalid assert state %d on interface %s",
+ __PRETTY_FUNCTION__,
+ ch->sg_str, ch->ifassert_state, ifp->name);
}
}
@@ -577,46 +553,25 @@ static int on_assert_timer(struct thread *t)
static void assert_timer_off(struct pim_ifchannel *ch)
{
- struct interface *ifp;
-
- zassert(ch);
- ifp = ch->interface;
- zassert(ifp);
-
if (PIM_DEBUG_PIM_TRACE) {
if (ch->t_ifassert_timer) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- zlog_debug("%s: (S,G)=(%s,%s) cancelling timer on interface %s",
+ zlog_debug("%s: (S,G)=%s cancelling timer on interface %s",
__PRETTY_FUNCTION__,
- src_str, grp_str, ifp->name);
+ ch->sg_str, ch->interface->name);
}
}
THREAD_OFF(ch->t_ifassert_timer);
- zassert(!ch->t_ifassert_timer);
}
static void pim_assert_timer_set(struct pim_ifchannel *ch,
int interval)
{
- struct interface *ifp;
-
- zassert(ch);
- ifp = ch->interface;
- zassert(ifp);
-
assert_timer_off(ch);
if (PIM_DEBUG_PIM_TRACE) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- zlog_debug("%s: (S,G)=(%s,%s) starting %u sec timer on interface %s",
+ zlog_debug("%s: (S,G)=%s starting %u sec timer on interface %s",
__PRETTY_FUNCTION__,
- src_str, grp_str, interval, ifp->name);
+ ch->sg_str, interval, ch->interface->name);
}
THREAD_TIMER_ON(master, ch->t_ifassert_timer,
@@ -644,17 +599,11 @@ int assert_action_a1(struct pim_ifchannel *ch)
struct interface *ifp = ch->interface;
struct pim_interface *pim_ifp;
- zassert(ifp);
-
pim_ifp = ifp->info;
if (!pim_ifp) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- zlog_warn("%s: (S,G)=(%s,%s) multicast not enabled on interface %s",
+ zlog_warn("%s: (S,G)=%s multicast not enabled on interface %s",
__PRETTY_FUNCTION__,
- src_str, grp_str, ifp->name);
+ ch->sg_str, ifp->name);
return -1; /* must return since pim_ifp is used below */
}
@@ -664,19 +613,19 @@ int assert_action_a1(struct pim_ifchannel *ch)
pim_macro_spt_assert_metric(&ch->upstream->rpf,
pim_ifp->primary_address));
- zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
if (assert_action_a3(ch)) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- zlog_warn("%s: (S,G)=(%s,%s) assert_action_a3 failure on interface %s",
+ zlog_warn("%s: (S,G)=%s assert_action_a3 failure on interface %s",
__PRETTY_FUNCTION__,
- src_str, grp_str, ifp->name);
+ ch->sg_str, ifp->name);
/* warning only */
}
- zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
+ if (ch->ifassert_state != PIM_IFASSERT_I_AM_WINNER)
+ {
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_warn("%s: channel%s not in expected PIM_IFASSERT_I_AM_WINNER state",
+ __PRETTY_FUNCTION__, ch->sg_str);
+ }
return 0;
}
@@ -699,7 +648,12 @@ static void assert_action_a2(struct pim_ifchannel *ch,
pim_assert_timer_set(ch, PIM_ASSERT_TIME);
- zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER);
+ if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
+ {
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_warn("%s: channel%s not in expected PIM_IFASSERT_I_AM_LOSER state",
+ __PRETTY_FUNCTION__, ch->sg_str);
+ }
}
/*
@@ -712,24 +666,23 @@ static void assert_action_a2(struct pim_ifchannel *ch,
*/
static int assert_action_a3(struct pim_ifchannel *ch)
{
- zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
+ if (ch->ifassert_state != PIM_IFASSERT_I_AM_WINNER)
+ {
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_warn("%s: channel%s expected to be in PIM_IFASSERT_I_AM_WINNER state",
+ __PRETTY_FUNCTION__, ch->sg_str);
+ return -1;
+ }
pim_assert_timer_reset(ch);
if (pim_assert_send(ch)) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
-
- zlog_warn("%s: (S,G)=(%s,%s) failure sending assert on interface %s",
+ zlog_warn("%s: (S,G)=%s failure sending assert on interface %s",
__PRETTY_FUNCTION__,
- src_str, grp_str, ch->interface->name);
+ ch->sg_str, ch->interface->name);
return -1;
}
- zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
-
return 0;
}
@@ -746,19 +699,20 @@ static int assert_action_a3(struct pim_ifchannel *ch)
void assert_action_a4(struct pim_ifchannel *ch)
{
if (pim_assert_cancel(ch)) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- zlog_warn("%s: failure sending AssertCancel(%s,%s) on interface %s",
+ zlog_warn("%s: failure sending AssertCancel%s on interface %s",
__PRETTY_FUNCTION__,
- src_str, grp_str, ch->interface->name);
+ ch->sg_str, ch->interface->name);
/* log warning only */
}
assert_action_a5(ch);
- zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO);
+ if (ch->ifassert_state != PIM_IFASSERT_NOINFO)
+ {
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_warn("%s: channel%s not in PIM_IFASSERT_NOINFO state as expected",
+ __PRETTY_FUNCTION__, ch->sg_str);
+ }
}
/*
@@ -772,7 +726,12 @@ void assert_action_a4(struct pim_ifchannel *ch)
void assert_action_a5(struct pim_ifchannel *ch)
{
reset_ifassert_state(ch);
- zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO);
+ if (ch->ifassert_state != PIM_IFASSERT_NOINFO)
+ {
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_warn("%s: channel%s not in PIM_IFSSERT_NOINFO state as expected",
+ __PRETTY_FUNCTION__, ch->sg_str);
+ }
}
/*
@@ -799,6 +758,11 @@ static void assert_action_a6(struct pim_ifchannel *ch,
if (ch->upstream->join_state == PIM_UPSTREAM_JOINED)
ch->upstream->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
- zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER);
+ if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
+ {
+ if(PIM_DEBUG_PIM_EVENTS)
+ zlog_warn("%s: channel%s not in PIM_IFASSERT_I_AM_LOSER state as expected",
+ __PRETTY_FUNCTION__, ch->sg_str);
+ }
}
diff --git a/pimd/pim_br.c b/pimd/pim_br.c
index 121a45fd16..3f84de79c8 100644
--- a/pimd/pim_br.c
+++ b/pimd/pim_br.c
@@ -30,8 +30,7 @@
#include "linklist.h"
struct pim_br {
- struct in_addr source;
- struct in_addr group;
+ struct prefix_sg sg;
struct in_addr pmbr;
};
@@ -40,14 +39,14 @@ struct in_addr pim_br_unknown = { .s_addr = 0 };
static struct list *pim_br_list = NULL;
struct in_addr
-pim_br_get_pmbr (struct in_addr source, struct in_addr group)
+pim_br_get_pmbr (struct prefix_sg *sg)
{
struct listnode *node;
struct pim_br *pim_br;
for (ALL_LIST_ELEMENTS_RO (pim_br_list, node, pim_br)) {
- if (source.s_addr == pim_br->source.s_addr &&
- group.s_addr == pim_br->group.s_addr)
+ if (sg->src.s_addr == pim_br->sg.src.s_addr &&
+ sg->grp.s_addr == pim_br->sg.grp.s_addr)
return pim_br->pmbr;
}
@@ -55,14 +54,14 @@ pim_br_get_pmbr (struct in_addr source, struct in_addr group)
}
void
-pim_br_set_pmbr (struct in_addr source, struct in_addr group, struct in_addr br)
+pim_br_set_pmbr (struct prefix_sg *sg, struct in_addr br)
{
struct listnode *node, *next;
struct pim_br *pim_br;
for (ALL_LIST_ELEMENTS (pim_br_list, node, next, pim_br)) {
- if (source.s_addr == pim_br->source.s_addr &&
- group.s_addr == pim_br->group.s_addr)
+ if (sg->src.s_addr == pim_br->sg.src.s_addr &&
+ sg->grp.s_addr == pim_br->sg.grp.s_addr)
break;
}
@@ -73,8 +72,7 @@ pim_br_set_pmbr (struct in_addr source, struct in_addr group, struct in_addr br)
return;
}
- pim_br->source = source;
- pim_br->group = group;
+ pim_br->sg = *sg;
listnode_add(pim_br_list, pim_br);
}
@@ -86,14 +84,14 @@ pim_br_set_pmbr (struct in_addr source, struct in_addr group, struct in_addr br)
* Remove the (S,G) from the stored values
*/
void
-pim_br_clear_pmbr (struct in_addr source, struct in_addr group)
+pim_br_clear_pmbr (struct prefix_sg *sg)
{
struct listnode *node, *next;
struct pim_br *pim_br;
for (ALL_LIST_ELEMENTS (pim_br_list, node, next, pim_br)) {
- if (source.s_addr == pim_br->source.s_addr &&
- group.s_addr == pim_br->group.s_addr)
+ if (sg->src.s_addr == pim_br->sg.src.s_addr &&
+ sg->grp.s_addr == pim_br->sg.grp.s_addr)
break;
}
diff --git a/pimd/pim_br.h b/pimd/pim_br.h
index 06b10ada30..8e4f719ed0 100644
--- a/pimd/pim_br.h
+++ b/pimd/pim_br.h
@@ -21,10 +21,10 @@
#ifndef PIM_BR_H
#define PIM_BR_H
-struct in_addr pim_br_get_pmbr (struct in_addr source, struct in_addr group);
+struct in_addr pim_br_get_pmbr (struct prefix_sg *sg);
-void pim_br_set_pmbr (struct in_addr source, struct in_addr group, struct in_addr value);
-void pim_br_clear_pmbr (struct in_addr source, struct in_addr group);
+void pim_br_set_pmbr (struct prefix_sg *sg, struct in_addr value);
+void pim_br_clear_pmbr (struct prefix_sg *sg);
void pim_br_init (void);
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 088713012e..b8bb694b78 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -20,10 +20,12 @@
#include <zebra.h>
+#include "lib/json.h"
#include "command.h"
#include "if.h"
#include "prefix.h"
#include "zclient.h"
+#include "plist.h"
#include "pimd.h"
#include "pim_mroute.h"
@@ -50,6 +52,8 @@
#include "pim_zebra.h"
#include "pim_static.h"
#include "pim_rp.h"
+#include "pim_zlookup.h"
+#include "pim_msdp.h"
static struct cmd_node pim_global_node = {
PIM_NODE,
@@ -63,6 +67,13 @@ static struct cmd_node interface_node = {
1 /* vtysh ? yes */
};
+static struct cmd_node debug_node =
+{
+ DEBUG_NODE,
+ "",
+ 1
+};
+
static void pim_if_membership_clear(struct interface *ifp)
{
struct pim_interface *pim_ifp;
@@ -127,9 +138,12 @@ static void pim_if_membership_refresh(struct interface *ifp)
for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, srcnode, src)) {
if (IGMP_SOURCE_TEST_FORWARDING(src->source_flags)) {
- pim_ifchannel_local_membership_add(ifp,
- src->source_addr,
- grp->group_addr);
+ struct prefix_sg sg;
+
+ memset (&sg, 0, sizeof (struct prefix_sg));
+ sg.src = src->source_addr;
+ sg.grp = grp->group_addr;
+ pim_ifchannel_local_membership_add(ifp, &sg);
}
} /* scan group sources */
@@ -146,9 +160,11 @@ static void pim_if_membership_refresh(struct interface *ifp)
static void pim_show_assert(struct vty *vty)
{
- struct listnode *ifnode;
- struct interface *ifp;
- time_t now;
+ struct pim_interface *pim_ifp;
+ struct pim_ifchannel *ch;
+ struct listnode *ch_node;
+ struct in_addr ifaddr;
+ time_t now;
now = pim_time_monotonic_sec();
@@ -156,55 +172,50 @@ static void pim_show_assert(struct vty *vty)
"Interface Address Source Group State Winner Uptime Timer%s",
VTY_NEWLINE);
- for (ALL_LIST_ELEMENTS_RO(vrf_iflist (VRF_DEFAULT), ifnode, ifp)) {
- struct pim_interface *pim_ifp;
- struct in_addr ifaddr;
- struct listnode *ch_node;
- struct pim_ifchannel *ch;
+ 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 = ifp->info;
+ pim_ifp = ch->interface->info;
if (!pim_ifp)
continue;
ifaddr = pim_ifp->primary_address;
- for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
- char ch_src_str[100];
- char ch_grp_str[100];
- char winner_str[100];
- char uptime[10];
- char timer[10];
-
- pim_inet4_dump("<ch_src?>", ch->source_addr,
- ch_src_str, sizeof(ch_src_str));
- pim_inet4_dump("<ch_grp?>", ch->group_addr,
- ch_grp_str, sizeof(ch_grp_str));
- pim_inet4_dump("<assrt_win?>", ch->ifassert_winner,
- winner_str, sizeof(winner_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("<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);
+ 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%s",
- ifp->name,
- inet_ntoa(ifaddr),
- ch_src_str,
- ch_grp_str,
- pim_ifchannel_ifassert_name(ch->ifassert_state),
- winner_str,
- uptime,
- timer,
- VTY_NEWLINE);
- } /* scan interface channels */
- } /* scan interfaces */
+ vty_out(vty, "%-9s %-15s %-15s %-15s %-6s %-15s %-8s %-5s%s",
+ ch->interface->name,
+ inet_ntoa(ifaddr),
+ ch_src_str,
+ ch_grp_str,
+ pim_ifchannel_ifassert_name(ch->ifassert_state),
+ winner_str,
+ uptime,
+ timer,
+ VTY_NEWLINE);
+ } /* scan interface channels */
}
static void pim_show_assert_internal(struct vty *vty)
{
- struct listnode *ifnode;
- struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ struct listnode *ch_node;
+ struct pim_ifchannel *ch;
+ struct in_addr ifaddr;
vty_out(vty,
"CA: CouldAssert%s"
@@ -217,210 +228,301 @@ static void pim_show_assert_internal(struct vty *vty)
"Interface Address Source Group CA eCA ATD eATD%s",
VTY_NEWLINE);
- for (ALL_LIST_ELEMENTS_RO(vrf_iflist (VRF_DEFAULT), ifnode, ifp)) {
- struct pim_interface *pim_ifp;
- struct in_addr ifaddr;
- struct listnode *ch_node;
- struct pim_ifchannel *ch;
-
- pim_ifp = ifp->info;
+ for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, ch_node, ch)) {
+ pim_ifp = ch->interface->info;
if (!pim_ifp)
continue;
ifaddr = pim_ifp->primary_address;
- for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
- char ch_src_str[100];
- char ch_grp_str[100];
+ char ch_src_str[INET_ADDRSTRLEN];
+ char ch_grp_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<ch_src?>", ch->source_addr,
- ch_src_str, sizeof(ch_src_str));
- pim_inet4_dump("<ch_grp?>", ch->group_addr,
- ch_grp_str, sizeof(ch_grp_str));
- vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %-3s %-3s %-4s%s",
- ifp->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",
- VTY_NEWLINE);
- } /* scan interface channels */
- } /* scan interfaces */
+ 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%s",
+ 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",
+ VTY_NEWLINE);
+ } /* scan interface channels */
}
static void pim_show_assert_metric(struct vty *vty)
{
- struct listnode *ifnode;
- struct interface *ifp;
-
+ struct pim_interface *pim_ifp;
+ struct listnode *ch_node;
+ struct pim_ifchannel *ch;
+ struct in_addr ifaddr;
+
vty_out(vty,
"Interface Address Source Group RPT Pref Metric Address %s",
VTY_NEWLINE);
- for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp)) {
- struct pim_interface *pim_ifp;
- struct in_addr ifaddr;
- struct listnode *ch_node;
- struct pim_ifchannel *ch;
+ for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, ch_node, ch)) {
+ pim_ifp = ch->interface->info;
- pim_ifp = ifp->info;
-
if (!pim_ifp)
continue;
ifaddr = pim_ifp->primary_address;
- for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
- char ch_src_str[100];
- char ch_grp_str[100];
- char addr_str[100];
- struct pim_assert_metric am;
+ char ch_src_str[INET_ADDRSTRLEN];
+ char ch_grp_str[INET_ADDRSTRLEN];
+ char addr_str[INET_ADDRSTRLEN];
+ struct pim_assert_metric am;
- am = pim_macro_spt_assert_metric(&ch->upstream->rpf, pim_ifp->primary_address);
+ am = pim_macro_spt_assert_metric(&ch->upstream->rpf, pim_ifp->primary_address);
- pim_inet4_dump("<ch_src?>", ch->source_addr,
- ch_src_str, sizeof(ch_src_str));
- pim_inet4_dump("<ch_grp?>", ch->group_addr,
- 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));
- vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %4u %6u %-15s%s",
- ifp->name,
- inet_ntoa(ifaddr),
- ch_src_str,
- ch_grp_str,
- am.rpt_bit_flag ? "yes" : "no",
- am.metric_preference,
- am.route_metric,
- addr_str,
- VTY_NEWLINE);
+ vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %4u %6u %-15s%s",
+ 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,
+ VTY_NEWLINE);
} /* scan interface channels */
- } /* scan interfaces */
}
static void pim_show_assert_winner_metric(struct vty *vty)
{
- struct listnode *ifnode;
- struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ struct listnode *ch_node;
+ struct pim_ifchannel *ch;
+ struct in_addr ifaddr;
vty_out(vty,
"Interface Address Source Group RPT Pref Metric Address %s",
VTY_NEWLINE);
- for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp)) {
- struct pim_interface *pim_ifp;
- struct in_addr ifaddr;
- struct listnode *ch_node;
- struct pim_ifchannel *ch;
-
- pim_ifp = ifp->info;
+ for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, ch_node, ch)) {
+ pim_ifp = ch->interface->info;
if (!pim_ifp)
continue;
ifaddr = pim_ifp->primary_address;
- for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
- char ch_src_str[100];
- char ch_grp_str[100];
- char addr_str[100];
- struct pim_assert_metric *am;
- char pref_str[5];
- char metr_str[7];
-
- am = &ch->ifassert_winner_metric;
-
- pim_inet4_dump("<ch_src?>", ch->source_addr,
- ch_src_str, sizeof(ch_src_str));
- pim_inet4_dump("<ch_grp?>", ch->group_addr,
- 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);
+ 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%s",
+ ch->interface->name,
+ inet_ntoa(ifaddr),
+ ch_src_str,
+ ch_grp_str,
+ am->rpt_bit_flag ? "yes" : "no",
+ pref_str,
+ metr_str,
+ addr_str,
+ VTY_NEWLINE);
+ } /* scan interface channels */
+}
- 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);
+static void json_object_pim_ifp_add(struct json_object *json, struct interface *ifp)
+{
+ struct pim_interface *pim_ifp;
- vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %-4s %-6s %-15s%s",
- ifp->name,
- inet_ntoa(ifaddr),
- ch_src_str,
- ch_grp_str,
- am->rpt_bit_flag ? "yes" : "no",
- pref_str,
- metr_str,
- addr_str,
- VTY_NEWLINE);
- } /* scan interface channels */
- } /* scan interfaces */
+ pim_ifp = ifp->info;
+ json_object_string_add(json, "name", ifp->name);
+ json_object_string_add(json, "state", if_is_up(ifp) ? "up" : "down");
+ json_object_string_add(json, "address", inet_ntoa(pim_ifp->primary_address));
+ json_object_int_add(json, "index", ifp->ifindex);
+
+ if (if_is_multicast(ifp))
+ json_object_boolean_true_add(json, "flagMulticast");
+
+ if (if_is_broadcast(ifp))
+ json_object_boolean_true_add(json, "flagBroadcast");
+
+ if (ifp->flags & IFF_ALLMULTI)
+ json_object_boolean_true_add(json, "flagAllMulticast");
+
+ if (ifp->flags & IFF_PROMISC)
+ json_object_boolean_true_add(json, "flagPromiscuous");
+
+ if (PIM_IF_IS_DELETED(ifp))
+ json_object_boolean_true_add(json, "flagDeleted");
+
+ if (pim_if_lan_delay_enabled(ifp))
+ json_object_boolean_true_add(json, "lanDelayEnabled");
}
-static void pim_show_membership(struct vty *vty)
+static void pim_show_membership(struct vty *vty, u_char uj)
{
- struct listnode *ifnode;
- struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ struct listnode *ch_node;
+ struct pim_ifchannel *ch;
+ enum json_type type;
+ json_object *json = NULL;
+ json_object *json_iface = NULL;
+ json_object *json_row = NULL;
+ json_object *json_tmp = NULL;
- vty_out(vty,
- "Interface Address Source Group Membership%s",
- VTY_NEWLINE);
+ json = json_object_new_object();
- for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp)) {
- struct pim_interface *pim_ifp;
- struct in_addr ifaddr;
- struct listnode *ch_node;
- struct pim_ifchannel *ch;
+ for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, ch_node, ch)) {
+
+ pim_ifp = ch->interface->info;
- 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];
- for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
- char ch_src_str[100];
- char ch_grp_str[100];
+ 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("<ch_src?>", ch->source_addr,
- ch_src_str, sizeof(ch_src_str));
- pim_inet4_dump("<ch_grp?>", ch->group_addr,
- ch_grp_str, sizeof(ch_grp_str));
+ json_object_object_get_ex(json, ch->interface->name, &json_iface);
- vty_out(vty, "%-9s %-15s %-15s %-15s %-10s%s",
- ifp->name,
- inet_ntoa(ifaddr),
- ch_src_str,
- ch_grp_str,
- ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO ?
- "NOINFO" : "INCLUDE",
- VTY_NEWLINE);
- } /* scan interface channels */
- } /* scan interfaces */
+ 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 */
+
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ } else {
+ vty_out(vty,
+ "Interface Address Source Group Membership%s",
+ VTY_NEWLINE);
+
+ /*
+ * Example of the json data we are traversing
+ *
+ * {
+ * "swp3":{
+ * "name":"swp3",
+ * "state":"up",
+ * "address":"10.1.20.1",
+ * "index":5,
+ * "flagMulticast":true,
+ * "flagBroadcast":true,
+ * "lanDelayEnabled":true,
+ * "226.10.10.10":{
+ * "source":"*",
+ * "group":"226.10.10.10",
+ * "localMembership":"INCLUDE"
+ * }
+ * }
+ * }
+ */
+
+ /* foreach interface */
+ json_object_object_foreach(json, key, val) {
+
+ /* Find all of the keys where the val is an object. In the example
+ * above the only one is 226.10.10.10
+ */
+ json_object_object_foreach(val, if_field_key, if_field_val) {
+ type = json_object_get_type(if_field_val);
+
+ if (type == json_type_object) {
+ vty_out(vty, "%-9s ", key);
+
+ json_object_object_get_ex(val, "address", &json_tmp);
+ vty_out(vty, "%-15s ", json_object_get_string(json_tmp));
+
+ json_object_object_get_ex(if_field_val, "source", &json_tmp);
+ vty_out(vty, "%-15s ", json_object_get_string(json_tmp));
+
+ /* Group */
+ vty_out(vty, "%-15s ", if_field_key);
+
+ json_object_object_get_ex(if_field_val, "localMembership", &json_tmp);
+ vty_out(vty, "%-10s%s", json_object_get_string(json_tmp), VTY_NEWLINE);
+ }
+ }
+ }
+ }
+
+ json_object_free(json);
+}
+
+static void pim_print_ifp_flags(struct vty *vty, struct interface *ifp, int mloop)
+{
+ vty_out(vty, "Flags%s", VTY_NEWLINE);
+ vty_out(vty, "-----%s", VTY_NEWLINE);
+ vty_out(vty, "All Multicast : %s%s", (ifp->flags & IFF_ALLMULTI) ? "yes" : "no", VTY_NEWLINE);
+ vty_out(vty, "Broadcast : %s%s", if_is_broadcast(ifp)? "yes" : "no", VTY_NEWLINE);
+ vty_out(vty, "Deleted : %s%s", PIM_IF_IS_DELETED(ifp) ? "yes" : "no", VTY_NEWLINE);
+ vty_out(vty, "Interface Index : %d%s", ifp->ifindex, VTY_NEWLINE);
+ vty_out(vty, "Multicast : %s%s", if_is_multicast(ifp) ? "yes" : "no", VTY_NEWLINE);
+ vty_out(vty, "Multicast Loop : %d%s", mloop, VTY_NEWLINE);
+ vty_out(vty, "Promiscuous : %s%s", (ifp->flags & IFF_PROMISC) ? "yes" : "no", VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
}
-static void igmp_show_interfaces(struct vty *vty)
+static void igmp_show_interfaces(struct vty *vty, u_char uj)
{
struct listnode *node;
struct interface *ifp;
time_t now;
-
+ json_object *json = NULL;
+ json_object *json_row = NULL;
+
now = pim_time_monotonic_sec();
- vty_out(vty,
- "Interface Address ifIndex Socket Uptime Multi Broad MLoop AllMu Prmsc Del%s",
- VTY_NEWLINE);
+ if (uj)
+ json = json_object_new_object();
+ else
+ vty_out(vty,
+ "Interface State Address V Querier Query Timer Uptime%s",
+ VTY_NEWLINE);
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) {
struct pim_interface *pim_ifp;
@@ -428,33 +530,176 @@ static void igmp_show_interfaces(struct vty *vty)
struct igmp_sock *igmp;
pim_ifp = ifp->info;
-
+
if (!pim_ifp)
continue;
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
char uptime[10];
- int mloop;
+ char query_hhmmss[10];
pim_time_uptime(uptime, sizeof(uptime), now - igmp->sock_creation);
+ pim_time_timer_to_hhmmss(query_hhmmss, sizeof(query_hhmmss), igmp->t_igmp_query_timer);
- mloop = pim_socket_mcastloop_get(igmp->fd);
-
- vty_out(vty, "%-9s %-15s %7d %6d %8s %5s %5s %5s %5s %5s %3s%s",
- ifp->name,
- inet_ntoa(igmp->ifaddr),
- ifp->ifindex,
- igmp->fd,
- uptime,
- if_is_multicast(ifp) ? "yes" : "no",
- if_is_broadcast(ifp) ? "yes" : "no",
- (mloop < 0) ? "?" : (mloop ? "yes" : "no"),
- (ifp->flags & IFF_ALLMULTI) ? "yes" : "no",
- (ifp->flags & IFF_PROMISC) ? "yes" : "no",
- PIM_IF_IS_DELETED(ifp) ? "yes" : "no",
- VTY_NEWLINE);
+ if (uj) {
+ json_row = json_object_new_object();
+ json_object_pim_ifp_add(json_row, ifp);
+ json_object_string_add(json_row, "upTime", uptime);
+ json_object_int_add(json_row, "version", pim_ifp->igmp_version);
+
+ if (igmp->t_igmp_query_timer) {
+ json_object_boolean_true_add(json_row, "querier");
+ json_object_string_add(json_row, "queryTimer", query_hhmmss);
+ }
+
+ json_object_object_add(json, ifp->name, json_row);
+
+ } else {
+ vty_out(vty, "%-9s %5s %15s %d %7s %11s %8s%s",
+ ifp->name,
+ if_is_up(ifp) ? "up" : "down",
+ inet_ntoa(igmp->ifaddr),
+ pim_ifp->igmp_version,
+ igmp->t_igmp_query_timer ? "local" : "other",
+ query_hhmmss,
+ uptime,
+ VTY_NEWLINE);
+ }
}
}
+
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
+ }
+}
+
+static void igmp_show_interfaces_single(struct vty *vty, const char *ifname, u_char uj)
+{
+ struct igmp_sock *igmp;
+ struct interface *ifp;
+ struct listnode *node;
+ struct listnode *sock_node;
+ struct pim_interface *pim_ifp;
+ char uptime[10];
+ char query_hhmmss[10];
+ char other_hhmmss[10];
+ int found_ifname = 0;
+ int sqi;
+ int mloop;
+ long gmi_msec; /* Group Membership Interval */
+ long lmqt_msec;
+ long ohpi_msec;
+ long oqpi_msec; /* Other Querier Present Interval */
+ long qri_msec;
+ time_t now;
+
+ json_object *json = NULL;
+ json_object *json_row = NULL;
+
+ if (uj)
+ json = json_object_new_object();
+
+ now = pim_time_monotonic_sec();
+
+ for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) {
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp)
+ continue;
+
+ if (strcmp(ifname, "detail") && strcmp(ifname, ifp->name))
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
+ found_ifname = 1;
+ pim_time_uptime(uptime, sizeof(uptime), now - igmp->sock_creation);
+ pim_time_timer_to_hhmmss(query_hhmmss, sizeof(query_hhmmss), igmp->t_igmp_query_timer);
+ pim_time_timer_to_hhmmss(other_hhmmss, sizeof(other_hhmmss), igmp->t_other_querier_timer);
+
+ gmi_msec = PIM_IGMP_GMI_MSEC(igmp->querier_robustness_variable,
+ igmp->querier_query_interval,
+ pim_ifp->igmp_query_max_response_time_dsec);
+
+ sqi = PIM_IGMP_SQI(pim_ifp->igmp_default_query_interval);
+
+ oqpi_msec = PIM_IGMP_OQPI_MSEC(igmp->querier_robustness_variable,
+ igmp->querier_query_interval,
+ pim_ifp->igmp_query_max_response_time_dsec);
+
+ lmqt_msec = PIM_IGMP_LMQT_MSEC(pim_ifp->igmp_query_max_response_time_dsec,
+ igmp->querier_robustness_variable);
+
+ ohpi_msec = PIM_IGMP_OHPI_DSEC(igmp->querier_robustness_variable,
+ igmp->querier_query_interval,
+ pim_ifp->igmp_query_max_response_time_dsec) * 100;
+
+ qri_msec = pim_ifp->igmp_query_max_response_time_dsec * 100;
+ mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd);
+
+ if (uj) {
+ json_row = json_object_new_object();
+ json_object_pim_ifp_add(json_row, ifp);
+ json_object_string_add(json_row, "upTime", uptime);
+ json_object_string_add(json_row, "querier", igmp->t_igmp_query_timer ? "local" : "other");
+ json_object_int_add(json_row, "queryStartCount", igmp->startup_query_count);
+ json_object_string_add(json_row, "queryQueryTimer", query_hhmmss);
+ json_object_string_add(json_row, "queryOtherTimer", other_hhmmss);
+ json_object_int_add(json_row, "version", pim_ifp->igmp_version);
+ json_object_int_add(json_row, "timerGroupMembershipIntervalMsec", gmi_msec);
+ json_object_int_add(json_row, "timerLastMemberQueryMsec", lmqt_msec);
+ json_object_int_add(json_row, "timerOlderHostPresentIntervalMsec", ohpi_msec);
+ json_object_int_add(json_row, "timerOtherQuerierPresentIntervalMsec", oqpi_msec);
+ json_object_int_add(json_row, "timerQueryInterval", igmp->querier_query_interval);
+ json_object_int_add(json_row, "timerQueryResponseIntervalMsec", qri_msec);
+ json_object_int_add(json_row, "timerRobustnessVariable", igmp->querier_robustness_variable);
+ json_object_int_add(json_row, "timerStartupQueryInterval", sqi);
+
+ json_object_object_add(json, ifp->name, json_row);
+
+ } else {
+ vty_out(vty, "Interface : %s%s", ifp->name, VTY_NEWLINE);
+ vty_out(vty, "State : %s%s", if_is_up(ifp) ? "up" : "down", VTY_NEWLINE);
+ vty_out(vty, "Address : %s%s", inet_ntoa(pim_ifp->primary_address), VTY_NEWLINE);
+ vty_out(vty, "Uptime : %s%s", uptime, VTY_NEWLINE);
+ vty_out(vty, "Version : %d%s", pim_ifp->igmp_version, VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
+
+ vty_out(vty, "Querier%s", VTY_NEWLINE);
+ vty_out(vty, "-------%s", VTY_NEWLINE);
+ vty_out(vty, "Querier : %s%s", igmp->t_igmp_query_timer ? "local" : "other", VTY_NEWLINE);
+ vty_out(vty, "Start Count : %d%s", igmp->startup_query_count, VTY_NEWLINE);
+ vty_out(vty, "Query Timer : %s%s", query_hhmmss, VTY_NEWLINE);
+ vty_out(vty, "Other Timer : %s%s", other_hhmmss, VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
+
+ vty_out(vty, "Timers%s", VTY_NEWLINE);
+ vty_out(vty, "------%s", VTY_NEWLINE);
+ vty_out(vty, "Group Membership Interval : %lis%s", gmi_msec/1000, VTY_NEWLINE);
+ vty_out(vty, "Last Member Query Time : %lis%s", lmqt_msec/1000, VTY_NEWLINE);
+ vty_out(vty, "Older Host Present Interval : %lis%s", ohpi_msec/1000, VTY_NEWLINE);
+ vty_out(vty, "Other Querier Present Interval : %lis%s", oqpi_msec/1000, VTY_NEWLINE);
+ vty_out(vty, "Query Interval : %ds%s", igmp->querier_query_interval, VTY_NEWLINE);
+ vty_out(vty, "Query Response Interval : %lis%s", qri_msec/1000, VTY_NEWLINE);
+ vty_out(vty, "Robustness Variable : %d%s", igmp->querier_robustness_variable, VTY_NEWLINE);
+ vty_out(vty, "Startup Query Interval : %ds%s", sqi, VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
+
+ pim_print_ifp_flags(vty, ifp, mloop);
+ }
+ }
+ }
+
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
+ } else {
+ if (!found_ifname)
+ vty_out (vty, "%% No such interface%s", VTY_NEWLINE);
+ }
}
static void igmp_show_interface_join(struct vty *vty)
@@ -474,7 +719,7 @@ static void igmp_show_interface_join(struct vty *vty)
struct listnode *join_node;
struct igmp_join *ij;
struct in_addr pri_addr;
- char pri_addr_str[100];
+ char pri_addr_str[INET_ADDRSTRLEN];
pim_ifp = ifp->info;
@@ -488,8 +733,8 @@ static void igmp_show_interface_join(struct vty *vty)
pim_inet4_dump("<pri?>", pri_addr, pri_addr_str, sizeof(pri_addr_str));
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_join_list, join_node, ij)) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
char uptime[10];
pim_time_uptime(uptime, sizeof(uptime), now - ij->sock_creation);
@@ -510,159 +755,297 @@ static void igmp_show_interface_join(struct vty *vty)
}
-static void show_interface_address(struct vty *vty)
+static void pim_show_interfaces_single(struct vty *vty, const char *ifname, u_char uj)
{
- struct listnode *ifpnode;
+ struct in_addr ifaddr;
struct interface *ifp;
-
- vty_out(vty,
- "Interface Primary Secondary %s",
- VTY_NEWLINE);
-
- for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifpnode, ifp)) {
- struct listnode *ifcnode;
- struct connected *ifc;
- struct in_addr pri_addr;
- char pri_addr_str[100];
-
- pri_addr = pim_find_primary_addr(ifp);
-
- pim_inet4_dump("<pri?>", pri_addr, pri_addr_str, sizeof(pri_addr_str));
-
- for (ALL_LIST_ELEMENTS_RO(ifp->connected, ifcnode, ifc)) {
- char sec_addr_str[100];
- struct prefix *p = ifc->address;
-
- if (p->family != AF_INET)
- continue;
-
- if (p->u.prefix4.s_addr == pri_addr.s_addr) {
- sec_addr_str[0] = '\0';
- }
- else {
- pim_inet4_dump("<sec?>", p->u.prefix4, sec_addr_str, sizeof(sec_addr_str));
- }
-
- vty_out(vty, "%-9s %-15s %-15s%s",
- ifp->name,
- pri_addr_str,
- sec_addr_str,
- VTY_NEWLINE);
- }
- }
-}
+ struct listnode *neighnode;
+ struct listnode*node;
+ struct listnode *upnode;
+ struct pim_interface *pim_ifp;
+ struct pim_neighbor *neigh;
+ struct pim_upstream *up;
+ time_t now;
+ char dr_str[INET_ADDRSTRLEN];
+ char dr_uptime[10];
+ char expire[10];
+ char grp_str[INET_ADDRSTRLEN];
+ char hello_period[10];
+ char hello_timer[10];
+ char neigh_src_str[INET_ADDRSTRLEN];
+ char src_str[INET_ADDRSTRLEN];
+ char stat_uptime[10];
+ char uptime[10];
+ int mloop;
+ int found_ifname = 0;
+ int print_header;
+ json_object *json = NULL;
+ json_object *json_row = NULL;
+ json_object *json_pim_neighbor = NULL;
+ json_object *json_pim_neighbors = NULL;
+ json_object *json_group = NULL;
+ json_object *json_group_source = NULL;
+ json_object *json_fhr_sources = NULL;
+ struct pim_secondary_addr *sec_addr;
+ struct listnode *sec_node;
-static void pim_show_dr(struct vty *vty)
-{
- struct listnode *node;
- struct interface *ifp;
- time_t now;
-
now = pim_time_monotonic_sec();
- vty_out(vty,
- "NonPri: Number of neighbors missing DR Priority hello option%s"
- "DrPri: Designated Router Priority sent%s%s",
- VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
-
- vty_out(vty, "Interface Address DR Uptime Elections Changes NonPri DrPri%s", VTY_NEWLINE);
+ if (uj)
+ json = json_object_new_object();
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) {
- struct pim_interface *pim_ifp;
- struct in_addr ifaddr;
- char dr_str[100];
- char dr_uptime[10];
-
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;
+
+ found_ifname = 1;
ifaddr = pim_ifp->primary_address;
+ pim_inet4_dump("<dr?>", pim_ifp->pim_dr_addr, dr_str, sizeof(dr_str));
+ pim_time_uptime_begin(dr_uptime, sizeof(dr_uptime), now, pim_ifp->pim_dr_election_last);
+ pim_time_timer_to_hhmmss(hello_timer, sizeof(hello_timer), pim_ifp->t_pim_hello_timer);
+ pim_time_mmss(hello_period, sizeof(hello_period), 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);
- pim_time_uptime_begin(dr_uptime, sizeof(dr_uptime),
- now, pim_ifp->pim_dr_election_last);
+ if (uj) {
+ json_row = json_object_new_object();
+ json_object_pim_ifp_add(json_row, ifp);
- pim_inet4_dump("<dr?>", pim_ifp->pim_dr_addr,
- dr_str, sizeof(dr_str));
+ if (pim_ifp->update_source.s_addr != INADDR_ANY) {
+ json_object_string_add(json_row, "useSource", inet_ntoa(pim_ifp->update_source));
+ }
+ if (pim_ifp->sec_addr_list) {
+ json_object *sec_list = NULL;
+
+ sec_list = json_object_new_array();
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, sec_node, sec_addr)) {
+ json_object_array_add(sec_list, json_object_new_string(inet_ntoa(sec_addr->addr)));
+ }
+ json_object_object_add(json_row, "secondaryAddressList", sec_list);
+ }
- vty_out(vty, "%-9s %-15s %-15s %8s %9d %7d %6d %10d%s",
- ifp->name,
- inet_ntoa(ifaddr),
- dr_str,
- dr_uptime,
- pim_ifp->pim_dr_election_count,
- pim_ifp->pim_dr_election_changes,
- pim_ifp->pim_dr_num_nondrpri_neighbors,
- pim_ifp->pim_dr_priority,
- VTY_NEWLINE);
- }
-}
+ // PIM neighbors
+ if (pim_ifp->pim_neighbor_list->count) {
+ json_pim_neighbors = json_object_new_object();
-static void pim_show_hello(struct vty *vty)
-{
- struct listnode *node;
- struct interface *ifp;
- time_t now;
-
- now = pim_time_monotonic_sec();
-
- vty_out(vty, "Interface Address Period Timer StatStart Recv Rfail Send Sfail%s", VTY_NEWLINE);
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) {
+ json_pim_neighbor = json_object_new_object();
+ pim_inet4_dump("<src?>", neigh->source_addr, neigh_src_str, sizeof(neigh_src_str));
+ pim_time_uptime(uptime, sizeof(uptime), now - neigh->creation);
+ pim_time_timer_to_hhmmss(expire, sizeof(expire), neigh->t_expire_timer);
- for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) {
- struct pim_interface *pim_ifp;
- struct in_addr ifaddr;
- char hello_period[10];
- char hello_timer[10];
- char stat_uptime[10];
+ json_object_string_add(json_pim_neighbor, "address", neigh_src_str);
+ json_object_string_add(json_pim_neighbor, "upTime", uptime);
+ json_object_string_add(json_pim_neighbor, "holdtime", expire);
- pim_ifp = ifp->info;
-
- if (!pim_ifp)
- continue;
+ json_object_object_add(json_pim_neighbors, neigh_src_str, json_pim_neighbor);
+ }
- if (pim_ifp->pim_sock_fd < 0)
- continue;
+ json_object_object_add(json_row, "neighbors", json_pim_neighbors);
+ }
- ifaddr = pim_ifp->primary_address;
+ json_object_string_add(json_row, "drAddress", dr_str);
+ json_object_int_add(json_row, "drPriority", pim_ifp->pim_dr_priority);
+ json_object_string_add(json_row, "drUptime", dr_uptime);
+ json_object_int_add(json_row, "drElections", pim_ifp->pim_dr_election_count);
+ json_object_int_add(json_row, "drChanges", pim_ifp->pim_dr_election_changes);
+
+ // FHR
+ 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) {
+ if (!json_fhr_sources) {
+ json_fhr_sources = json_object_new_object();
+ }
+
+ pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
+ pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
+ pim_time_uptime(uptime, sizeof(uptime), now - up->state_transition);
+
+ /* Does this group live in json_fhr_sources? If not create it. */
+ json_object_object_get_ex(json_fhr_sources, grp_str, &json_group);
+
+ if (!json_group) {
+ json_group = json_object_new_object();
+ json_object_object_add(json_fhr_sources, grp_str, json_group);
+ }
+
+ json_group_source = json_object_new_object();
+ json_object_string_add(json_group_source, "source", src_str);
+ json_object_string_add(json_group_source, "group", grp_str);
+ json_object_string_add(json_group_source, "upTime", uptime);
+ json_object_object_add(json_group, src_str, json_group_source);
+ }
+ }
+ }
- pim_time_timer_to_mmss(hello_timer, sizeof(hello_timer), pim_ifp->t_pim_hello_timer);
- pim_time_mmss(hello_period, sizeof(hello_period), pim_ifp->pim_hello_period);
- pim_time_uptime(stat_uptime, sizeof(stat_uptime), now - pim_ifp->pim_ifstat_start);
+ if (json_fhr_sources) {
+ json_object_object_add(json_row, "firstHopRouter", json_fhr_sources);
+ }
- vty_out(vty, "%-9s %-15s %6s %5s %9s %4u %5u %4u %5u%s",
- ifp->name,
- inet_ntoa(ifaddr),
- hello_period,
- hello_timer,
- stat_uptime,
- pim_ifp->pim_ifstat_hello_recv,
- pim_ifp->pim_ifstat_hello_recvfail,
- pim_ifp->pim_ifstat_hello_sent,
- pim_ifp->pim_ifstat_hello_sendfail,
- VTY_NEWLINE);
+ json_object_int_add(json_row, "helloPeriod", pim_ifp->pim_hello_period);
+ json_object_string_add(json_row, "helloTimer", hello_timer);
+ json_object_string_add(json_row, "helloStatStart", stat_uptime);
+ json_object_int_add(json_row, "helloReceived", pim_ifp->pim_ifstat_hello_recv);
+ json_object_int_add(json_row, "helloReceivedFailed", pim_ifp->pim_ifstat_hello_recvfail);
+ json_object_int_add(json_row, "helloSend", pim_ifp->pim_ifstat_hello_sent);
+ json_object_int_add(json_row, "hellosendFailed", pim_ifp->pim_ifstat_hello_sendfail);
+ json_object_int_add(json_row, "helloGenerationId", pim_ifp->pim_generation_id);
+ json_object_int_add(json_row, "flagMulticastLoop", mloop);
+
+ json_object_int_add(json_row, "effectivePropagationDelay", pim_if_effective_propagation_delay_msec(ifp));
+ json_object_int_add(json_row, "effectiveOverrideInterval", pim_if_effective_override_interval_msec(ifp));
+ json_object_int_add(json_row, "joinPruneOverrideInterval", pim_if_jp_override_interval_msec(ifp));
+
+ json_object_int_add(json_row, "propagationDelay", pim_ifp->pim_propagation_delay_msec);
+ json_object_int_add(json_row, "propagationDelayHighest", pim_ifp->pim_neighbors_highest_propagation_delay_msec);
+ json_object_int_add(json_row, "overrideInterval", pim_ifp->pim_override_interval_msec);
+ json_object_int_add(json_row, "overrideIntervalHighest", pim_ifp->pim_neighbors_highest_override_interval_msec);
+ json_object_object_add(json, ifp->name, json_row);
+
+ } else {
+ vty_out(vty, "Interface : %s%s", ifp->name, VTY_NEWLINE);
+ vty_out(vty, "State : %s%s", if_is_up(ifp) ? "up" : "down", VTY_NEWLINE);
+ if (pim_ifp->update_source.s_addr != INADDR_ANY) {
+ vty_out(vty, "Use Source : %s%s", inet_ntoa(pim_ifp->update_source), VTY_NEWLINE);
+ }
+ if (pim_ifp->sec_addr_list) {
+ vty_out(vty, "Address : %s (primary)%s",
+ inet_ntoa(ifaddr), VTY_NEWLINE);
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, sec_node, sec_addr)) {
+ vty_out(vty, " %s%s",
+ inet_ntoa(sec_addr->addr), VTY_NEWLINE);
+ }
+ } else {
+ vty_out(vty, "Address : %s%s", inet_ntoa(ifaddr), VTY_NEWLINE);
+ }
+ vty_out(vty, "%s", VTY_NEWLINE);
+
+ // PIM neighbors
+ print_header = 1;
+
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) {
+
+ if (print_header) {
+ vty_out(vty, "PIM Neighbors%s", VTY_NEWLINE);
+ vty_out(vty, "-------------%s", VTY_NEWLINE);
+ print_header = 0;
+ }
+
+ pim_inet4_dump("<src?>", neigh->source_addr, neigh_src_str, sizeof(neigh_src_str));
+ pim_time_uptime(uptime, sizeof(uptime), now - neigh->creation);
+ pim_time_timer_to_hhmmss(expire, sizeof(expire), neigh->t_expire_timer);
+ vty_out(vty, "%-15s : up for %s, holdtime expires in %s%s", neigh_src_str, uptime, expire, VTY_NEWLINE);
+ }
+
+ if (!print_header) {
+ vty_out(vty, "%s", VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
+
+ vty_out(vty, "Designated Router%s", VTY_NEWLINE);
+ vty_out(vty, "-----------------%s", VTY_NEWLINE);
+ vty_out(vty, "Address : %s%s", dr_str, VTY_NEWLINE);
+ vty_out(vty, "Priority : %d%s", pim_ifp->pim_dr_priority, VTY_NEWLINE);
+ vty_out(vty, "Uptime : %s%s", dr_uptime, VTY_NEWLINE);
+ vty_out(vty, "Elections : %d%s", pim_ifp->pim_dr_election_count, VTY_NEWLINE);
+ vty_out(vty, "Changes : %d%s", pim_ifp->pim_dr_election_changes, VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
+
+ // FHR
+ print_header = 1;
+ for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode, up)) {
+ if (strcmp(ifp->name, up->rpf.source_nexthop.interface->name) == 0) {
+ if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR) {
+
+ if (print_header) {
+ vty_out(vty, "FHR - First Hop Router%s", VTY_NEWLINE);
+ vty_out(vty, "----------------------%s", VTY_NEWLINE);
+ print_header = 0;
+ }
+
+ pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
+ pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
+ pim_time_uptime(uptime, sizeof(uptime), now - up->state_transition);
+ vty_out(vty, "%s : %s is a source, uptime is %s%s", grp_str, src_str, uptime, VTY_NEWLINE);
+ }
+ }
+ }
+
+ if (!print_header) {
+ vty_out(vty, "%s", VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
+
+ vty_out(vty, "Hellos%s", VTY_NEWLINE);
+ vty_out(vty, "------%s", VTY_NEWLINE);
+ vty_out(vty, "Period : %d%s", pim_ifp->pim_hello_period, VTY_NEWLINE);
+ vty_out(vty, "Timer : %s%s", hello_timer, VTY_NEWLINE);
+ vty_out(vty, "StatStart : %s%s", stat_uptime, VTY_NEWLINE);
+ vty_out(vty, "Receive : %d%s", pim_ifp->pim_ifstat_hello_recv, VTY_NEWLINE);
+ vty_out(vty, "Receive Failed : %d%s", pim_ifp->pim_ifstat_hello_recvfail, VTY_NEWLINE);
+ vty_out(vty, "Send : %d%s", pim_ifp->pim_ifstat_hello_sent, VTY_NEWLINE);
+ vty_out(vty, "Send Failed : %d%s", pim_ifp->pim_ifstat_hello_sendfail, VTY_NEWLINE);
+ vty_out(vty, "Generation ID : %08x%s", pim_ifp->pim_generation_id, VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
+
+ pim_print_ifp_flags(vty, ifp, mloop);
+
+ vty_out(vty, "Join Prune Interval%s", VTY_NEWLINE);
+ vty_out(vty, "-------------------%s", VTY_NEWLINE);
+ vty_out(vty, "LAN Delay : %s%s", pim_if_lan_delay_enabled(ifp) ? "yes" : "no", VTY_NEWLINE);
+ vty_out(vty, "Effective Propagation Delay : %d msec%s", pim_if_effective_propagation_delay_msec(ifp), VTY_NEWLINE);
+ vty_out(vty, "Effective Override Interval : %d msec%s", pim_if_effective_override_interval_msec(ifp), VTY_NEWLINE);
+ vty_out(vty, "Join Prune Override Interval : %d msec%s", pim_if_jp_override_interval_msec(ifp), VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
+
+ vty_out(vty, "LAN Prune Delay%s", VTY_NEWLINE);
+ vty_out(vty, "---------------%s", VTY_NEWLINE);
+ vty_out(vty, "Propagation Delay : %d msec%s", pim_ifp->pim_propagation_delay_msec, VTY_NEWLINE);
+ vty_out(vty, "Propagation Delay (Highest) : %d msec%s", pim_ifp->pim_neighbors_highest_propagation_delay_msec, VTY_NEWLINE);
+ vty_out(vty, "Override Interval : %d msec%s", pim_ifp->pim_override_interval_msec, VTY_NEWLINE);
+ vty_out(vty, "Override Interval (Highest) : %d msec%s", pim_ifp->pim_neighbors_highest_override_interval_msec, VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
+ }
+
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
+ } else {
+ if (!found_ifname)
+ vty_out (vty, "%% No such interface%s", VTY_NEWLINE);
}
}
-static void pim_show_interfaces(struct vty *vty)
+static void pim_show_interfaces(struct vty *vty, u_char uj)
{
- struct listnode *node;
struct interface *ifp;
- time_t now;
-
- now = pim_time_monotonic_sec();
+ struct listnode *node;
+ struct listnode *upnode;
+ struct pim_interface *pim_ifp;
+ struct pim_upstream *up;
+ int fhr = 0;
+ int pim_nbrs = 0;
+ json_object *json = NULL;
+ json_object *json_row = NULL;
+ json_object *json_tmp;
- vty_out(vty, "Interface Address ifIndex Socket Uptime Multi Broad MLoop AllMu Prmsc Del%s", VTY_NEWLINE);
+ json = json_object_new_object();
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) {
- struct pim_interface *pim_ifp;
- struct in_addr ifaddr;
- char uptime[10];
- int mloop;
-
pim_ifp = ifp->info;
if (!pim_ifp)
@@ -671,73 +1054,136 @@ static void pim_show_interfaces(struct vty *vty)
if (pim_ifp->pim_sock_fd < 0)
continue;
- ifaddr = pim_ifp->primary_address;
+ pim_nbrs = pim_ifp->pim_neighbor_list->count;
+ fhr = 0;
- pim_time_uptime(uptime, sizeof(uptime), now - pim_ifp->pim_sock_creation);
+ 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++;
- mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd);
-
- vty_out(vty, "%-9s %-15s %7d %6d %8s %5s %5s %5s %5s %5s %3s%s",
- ifp->name,
- inet_ntoa(ifaddr),
- ifp->ifindex,
- pim_ifp->pim_sock_fd,
- uptime,
- if_is_multicast(ifp) ? "yes" : "no",
- if_is_broadcast(ifp) ? "yes" : "no",
- (mloop < 0) ? "?" : (mloop ? "yes" : "no"),
- (ifp->flags & IFF_ALLMULTI) ? "yes" : "no",
- (ifp->flags & IFF_PROMISC) ? "yes" : "no",
- PIM_IF_IS_DELETED(ifp) ? "yes" : "no",
- VTY_NEWLINE);
+ json_row = json_object_new_object();
+ json_object_pim_ifp_add(json_row, ifp);
+ json_object_int_add(json_row, "pimNeighbors", pim_nbrs);
+ json_object_int_add(json_row, "firstHopRouter", fhr);
+ json_object_string_add(json_row, "pimDesignatedRouter", inet_ntoa(pim_ifp->pim_dr_addr));
+
+ if (pim_ifp->pim_dr_addr.s_addr == pim_ifp->primary_address.s_addr)
+ json_object_boolean_true_add(json_row, "pimDesignatedRouterLocal");
+
+ json_object_object_add(json, ifp->name, json_row);
+ }
+
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ } else {
+ vty_out(vty, "Interface State Address PIM Nbrs PIM DR FHR%s", VTY_NEWLINE);
+
+ json_object_object_foreach(json, key, val) {
+ vty_out(vty, "%-9s ", key);
+
+ json_object_object_get_ex(val, "state", &json_tmp);
+ vty_out(vty, "%5s ", json_object_get_string(json_tmp));
+
+ json_object_object_get_ex(val, "address", &json_tmp);
+ vty_out(vty, "%15s ", json_object_get_string(json_tmp));
+
+ json_object_object_get_ex(val, "pimNeighbors", &json_tmp);
+ vty_out(vty, "%8d ", json_object_get_int(json_tmp));
+
+ if (json_object_object_get_ex(val, "pimDesignatedRouterLocal", &json_tmp)) {
+ vty_out(vty, "%15s ", "local");
+ } else {
+ json_object_object_get_ex(val, "pimDesignatedRouter", &json_tmp);
+ vty_out(vty, "%15s ", json_object_get_string(json_tmp));
+ }
+
+ json_object_object_get_ex(val, "firstHopRouter", &json_tmp);
+ vty_out(vty, "%3d%s", json_object_get_int(json_tmp), VTY_NEWLINE);
+ }
}
+
+ json_object_free(json);
}
-static void pim_show_join(struct vty *vty)
+static void pim_show_join(struct vty *vty, u_char uj)
{
- struct listnode *ifnode;
- struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ struct in_addr ifaddr;
+ struct listnode *ch_node;
+ struct pim_ifchannel *ch;
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%s",
- VTY_NEWLINE);
+ if (uj)
+ json = json_object_new_object();
+ else
+ vty_out(vty,
+ "Interface Address Source Group State Uptime Expire Prune%s",
+ VTY_NEWLINE);
- for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp)) {
- struct pim_interface *pim_ifp;
- struct in_addr ifaddr;
- struct listnode *ch_node;
- struct pim_ifchannel *ch;
+ for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, ch_node, ch)) {
- pim_ifp = ifp->info;
+ pim_ifp = ch->interface->info;
if (!pim_ifp)
continue;
ifaddr = pim_ifp->primary_address;
- for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
- char ch_src_str[100];
- char ch_grp_str[100];
- char uptime[10];
- char expire[10];
- char prune[10];
-
- pim_inet4_dump("<ch_src?>", ch->source_addr,
- ch_src_str, sizeof(ch_src_str));
- pim_inet4_dump("<ch_grp?>", ch->group_addr,
- 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);
+ 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));
+ 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%s",
- ifp->name,
+ ch->interface->name,
inet_ntoa(ifaddr),
ch_src_str,
ch_grp_str,
@@ -746,172 +1192,366 @@ static void pim_show_join(struct vty *vty)
expire,
prune,
VTY_NEWLINE);
- } /* scan interface channels */
- } /* scan interfaces */
+ }
+ } /* scan interface channels */
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
+ }
}
-static void pim_show_neighbors(struct vty *vty)
+static void pim_show_neighbors_single(struct vty *vty, const char *neighbor, u_char uj)
{
struct listnode *node;
+ struct listnode *neighnode;
struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ struct pim_neighbor *neigh;
time_t now;
-
- now = pim_time_monotonic_sec();
+ int found_neighbor = 0;
+ int option_address_list;
+ int option_dr_priority;
+ int option_generation_id;
+ int option_holdtime;
+ int option_lan_prune_delay;
+ int option_t_bit;
+ char uptime[10];
+ char expire[10];
+ char neigh_src_str[INET_ADDRSTRLEN];
+
+ json_object *json = NULL;
+ json_object *json_ifp = NULL;
+ json_object *json_row = NULL;
- vty_out(vty,
- "Recv flags: H=holdtime L=lan_prune_delay P=dr_priority G=generation_id A=address_list%s"
- " T=can_disable_join_suppression%s%s",
- VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+ now = pim_time_monotonic_sec();
- vty_out(vty, "Interface Address Neighbor Uptime Timer Holdt DrPri GenId Recv %s", VTY_NEWLINE);
+ if (uj)
+ json = json_object_new_object();
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) {
- struct pim_interface *pim_ifp;
- struct in_addr ifaddr;
- struct listnode *neighnode;
- struct pim_neighbor *neigh;
-
pim_ifp = ifp->info;
-
+
if (!pim_ifp)
continue;
if (pim_ifp->pim_sock_fd < 0)
continue;
- ifaddr = pim_ifp->primary_address;
-
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) {
- char uptime[10];
- char holdtime[10];
- char expire[10];
- char neigh_src_str[100];
- char recv[7];
-
pim_inet4_dump("<src?>", neigh->source_addr,
neigh_src_str, sizeof(neigh_src_str));
+
+ /*
+ * The user can specify either the interface name or the PIM neighbor IP.
+ * If this pim_ifp matches neither then skip.
+ */
+ if (strcmp(neighbor, "detail") &&
+ strcmp(neighbor, ifp->name) &&
+ strcmp(neighbor, neigh_src_str))
+ continue;
+
+ found_neighbor = 1;
pim_time_uptime(uptime, sizeof(uptime), now - neigh->creation);
- pim_time_mmss(holdtime, sizeof(holdtime), neigh->holdtime);
- pim_time_timer_to_mmss(expire, sizeof(expire), neigh->t_expire_timer);
-
- recv[0] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_HOLDTIME) ? 'H' : ' ';
- recv[1] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY) ? 'L' : ' ';
- recv[2] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_DR_PRIORITY) ? 'P' : ' ';
- recv[3] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_GENERATION_ID) ? 'G' : ' ';
- recv[4] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_ADDRESS_LIST) ? 'A' : ' ';
- recv[5] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION) ? 'T' : ' ';
- recv[6] = '\0';
-
- vty_out(vty, "%-9s %-15s %-15s %8s %5s %5s %5u %08x %6s%s",
- ifp->name,
- inet_ntoa(ifaddr),
- neigh_src_str,
- uptime,
- expire,
- holdtime,
- neigh->dr_priority,
- neigh->generation_id,
- recv,
- VTY_NEWLINE);
+ pim_time_timer_to_hhmmss(expire, sizeof(expire), neigh->t_expire_timer);
+
+ option_address_list = 0;
+ option_dr_priority = 0;
+ option_generation_id = 0;
+ option_holdtime = 0;
+ option_lan_prune_delay = 0;
+ option_t_bit = 0;
+
+ if (PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_ADDRESS_LIST))
+ option_address_list = 1;
+
+ if (PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_DR_PRIORITY))
+ option_dr_priority = 1;
+
+ if (PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_GENERATION_ID))
+ option_generation_id = 1;
+
+ if (PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_HOLDTIME))
+ option_holdtime = 1;
+
+ if (PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY))
+ option_lan_prune_delay = 1;
+
+ if (PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION))
+ option_t_bit = 1;
+
+ if (uj) {
+
+ /* Does this ifp live in json? If not create it. */
+ json_object_object_get_ex(json, ifp->name, &json_ifp);
+
+ if (!json_ifp) {
+ json_ifp = json_object_new_object();
+ json_object_pim_ifp_add(json_ifp, ifp);
+ json_object_object_add(json, ifp->name, json_ifp);
+ }
+
+ json_row = json_object_new_object();
+ json_object_string_add(json_row, "interface", ifp->name);
+ json_object_string_add(json_row, "address", neigh_src_str);
+ json_object_string_add(json_row, "upTime", uptime);
+ json_object_string_add(json_row, "holdtime", expire);
+ json_object_int_add(json_row, "drPriority", neigh->dr_priority);
+ json_object_int_add(json_row, "generationId", neigh->generation_id);
+
+ if (option_address_list)
+ json_object_boolean_true_add(json_row, "helloOptionAddressList");
+
+ if (option_dr_priority)
+ json_object_boolean_true_add(json_row, "helloOptionDrPriority");
+
+ if (option_generation_id)
+ json_object_boolean_true_add(json_row, "helloOptionGenerationId");
+
+ if (option_holdtime)
+ json_object_boolean_true_add(json_row, "helloOptionHoldtime");
+
+ if (option_lan_prune_delay)
+ json_object_boolean_true_add(json_row, "helloOptionLanPruneDelay");
+
+ if (option_t_bit)
+ json_object_boolean_true_add(json_row, "helloOptionTBit");
+
+ json_object_object_add(json_ifp, neigh_src_str, json_row);
+
+ } else {
+ vty_out(vty, "Interface : %s%s", ifp->name, VTY_NEWLINE);
+ vty_out(vty, "Neighbor : %s%s", neigh_src_str, VTY_NEWLINE);
+ vty_out(vty, " Uptime : %s%s", uptime, VTY_NEWLINE);
+ vty_out(vty, " Holdtime : %s%s", expire, VTY_NEWLINE);
+ vty_out(vty, " DR Priority : %d%s", neigh->dr_priority, VTY_NEWLINE);
+ vty_out(vty, " Generation ID : %08x%s", neigh->generation_id, VTY_NEWLINE);
+ vty_out(vty, " Override Interval (msec) : %d%s", neigh->override_interval_msec, VTY_NEWLINE);
+ vty_out(vty, " Propagation Delay (msec) : %d%s", neigh->propagation_delay_msec, VTY_NEWLINE);
+ vty_out(vty, " Hello Option - Address List : %s%s", option_address_list ? "yes" : "no", VTY_NEWLINE);
+ vty_out(vty, " Hello Option - DR Priority : %s%s", option_dr_priority ? "yes" : "no", VTY_NEWLINE);
+ vty_out(vty, " Hello Option - Generation ID : %s%s", option_generation_id? "yes" : "no", VTY_NEWLINE);
+ vty_out(vty, " Hello Option - Holdtime : %s%s", option_holdtime ? "yes" : "no", VTY_NEWLINE);
+ vty_out(vty, " Hello Option - LAN Prune Delay : %s%s", option_lan_prune_delay ? "yes" : "no", VTY_NEWLINE);
+ vty_out(vty, " Hello Option - T-bit : %s%s", option_t_bit ? "yes" : "no", VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
}
+ }
-
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
+ } else {
+ {
+ if (!found_neighbor)
+ vty_out (vty, "%% No such interface or neighbor%s", VTY_NEWLINE);
+ }
}
}
-static void pim_show_lan_prune_delay(struct vty *vty)
+static void
+pim_show_state(struct vty *vty, const char *src_or_group, const char *group, u_char uj)
{
- struct listnode *node;
- struct interface *ifp;
-
- vty_out(vty,
- "PrDly=propagation_delay (msec) OvInt=override_interval (msec)%s"
- "HiDly=highest_propagation_delay (msec) HiInt=highest_override_interval (msec)%s"
- "NoDly=number_of_non_lan_delay_neighbors%s"
- "T=t_bit LPD=lan_prune_delay_hello_option%s%s",
- VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+ struct channel_oil *c_oil;
+ struct listnode *node;
+ json_object *json = NULL;
+ json_object *json_group = NULL;
+ json_object *json_ifp_in = NULL;
+ json_object *json_ifp_out = NULL;
+ json_object *json_source = NULL;
+ time_t now;
+ int first_oif;
+ now = pim_time_monotonic_sec();
- vty_out(vty, "Interface Address PrDly OvInt NoDly HiDly HiInt T | Neighbor LPD PrDly OvInt T%s", VTY_NEWLINE);
+ if (uj) {
+ json = json_object_new_object();
+ } else {
+ vty_out(vty, "%sSource Group IIF OIL%s", VTY_NEWLINE, VTY_NEWLINE);
+ }
- for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) {
- struct pim_interface *pim_ifp;
- struct in_addr ifaddr;
- struct listnode *neighnode;
- struct pim_neighbor *neigh;
+ 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[16];
+ char out_ifname[16];
+ int oif_vif_index;
+ struct interface *ifp_in;
+ first_oif = 1;
- pim_ifp = ifp->info;
-
- if (!pim_ifp)
+ if (!c_oil->installed)
continue;
- if (pim_ifp->pim_sock_fd < 0)
- continue;
+ pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, grp_str, 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);
- ifaddr = pim_ifp->primary_address;
+ if (ifp_in)
+ strcpy(in_ifname, ifp_in->name);
+ else
+ strcpy(in_ifname, "<iif?>");
- for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) {
- char neigh_src_str[100];
+ if (src_or_group)
+ {
+ if (strcmp(src_or_group, src_str) && strcmp(src_or_group, grp_str))
+ continue;
- pim_inet4_dump("<src?>", neigh->source_addr,
- neigh_src_str, sizeof(neigh_src_str));
+ if (group && strcmp(group, grp_str))
+ continue;
+ }
- vty_out(vty, "%-9s %-15s %5u %5u %5u %5u %5u %1u | %-15s %-3s %5u %5u %1u%s",
- ifp->name,
- inet_ntoa(ifaddr),
- pim_ifp->pim_propagation_delay_msec,
- pim_ifp->pim_override_interval_msec,
- pim_ifp->pim_number_of_nonlandelay_neighbors,
- pim_ifp->pim_neighbors_highest_propagation_delay_msec,
- pim_ifp->pim_neighbors_highest_override_interval_msec,
- PIM_FORCE_BOOLEAN(PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options)),
- neigh_src_str,
- PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY) ? "yes" : "no",
- neigh->propagation_delay_msec,
- neigh->override_interval_msec,
- PIM_FORCE_BOOLEAN(PIM_OPTION_IS_SET(neigh->hello_options,
- PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION)),
- VTY_NEWLINE);
+ if (uj) {
+
+ /* Find the group, create it if it doesn't exist */
+ json_object_object_get_ex(json, grp_str, &json_group);
+
+ if (!json_group) {
+ json_group = json_object_new_object();
+ json_object_object_add(json, grp_str, json_group);
+ }
+
+ /* Find the source nested under the group, create it if it doesn't exist */
+ json_object_object_get_ex(json_group, src_str, &json_source);
+
+ if (!json_source) {
+ json_source = json_object_new_object();
+ json_object_object_add(json_group, src_str, json_source);
+ }
+
+ /* Find the inbound interface nested under the source, create it if it doesn't exist */
+ json_object_object_get_ex(json_source, in_ifname, &json_ifp_in);
+
+ if (!json_ifp_in) {
+ json_ifp_in = json_object_new_object();
+ json_object_object_add(json_source, in_ifname, json_ifp_in);
+ }
+ } else {
+ vty_out(vty, "%-15s %-15s %-5s ",
+ src_str,
+ grp_str,
+ ifp_in->name);
}
+ for (oif_vif_index = 0; oif_vif_index < MAXVIFS; ++oif_vif_index) {
+ struct interface *ifp_out;
+ char oif_uptime[10];
+ int ttl;
+
+ ttl = c_oil->oil.mfcc_ttls[oif_vif_index];
+ if (ttl < 1)
+ continue;
+
+ ifp_out = pim_if_find_by_vif_index(oif_vif_index);
+ pim_time_uptime(oif_uptime, sizeof(oif_uptime), now - c_oil->oif_creation[oif_vif_index]);
+
+ if (ifp_out)
+ strcpy(out_ifname, ifp_out->name);
+ else
+ strcpy(out_ifname, "<oif?>");
+
+ if (uj) {
+ json_ifp_out = json_object_new_object();
+ json_object_string_add(json_ifp_out, "source", src_str);
+ json_object_string_add(json_ifp_out, "group", grp_str);
+ json_object_string_add(json_ifp_out, "inboundInterface", in_ifname);
+ json_object_string_add(json_ifp_out, "outboundInterface", out_ifname);
+
+ json_object_object_add(json_ifp_in, out_ifname, json_ifp_out);
+ } else {
+ if (first_oif)
+ {
+ first_oif = 0;
+ vty_out(vty, "%s", out_ifname);
+ }
+ else
+ vty_out(vty, ",%s", out_ifname);
+ }
+ }
+
+ if (!uj)
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
+
+
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
+ } else {
+ vty_out(vty, "%s", VTY_NEWLINE);
}
}
-static void pim_show_jp_override_interval(struct vty *vty)
+static void pim_show_neighbors(struct vty *vty, u_char uj)
{
- struct listnode *node;
+ struct listnode *node;
+ struct listnode *neighnode;
struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ struct pim_neighbor *neigh;
+ time_t now;
+ char uptime[10];
+ char expire[10];
+ char neigh_src_str[INET_ADDRSTRLEN];
+ json_object *json = NULL;
+ json_object *json_ifp_rows = NULL;
+ json_object *json_row = NULL;
- vty_out(vty,
- "EffPDelay=effective_propagation_delay (msec)%s"
- "EffOvrInt=override_interval (msec)%s"
- "JPOvrInt=jp_override_interval (msec)%s%s",
- VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+ now = pim_time_monotonic_sec();
- vty_out(vty, "Interface Address LAN_Delay EffPDelay EffOvrInt JPOvrInt%s", VTY_NEWLINE);
+ if (uj) {
+ json = json_object_new_object();
+ } else {
+ vty_out(vty, "Interface Neighbor Uptime Holdtime DR Pri%s", VTY_NEWLINE);
+ }
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) {
- struct pim_interface *pim_ifp;
- struct in_addr ifaddr;
-
pim_ifp = ifp->info;
-
+
if (!pim_ifp)
continue;
if (pim_ifp->pim_sock_fd < 0)
continue;
- ifaddr = pim_ifp->primary_address;
+ if (uj)
+ json_ifp_rows = json_object_new_object();
- vty_out(vty, "%-9s %-15s %-9s %9u %9u %8u%s",
- ifp->name,
- inet_ntoa(ifaddr),
- pim_if_lan_delay_enabled(ifp) ? "enabled" : "disabled",
- pim_if_effective_propagation_delay_msec(ifp),
- pim_if_effective_override_interval_msec(ifp),
- pim_if_jp_override_interval_msec(ifp),
- VTY_NEWLINE);
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) {
+ pim_inet4_dump("<src?>", neigh->source_addr,
+ neigh_src_str, sizeof(neigh_src_str));
+ pim_time_uptime(uptime, sizeof(uptime), now - neigh->creation);
+ pim_time_timer_to_hhmmss(expire, sizeof(expire), neigh->t_expire_timer);
+
+ if (uj) {
+ json_row = json_object_new_object();
+ json_object_string_add(json_row, "interface", ifp->name);
+ json_object_string_add(json_row, "neighbor", neigh_src_str);
+ json_object_string_add(json_row, "upTime", uptime);
+ json_object_string_add(json_row, "holdTime", expire);
+ json_object_int_add(json_row, "holdTimeMax", neigh->holdtime);
+ json_object_int_add(json_row, "drPriority", neigh->dr_priority);
+ json_object_object_add(json_ifp_rows, neigh_src_str, json_row);
+
+ } else {
+ vty_out(vty, "%-9s %15s %8s %8s %6d%s",
+ ifp->name,
+ neigh_src_str,
+ uptime,
+ expire,
+ neigh->dr_priority,
+ VTY_NEWLINE);
+ }
+ }
+
+ if (uj) {
+ json_object_object_add(json, ifp->name, json_ifp_rows);
+ json_ifp_rows = NULL;
+ }
+ }
+
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
}
}
@@ -939,7 +1579,7 @@ static void pim_show_neighbors_secondary(struct vty *vty)
ifaddr = pim_ifp->primary_address;
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) {
- char neigh_src_str[100];
+ char neigh_src_str[INET_ADDRSTRLEN];
struct listnode *prefix_node;
struct prefix *p;
@@ -950,7 +1590,7 @@ static void pim_show_neighbors_secondary(struct vty *vty)
neigh_src_str, sizeof(neigh_src_str));
for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, prefix_node, p)) {
- char neigh_sec_str[100];
+ char neigh_sec_str[INET_ADDRSTRLEN];
if (p->family != AF_INET)
continue;
@@ -969,68 +1609,169 @@ static void pim_show_neighbors_secondary(struct vty *vty)
}
}
-static void pim_show_upstream(struct vty *vty)
+static void
+json_object_pim_upstream_add (json_object *json, struct pim_upstream *up)
+{
+ if (up->flags & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
+ json_object_boolean_true_add(json, "drJoinDesired");
+
+ if (up->flags & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
+ json_object_boolean_true_add(json, "drJoinDesiredUpdated");
+
+ if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR)
+ json_object_boolean_true_add(json, "firstHopRouter");
+
+ if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
+ json_object_boolean_true_add(json, "sourceIgmp");
+
+ if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
+ json_object_boolean_true_add(json, "sourcePim");
+
+ if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
+ json_object_boolean_true_add(json, "sourceStream");
+
+ /* XXX: need to print ths flag in the plain text display as well */
+ if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
+ json_object_boolean_true_add(json, "sourceMsdp");
+}
+
+static void pim_show_upstream(struct vty *vty, u_char uj)
{
struct listnode *upnode;
struct pim_upstream *up;
time_t now;
+ json_object *json = NULL;
+ json_object *json_group = NULL;
+ json_object *json_row = NULL;
now = pim_time_monotonic_sec();
- vty_out(vty, "Iif Source Group State Uptime JoinTimer RefCnt%s", VTY_NEWLINE);
+ if (uj)
+ json = json_object_new_object();
+ else
+ vty_out(vty, "Iif Source Group State Uptime JoinTimer RSTimer KATimer RefCnt%s", VTY_NEWLINE);
- for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, upnode, up)) {
- char src_str[100];
- char grp_str[100];
- char uptime[10];
- char join_timer[10];
+ for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode, up)) {
+ char src_str[INET_ADDRSTRLEN];
+ char grp_str[INET_ADDRSTRLEN];
+ char uptime[10];
+ char join_timer[10];
+ char rs_timer[10];
+ char ka_timer[10];
+ char msdp_reg_timer[10];
+
+ pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
+ pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
+ pim_time_uptime(uptime, sizeof(uptime), now - up->state_transition);
+ pim_time_timer_to_hhmmss (join_timer, sizeof(join_timer), up->t_join_timer);
+ pim_time_timer_to_hhmmss (rs_timer, sizeof (rs_timer), up->t_rs_timer);
+ pim_time_timer_to_hhmmss (ka_timer, sizeof (ka_timer), up->t_ka_timer);
+ pim_time_timer_to_hhmmss (msdp_reg_timer, sizeof (msdp_reg_timer), up->t_msdp_reg_timer);
+
+ if (uj) {
+ json_object_object_get_ex(json, grp_str, &json_group);
+
+ if (!json_group) {
+ json_group = json_object_new_object();
+ json_object_object_add(json, grp_str, json_group);
+ }
- pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
- pim_time_uptime(uptime, sizeof(uptime), now - up->state_transition);
- pim_time_timer_to_hhmmss(join_timer, sizeof(join_timer), up->t_join_timer);
+ json_row = json_object_new_object();
+ json_object_pim_upstream_add(json_row, up);
+ json_object_string_add(json_row, "inboundInterface", up->rpf.source_nexthop.interface->name);
+ json_object_string_add(json_row, "source", src_str);
+ json_object_string_add(json_row, "group", grp_str);
+ json_object_string_add(json_row, "state", pim_upstream_state2str (up->join_state));
+ json_object_string_add(json_row, "upTime", uptime);
+ json_object_string_add(json_row, "joinTimer", join_timer);
+ json_object_string_add(json_row, "resetTimer", rs_timer);
+ json_object_string_add(json_row, "keepaliveTimer", ka_timer);
+ json_object_string_add(json_row, "msdpRegTimer", msdp_reg_timer);
+ json_object_int_add(json_row, "refCount", up->ref_count);
+ json_object_int_add(json_row, "sptBit", up->sptbit);
+ json_object_object_add(json_group, src_str, json_row);
+ } else {
+ vty_out(vty, "%-10s%-15s %-15s %-11s %-8s %-9s %-9s %-9s %6d%s",
+ up->rpf.source_nexthop.interface->name,
+ src_str,
+ grp_str,
+ pim_upstream_state2str (up->join_state),
+ uptime,
+ join_timer,
+ rs_timer,
+ ka_timer,
+ up->ref_count,
+ VTY_NEWLINE);
+ }
+ }
- vty_out(vty, "%-10s%-15s %-15s %-5s %-8s %-9s %6d%s",
- up->rpf.source_nexthop.interface->name,
- src_str,
- grp_str,
- up->join_state == PIM_UPSTREAM_JOINED ? "Jnd" : "NtJnd",
- uptime,
- join_timer,
- up->ref_count,
- VTY_NEWLINE);
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
}
}
-static void pim_show_join_desired(struct vty *vty)
+static void pim_show_join_desired(struct vty *vty, u_char uj)
{
- struct listnode *ifnode;
struct listnode *chnode;
- struct interface *ifp;
struct pim_interface *pim_ifp;
struct pim_ifchannel *ch;
- char src_str[100];
- char grp_str[100];
-
- vty_out(vty,
- "Interface Source Group LostAssert Joins PimInclude JoinDesired EvalJD%s",
- VTY_NEWLINE);
+ 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%s",
+ VTY_NEWLINE);
- /* scan all interfaces */
- for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp)) {
- pim_ifp = ifp->info;
+ /* 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;
- /* scan per-interface (S,G) state */
- for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, chnode, ch)) {
- struct pim_upstream *up = ch->upstream;
+ struct pim_upstream *up = ch->upstream;
+
+ pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
+ pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
+
+ if (uj) {
+ json_object_object_get_ex(json, grp_str, &json_group);
+
+ if (!json_group) {
+ json_group = json_object_new_object();
+ json_object_object_add(json, grp_str, json_group);
+ }
+
+ 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_ch_lost_assert(ch))
+ json_object_boolean_true_add(json_row, "lostAssert");
+
+ if (pim_macro_chisin_joins(ch))
+ json_object_boolean_true_add(json_row, "joins");
- pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
+ if (pim_macro_chisin_pim_include(ch))
+ json_object_boolean_true_add(json_row, "pimInclude");
+ if (pim_upstream_evaluate_join_desired(up))
+ json_object_boolean_true_add(json_row, "evaluateJoinDesired");
+
+ json_object_object_add(json_group, src_str, json_row);
+
+ } else {
vty_out(vty, "%-9s %-15s %-15s %-10s %-5s %-10s %-11s %-6s%s",
- ifp->name,
+ ch->interface->name,
src_str,
grp_str,
pim_macro_ch_lost_assert(ch) ? "yes" : "no",
@@ -1041,61 +1782,109 @@ static void pim_show_join_desired(struct vty *vty)
VTY_NEWLINE);
}
}
+
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
+ }
}
-static void pim_show_upstream_rpf(struct vty *vty)
+static void pim_show_upstream_rpf(struct vty *vty, u_char uj)
{
struct listnode *upnode;
struct pim_upstream *up;
+ json_object *json = NULL;
+ json_object *json_group = NULL;
+ json_object *json_row = NULL;
- vty_out(vty,
- "Source Group RpfIface RibNextHop RpfAddress %s",
- VTY_NEWLINE);
-
- for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, upnode, up)) {
- char src_str[100];
- char grp_str[100];
- char rpf_nexthop_str[100];
- char rpf_addr_str[100];
+ if (uj)
+ json = json_object_new_object();
+ else
+ vty_out(vty,
+ "Source Group RpfIface RibNextHop RpfAddress %s",
+ VTY_NEWLINE);
+
+ 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];
+ char rpf_addr_str[PREFIX_STRLEN];
struct pim_rpf *rpf;
const char *rpf_ifname;
-
+
rpf = &up->rpf;
-
- pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
- pim_inet4_dump("<nexthop?>", rpf->source_nexthop.mrib_nexthop_addr, rpf_nexthop_str, sizeof(rpf_nexthop_str));
- pim_inet4_dump("<rpf?>", rpf->rpf_addr, rpf_addr_str, sizeof(rpf_addr_str));
-
+
+ pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
+ pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
+ pim_addr_dump("<nexthop?>", &rpf->source_nexthop.mrib_nexthop_addr, rpf_nexthop_str, sizeof(rpf_nexthop_str));
+ pim_addr_dump("<rpf?>", &rpf->rpf_addr, rpf_addr_str, sizeof(rpf_addr_str));
+
rpf_ifname = rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "<ifname?>";
-
- vty_out(vty, "%-15s %-15s %-8s %-15s %-15s%s",
- src_str,
- grp_str,
- rpf_ifname,
- rpf_nexthop_str,
- rpf_addr_str,
- VTY_NEWLINE);
+
+ if (uj) {
+ json_object_object_get_ex(json, grp_str, &json_group);
+
+ if (!json_group) {
+ json_group = json_object_new_object();
+ json_object_object_add(json, grp_str, json_group);
+ }
+
+ json_row = json_object_new_object();
+ json_object_pim_upstream_add(json_row, up);
+ json_object_string_add(json_row, "source", src_str);
+ json_object_string_add(json_row, "group", grp_str);
+ json_object_string_add(json_row, "rpfInterface", rpf_ifname);
+ json_object_string_add(json_row, "ribNexthop", rpf_nexthop_str);
+ json_object_string_add(json_row, "rpfAddress", rpf_addr_str);
+ json_object_object_add(json_group, src_str, json_row);
+ } else {
+ vty_out(vty, "%-15s %-15s %-8s %-15s %-15s%s",
+ src_str,
+ grp_str,
+ rpf_ifname,
+ rpf_nexthop_str,
+ rpf_addr_str,
+ VTY_NEWLINE);
+ }
+ }
+
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
}
}
-static void show_rpf_refresh_stats(struct vty *vty, time_t now)
+static void show_rpf_refresh_stats(struct vty *vty, time_t now, json_object *json)
{
char refresh_uptime[10];
pim_time_uptime_begin(refresh_uptime, sizeof(refresh_uptime), now, qpim_rpf_cache_refresh_last);
- vty_out(vty,
- "RPF Cache Refresh Delay: %ld msecs%s"
- "RPF Cache Refresh Timer: %ld msecs%s"
- "RPF Cache Refresh Requests: %lld%s"
- "RPF Cache Refresh Events: %lld%s"
- "RPF Cache Refresh Last: %s%s",
- qpim_rpf_cache_refresh_delay_msec, VTY_NEWLINE,
- pim_time_timer_remain_msec(qpim_rpf_cache_refresher), VTY_NEWLINE,
- (long long)qpim_rpf_cache_refresh_requests, VTY_NEWLINE,
- (long long)qpim_rpf_cache_refresh_events, VTY_NEWLINE,
- refresh_uptime, VTY_NEWLINE);
+ if (json) {
+ json_object_int_add(json, "rpfCacheRefreshDelayMsecs", qpim_rpf_cache_refresh_delay_msec);
+ json_object_int_add(json, "rpfCacheRefreshTimer", pim_time_timer_remain_msec(qpim_rpf_cache_refresher));
+ json_object_int_add(json, "rpfCacheRefreshRequests", qpim_rpf_cache_refresh_requests);
+ json_object_int_add(json, "rpfCacheRefreshEvents", qpim_rpf_cache_refresh_events);
+ json_object_string_add(json, "rpfCacheRefreshLast", refresh_uptime);
+ json_object_int_add(json, "nexthopLookups", qpim_nexthop_lookups);
+ json_object_int_add(json, "nexthopLookupsAvoided", nexthop_lookups_avoided);
+ } else {
+ vty_out(vty,
+ "RPF Cache Refresh Delay: %ld msecs%s"
+ "RPF Cache Refresh Timer: %ld msecs%s"
+ "RPF Cache Refresh Requests: %lld%s"
+ "RPF Cache Refresh Events: %lld%s"
+ "RPF Cache Refresh Last: %s%s"
+ "Nexthop Lookups: %lld%s"
+ "Nexthop Lookups Avoided: %lld%s",
+ qpim_rpf_cache_refresh_delay_msec, VTY_NEWLINE,
+ pim_time_timer_remain_msec(qpim_rpf_cache_refresher), VTY_NEWLINE,
+ (long long)qpim_rpf_cache_refresh_requests, VTY_NEWLINE,
+ (long long)qpim_rpf_cache_refresh_events, VTY_NEWLINE,
+ refresh_uptime, VTY_NEWLINE,
+ (long long) qpim_nexthop_lookups, VTY_NEWLINE,
+ (long long)nexthop_lookups_avoided, VTY_NEWLINE);
+ }
}
static void show_scan_oil_stats(struct vty *vty, time_t now)
@@ -1117,90 +1906,93 @@ static void show_scan_oil_stats(struct vty *vty, time_t now)
uptime_mroute_del, (long long) qpim_mroute_del_events, VTY_NEWLINE);
}
-static void pim_show_rpf(struct vty *vty)
+static void pim_show_rpf(struct vty *vty, u_char uj)
{
struct listnode *up_node;
struct pim_upstream *up;
time_t now = pim_time_monotonic_sec();
+ json_object *json = NULL;
+ json_object *json_group = NULL;
+ json_object *json_row = NULL;
+
+ if (uj) {
+ json = json_object_new_object();
+ show_rpf_refresh_stats(vty, now, json);
+ } else {
+ show_rpf_refresh_stats(vty, now, json);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ vty_out(vty,
+ "Source Group RpfIface RpfAddress RibNextHop Metric Pref%s",
+ VTY_NEWLINE);
+ }
- show_rpf_refresh_stats(vty, now);
-
- vty_out(vty, "%s", VTY_NEWLINE);
-
- vty_out(vty,
- "Source Group RpfIface RpfAddress RibNextHop Metric Pref%s",
- VTY_NEWLINE);
-
- for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, up_node, up)) {
- char src_str[100];
- char grp_str[100];
- char rpf_addr_str[100];
- char rib_nexthop_str[100];
+ 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];
+ char rib_nexthop_str[PREFIX_STRLEN];
const char *rpf_ifname;
struct pim_rpf *rpf = &up->rpf;
- pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
- pim_inet4_dump("<rpf?>", rpf->rpf_addr, rpf_addr_str, sizeof(rpf_addr_str));
- pim_inet4_dump("<nexthop?>", rpf->source_nexthop.mrib_nexthop_addr, rib_nexthop_str, sizeof(rib_nexthop_str));
+ pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
+ pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
+ pim_addr_dump("<rpf?>", &rpf->rpf_addr, rpf_addr_str, sizeof(rpf_addr_str));
+ pim_addr_dump("<nexthop?>", &rpf->source_nexthop.mrib_nexthop_addr, rib_nexthop_str, sizeof(rib_nexthop_str));
rpf_ifname = rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "<ifname?>";
- vty_out(vty, "%-15s %-15s %-8s %-15s %-15s %6d %4d%s",
- src_str,
- grp_str,
- rpf_ifname,
- rpf_addr_str,
- rib_nexthop_str,
- rpf->source_nexthop.mrib_route_metric,
- rpf->source_nexthop.mrib_metric_preference,
- VTY_NEWLINE);
- }
-}
-
-static void igmp_show_querier(struct vty *vty)
-{
- struct listnode *node;
- struct interface *ifp;
-
- vty_out(vty, "Interface Address Querier StartCount Query-Timer Other-Timer%s", VTY_NEWLINE);
+ if (uj) {
+ json_object_object_get_ex(json, grp_str, &json_group);
- for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) {
- struct pim_interface *pim_ifp = ifp->info;
- struct listnode *sock_node;
- struct igmp_sock *igmp;
-
- if (!pim_ifp)
- continue;
-
- for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
- char query_hhmmss[10];
- char other_hhmmss[10];
-
- pim_time_timer_to_hhmmss(query_hhmmss, sizeof(query_hhmmss), igmp->t_igmp_query_timer);
- pim_time_timer_to_hhmmss(other_hhmmss, sizeof(other_hhmmss), igmp->t_other_querier_timer);
+ if (!json_group) {
+ json_group = json_object_new_object();
+ json_object_object_add(json, grp_str, json_group);
+ }
- vty_out(vty, "%-9s %-15s %-7s %10d %11s %11s%s",
- ifp->name,
- inet_ntoa(igmp->ifaddr),
- igmp->t_igmp_query_timer ? "THIS" : "OTHER",
- igmp->startup_query_count,
- query_hhmmss,
- other_hhmmss,
- VTY_NEWLINE);
+ json_row = json_object_new_object();
+ json_object_string_add(json_row, "source", src_str);
+ json_object_string_add(json_row, "group", grp_str);
+ json_object_string_add(json_row, "rpfInterface", rpf_ifname);
+ json_object_string_add(json_row, "rpfAddress", rpf_addr_str);
+ json_object_string_add(json_row, "ribNexthop", rib_nexthop_str);
+ json_object_int_add(json_row, "routeMetric", rpf->source_nexthop.mrib_route_metric);
+ json_object_int_add(json_row, "routePreference", rpf->source_nexthop.mrib_metric_preference);
+ json_object_object_add(json_group, src_str, json_row);
+
+ } else {
+ vty_out(vty, "%-15s %-15s %-8s %-15s %-15s %6d %4d%s",
+ src_str,
+ grp_str,
+ rpf_ifname,
+ rpf_addr_str,
+ rib_nexthop_str,
+ rpf->source_nexthop.mrib_route_metric,
+ rpf->source_nexthop.mrib_metric_preference,
+ VTY_NEWLINE);
}
}
+
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
+ }
}
-static void igmp_show_groups(struct vty *vty)
+static void igmp_show_groups(struct vty *vty, u_char uj)
{
struct listnode *ifnode;
struct interface *ifp;
time_t now;
+ json_object *json = NULL;
+ json_object *json_iface = NULL;
+ json_object *json_row = NULL;
now = pim_time_monotonic_sec();
- vty_out(vty, "Interface Address Group Mode Timer Srcs V Uptime %s", VTY_NEWLINE);
+ if (uj)
+ json = json_object_new_object();
+ else
+ vty_out(vty, "Interface Address Group Mode Timer Srcs V Uptime %s", VTY_NEWLINE);
/* scan interfaces */
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp)) {
@@ -1213,7 +2005,7 @@ static void igmp_show_groups(struct vty *vty)
/* scan igmp sockets */
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
- char ifaddr_str[100];
+ char ifaddr_str[INET_ADDRSTRLEN];
struct listnode *grpnode;
struct igmp_group *grp;
@@ -1221,7 +2013,7 @@ static void igmp_show_groups(struct vty *vty)
/* scan igmp groups */
for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, grp)) {
- char group_str[100];
+ char group_str[INET_ADDRSTRLEN];
char hhmmss[10];
char uptime[10];
@@ -1229,20 +2021,48 @@ static void igmp_show_groups(struct vty *vty)
pim_time_timer_to_hhmmss(hhmmss, sizeof(hhmmss), grp->t_group_timer);
pim_time_uptime(uptime, sizeof(uptime), now - grp->group_creation);
- vty_out(vty, "%-9s %-15s %-15s %4s %8s %4d %d %8s%s",
- ifp->name,
- ifaddr_str,
- group_str,
- grp->group_filtermode_isexcl ? "EXCL" : "INCL",
- hhmmss,
- grp->group_source_list ? listcount(grp->group_source_list) : 0,
- igmp_group_compat_mode(igmp, grp),
- uptime,
- VTY_NEWLINE);
-
+ if (uj) {
+ json_object_object_get_ex(json, ifp->name, &json_iface);
+
+ if (!json_iface) {
+ json_iface = json_object_new_object();
+ json_object_pim_ifp_add(json_iface, ifp);
+ json_object_object_add(json, ifp->name, json_iface);
+ }
+
+ json_row = json_object_new_object();
+ json_object_string_add(json_row, "source", ifaddr_str);
+ json_object_string_add(json_row, "group", group_str);
+
+ if (grp->igmp_version == 3)
+ json_object_string_add(json_row, "mode", grp->group_filtermode_isexcl ? "EXCLUDE" : "INCLUDE");
+
+ json_object_string_add(json_row, "timer", hhmmss);
+ json_object_int_add(json_row, "sourcesCount", grp->group_source_list ? listcount(grp->group_source_list) : 0);
+ json_object_int_add(json_row, "version", grp->igmp_version);
+ json_object_string_add(json_row, "uptime", uptime);
+ json_object_object_add(json_iface, group_str, json_row);
+
+ } else {
+ vty_out(vty, "%-9s %-15s %-15s %4s %8s %4d %d %8s%s",
+ ifp->name,
+ ifaddr_str,
+ group_str,
+ grp->igmp_version == 3 ? (grp->group_filtermode_isexcl ? "EXCL" : "INCL") : "----",
+ hhmmss,
+ grp->group_source_list ? listcount(grp->group_source_list) : 0,
+ grp->igmp_version,
+ uptime,
+ VTY_NEWLINE);
+ }
} /* scan igmp groups */
} /* scan igmp sockets */
} /* scan interfaces */
+
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
+ }
}
static void igmp_show_group_retransmission(struct vty *vty)
@@ -1263,7 +2083,7 @@ static void igmp_show_group_retransmission(struct vty *vty)
/* scan igmp sockets */
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
- char ifaddr_str[100];
+ char ifaddr_str[INET_ADDRSTRLEN];
struct listnode *grpnode;
struct igmp_group *grp;
@@ -1271,7 +2091,7 @@ static void igmp_show_group_retransmission(struct vty *vty)
/* scan igmp groups */
for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, grp)) {
- char group_str[100];
+ char group_str[INET_ADDRSTRLEN];
char grp_retr_mmss[10];
struct listnode *src_node;
struct igmp_source *src;
@@ -1302,80 +2122,6 @@ static void igmp_show_group_retransmission(struct vty *vty)
} /* scan interfaces */
}
-static void igmp_show_parameters(struct vty *vty)
-{
- struct listnode *ifnode;
- struct interface *ifp;
-
- vty_out(vty,
- "QRV: Robustness Variable SQI: Startup Query Interval%s"
- "QQI: Query Interval OQPI: Other Querier Present Interval%s"
- "QRI: Query Response Interval LMQT: Last Member Query Time%s"
- "GMI: Group Membership Interval OHPI: Older Host Present Interval%s%s",
- VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
-
- vty_out(vty,
- "Interface Address QRV QQI QRI GMI SQI OQPI LMQT OHPI %s",
- VTY_NEWLINE);
-
- /* scan interfaces */
- 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)
- continue;
-
- /* scan igmp sockets */
- for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
- char ifaddr_str[100];
- long gmi_dsec; /* Group Membership Interval */
- long oqpi_dsec; /* Other Querier Present Interval */
- int sqi;
- long lmqt_dsec;
- long ohpi_dsec;
- long qri_dsec;
-
- pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str));
-
- gmi_dsec = PIM_IGMP_GMI_MSEC(igmp->querier_robustness_variable,
- igmp->querier_query_interval,
- pim_ifp->igmp_query_max_response_time_dsec) / 100;
-
- sqi = PIM_IGMP_SQI(pim_ifp->igmp_default_query_interval);
-
- oqpi_dsec = PIM_IGMP_OQPI_MSEC(igmp->querier_robustness_variable,
- igmp->querier_query_interval,
- pim_ifp->igmp_query_max_response_time_dsec) / 100;
-
- lmqt_dsec = PIM_IGMP_LMQT_MSEC(pim_ifp->igmp_query_max_response_time_dsec,
- igmp->querier_robustness_variable) / 100;
-
- ohpi_dsec = PIM_IGMP_OHPI_DSEC(igmp->querier_robustness_variable,
- igmp->querier_query_interval,
- pim_ifp->igmp_query_max_response_time_dsec);
-
- qri_dsec = pim_ifp->igmp_query_max_response_time_dsec;
-
- vty_out(vty,
- "%-9s %-15s %3d %3d %3ld.%ld %3ld.%ld %3d %3ld.%ld %3ld.%ld %3ld.%ld%s",
- ifp->name,
- ifaddr_str,
- igmp->querier_robustness_variable,
- igmp->querier_query_interval,
- qri_dsec / 10, qri_dsec % 10,
- gmi_dsec / 10, gmi_dsec % 10,
- sqi,
- oqpi_dsec / 10, oqpi_dsec % 10,
- lmqt_dsec / 10, lmqt_dsec % 10,
- ohpi_dsec / 10, ohpi_dsec % 10,
- VTY_NEWLINE);
-
- } /* scan igmp sockets */
- } /* scan interfaces */
-}
-
static void igmp_show_sources(struct vty *vty)
{
struct listnode *ifnode;
@@ -1397,7 +2143,7 @@ static void igmp_show_sources(struct vty *vty)
/* scan igmp sockets */
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
- char ifaddr_str[100];
+ char ifaddr_str[INET_ADDRSTRLEN];
struct listnode *grpnode;
struct igmp_group *grp;
@@ -1405,7 +2151,7 @@ static void igmp_show_sources(struct vty *vty)
/* scan igmp groups */
for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, grp)) {
- char group_str[100];
+ char group_str[INET_ADDRSTRLEN];
struct listnode *srcnode;
struct igmp_source *src;
@@ -1413,7 +2159,7 @@ static void igmp_show_sources(struct vty *vty)
/* scan group sources */
for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, srcnode, src)) {
- char source_str[100];
+ char source_str[INET_ADDRSTRLEN];
char mmss[10];
char uptime[10];
@@ -1457,7 +2203,7 @@ static void igmp_show_source_retransmission(struct vty *vty)
/* scan igmp sockets */
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
- char ifaddr_str[100];
+ char ifaddr_str[INET_ADDRSTRLEN];
struct listnode *grpnode;
struct igmp_group *grp;
@@ -1465,7 +2211,7 @@ static void igmp_show_source_retransmission(struct vty *vty)
/* scan igmp groups */
for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, grp)) {
- char group_str[100];
+ char group_str[INET_ADDRSTRLEN];
struct listnode *srcnode;
struct igmp_source *src;
@@ -1473,7 +2219,7 @@ static void igmp_show_source_retransmission(struct vty *vty)
/* scan group sources */
for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, srcnode, src)) {
- char source_str[100];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", src->source_addr, source_str, sizeof(source_str));
@@ -1555,11 +2301,11 @@ static void mroute_add_all()
struct listnode *node;
struct channel_oil *c_oil;
- for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) {
- if (pim_mroute_add(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[100];
- char group_str[100];
+ char source_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
zlog_warn("%s %s: (S,G)=(%s,%s) failure writing MFC",
@@ -1574,11 +2320,11 @@ static void mroute_del_all()
struct listnode *node;
struct channel_oil *c_oil;
- for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) {
- if (pim_mroute_del(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[100];
- char group_str[100];
+ char source_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
zlog_warn("%s %s: (S,G)=(%s,%s) failure clearing MFC",
@@ -1594,10 +2340,10 @@ static void static_mroute_add_all()
struct static_route *s_route;
for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) {
- if (pim_mroute_add(&s_route->c_oil)) {
+ if (pim_mroute_add(&s_route->c_oil, __PRETTY_FUNCTION__)) {
/* just log warning */
- char source_str[100];
- char group_str[100];
+ char source_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", s_route->c_oil.oil.mfcc_origin, source_str, sizeof(source_str));
pim_inet4_dump("<group?>", s_route->c_oil.oil.mfcc_mcastgrp, group_str, sizeof(group_str));
zlog_warn("%s %s: (S,G)=(%s,%s) failure writing MFC",
@@ -1613,10 +2359,10 @@ static void static_mroute_del_all()
struct static_route *s_route;
for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) {
- if (pim_mroute_del(&s_route->c_oil)) {
+ if (pim_mroute_del(&s_route->c_oil, __PRETTY_FUNCTION__)) {
/* just log warning */
- char source_str[100];
- char group_str[100];
+ char source_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", s_route->c_oil.oil.mfcc_origin, source_str, sizeof(source_str));
pim_inet4_dump("<group?>", s_route->c_oil.oil.mfcc_mcastgrp, group_str, sizeof(group_str));
zlog_warn("%s %s: (S,G)=(%s,%s) failure clearing MFC",
@@ -1667,13 +2413,20 @@ DEFUN (clear_ip_pim_oil,
DEFUN (show_ip_igmp_interface,
show_ip_igmp_interface_cmd,
- "show ip igmp interface",
+ "show ip igmp interface [detail|WORD] [json]",
SHOW_STR
IP_STR
IGMP_STR
- "IGMP interface information\n")
+ "IGMP interface information\n"
+ "Detailed output\n"
+ "interface name\n"
+ "JavaScript Object Notation\n")
{
- igmp_show_interfaces(vty);
+ u_char uj = use_json(argc, argv);
+ if (argv[4]->arg)
+ igmp_show_interfaces_single(vty, argv[4]->arg, uj);
+ else
+ igmp_show_interfaces(vty, uj);
return CMD_SUCCESS;
}
@@ -1693,13 +2446,15 @@ DEFUN (show_ip_igmp_join,
DEFUN (show_ip_igmp_groups,
show_ip_igmp_groups_cmd,
- "show ip igmp groups",
+ "show ip igmp groups [json]",
SHOW_STR
IP_STR
IGMP_STR
- IGMP_GROUP_STR)
+ IGMP_GROUP_STR
+ "JavaScript Object Notation\n")
{
- igmp_show_groups(vty);
+ u_char uj = use_json(argc, argv);
+ igmp_show_groups(vty, uj);
return CMD_SUCCESS;
}
@@ -1718,19 +2473,6 @@ DEFUN (show_ip_igmp_groups_retransmissions,
return CMD_SUCCESS;
}
-DEFUN (show_ip_igmp_parameters,
- show_ip_igmp_parameters_cmd,
- "show ip igmp parameters",
- SHOW_STR
- IP_STR
- IGMP_STR
- "IGMP parameters information\n")
-{
- igmp_show_parameters(vty);
-
- return CMD_SUCCESS;
-}
-
DEFUN (show_ip_igmp_sources,
show_ip_igmp_sources_cmd,
"show ip igmp sources",
@@ -1758,32 +2500,6 @@ DEFUN (show_ip_igmp_sources_retransmissions,
return CMD_SUCCESS;
}
-DEFUN (show_ip_igmp_querier,
- show_ip_igmp_querier_cmd,
- "show ip igmp querier",
- SHOW_STR
- IP_STR
- IGMP_STR
- "IGMP querier information\n")
-{
- igmp_show_querier(vty);
-
- return CMD_SUCCESS;
-}
-
-DEFUN (show_ip_pim_address,
- show_ip_pim_address_cmd,
- "show ip pim address",
- SHOW_STR
- IP_STR
- PIM_STR
- "PIM interface address\n")
-{
- show_interface_address(vty);
-
- return CMD_SUCCESS;
-}
-
DEFUN (show_ip_pim_assert,
show_ip_pim_assert_cmd,
"show ip pim assert",
@@ -1836,171 +2552,183 @@ DEFUN (show_ip_pim_assert_winner_metric,
return CMD_SUCCESS;
}
-DEFUN (show_ip_pim_dr,
- show_ip_pim_dr_cmd,
- "show ip pim designated-router",
- SHOW_STR
- IP_STR
- PIM_STR
- "PIM interface designated router\n")
-{
- pim_show_dr(vty);
-
- return CMD_SUCCESS;
-}
-
-DEFUN (show_ip_pim_hello,
- show_ip_pim_hello_cmd,
- "show ip pim hello",
- SHOW_STR
- IP_STR
- PIM_STR
- "PIM interface hello information\n")
-{
- pim_show_hello(vty);
-
- return CMD_SUCCESS;
-}
-
DEFUN (show_ip_pim_interface,
show_ip_pim_interface_cmd,
- "show ip pim interface",
+ "show ip pim interface [detail|WORD] [json]",
SHOW_STR
IP_STR
PIM_STR
- "PIM interface information\n")
+ "PIM interface information\n"
+ "Detailed output\n"
+ "interface name\n"
+ "JavaScript Object Notation\n")
{
- pim_show_interfaces(vty);
+ u_char uj = use_json(argc, argv);
+ if (argv[4]->arg)
+ pim_show_interfaces_single(vty, argv[4]->arg, uj);
+ else
+ pim_show_interfaces(vty, uj);
return CMD_SUCCESS;
}
DEFUN (show_ip_pim_join,
show_ip_pim_join_cmd,
- "show ip pim join",
+ "show ip pim join [json]",
SHOW_STR
IP_STR
PIM_STR
- "PIM interface join information\n")
+ "PIM interface join information\n"
+ JSON_STR)
{
- pim_show_join(vty);
-
- return CMD_SUCCESS;
-}
-
-DEFUN (show_ip_pim_lan_prune_delay,
- show_ip_pim_lan_prune_delay_cmd,
- "show ip pim lan-prune-delay",
- SHOW_STR
- IP_STR
- PIM_STR
- "PIM neighbors LAN prune delay parameters\n")
-{
- pim_show_lan_prune_delay(vty);
+ u_char uj = use_json(argc, argv);
+ pim_show_join(vty, uj);
return CMD_SUCCESS;
}
DEFUN (show_ip_pim_local_membership,
show_ip_pim_local_membership_cmd,
- "show ip pim local-membership",
+ "show ip pim local-membership [json]",
SHOW_STR
IP_STR
PIM_STR
- "PIM interface local-membership\n")
+ "PIM interface local-membership\n"
+ JSON_STR)
{
- pim_show_membership(vty);
+ u_char uj = use_json(argc, argv);
+ pim_show_membership(vty, uj);
return CMD_SUCCESS;
}
-DEFUN (show_ip_pim_jp_override_interval,
- show_ip_pim_jp_override_interval_cmd,
- "show ip pim jp-override-interval",
+DEFUN (show_ip_pim_neighbor,
+ show_ip_pim_neighbor_cmd,
+ "show ip pim neighbor [detail|WORD] [json]",
SHOW_STR
IP_STR
PIM_STR
- "PIM interface J/P override interval\n")
+ "PIM neighbor information\n"
+ "Detailed output\n"
+ "Name of interface or neighbor\n"
+ "JavaScript Object Notation\n")
{
- pim_show_jp_override_interval(vty);
+ u_char uj = use_json(argc, argv);
+ if (argv[4]->arg)
+ pim_show_neighbors_single(vty, argv[4]->arg, uj);
+ else
+ pim_show_neighbors(vty, uj);
return CMD_SUCCESS;
}
-DEFUN (show_ip_pim_neighbor,
- show_ip_pim_neighbor_cmd,
- "show ip pim neighbor",
+DEFUN (show_ip_pim_secondary,
+ show_ip_pim_secondary_cmd,
+ "show ip pim secondary",
SHOW_STR
IP_STR
PIM_STR
- "PIM neighbor information\n")
+ "PIM neighbor addresses\n")
{
- pim_show_neighbors(vty);
+ pim_show_neighbors_secondary(vty);
return CMD_SUCCESS;
}
-DEFUN (show_ip_pim_secondary,
- show_ip_pim_secondary_cmd,
- "show ip pim secondary",
+DEFUN (show_ip_pim_state,
+ show_ip_pim_state_cmd,
+ "show ip pim state [A.B.C.D] [A.B.C.D] [json]",
SHOW_STR
IP_STR
PIM_STR
- "PIM neighbor addresses\n")
+ "PIM state information\n"
+ "Unicast or Multicast address\n"
+ "Multicast address\n"
+ "JavaScript Object Notation\n")
{
- pim_show_neighbors_secondary(vty);
+ const char *src_or_group = NULL;
+ const char *group = NULL;
+ u_char uj = use_json(argc, argv);
+
+ src_or_group = argv[4]->arg;
+ group = argv[5]->arg;
+
+ pim_show_state(vty, src_or_group, group, uj);
return CMD_SUCCESS;
}
DEFUN (show_ip_pim_upstream,
show_ip_pim_upstream_cmd,
- "show ip pim upstream",
+ "show ip pim upstream [json]",
SHOW_STR
IP_STR
PIM_STR
- "PIM upstream information\n")
+ "PIM upstream information\n"
+ "JavaScript Object Notation\n")
{
- pim_show_upstream(vty);
+ u_char uj = use_json(argc, argv);
+ pim_show_upstream(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",
+ "show ip pim upstream-join-desired [json]",
SHOW_STR
IP_STR
PIM_STR
- "PIM upstream join-desired\n")
+ "PIM upstream join-desired\n"
+ "JavaScript Object Notation\n")
{
- pim_show_join_desired(vty);
+ u_char uj = use_json(argc, argv);
+ pim_show_join_desired(vty, uj);
return CMD_SUCCESS;
}
DEFUN (show_ip_pim_upstream_rpf,
show_ip_pim_upstream_rpf_cmd,
- "show ip pim upstream-rpf",
+ "show ip pim upstream-rpf [json]",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ "PIM upstream source rpf\n"
+ "JavaScript Object Notation\n")
+{
+ u_char uj = use_json(argc, argv);
+ pim_show_upstream_rpf(vty, uj);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_pim_rp,
+ show_ip_pim_rp_cmd,
+ "show ip pim rp-info [json]",
SHOW_STR
IP_STR
PIM_STR
- "PIM upstream source rpf\n")
+ "PIM RP information\n"
+ "JavaScript Object Notation\n")
{
- pim_show_upstream_rpf(vty);
+ u_char uj = use_json(argc, argv);
+ pim_rp_show_information (vty, uj);
return CMD_SUCCESS;
}
DEFUN (show_ip_pim_rpf,
show_ip_pim_rpf_cmd,
- "show ip pim rpf",
+ "show ip pim rpf [json]",
SHOW_STR
IP_STR
PIM_STR
- "PIM cached source rpf information\n")
+ "PIM cached source rpf information\n"
+ "JavaScript Object Notation\n")
{
- pim_show_rpf(vty);
+ u_char uj = use_json(argc, argv);
+ pim_show_rpf(vty, uj);
return CMD_SUCCESS;
}
@@ -2088,14 +2816,8 @@ DEFUN (show_ip_multicast,
else {
vty_out(vty, "<null zclient>%s", VTY_NEWLINE);
}
- vty_out(vty, "Zclient lookup socket: ");
- if (qpim_zclient_lookup) {
- vty_out(vty, "%d failures=%d%s", qpim_zclient_lookup->sock,
- qpim_zclient_lookup->fail, VTY_NEWLINE);
- }
- else {
- vty_out(vty, "<null zclient>%s", VTY_NEWLINE);
- }
+
+ pim_zlookup_show_ip_multicast (vty);
vty_out(vty, "%s", VTY_NEWLINE);
vty_out(vty, "Current highest VifIndex: %d%s",
@@ -2115,7 +2837,7 @@ DEFUN (show_ip_multicast,
vty_out(vty, "%s", VTY_NEWLINE);
- show_rpf_refresh_stats(vty, now);
+ show_rpf_refresh_stats(vty, now, NULL);
vty_out(vty, "%s", VTY_NEWLINE);
@@ -2126,127 +2848,299 @@ DEFUN (show_ip_multicast,
return CMD_SUCCESS;
}
-static void show_mroute(struct vty *vty)
+static void show_mroute(struct vty *vty, u_char uj)
{
struct listnode *node;
struct channel_oil *c_oil;
struct static_route *s_route;
time_t now;
-
- vty_out(vty, "Proto: I=IGMP P=PIM S=STATIC O=SOURCE%s%s", VTY_NEWLINE, VTY_NEWLINE);
-
- vty_out(vty, "Source Group Proto Input iVifI Output oVifI TTL Uptime %s",
- VTY_NEWLINE);
+ json_object *json = NULL;
+ json_object *json_group = NULL;
+ json_object *json_source = NULL;
+ json_object *json_oil = NULL;
+ json_object *json_ifp_out = NULL;
+ int found_oif = 0;
+ int first = 1;
+
+ if (uj) {
+ json = json_object_new_object();
+ } else {
+ vty_out(vty, "Source Group Proto Input Output TTL Uptime%s",
+ VTY_NEWLINE);
+ }
now = pim_time_monotonic_sec();
/* print list of PIM and IGMP routes */
- for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) {
- char group_str[100];
- char source_str[100];
+ 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[16];
+ char out_ifname[16];
int oif_vif_index;
-
- if (!c_oil->installed)
+ char proto[100];
+ struct interface *ifp_in;
+ found_oif = 0;
+ first = 1;
+ if (!c_oil->installed && !uj)
continue;
- pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
-
+ pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, grp_str, 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);
+
+ if (ifp_in)
+ strcpy(in_ifname, ifp_in->name);
+ else
+ strcpy(in_ifname, "<iif?>");
+
+ if (uj) {
+
+ /* Find the group, create it if it doesn't exist */
+ json_object_object_get_ex(json, grp_str, &json_group);
+
+ if (!json_group) {
+ json_group = json_object_new_object();
+ json_object_object_add(json, grp_str, json_group);
+ }
+
+ /* Find the source nested under the group, create it if it doesn't exist */
+ json_object_object_get_ex(json_group, src_str, &json_source);
+
+ if (!json_source) {
+ json_source = json_object_new_object();
+ json_object_object_add(json_group, src_str, json_source);
+ }
+
+ /* Find the inbound interface nested under the source, create it if it doesn't exist */
+ json_object_int_add(json_source, "installed", c_oil->installed);
+ json_object_int_add(json_source, "refCount", c_oil->oil_ref_count);
+ json_object_int_add(json_source, "oilSize", c_oil->oil_size);
+ json_object_int_add(json_source, "OilInheritedRescan", c_oil->oil_inherited_rescan);
+ json_object_string_add(json_source, "iif", in_ifname);
+ json_oil = NULL;
+ }
+
for (oif_vif_index = 0; oif_vif_index < MAXVIFS; ++oif_vif_index) {
- struct interface *ifp_in;
struct interface *ifp_out;
char oif_uptime[10];
int ttl;
- char proto[5];
ttl = c_oil->oil.mfcc_ttls[oif_vif_index];
if (ttl < 1)
continue;
- ifp_in = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent);
ifp_out = pim_if_find_by_vif_index(oif_vif_index);
-
pim_time_uptime(oif_uptime, sizeof(oif_uptime), now - c_oil->oif_creation[oif_vif_index]);
+ found_oif = 1;
- proto[0] = '\0';
- if (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_PROTO_PIM) {
- strcat(proto, "P");
- }
- if (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_PROTO_IGMP) {
- strcat(proto, "I");
- }
- if (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_PROTO_SOURCE) {
- strcat(proto, "O");
+ if (ifp_out)
+ strcpy(out_ifname, ifp_out->name);
+ else
+ strcpy(out_ifname, "<oif?>");
+
+ if (uj) {
+ json_ifp_out = json_object_new_object();
+ json_object_string_add(json_ifp_out, "source", src_str);
+ json_object_string_add(json_ifp_out, "group", grp_str);
+
+ if (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_PROTO_PIM)
+ json_object_boolean_true_add(json_ifp_out, "protocolPim");
+
+ if (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_PROTO_IGMP)
+ json_object_boolean_true_add(json_ifp_out, "protocolIgmp");
+
+ if (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_PROTO_SOURCE)
+ json_object_boolean_true_add(json_ifp_out, "protocolSource");
+
+ json_object_string_add(json_ifp_out, "inboundInterface", in_ifname);
+ json_object_int_add(json_ifp_out, "iVifI", c_oil->oil.mfcc_parent);
+ json_object_string_add(json_ifp_out, "outboundInterface", out_ifname);
+ json_object_int_add(json_ifp_out, "oVifI", oif_vif_index);
+ json_object_int_add(json_ifp_out, "ttl", ttl);
+ json_object_string_add(json_ifp_out, "upTime", oif_uptime);
+ if (!json_oil) {
+ json_oil = json_object_new_object();
+ json_object_object_add(json_source, "oil", json_oil);
+ }
+ json_object_object_add(json_oil, out_ifname, json_ifp_out);
+ } else {
+ if (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_PROTO_PIM) {
+ strcpy(proto, "PIM");
+ }
+
+ if (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_PROTO_IGMP) {
+ strcpy(proto, "IGMP");
+ }
+
+ if (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_PROTO_SOURCE) {
+ strcpy(proto, "SRC");
+ }
+
+ vty_out(vty, "%-15s %-15s %-6s %-10s %-10s %-3d %8s%s",
+ src_str,
+ grp_str,
+ proto,
+ in_ifname,
+ out_ifname,
+ ttl,
+ oif_uptime,
+ VTY_NEWLINE);
+
+ if (first)
+ {
+ src_str[0] = '\0';
+ grp_str[0] = '\0';
+ in_ifname[0] = '\0';
+ first = 0;
+ }
}
+ }
- vty_out(vty, "%-15s %-15s %-5s %-5s %5d %-6s %5d %3d %8s %s",
- source_str,
- group_str,
- proto,
- ifp_in ? ifp_in->name : "<iif?>",
- c_oil->oil.mfcc_parent,
- ifp_out ? ifp_out->name : "<oif?>",
- oif_vif_index,
- ttl,
- oif_uptime,
- VTY_NEWLINE);
+ if (!uj && !found_oif) {
+ vty_out(vty, "%-15s %-15s %-6s %-10s %-10s %-3d %8s%s",
+ src_str,
+ grp_str,
+ "none",
+ in_ifname,
+ "none",
+ 0,
+ "--:--:--",
+ VTY_NEWLINE);
}
}
/* Print list of static routes */
for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) {
- char group_str[100];
- char source_str[100];
+ char grp_str[INET_ADDRSTRLEN];
+ char src_str[INET_ADDRSTRLEN];
+ char in_ifname[16];
+ char out_ifname[16];
int oif_vif_index;
+ struct interface *ifp_in;
+ char proto[100];
+ first = 1;
if (!s_route->c_oil.installed)
continue;
- pim_inet4_dump("<group?>", s_route->group, group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", s_route->source, source_str, sizeof(source_str));
+ pim_inet4_dump("<group?>", s_route->group, grp_str, 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);
+ found_oif = 0;
+
+ if (ifp_in)
+ strcpy(in_ifname, ifp_in->name);
+ else
+ strcpy(in_ifname, "<iif?>");
+
+ if (uj) {
+
+ /* Find the group, create it if it doesn't exist */
+ json_object_object_get_ex(json, grp_str, &json_group);
+
+ if (!json_group) {
+ json_group = json_object_new_object();
+ json_object_object_add(json, grp_str, json_group);
+ }
+
+ /* Find the source nested under the group, create it if it doesn't exist */
+ json_object_object_get_ex(json_group, src_str, &json_source);
+
+ if (!json_source) {
+ json_source = json_object_new_object();
+ json_object_object_add(json_group, src_str, json_source);
+ }
+
+ json_object_string_add(json_source, "iif", in_ifname);
+ json_oil = NULL;
+ } else {
+ strcpy(proto, "STATIC");
+ }
for (oif_vif_index = 0; oif_vif_index < MAXVIFS; ++oif_vif_index) {
- struct interface *ifp_in;
struct interface *ifp_out;
char oif_uptime[10];
int ttl;
- char proto[5];
ttl = s_route->oif_ttls[oif_vif_index];
if (ttl < 1)
continue;
- ifp_in = pim_if_find_by_vif_index(s_route->iif);
ifp_out = pim_if_find_by_vif_index(oif_vif_index);
-
pim_time_uptime(oif_uptime, sizeof(oif_uptime), now - s_route->c_oil.oif_creation[oif_vif_index]);
+ found_oif = 1;
- proto[0] = '\0';
- strcat(proto, "S");
-
- vty_out(vty, "%-15s %-15s %-5s %-5s %5d %-6s %5d %3d %8s %s",
- source_str,
- group_str,
- proto,
- ifp_in ? ifp_in->name : "<iif?>",
- s_route->iif,
- ifp_out ? ifp_out->name : "<oif?>",
- oif_vif_index,
- ttl,
- oif_uptime,
- VTY_NEWLINE);
+ if (ifp_out)
+ strcpy(out_ifname, ifp_out->name);
+ else
+ strcpy(out_ifname, "<oif?>");
+
+ if (uj) {
+ json_ifp_out = json_object_new_object();
+ json_object_string_add(json_ifp_out, "source", src_str);
+ json_object_string_add(json_ifp_out, "group", grp_str);
+ json_object_boolean_true_add(json_ifp_out, "protocolStatic");
+ json_object_string_add(json_ifp_out, "inboundInterface", in_ifname);
+ json_object_int_add(json_ifp_out, "iVifI", c_oil->oil.mfcc_parent);
+ json_object_string_add(json_ifp_out, "outboundInterface", out_ifname);
+ json_object_int_add(json_ifp_out, "oVifI", oif_vif_index);
+ json_object_int_add(json_ifp_out, "ttl", ttl);
+ json_object_string_add(json_ifp_out, "upTime", oif_uptime);
+ if (!json_oil) {
+ json_oil = json_object_new_object();
+ json_object_object_add(json_source, "oil", json_oil);
+ }
+ json_object_object_add(json_oil, out_ifname, json_ifp_out);
+ } else {
+ vty_out(vty, "%-15s %-15s %-6s %-10s %-10s %-3d %8s%s",
+ src_str,
+ grp_str,
+ proto,
+ in_ifname,
+ out_ifname,
+ ttl,
+ oif_uptime,
+ VTY_NEWLINE);
+ if (first)
+ {
+ src_str[0] = '\0';
+ grp_str[0] = '\0';
+ in_ifname[0] = '\0';
+ first = 0;
+ }
+ }
+ }
+
+ if (!uj && !found_oif) {
+ vty_out(vty, "%-15s %-15s %-6s %-10s %-10s %-3d %8s%s",
+ src_str,
+ grp_str,
+ proto,
+ in_ifname,
+ "none",
+ 0,
+ "--:--:--",
+ VTY_NEWLINE);
}
}
+
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
+ }
}
DEFUN (show_ip_mroute,
show_ip_mroute_cmd,
- "show ip mroute",
+ "show ip mroute [json]",
SHOW_STR
IP_STR
- MROUTE_STR)
+ MROUTE_STR
+ JSON_STR)
{
- show_mroute(vty);
+ u_char uj = use_json(argc, argv);
+ show_mroute(vty, uj);
return CMD_SUCCESS;
}
@@ -2258,13 +3152,13 @@ static void show_mroute_count(struct vty *vty)
vty_out(vty, "%s", VTY_NEWLINE);
- vty_out(vty, "Source Group Packets Bytes WrongIf %s",
+ vty_out(vty, "Source Group LastUsed Packets Bytes WrongIf %s",
VTY_NEWLINE);
/* Print PIM and IGMP route counts */
- for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) {
- char group_str[100];
- char source_str[100];
+ for (ALL_LIST_ELEMENTS_RO(pim_channel_oil_list, node, c_oil)) {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
if (!c_oil->installed)
continue;
@@ -2274,9 +3168,10 @@ static void show_mroute_count(struct vty *vty)
pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
- vty_out(vty, "%-15s %-15s %7ld %10ld %7ld %s",
+ vty_out(vty, "%-15s %-15s %-8llu %-7ld %-10ld %-7ld%s",
source_str,
group_str,
+ c_oil->cc.lastused/100,
c_oil->cc.pktcnt,
c_oil->cc.bytecnt,
c_oil->cc.wrong_if,
@@ -2285,8 +3180,8 @@ static void show_mroute_count(struct vty *vty)
/* Print static route counts */
for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
if (!s_route->c_oil.installed)
continue;
@@ -2296,9 +3191,10 @@ static void show_mroute_count(struct vty *vty)
pim_inet4_dump("<group?>", s_route->c_oil.oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", s_route->c_oil.oil.mfcc_origin, source_str, sizeof(source_str));
- vty_out(vty, "%-15s %-15s %7ld %10ld %7ld %s",
+ vty_out(vty, "%-15s %-15s %-8llu %-7ld %-10ld %-7ld%s",
source_str,
group_str,
+ s_route->c_oil.cc.lastused,
s_route->c_oil.cc.pktcnt,
s_route->c_oil.cc.bytecnt,
s_route->c_oil.cc.wrong_if,
@@ -2330,9 +3226,10 @@ DEFUN (show_ip_rib,
struct in_addr addr;
const char *addr_str;
struct pim_nexthop nexthop;
- char nexthop_addr_str[100];
+ char nexthop_addr_str[PREFIX_STRLEN];
int result;
+ memset (&nexthop, 0, sizeof (nexthop));
addr_str = argv[idx_ipv4]->arg;
result = inet_pton(AF_INET, addr_str, &addr);
if (result <= 0) {
@@ -2341,7 +3238,7 @@ DEFUN (show_ip_rib,
return CMD_WARNING;
}
- if (pim_nexthop_lookup(&nexthop, addr, NULL)) {
+ if (pim_nexthop_lookup(&nexthop, addr, 0)) {
vty_out(vty, "Failure querying RIB nexthop for unicast address %s%s",
addr_str, VTY_NEWLINE);
return CMD_WARNING;
@@ -2350,8 +3247,8 @@ DEFUN (show_ip_rib,
vty_out(vty, "Address NextHop Interface Metric Preference%s",
VTY_NEWLINE);
- pim_inet4_dump("<nexthop?>", nexthop.mrib_nexthop_addr,
- nexthop_addr_str, sizeof(nexthop_addr_str));
+ pim_addr_dump("<nexthop?>", &nexthop.mrib_nexthop_addr,
+ nexthop_addr_str, sizeof(nexthop_addr_str));
vty_out(vty, "%-15s %-15s %-9s %6d %10d%s",
addr_str,
@@ -2379,11 +3276,11 @@ static void show_ssmpingd(struct vty *vty)
now = pim_time_monotonic_sec();
for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) {
- char source_str[100];
+ char source_str[INET_ADDRSTRLEN];
char ss_uptime[10];
struct sockaddr_in bind_addr;
socklen_t len = sizeof(bind_addr);
- char bind_addr_str[100];
+ char bind_addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str));
@@ -2417,43 +3314,237 @@ DEFUN (show_ip_ssmpingd,
return CMD_SUCCESS;
}
+static int
+pim_rp_cmd_worker (struct vty *vty, const char *rp, const char *group, const char *plist)
+{
+ int result;
+
+ result = pim_rp_new (rp, group, plist);
+
+ if (result == PIM_MALLOC_FAIL)
+ {
+ vty_out (vty, "%% Out of memory%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (result == PIM_GROUP_BAD_ADDRESS)
+ {
+ vty_out (vty, "%% Bad group address specified: %s%s", group, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (result == PIM_RP_BAD_ADDRESS)
+ {
+ vty_out (vty, "%% Bad RP address specified: %s%s", rp, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (result == PIM_RP_NO_PATH)
+ {
+ vty_out (vty, "%% No Path to RP address specified: %s%s", rp, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (result == PIM_GROUP_OVERLAP)
+ {
+ vty_out (vty, "%% Group range specified cannot overlap%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (result == PIM_GROUP_PFXLIST_OVERLAP)
+ {
+ vty_out (vty, "%% This group is already covered by a RP prefix-list%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (result == PIM_RP_PFXLIST_IN_USE)
+ {
+ vty_out (vty, "%% The same prefix-list cannot be applied to multiple RPs%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (ip_pim_joinprune_time,
+ ip_pim_joinprune_time_cmd,
+ "ip pim join-prune-interval <60-600>",
+ IP_STR
+ "pim multicast routing\n"
+ "Join Prune Send Interval\n"
+ "Seconds\n")
+{
+ qpim_t_periodic = atoi(argv[3]->arg);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_pim_joinprune_time,
+ no_ip_pim_joinprune_time_cmd,
+ "no ip pim join-prune-interval <60-600>",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Join Prune Send Interval\n"
+ "Seconds\n")
+{
+ qpim_t_periodic = PIM_DEFAULT_T_PERIODIC;
+ return CMD_SUCCESS;
+}
+
+DEFUN (ip_pim_register_suppress,
+ ip_pim_register_suppress_cmd,
+ "ip pim register-suppress-time <5-60000>",
+ IP_STR
+ "pim multicast routing\n"
+ "Register Suppress Timer\n"
+ "Seconds\n")
+{
+ qpim_keep_alive_time = atoi (argv[3]->arg);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_pim_register_suppress,
+ no_ip_pim_register_suppress_cmd,
+ "no ip pim register-suppress-time <5-60000>",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Register Suppress Timer\n"
+ "Seconds\n")
+{
+ qpim_register_suppress_time = PIM_REGISTER_SUPPRESSION_TIME_DEFAULT;
+ return CMD_SUCCESS;
+}
+
+DEFUN (ip_pim_keep_alive,
+ ip_pim_keep_alive_cmd,
+ "ip pim keep-alive-timer <31-60000>",
+ IP_STR
+ "pim multicast routing\n"
+ "Keep alive Timer\n"
+ "Seconds\n")
+{
+ qpim_rp_keep_alive_time = atoi (argv[4]->arg);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_pim_keep_alive,
+ no_ip_pim_keep_alive_cmd,
+ "no ip pim keep-alive-timer <31-60000>",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Keep alive Timer\n"
+ "Seconds\n")
+{
+ qpim_keep_alive_time = PIM_KEEPALIVE_PERIOD;
+ return CMD_SUCCESS;
+}
+
+DEFUN (ip_pim_packets,
+ ip_pim_packets_cmd,
+ "ip pim packets <1-100>",
+ IP_STR
+ "pim multicast routing\n"
+ "packets to process at one time per fd\n"
+ "Number of packets\n")
+{
+ qpim_packet_process = atoi (argv[3]->arg);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_pim_packets,
+ no_ip_pim_packets_cmd,
+ "no ip pim packets <1-100>",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "packets to process at one time per fd\n"
+ "Number of packets\n")
+{
+ qpim_packet_process = PIM_DEFAULT_PACKET_PROCESS;
+ return CMD_SUCCESS;
+}
+
DEFUN (ip_pim_rp,
ip_pim_rp_cmd,
- "ip pim rp A.B.C.D",
+ "ip pim rp A.B.C.D [A.B.C.D/M]",
IP_STR
"pim multicast routing\n"
"Rendevous Point\n"
- "ip address of RP\n")
+ "ip address of RP\n"
+ "Group Address range to cover\n")
{
int idx_ipv4 = 3;
- int result;
+ return pim_rp_cmd_worker (vty, argv[idx_ipv4]->arg, argv[idx_ipv4 + 1]->arg, NULL);
+}
- result = inet_pton(AF_INET, argv[idx_ipv4]->arg, &qpim_rp.rpf_addr.s_addr);
- if (result <= 0) {
- vty_out(vty, "%% Bad RP address specified: %s", argv[idx_ipv4]->arg);
- return CMD_WARNING;
- }
+DEFUN (ip_pim_rp_prefix_list,
+ ip_pim_rp_prefix_list_cmd,
+ "ip pim rp A.B.C.D prefix-list WORD",
+ IP_STR
+ "pim multicast routing\n"
+ "Rendevous Point\n"
+ "ip address of RP\n"
+ "group prefix-list filter\n"
+ "Name of a prefix-list\n")
+{
+ return pim_rp_cmd_worker (vty, argv[3]->arg, NULL, argv[5]->arg);
+}
- if (pim_nexthop_lookup(&qpim_rp.source_nexthop, qpim_rp.rpf_addr, NULL) != 0) {
- vty_out(vty, "%% No Path to RP address specified: %s", argv[idx_ipv4]->arg);
- return CMD_WARNING;
- }
+static int
+pim_no_rp_cmd_worker (struct vty *vty, const char *rp, const char *group,
+ const char *plist)
+{
+ int result = pim_rp_del (rp, group, plist);
+
+ if (result == PIM_GROUP_BAD_ADDRESS)
+ {
+ vty_out (vty, "%% Bad group address specified: %s%s", group, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (result == PIM_RP_BAD_ADDRESS)
+ {
+ vty_out (vty, "%% Bad RP address specified: %s%s", rp, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (result == PIM_RP_NOT_FOUND)
+ {
+ vty_out (vty, "%% Unable to find specified RP%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
return CMD_SUCCESS;
}
DEFUN (no_ip_pim_rp,
no_ip_pim_rp_cmd,
- "no ip pim rp [A.B.C.D]",
+ "no ip pim rp A.B.C.D [A.B.C.D/M]",
NO_STR
IP_STR
"pim multicast routing\n"
"Rendevous Point\n"
- "ip address of RP\n")
+ "ip address of RP\n"
+ "Group Address range to cover\n")
{
- qpim_rp.rpf_addr.s_addr = INADDR_NONE;
+ int idx_ipv4 = 4;
+ return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, argv[idx_ipv4 + 1]->arg, NULL);
+}
- return CMD_SUCCESS;
+DEFUN (no_ip_pim_rp_prefix_list,
+ no_ip_pim_rp_prefix_list_cmd,
+ "no ip pim rp A.B.C.D prefix-list WORD",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Rendevous Point\n"
+ "ip address of RP\n"
+ "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);
}
DEFUN (ip_multicast_routing,
@@ -2718,7 +3809,7 @@ static void igmp_sock_query_interval_reconfig(struct igmp_sock *igmp)
pim_ifp = ifp->info;
if (PIM_DEBUG_IGMP_TRACE) {
- char ifaddr_str[100];
+ char ifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str));
zlog_debug("%s: Querier %s on %s reconfig query_interval=%d",
__PRETTY_FUNCTION__,
@@ -2913,16 +4004,66 @@ DEFUN (interface_no_ip_igmp_query_interval,
return CMD_SUCCESS;
}
-#define IGMP_QUERY_MAX_RESPONSE_TIME_MIN (1)
-#define IGMP_QUERY_MAX_RESPONSE_TIME_MAX (25)
+DEFUN (interface_ip_igmp_version,
+ interface_ip_igmp_version_cmd,
+ "ip igmp version <2-3>",
+ IP_STR
+ IFACE_IGMP_STR
+ "IGMP version\n"
+ "IGMP version number\n")
+{
+ VTY_DECLVAR_CONTEXT(interface,ifp);
+ struct pim_interface *pim_ifp;
+ int igmp_version;
+
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp) {
+ vty_out(vty,
+ "IGMP not enabled on interface %s. Please enable IGMP first.%s",
+ ifp->name,
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ igmp_version = atoi(argv[3]->arg);
+ pim_ifp->igmp_version = igmp_version;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (interface_no_ip_igmp_version,
+ interface_no_ip_igmp_version_cmd,
+ "no ip igmp version <2-3>",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR
+ "IGMP version\n"
+ "IGMP version number\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct pim_interface *pim_ifp;
+
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp)
+ return CMD_SUCCESS;
+
+ pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
+
+ return CMD_SUCCESS;
+}
+
+#define IGMP_QUERY_MAX_RESPONSE_TIME_MIN_DSEC (10)
+#define IGMP_QUERY_MAX_RESPONSE_TIME_MAX_DSEC (250)
DEFUN (interface_ip_igmp_query_max_response_time,
interface_ip_igmp_query_max_response_time_cmd,
- "ip igmp query-max-response-time (1-25)",
+ "ip igmp query-max-response-time (10-250)",
IP_STR
IFACE_IGMP_STR
IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR
- "Query response value in seconds\n")
+ "Query response value in deci-seconds\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct pim_interface *pim_ifp;
@@ -2940,26 +4081,7 @@ DEFUN (interface_ip_igmp_query_max_response_time,
query_max_response_time = atoi(argv[4]->arg);
- /*
- It seems we don't need to check bounds since command.c does it
- already, but we verify them anyway for extra safety.
- */
- if (query_max_response_time < IGMP_QUERY_MAX_RESPONSE_TIME_MIN) {
- vty_out(vty, "Query max response time %d sec lower than minimum %d sec%s",
- query_max_response_time,
- IGMP_QUERY_MAX_RESPONSE_TIME_MIN,
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- if (query_max_response_time > IGMP_QUERY_MAX_RESPONSE_TIME_MAX) {
- vty_out(vty, "Query max response time %d sec higher than maximum %d sec%s",
- query_max_response_time,
- IGMP_QUERY_MAX_RESPONSE_TIME_MAX,
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (query_max_response_time >= pim_ifp->igmp_default_query_interval) {
+ if (query_max_response_time >= pim_ifp->igmp_default_query_interval * 10) {
vty_out(vty,
"Can't set query max response time %d sec >= general query interval %d sec%s",
query_max_response_time, pim_ifp->igmp_default_query_interval,
@@ -2967,38 +4089,28 @@ DEFUN (interface_ip_igmp_query_max_response_time,
return CMD_WARNING;
}
- change_query_max_response_time(pim_ifp, 10 * query_max_response_time);
+ change_query_max_response_time(pim_ifp, query_max_response_time);
return CMD_SUCCESS;
}
DEFUN (interface_no_ip_igmp_query_max_response_time,
interface_no_ip_igmp_query_max_response_time_cmd,
- "no ip igmp query-max-response-time",
+ "no ip igmp query-max-response-time <10-250>",
NO_STR
IP_STR
IFACE_IGMP_STR
- IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR)
+ IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR
+ "Time for response in deci-seconds\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct pim_interface *pim_ifp;
- int default_query_interval_dsec;
pim_ifp = ifp->info;
if (!pim_ifp)
return CMD_SUCCESS;
- default_query_interval_dsec = 10 * pim_ifp->igmp_default_query_interval;
-
- if (IGMP_QUERY_MAX_RESPONSE_TIME_DSEC >= default_query_interval_dsec) {
- vty_out(vty,
- "Can't set default query max response time %d dsec >= general query interval %d dsec.%s",
- IGMP_QUERY_MAX_RESPONSE_TIME_DSEC, default_query_interval_dsec,
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
change_query_max_response_time(pim_ifp, IGMP_QUERY_MAX_RESPONSE_TIME_DSEC);
return CMD_SUCCESS;
@@ -3007,13 +4119,13 @@ DEFUN (interface_no_ip_igmp_query_max_response_time,
#define IGMP_QUERY_MAX_RESPONSE_TIME_MIN_DSEC (10)
#define IGMP_QUERY_MAX_RESPONSE_TIME_MAX_DSEC (250)
-DEFUN (interface_ip_igmp_query_max_response_time_dsec,
- interface_ip_igmp_query_max_response_time_dsec_cmd,
- "ip igmp query-max-response-time-dsec (10-250)",
- IP_STR
- IFACE_IGMP_STR
- IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR
- "Query response value in deciseconds\n")
+DEFUN_HIDDEN (interface_ip_igmp_query_max_response_time_dsec,
+ interface_ip_igmp_query_max_response_time_dsec_cmd,
+ "ip igmp query-max-response-time-dsec (10-250)",
+ IP_STR
+ IFACE_IGMP_STR
+ IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR
+ "Query response value in deciseconds\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct pim_interface *pim_ifp;
@@ -3032,25 +4144,6 @@ DEFUN (interface_ip_igmp_query_max_response_time_dsec,
query_max_response_time_dsec = atoi(argv[4]->arg);
- /*
- It seems we don't need to check bounds since command.c does it
- already, but we verify them anyway for extra safety.
- */
- if (query_max_response_time_dsec < IGMP_QUERY_MAX_RESPONSE_TIME_MIN_DSEC) {
- vty_out(vty, "Query max response time %d dsec lower than minimum %d dsec%s",
- query_max_response_time_dsec,
- IGMP_QUERY_MAX_RESPONSE_TIME_MIN_DSEC,
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- if (query_max_response_time_dsec > IGMP_QUERY_MAX_RESPONSE_TIME_MAX_DSEC) {
- vty_out(vty, "Query max response time %d dsec higher than maximum %d dsec%s",
- query_max_response_time_dsec,
- IGMP_QUERY_MAX_RESPONSE_TIME_MAX_DSEC,
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
default_query_interval_dsec = 10 * pim_ifp->igmp_default_query_interval;
if (query_max_response_time_dsec >= default_query_interval_dsec) {
@@ -3066,33 +4159,22 @@ DEFUN (interface_ip_igmp_query_max_response_time_dsec,
return CMD_SUCCESS;
}
-DEFUN (interface_no_ip_igmp_query_max_response_time_dsec,
- interface_no_ip_igmp_query_max_response_time_dsec_cmd,
- "no ip igmp query-max-response-time-dsec",
- NO_STR
- IP_STR
- IFACE_IGMP_STR
- IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR)
+DEFUN_HIDDEN (interface_no_ip_igmp_query_max_response_time_dsec,
+ interface_no_ip_igmp_query_max_response_time_dsec_cmd,
+ "no ip igmp query-max-response-time-dsec",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR
+ IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR)
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct pim_interface *pim_ifp;
- int default_query_interval_dsec;
pim_ifp = ifp->info;
if (!pim_ifp)
return CMD_SUCCESS;
- default_query_interval_dsec = 10 * pim_ifp->igmp_default_query_interval;
-
- if (IGMP_QUERY_MAX_RESPONSE_TIME_DSEC >= default_query_interval_dsec) {
- vty_out(vty,
- "Can't set default query max response time %d dsec >= general query interval %d dsec.%s",
- IGMP_QUERY_MAX_RESPONSE_TIME_DSEC, default_query_interval_dsec,
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
change_query_max_response_time(pim_ifp, IGMP_QUERY_MAX_RESPONSE_TIME_DSEC);
return CMD_SUCCESS;
@@ -3162,7 +4244,6 @@ static int
pim_cmd_interface_add (struct interface *ifp, enum pim_interface_type itype)
{
struct pim_interface *pim_ifp = ifp->info;
- struct in_addr null = { .s_addr = 0 };
if (!pim_ifp) {
pim_ifp = pim_if_new(ifp, 0 /* igmp=false */, 1 /* pim=true */);
@@ -3177,8 +4258,6 @@ pim_cmd_interface_add (struct interface *ifp, enum pim_interface_type itype)
pim_ifp->itype = itype;
pim_if_addr_add_all(ifp);
pim_if_membership_refresh(ifp);
-
- pim_rp_check_rp (null, pim_ifp->primary_address);
return 1;
}
@@ -3231,18 +4310,13 @@ pim_cmd_interface_delete (struct interface *ifp)
pim_if_membership_clear(ifp);
/*
- pim_if_addr_del_all() removes all sockets from
- pim_ifp->igmp_socket_list.
- */
- pim_if_addr_del_all(ifp);
-
- /*
pim_sock_delete() removes all neighbors from
pim_ifp->pim_neighbor_list.
*/
pim_sock_delete(ifp, "pim unconfigured on interface");
if (!PIM_IF_TEST_IGMP(pim_ifp->options)) {
+ pim_if_addr_del_all(ifp);
pim_if_delete(ifp);
}
@@ -3644,6 +4718,17 @@ DEFUN (debug_mroute,
return CMD_SUCCESS;
}
+DEFUN (debug_mroute_detail,
+ debug_mroute_detail_cmd,
+ "debug mroute detail",
+ DEBUG_STR
+ DEBUG_MROUTE_STR
+ "detailed\n")
+{
+ PIM_DO_DEBUG_MROUTE_DETAIL;
+ return CMD_SUCCESS;
+}
+
DEFUN (no_debug_mroute,
no_debug_mroute_cmd,
"no debug mroute",
@@ -3655,6 +4740,17 @@ DEFUN (no_debug_mroute,
return CMD_SUCCESS;
}
+DEFUN (no_debug_mroute_detail,
+ no_debug_mroute_detail_cmd,
+ "no debug mroute detail",
+ NO_STR
+ DEBUG_STR
+ DEBUG_MROUTE_STR
+ "detailed\n")
+{
+ PIM_DONT_DEBUG_MROUTE_DETAIL;
+ return CMD_SUCCESS;
+}
DEFUN (debug_static,
debug_static_cmd,
@@ -3687,6 +4783,8 @@ DEFUN (debug_pim,
PIM_DO_DEBUG_PIM_EVENTS;
PIM_DO_DEBUG_PIM_PACKETS;
PIM_DO_DEBUG_PIM_TRACE;
+ PIM_DO_DEBUG_MSDP_EVENTS;
+ PIM_DO_DEBUG_MSDP_PACKETS;
return CMD_SUCCESS;
}
@@ -3700,6 +4798,8 @@ DEFUN (no_debug_pim,
PIM_DONT_DEBUG_PIM_EVENTS;
PIM_DONT_DEBUG_PIM_PACKETS;
PIM_DONT_DEBUG_PIM_TRACE;
+ PIM_DONT_DEBUG_MSDP_EVENTS;
+ PIM_DONT_DEBUG_MSDP_PACKETS;
PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND;
PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV;
@@ -3731,79 +4831,71 @@ DEFUN (no_debug_pim_events,
return CMD_SUCCESS;
}
-
DEFUN (debug_pim_packets,
debug_pim_packets_cmd,
- "debug pim packets",
- DEBUG_STR
- DEBUG_PIM_STR
- DEBUG_PIM_PACKETS_STR)
-{
- PIM_DO_DEBUG_PIM_PACKETS;
- vty_out (vty, "PIM Packet debugging is on %s", VTY_NEWLINE);
- return CMD_SUCCESS;
-}
-
-DEFUN (debug_pim_packets_filter,
- debug_pim_packets_filter_cmd,
- "debug pim packets <hello|joins>",
+ "debug pim packets [<hello|joins|register>]",
DEBUG_STR
DEBUG_PIM_STR
DEBUG_PIM_PACKETS_STR
DEBUG_PIM_HELLO_PACKETS_STR
- DEBUG_PIM_J_P_PACKETS_STR)
+ DEBUG_PIM_J_P_PACKETS_STR
+ DEBUG_PIM_PIM_REG_PACKETS_STR)
{
- int idx_hello_join = 3;
- if (strncmp(argv[idx_hello_join]->arg,"h",1) == 0)
+ int idx;
+ if (argv_find (argv, argc, "hello", &idx))
{
PIM_DO_DEBUG_PIM_HELLO;
- vty_out (vty, "PIM Hello debugging is on %s", VTY_NEWLINE);
+ vty_out (vty, "PIM Hello debugging is on%s", VTY_NEWLINE);
}
- else if (strncmp(argv[idx_hello_join]->arg,"j",1) == 0)
+ else if (argv_find (argv, argc ,"joins", &idx))
{
PIM_DO_DEBUG_PIM_J_P;
- vty_out (vty, "PIM Join/Prune debugging is on %s", VTY_NEWLINE);
+ vty_out (vty, "PIM Join/Prune debugging is on%s", VTY_NEWLINE);
+ }
+ else if (argv_find (argv, argc, "register", &idx))
+ {
+ PIM_DO_DEBUG_PIM_REG;
+ vty_out (vty, "PIM Register debugging is on%s", VTY_NEWLINE);
+ }
+ else
+ {
+ PIM_DO_DEBUG_PIM_PACKETS;
+ vty_out (vty, "PIM Packet debugging is on %s", VTY_NEWLINE);
}
return CMD_SUCCESS;
}
DEFUN (no_debug_pim_packets,
no_debug_pim_packets_cmd,
- "no debug pim packets",
+ "no debug pim packets [<hello|joins|register>]",
NO_STR
DEBUG_STR
DEBUG_PIM_STR
DEBUG_PIM_PACKETS_STR
DEBUG_PIM_HELLO_PACKETS_STR
- DEBUG_PIM_J_P_PACKETS_STR)
+ DEBUG_PIM_J_P_PACKETS_STR
+ DEBUG_PIM_PIM_REG_PACKETS_STR)
{
- PIM_DONT_DEBUG_PIM_PACKETS;
- vty_out (vty, "PIM Packet debugging is off %s", VTY_NEWLINE);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_debug_pim_packets_filter,
- no_debug_pim_packets_filter_cmd,
- "no debug pim packets <hello|joins>",
- NO_STR
- DEBUG_STR
- DEBUG_PIM_STR
- DEBUG_PIM_PACKETS_STR
- DEBUG_PIM_HELLO_PACKETS_STR
- DEBUG_PIM_J_P_PACKETS_STR)
-{
- int idx_hello_join = 4;
- if (strncmp(argv[idx_hello_join]->arg,"h",1) == 0)
+ int idx = 0;
+ if (argv_find (argv, argc,"hello",&idx))
{
PIM_DONT_DEBUG_PIM_HELLO;
vty_out (vty, "PIM Hello debugging is off %s", VTY_NEWLINE);
}
- else if (strncmp(argv[idx_hello_join]->arg,"j",1) == 0)
+ else if (argv_find (argv, argc, "joins", &idx))
{
PIM_DONT_DEBUG_PIM_J_P;
vty_out (vty, "PIM Join/Prune debugging is off %s", VTY_NEWLINE);
}
- return CMD_SUCCESS;
+ else if (argv_find (argv, argc, "register", &idx))
+ {
+ PIM_DONT_DEBUG_PIM_REG;
+ vty_out (vty, "PIM Register debugging is off%s", VTY_NEWLINE);
+ }
+ else
+ PIM_DONT_DEBUG_PIM_PACKETS;
+
+ return CMD_SUCCESS;
}
@@ -3931,6 +5023,95 @@ DEFUN (no_debug_pim_zebra,
}
+DEFUN (debug_msdp,
+ debug_msdp_cmd,
+ "debug msdp",
+ DEBUG_STR
+ DEBUG_MSDP_STR)
+{
+ PIM_DO_DEBUG_MSDP_EVENTS;
+ PIM_DO_DEBUG_MSDP_PACKETS;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_msdp,
+ no_debug_msdp_cmd,
+ "no debug msdp",
+ NO_STR
+ DEBUG_STR
+ DEBUG_MSDP_STR)
+{
+ PIM_DONT_DEBUG_MSDP_EVENTS;
+ PIM_DONT_DEBUG_MSDP_PACKETS;
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_msdp,
+ undebug_msdp_cmd,
+ "undebug msdp",
+ UNDEBUG_STR
+ DEBUG_MSDP_STR)
+
+DEFUN (debug_msdp_events,
+ debug_msdp_events_cmd,
+ "debug msdp events",
+ DEBUG_STR
+ DEBUG_MSDP_STR
+ DEBUG_MSDP_EVENTS_STR)
+{
+ PIM_DO_DEBUG_MSDP_EVENTS;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_msdp_events,
+ no_debug_msdp_events_cmd,
+ "no debug msdp events",
+ NO_STR
+ DEBUG_STR
+ DEBUG_MSDP_STR
+ DEBUG_MSDP_EVENTS_STR)
+{
+ PIM_DONT_DEBUG_MSDP_EVENTS;
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_msdp_events,
+ undebug_msdp_events_cmd,
+ "undebug msdp events",
+ UNDEBUG_STR
+ DEBUG_MSDP_STR
+ DEBUG_MSDP_EVENTS_STR)
+
+DEFUN (debug_msdp_packets,
+ debug_msdp_packets_cmd,
+ "debug msdp packets",
+ DEBUG_STR
+ DEBUG_MSDP_STR
+ DEBUG_MSDP_PACKETS_STR)
+{
+ PIM_DO_DEBUG_MSDP_PACKETS;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_msdp_packets,
+ no_debug_msdp_packets_cmd,
+ "no debug msdp packets",
+ NO_STR
+ DEBUG_STR
+ DEBUG_MSDP_STR
+ DEBUG_MSDP_PACKETS_STR)
+{
+ PIM_DONT_DEBUG_MSDP_PACKETS;
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_msdp_packets,
+ undebug_msdp_packets_cmd,
+ "undebug msdp packets",
+ UNDEBUG_STR
+ DEBUG_MSDP_STR
+ DEBUG_MSDP_PACKETS_STR)
+
DEFUN (show_debugging_pim,
show_debugging_pim_cmd,
"show debugging pim",
@@ -3942,813 +5123,837 @@ DEFUN (show_debugging_pim,
return CMD_SUCCESS;
}
-static struct igmp_sock *find_igmp_sock_by_fd(int fd)
+static int
+interface_pim_use_src_cmd_worker(struct vty *vty, const char *source)
{
- struct listnode *ifnode;
- struct interface *ifp;
-
- /* scan all interfaces */
- for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp)) {
- struct pim_interface *pim_ifp;
- struct igmp_sock *igmp;
-
- if (!ifp->info)
- continue;
-
- pim_ifp = ifp->info;
-
- /* lookup igmp socket under current interface */
- igmp = igmp_sock_lookup_by_fd(pim_ifp->igmp_socket_list, fd);
- if (igmp)
- return igmp;
- }
-
- return 0;
-}
-
-DEFUN (test_igmp_receive_report,
- test_igmp_receive_report_cmd,
- "test igmp receive report (0-65535) A.B.C.D (1-6) LINE...",
- "Test\n"
- "Test IGMP protocol\n"
- "Test IGMP message\n"
- "Test IGMP report\n"
- "Socket\n"
- "IGMP group address\n"
- "Record type\n"
- "Sources\n")
-{
- int idx_number = 4;
- int idx_ipv4 = 5;
- int idx_number_2 = 6;
- int idx_line = 7;
- char buf[1000];
- char *igmp_msg;
- struct ip *ip_hdr;
- size_t ip_hlen; /* ip header length in bytes */
- int ip_msg_len;
- int igmp_msg_len;
- const char *socket;
- int socket_fd;
- const char *grp_str;
- struct in_addr grp_addr;
- const char *record_type_str;
- int record_type;
- const char *src_str;
- int result;
- struct igmp_sock *igmp;
- char *group_record;
- int num_sources;
- struct in_addr *sources;
- struct in_addr *src_addr;
- int argi;
-
- socket = argv[idx_number]->arg;
- socket_fd = atoi(socket);
- igmp = find_igmp_sock_by_fd(socket_fd);
- if (!igmp) {
- vty_out(vty, "Could not find IGMP socket %s: fd=%d%s",
- socket, socket_fd, VTY_NEWLINE);
- return CMD_WARNING;
- }
+ int result;
+ struct in_addr source_addr;
+ VTY_DECLVAR_CONTEXT(interface, ifp);
- grp_str = argv[idx_ipv4]->arg;
- result = inet_pton(AF_INET, grp_str, &grp_addr);
+ result = inet_pton(AF_INET, source, &source_addr);
if (result <= 0) {
- vty_out(vty, "Bad group address %s: errno=%d: %s%s",
- grp_str, errno, safe_strerror(errno), VTY_NEWLINE);
+ vty_out(vty, "%% Bad source address %s: errno=%d: %s%s",
+ source, errno, safe_strerror(errno), VTY_NEWLINE);
return CMD_WARNING;
}
- record_type_str = argv[idx_number_2]->arg;
- record_type = atoi(record_type_str);
-
- /*
- Tweak IP header
- */
- ip_hdr = (struct ip *) buf;
- ip_hdr->ip_p = PIM_IP_PROTO_IGMP;
- ip_hlen = PIM_IP_HEADER_MIN_LEN; /* ip header length in bytes */
- ip_hdr->ip_hl = ip_hlen >> 2; /* ip header length in 4-byte words */
- ip_hdr->ip_src = igmp->ifaddr;
- ip_hdr->ip_dst = igmp->ifaddr;
-
- /*
- Build IGMP v3 report message
- */
- igmp_msg = buf + ip_hlen;
- group_record = igmp_msg + IGMP_V3_REPORT_GROUPPRECORD_OFFSET;
- *igmp_msg = PIM_IGMP_V3_MEMBERSHIP_REPORT; /* type */
- *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = 0; /* for computing checksum */
- *(uint16_t *) (igmp_msg + IGMP_V3_REPORT_NUMGROUPS_OFFSET) = htons(1); /* one group record */
- *(uint8_t *) (group_record + IGMP_V3_GROUP_RECORD_TYPE_OFFSET) = record_type;
- memcpy(group_record + IGMP_V3_GROUP_RECORD_GROUP_OFFSET, &grp_addr, sizeof(struct in_addr));
-
- /* Scan LINE sources */
- sources = (struct in_addr *) (group_record + IGMP_V3_GROUP_RECORD_SOURCE_OFFSET);
- src_addr = sources;
- for (argi = idx_line; argi < argc; ++argi,++src_addr) {
- src_str = argv[argi]->arg;
- result = inet_pton(AF_INET, src_str, src_addr);
- if (result <= 0) {
- vty_out(vty, "Bad source address %s: errno=%d: %s%s",
- src_str, errno, safe_strerror(errno), VTY_NEWLINE);
- return CMD_WARNING;
- }
+ result = pim_update_source_set(ifp, source_addr);
+ switch (result) {
+ case PIM_SUCCESS:
+ break;
+ case PIM_IFACE_NOT_FOUND:
+ vty_out(vty, "Pim not enabled on this interface%s", VTY_NEWLINE);
+ break;
+ case PIM_UPDATE_SOURCE_DUP:
+ vty_out(vty, "%% Source already set to %s%s", source, VTY_NEWLINE);
+ break;
+ default:
+ vty_out(vty, "%% Source set failed%s", VTY_NEWLINE);
}
- num_sources = src_addr - sources;
- *(uint16_t *)(group_record + IGMP_V3_GROUP_RECORD_NUMSOURCES_OFFSET) = htons(num_sources);
+ return result?CMD_WARNING:CMD_SUCCESS;
+}
- igmp_msg_len = IGMP_V3_MSG_MIN_SIZE + (num_sources << 4); /* v3 report for one single group record */
+DEFUN (interface_pim_use_source,
+ interface_pim_use_source_cmd,
+ "ip pim use-source A.B.C.D",
+ IP_STR
+ "pim multicast routing\n"
+ "Configure primary IP address\n"
+ "source ip address\n")
+{
+ return interface_pim_use_src_cmd_worker (vty, argv[3]->arg);
+}
- /* compute checksum */
- *(uint16_t *)(igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = in_cksum(igmp_msg, igmp_msg_len);
+DEFUN (interface_no_pim_use_source,
+ interface_no_pim_use_source_cmd,
+ "no ip pim use-source",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Delete source IP address\n")
+{
+ return interface_pim_use_src_cmd_worker (vty, "0.0.0.0");
+}
- /* "receive" message */
+static int
+ip_msdp_peer_cmd_worker (struct vty *vty, const char *peer, const char *local)
+{
+ enum pim_msdp_err result;
+ struct in_addr peer_addr;
+ struct in_addr local_addr;
- ip_msg_len = ip_hlen + igmp_msg_len;
- result = pim_igmp_packet(igmp, buf, ip_msg_len);
- if (result) {
- vty_out(vty, "pim_igmp_packet(len=%d) returned: %d%s",
- ip_msg_len, result, VTY_NEWLINE);
+ result = inet_pton(AF_INET, peer, &peer_addr);
+ if (result <= 0) {
+ vty_out(vty, "%% Bad peer address %s: errno=%d: %s%s",
+ peer, errno, safe_strerror(errno), VTY_NEWLINE);
return CMD_WARNING;
}
- return CMD_SUCCESS;
-}
-
-static int hexval(uint8_t ch)
-{
- return isdigit(ch) ? (ch - '0') : (10 + tolower(ch) - 'a');
-}
-
-DEFUN (test_pim_receive_dump,
- test_pim_receive_dump_cmd,
- "test pim receive dump INTERFACE A.B.C.D LINE...",
- "Test\n"
- "Test PIM protocol\n"
- "Test PIM message reception\n"
- "Test PIM packet dump reception from neighbor\n"
- "Interface\n"
- "Neighbor address\n"
- "Packet dump\n")
-{
- int idx_interface = 4;
- int idx_ipv4 = 5;
- int idx_line = 6;
- uint8_t buf[1000];
- uint8_t *pim_msg;
- struct ip *ip_hdr;
- size_t ip_hlen; /* ip header length in bytes */
- int ip_msg_len;
- int pim_msg_size;
- const char *neigh_str;
- struct in_addr neigh_addr;
- const char *ifname;
- struct interface *ifp;
- int argi;
- int result;
-
- /* Find interface */
- ifname = argv[idx_interface]->arg;
- ifp = if_lookup_by_name(ifname);
- if (!ifp) {
- vty_out(vty, "No such interface name %s%s",
- ifname, VTY_NEWLINE);
+ result = inet_pton(AF_INET, local, &local_addr);
+ if (result <= 0) {
+ vty_out(vty, "%% Bad source address %s: errno=%d: %s%s",
+ local, errno, safe_strerror(errno), VTY_NEWLINE);
return CMD_WARNING;
}
- /* Neighbor address */
- neigh_str = argv[idx_ipv4]->arg;
- result = inet_pton(AF_INET, neigh_str, &neigh_addr);
- if (result <= 0) {
- vty_out(vty, "Bad neighbor address %s: errno=%d: %s%s",
- neigh_str, errno, safe_strerror(errno), VTY_NEWLINE);
- return CMD_WARNING;
+ result = pim_msdp_peer_add(peer_addr, local_addr, "default", NULL/* mp_p */);
+ switch (result) {
+ case PIM_MSDP_ERR_NONE:
+ break;
+ case PIM_MSDP_ERR_OOM:
+ vty_out(vty, "%% Out of memory%s", VTY_NEWLINE);
+ break;
+ case PIM_MSDP_ERR_PEER_EXISTS:
+ vty_out(vty, "%% Peer exists%s", VTY_NEWLINE);
+ break;
+ case PIM_MSDP_ERR_MAX_MESH_GROUPS:
+ vty_out(vty, "%% Only one mesh-group allowed currently%s", VTY_NEWLINE);
+ break;
+ default:
+ vty_out(vty, "%% peer add failed%s", VTY_NEWLINE);
}
- /*
- Tweak IP header
- */
- ip_hdr = (struct ip *) buf;
- ip_hdr->ip_p = PIM_IP_PROTO_PIM;
- ip_hlen = PIM_IP_HEADER_MIN_LEN; /* ip header length in bytes */
- ip_hdr->ip_hl = ip_hlen >> 2; /* ip header length in 4-byte words */
- ip_hdr->ip_src = neigh_addr;
- ip_hdr->ip_dst = qpim_all_pim_routers_addr;
+ return result?CMD_WARNING:CMD_SUCCESS;
+}
- /*
- Build PIM hello message
- */
- pim_msg = buf + ip_hlen;
- pim_msg_size = 0;
-
- /* Scan LINE dump into buffer */
- for (argi = idx_line; argi < argc; ++argi) {
- const char *str = argv[argi]->arg;
- int str_len = strlen(str);
- int str_last = str_len - 1;
- int i;
-
- if (str_len % 2) {
- vty_out(vty, "%% Uneven hex array arg %d=%s%s",
- argi, str, VTY_NEWLINE);
- return CMD_WARNING;
- }
+DEFUN_HIDDEN (ip_msdp_peer,
+ ip_msdp_peer_cmd,
+ "ip msdp peer A.B.C.D source A.B.C.D",
+ IP_STR
+ CFG_MSDP_STR
+ "Configure MSDP peer\n"
+ "peer ip address\n"
+ "Source address for TCP connection\n"
+ "local ip address\n")
+{
+ return ip_msdp_peer_cmd_worker (vty, argv[3]->arg, argv[5]->arg);
+}
- for (i = 0; i < str_last; i += 2) {
- uint8_t octet;
- int left;
- uint8_t h1 = str[i];
- uint8_t h2 = str[i + 1];
+static int
+ip_no_msdp_peer_cmd_worker (struct vty *vty, const char *peer)
+{
+ enum pim_msdp_err result;
+ struct in_addr peer_addr;
- if (!isxdigit(h1) || !isxdigit(h2)) {
- vty_out(vty, "%% Non-hex octet %c%c at hex array arg %d=%s%s",
- h1, h2, argi, str, VTY_NEWLINE);
- return CMD_WARNING;
- }
- octet = (hexval(h1) << 4) + hexval(h2);
+ result = inet_pton(AF_INET, peer, &peer_addr);
+ if (result <= 0) {
+ vty_out(vty, "%% Bad peer address %s: errno=%d: %s%s",
+ peer, errno, safe_strerror(errno), VTY_NEWLINE);
+ return CMD_WARNING;
+ }
- left = sizeof(buf) - ip_hlen - pim_msg_size;
- if (left < 1) {
- vty_out(vty, "%% Overflow buf_size=%zu buf_left=%d at hex array arg %d=%s octet %02x%s",
- sizeof(buf), left, argi, str, octet, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- pim_msg[pim_msg_size++] = octet;
- }
+ result = pim_msdp_peer_del(peer_addr);
+ switch (result) {
+ case PIM_MSDP_ERR_NONE:
+ break;
+ case PIM_MSDP_ERR_NO_PEER:
+ vty_out(vty, "%% Peer does not exist%s", VTY_NEWLINE);
+ break;
+ default:
+ vty_out(vty, "%% peer del failed%s", VTY_NEWLINE);
}
- ip_msg_len = ip_hlen + pim_msg_size;
+ return result?CMD_WARNING:CMD_SUCCESS;
+}
- vty_out(vty, "Receiving: buf_size=%zu ip_msg_size=%d pim_msg_size=%d%s",
- sizeof(buf), ip_msg_len, pim_msg_size, VTY_NEWLINE);
+DEFUN_HIDDEN (no_ip_msdp_peer,
+ no_ip_msdp_peer_cmd,
+ "no ip msdp peer A.B.C.D",
+ NO_STR
+ IP_STR
+ CFG_MSDP_STR
+ "Delete MSDP peer\n"
+ "peer ip address\n")
+{
+ return ip_no_msdp_peer_cmd_worker (vty, argv[4]->arg);
+}
- /* "receive" message */
+static int
+ip_msdp_mesh_group_member_cmd_worker(struct vty *vty, const char *mg, const char *mbr)
+{
+ enum pim_msdp_err result;
+ struct in_addr mbr_ip;
- result = pim_pim_packet(ifp, buf, ip_msg_len);
- if (result) {
- vty_out(vty, "%% pim_pim_packet(len=%d) returned failure: %d%s",
- ip_msg_len, result, VTY_NEWLINE);
+ result = inet_pton(AF_INET, mbr, &mbr_ip);
+ if (result <= 0) {
+ vty_out(vty, "%% Bad member address %s: errno=%d: %s%s",
+ mbr, errno, safe_strerror(errno), VTY_NEWLINE);
return CMD_WARNING;
}
- return CMD_SUCCESS;
+ result = pim_msdp_mg_mbr_add(mg, mbr_ip);
+ switch (result) {
+ case PIM_MSDP_ERR_NONE:
+ break;
+ case PIM_MSDP_ERR_OOM:
+ vty_out(vty, "%% Out of memory%s", VTY_NEWLINE);
+ break;
+ case PIM_MSDP_ERR_MG_MBR_EXISTS:
+ vty_out(vty, "%% mesh-group member exists%s", VTY_NEWLINE);
+ break;
+ case PIM_MSDP_ERR_MAX_MESH_GROUPS:
+ vty_out(vty, "%% Only one mesh-group allowed currently%s", VTY_NEWLINE);
+ break;
+ default:
+ vty_out(vty, "%% member add failed%s", VTY_NEWLINE);
+ }
+
+ return result?CMD_WARNING:CMD_SUCCESS;
}
-DEFUN (test_pim_receive_hello,
- test_pim_receive_hello_cmd,
- "test pim receive hello INTERFACE A.B.C.D (0-65535) (0-65535) (0-65535) (0-32767) (0-65535) (0-1) [LINE]",
- "Test\n"
- "Test PIM protocol\n"
- "Test PIM message reception\n"
- "Test PIM hello reception from neighbor\n"
- "Interface\n"
- "Neighbor address\n"
- "Neighbor holdtime\n"
- "Neighbor DR priority\n"
- "Neighbor generation ID\n"
- "Neighbor propagation delay (msec)\n"
- "Neighbor override interval (msec)\n"
- "Neighbor LAN prune delay T-bit\n"
- "Neighbor secondary addresses\n")
-{
- int idx_interface = 4;
- int idx_ipv4 = 5;
- int idx_number = 6;
- int idx_number_2 = 7;
- int idx_number_3 = 8;
- int idx_number_4 = 9;
- int idx_number_5 = 10;
- int idx_number_6 = 11;
- int idx_line = 12;
- uint8_t buf[1000];
- uint8_t *pim_msg;
- struct ip *ip_hdr;
- size_t ip_hlen; /* ip header length in bytes */
- int ip_msg_len;
- int pim_tlv_size;
- int pim_msg_size;
- const char *neigh_str;
- struct in_addr neigh_addr;
- const char *ifname;
- struct interface *ifp;
- uint16_t neigh_holdtime;
- uint16_t neigh_propagation_delay;
- uint16_t neigh_override_interval;
- int neigh_can_disable_join_suppression;
- uint32_t neigh_dr_priority;
- uint32_t neigh_generation_id;
- int argi;
- int result;
-
- /* Find interface */
- ifname = argv[idx_interface]->arg;
- ifp = if_lookup_by_name(ifname);
- if (!ifp) {
- vty_out(vty, "No such interface name %s%s",
- ifname, VTY_NEWLINE);
- return CMD_WARNING;
- }
+DEFUN (ip_msdp_mesh_group_member,
+ ip_msdp_mesh_group_member_cmd,
+ "ip msdp mesh-group WORD member A.B.C.D",
+ IP_STR
+ CFG_MSDP_STR
+ "Configure MSDP mesh-group\n"
+ "mesh group name\n"
+ "mesh group member\n"
+ "peer ip address\n")
+{
+ return ip_msdp_mesh_group_member_cmd_worker(vty, argv[3]->arg, argv[5]->arg);
+}
- /* Neighbor address */
- neigh_str = argv[idx_ipv4]->arg;
- result = inet_pton(AF_INET, neigh_str, &neigh_addr);
+static int
+ip_no_msdp_mesh_group_member_cmd_worker(struct vty *vty, const char *mg, const char *mbr)
+{
+ enum pim_msdp_err result;
+ struct in_addr mbr_ip;
+
+ result = inet_pton(AF_INET, mbr, &mbr_ip);
if (result <= 0) {
- vty_out(vty, "Bad neighbor address %s: errno=%d: %s%s",
- neigh_str, errno, safe_strerror(errno), VTY_NEWLINE);
+ vty_out(vty, "%% Bad member address %s: errno=%d: %s%s",
+ mbr, errno, safe_strerror(errno), VTY_NEWLINE);
return CMD_WARNING;
}
- neigh_holdtime = atoi(argv[idx_number]->arg);
- neigh_dr_priority = atoi(argv[idx_number_2]->arg);
- neigh_generation_id = atoi(argv[idx_number_3]->arg);
- neigh_propagation_delay = atoi(argv[idx_number_4]->arg);
- neigh_override_interval = atoi(argv[idx_number_5]->arg);
- neigh_can_disable_join_suppression = atoi(argv[idx_number_6]->arg);
+ result = pim_msdp_mg_mbr_del(mg, mbr_ip);
+ switch (result) {
+ case PIM_MSDP_ERR_NONE:
+ break;
+ case PIM_MSDP_ERR_NO_MG:
+ vty_out(vty, "%% mesh-group does not exist%s", VTY_NEWLINE);
+ break;
+ case PIM_MSDP_ERR_NO_MG_MBR:
+ vty_out(vty, "%% mesh-group member does not exist%s", VTY_NEWLINE);
+ break;
+ default:
+ vty_out(vty, "%% mesh-group member del failed%s", VTY_NEWLINE);
+ }
- /*
- Tweak IP header
- */
- ip_hdr = (struct ip *) buf;
- ip_hdr->ip_p = PIM_IP_PROTO_PIM;
- ip_hlen = PIM_IP_HEADER_MIN_LEN; /* ip header length in bytes */
- ip_hdr->ip_hl = ip_hlen >> 2; /* ip header length in 4-byte words */
- ip_hdr->ip_src = neigh_addr;
- ip_hdr->ip_dst = qpim_all_pim_routers_addr;
+ return result?CMD_WARNING:CMD_SUCCESS;
+}
+DEFUN (no_ip_msdp_mesh_group_member,
+ no_ip_msdp_mesh_group_member_cmd,
+ "no ip msdp mesh-group WORD member A.B.C.D",
+ NO_STR
+ IP_STR
+ CFG_MSDP_STR
+ "Delete MSDP mesh-group member\n"
+ "mesh group name\n"
+ "mesh group member\n"
+ "peer ip address\n")
+{
+ return ip_no_msdp_mesh_group_member_cmd_worker(vty, argv[4]->arg, argv[6]->arg);
+}
- /*
- Build PIM hello message
- */
- pim_msg = buf + ip_hlen;
-
- /* Scan LINE addresses */
- for (argi = idx_line; argi < argc; ++argi) {
- const char *sec_str = argv[argi]->arg;
- struct in_addr sec_addr;
- result = inet_pton(AF_INET, sec_str, &sec_addr);
- if (result <= 0) {
- vty_out(vty, "Bad neighbor secondary address %s: errno=%d: %s%s",
- sec_str, errno, safe_strerror(errno), VTY_NEWLINE);
- return CMD_WARNING;
- }
+static int
+ip_msdp_mesh_group_source_cmd_worker(struct vty *vty, const char *mg, const char *src)
+{
+ enum pim_msdp_err result;
+ struct in_addr src_ip;
- vty_out(vty,
- "FIXME WRITEME consider neighbor secondary address %s%s",
- sec_str, VTY_NEWLINE);
- }
-
- pim_tlv_size = pim_hello_build_tlv(ifp->name,
- pim_msg + PIM_PIM_MIN_LEN,
- sizeof(buf) - ip_hlen - PIM_PIM_MIN_LEN,
- neigh_holdtime,
- neigh_dr_priority,
- neigh_generation_id,
- neigh_propagation_delay,
- neigh_override_interval,
- neigh_can_disable_join_suppression,
- 0 /* FIXME secondary address list */);
- if (pim_tlv_size < 0) {
- vty_out(vty, "pim_hello_build_tlv() returned failure: %d%s",
- pim_tlv_size, VTY_NEWLINE);
+ result = inet_pton(AF_INET, src, &src_ip);
+ if (result <= 0) {
+ vty_out(vty, "%% Bad source address %s: errno=%d: %s%s",
+ src, errno, safe_strerror(errno), VTY_NEWLINE);
return CMD_WARNING;
}
- pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN;
+ result = pim_msdp_mg_src_add(mg, src_ip);
+ switch (result) {
+ case PIM_MSDP_ERR_NONE:
+ break;
+ case PIM_MSDP_ERR_OOM:
+ vty_out(vty, "%% Out of memory%s", VTY_NEWLINE);
+ break;
+ case PIM_MSDP_ERR_MAX_MESH_GROUPS:
+ vty_out(vty, "%% Only one mesh-group allowed currently%s", VTY_NEWLINE);
+ break;
+ default:
+ vty_out(vty, "%% source add failed%s", VTY_NEWLINE);
+ }
- pim_msg_build_header(pim_msg, pim_msg_size,
- PIM_MSG_TYPE_HELLO);
+ return result?CMD_WARNING:CMD_SUCCESS;
+}
- /* "receive" message */
- ip_msg_len = ip_hlen + pim_msg_size;
- result = pim_pim_packet(ifp, buf, ip_msg_len);
- if (result) {
- vty_out(vty, "pim_pim_packet(len=%d) returned failure: %d%s",
- ip_msg_len, result, VTY_NEWLINE);
- return CMD_WARNING;
+DEFUN (ip_msdp_mesh_group_source,
+ ip_msdp_mesh_group_source_cmd,
+ "ip msdp mesh-group WORD source A.B.C.D",
+ IP_STR
+ CFG_MSDP_STR
+ "Configure MSDP mesh-group\n"
+ "mesh group name\n"
+ "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, argv[5]->arg);
+}
+
+static int
+ip_no_msdp_mesh_group_source_cmd_worker(struct vty *vty, const char *mg)
+{
+ enum pim_msdp_err result;
+
+ result = pim_msdp_mg_src_del(mg);
+ switch (result) {
+ case PIM_MSDP_ERR_NONE:
+ break;
+ case PIM_MSDP_ERR_NO_MG:
+ vty_out(vty, "%% mesh-group does not exist%s", VTY_NEWLINE);
+ break;
+ default:
+ vty_out(vty, "%% mesh-group source del failed%s", VTY_NEWLINE);
}
- return CMD_SUCCESS;
+ return result?CMD_WARNING:CMD_SUCCESS;
}
-DEFUN (test_pim_receive_assert,
- test_pim_receive_assert_cmd,
- "test pim receive assert INTERFACE A.B.C.D A.B.C.D A.B.C.D (0-65535) (0-65535) (0-1)",
- "Test\n"
- "Test PIM protocol\n"
- "Test PIM message reception\n"
- "Test reception of PIM assert\n"
- "Interface\n"
- "Neighbor address\n"
- "Assert multicast group address\n"
- "Assert unicast source address\n"
- "Assert metric preference\n"
- "Assert route metric\n"
- "Assert RPT bit flag\n")
-{
- int idx_interface = 4;
- int idx_ipv4 = 5;
- int idx_ipv4_2 = 6;
- int idx_ipv4_3 = 7;
- int idx_number = 8;
- int idx_number_2 = 9;
- int idx_number_3 = 10;
- uint8_t buf[1000];
- uint8_t *buf_pastend = buf + sizeof(buf);
- uint8_t *pim_msg;
- struct ip *ip_hdr;
- size_t ip_hlen; /* ip header length in bytes */
- int ip_msg_len;
- int pim_msg_size;
- const char *neigh_str;
- struct in_addr neigh_addr;
- const char *group_str;
- struct in_addr group_addr;
- const char *source_str;
- struct in_addr source_addr;
- const char *ifname;
- struct interface *ifp;
- uint32_t assert_metric_preference;
- uint32_t assert_route_metric;
- uint32_t assert_rpt_bit_flag;
- int remain;
- int result;
-
- /* Find interface */
- ifname = argv[idx_interface]->arg;
- ifp = if_lookup_by_name(ifname);
- if (!ifp) {
- vty_out(vty, "No such interface name %s%s",
- ifname, VTY_NEWLINE);
- return CMD_WARNING;
+static int
+ip_no_msdp_mesh_group_cmd_worker(struct vty *vty, const char *mg)
+{
+ enum pim_msdp_err result;
+
+ result = pim_msdp_mg_del(mg);
+ switch (result) {
+ case PIM_MSDP_ERR_NONE:
+ break;
+ case PIM_MSDP_ERR_NO_MG:
+ vty_out(vty, "%% mesh-group does not exist%s", VTY_NEWLINE);
+ break;
+ default:
+ vty_out(vty, "%% mesh-group source del failed%s", VTY_NEWLINE);
}
- /* Neighbor address */
- neigh_str = argv[idx_ipv4]->arg;
- result = inet_pton(AF_INET, neigh_str, &neigh_addr);
- if (result <= 0) {
- vty_out(vty, "Bad neighbor address %s: errno=%d: %s%s",
- neigh_str, errno, safe_strerror(errno), VTY_NEWLINE);
- return CMD_WARNING;
- }
+ return result ? CMD_WARNING : CMD_SUCCESS;
+}
- /* Group address */
- group_str = argv[idx_ipv4_2]->arg;
- result = inet_pton(AF_INET, group_str, &group_addr);
- if (result <= 0) {
- vty_out(vty, "Bad group address %s: errno=%d: %s%s",
- group_str, errno, safe_strerror(errno), VTY_NEWLINE);
- return CMD_WARNING;
+DEFUN (no_ip_msdp_mesh_group_source,
+ no_ip_msdp_mesh_group_source_cmd,
+ "no ip msdp mesh-group WORD source [A.B.C.D]",
+ NO_STR
+ IP_STR
+ CFG_MSDP_STR
+ "Delete MSDP mesh-group source\n"
+ "mesh group name\n"
+ "mesh group source\n"
+ "mesh group local address\n")
+{
+ if (argv[6]->arg)
+ return ip_no_msdp_mesh_group_cmd_worker(vty, argv[6]->arg);
+ else
+ return ip_no_msdp_mesh_group_source_cmd_worker(vty, argv[4]->arg);
+}
+
+static void
+print_empty_json_obj(struct vty *vty)
+{
+ json_object *json;
+ json = json_object_new_object();
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
+}
+
+static void
+ip_msdp_show_mesh_group(struct vty *vty, u_char uj)
+{
+ struct listnode *mbrnode;
+ struct pim_msdp_mg_mbr *mbr;
+ struct pim_msdp_mg *mg = msdp->mg;
+ char mbr_str[INET_ADDRSTRLEN];
+ char src_str[INET_ADDRSTRLEN];
+ char state_str[PIM_MSDP_STATE_STRLEN];
+ enum pim_msdp_peer_state state;
+ json_object *json = NULL;
+ json_object *json_mg_row = NULL;
+ json_object *json_members = NULL;
+ json_object *json_row = NULL;
+
+ if (!mg) {
+ if (uj)
+ print_empty_json_obj(vty);
+ return;
}
- /* Source address */
- source_str = argv[idx_ipv4_3]->arg;
- result = inet_pton(AF_INET, source_str, &source_addr);
- if (result <= 0) {
- vty_out(vty, "Bad source address %s: errno=%d: %s%s",
- source_str, errno, safe_strerror(errno), VTY_NEWLINE);
- return CMD_WARNING;
+ pim_inet4_dump("<source?>", mg->src_ip, src_str, sizeof(src_str));
+ if (uj) {
+ json = json_object_new_object();
+ /* currently there is only one mesh group but we should still make
+ * it a dict with mg-name as key */
+ json_mg_row = json_object_new_object();
+ json_object_string_add(json_mg_row, "name", mg->mesh_group_name);
+ json_object_string_add(json_mg_row, "source", src_str);
+ } else {
+ vty_out(vty, "Mesh group : %s%s", mg->mesh_group_name, VTY_NEWLINE);
+ vty_out(vty, " Source : %s%s", src_str, VTY_NEWLINE);
+ vty_out(vty, " Member State%s", VTY_NEWLINE);
}
- assert_metric_preference = atoi(argv[idx_number]->arg);
- assert_route_metric = atoi(argv[idx_number_2]->arg);
- assert_rpt_bit_flag = atoi(argv[idx_number_3]->arg);
-
- remain = buf_pastend - buf;
- if (remain < (int) sizeof(struct ip)) {
- vty_out(vty, "No room for ip header: buf_size=%d < ip_header_size=%zu%s",
- remain, sizeof(struct ip), VTY_NEWLINE);
- return CMD_WARNING;
+ for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbrnode, mbr)) {
+ pim_inet4_dump("<mbr?>", mbr->mbr_ip, mbr_str, sizeof(mbr_str));
+ if (mbr->mp) {
+ state = mbr->mp->state;
+ } else {
+ state = PIM_MSDP_DISABLED;
+ }
+ pim_msdp_state_dump(state, state_str, sizeof(state_str));
+ if (uj) {
+ json_row = json_object_new_object();
+ json_object_string_add(json_row, "member", mbr_str);
+ json_object_string_add(json_row, "state", state_str);
+ if (!json_members) {
+ json_members = json_object_new_object();
+ json_object_object_add(json_mg_row, "members", json_members);
+ }
+ json_object_object_add(json_members, mbr_str, json_row);
+ } else {
+ vty_out(vty, " %-15s %11s%s",
+ mbr_str, state_str, VTY_NEWLINE);
+ }
}
- /*
- Tweak IP header
- */
- ip_hdr = (struct ip *) buf;
- ip_hdr->ip_p = PIM_IP_PROTO_PIM;
- ip_hlen = PIM_IP_HEADER_MIN_LEN; /* ip header length in bytes */
- ip_hdr->ip_hl = ip_hlen >> 2; /* ip header length in 4-byte words */
- ip_hdr->ip_src = neigh_addr;
- ip_hdr->ip_dst = qpim_all_pim_routers_addr;
-
- /*
- Build PIM assert message
- */
- pim_msg = buf + ip_hlen; /* skip ip header */
-
- pim_msg_size = pim_assert_build_msg(pim_msg, buf_pastend - pim_msg, ifp,
- group_addr, source_addr,
- assert_metric_preference,
- assert_route_metric,
- assert_rpt_bit_flag);
- if (pim_msg_size < 0) {
- vty_out(vty, "Failure building PIM assert message: size=%d%s",
- pim_msg_size, VTY_NEWLINE);
- return CMD_WARNING;
+ if (uj) {
+ json_object_object_add(json, mg->mesh_group_name, json_mg_row);
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
}
+}
- /* "receive" message */
-
- ip_msg_len = ip_hlen + pim_msg_size;
- result = pim_pim_packet(ifp, buf, ip_msg_len);
- if (result) {
- vty_out(vty, "pim_pim_packet(len=%d) returned failure: %d%s",
- ip_msg_len, result, VTY_NEWLINE);
- return CMD_WARNING;
- }
+DEFUN (show_ip_msdp_mesh_group,
+ show_ip_msdp_mesh_group_cmd,
+ "show ip msdp mesh-group [json]",
+ SHOW_STR
+ IP_STR
+ MSDP_STR
+ "MSDP mesh-group information\n"
+ "JavaScript Object Notation\n")
+{
+ u_char uj = use_json(argc, argv);
+ ip_msdp_show_mesh_group(vty, uj);
return CMD_SUCCESS;
}
-static int recv_joinprune(struct vty *vty,
- struct cmd_token **argv,
- int src_is_join)
-{
- uint8_t buf[1000];
- const uint8_t *buf_pastend = buf + sizeof(buf);
- uint8_t *pim_msg;
- uint8_t *pim_msg_curr;
- int pim_msg_size;
- struct ip *ip_hdr;
- size_t ip_hlen; /* ip header length in bytes */
- int ip_msg_len;
- uint16_t neigh_holdtime;
- const char *neigh_dst_str;
- struct in_addr neigh_dst_addr;
- const char *neigh_src_str;
- struct in_addr neigh_src_addr;
- const char *group_str;
- struct in_addr group_addr;
- const char *source_str;
- struct in_addr source_addr;
- const char *ifname;
- struct interface *ifp;
- int result;
- int remain;
- uint16_t num_joined;
- uint16_t num_pruned;
-
- /* Find interface */
- ifname = argv[0]->arg;
- ifp = if_lookup_by_name(ifname);
- if (!ifp) {
- vty_out(vty, "No such interface name %s%s",
- ifname, VTY_NEWLINE);
- return CMD_WARNING;
- }
+static void
+ip_msdp_show_peers(struct vty *vty, u_char uj)
+{
+ struct listnode *mpnode;
+ struct pim_msdp_peer *mp;
+ char peer_str[INET_ADDRSTRLEN];
+ char local_str[INET_ADDRSTRLEN];
+ char state_str[PIM_MSDP_STATE_STRLEN];
+ char timebuf[PIM_MSDP_UPTIME_STRLEN];
+ int64_t now;
+ json_object *json = NULL;
+ json_object *json_row = NULL;
- neigh_holdtime = atoi(argv[1]->arg);
- /* Neighbor destination address */
- neigh_dst_str = argv[2]->arg;
- result = inet_pton(AF_INET, neigh_dst_str, &neigh_dst_addr);
- if (result <= 0) {
- vty_out(vty, "Bad neighbor destination address %s: errno=%d: %s%s",
- neigh_dst_str, errno, safe_strerror(errno), VTY_NEWLINE);
- return CMD_WARNING;
+ if (uj) {
+ json = json_object_new_object();
+ } else {
+ vty_out(vty, "Peer Local State Uptime SaCnt%s", VTY_NEWLINE);
}
- /* Neighbor source address */
- neigh_src_str = argv[3]->arg;
- result = inet_pton(AF_INET, neigh_src_str, &neigh_src_addr);
- if (result <= 0) {
- vty_out(vty, "Bad neighbor source address %s: errno=%d: %s%s",
- neigh_src_str, errno, safe_strerror(errno), VTY_NEWLINE);
- return CMD_WARNING;
+ for (ALL_LIST_ELEMENTS_RO(msdp->peer_list, mpnode, mp)) {
+ if (mp->state == PIM_MSDP_ESTABLISHED) {
+ now = pim_time_monotonic_sec();
+ pim_time_uptime(timebuf, sizeof(timebuf), now - mp->uptime);
+ } else {
+ strcpy(timebuf, "-");
+ }
+ pim_inet4_dump("<peer?>", mp->peer, peer_str, sizeof(peer_str));
+ pim_inet4_dump("<local?>", mp->local, local_str, sizeof(local_str));
+ pim_msdp_state_dump(mp->state, state_str, sizeof(state_str));
+ if (uj) {
+ json_row = json_object_new_object();
+ json_object_string_add(json_row, "peer", peer_str);
+ json_object_string_add(json_row, "local", local_str);
+ json_object_string_add(json_row, "state", state_str);
+ json_object_string_add(json_row, "upTime", timebuf);
+ json_object_int_add(json_row, "saCount", mp->sa_cnt);
+ json_object_object_add(json, peer_str, json_row);
+ } else {
+ vty_out(vty, "%-15s %15s %11s %8s %6d%s",
+ peer_str, local_str, state_str,
+ timebuf, mp->sa_cnt, VTY_NEWLINE);
+ }
}
- /* Multicast group address */
- group_str = argv[4]->arg;
- result = inet_pton(AF_INET, group_str, &group_addr);
- if (result <= 0) {
- vty_out(vty, "Bad group address %s: errno=%d: %s%s",
- group_str, errno, safe_strerror(errno), VTY_NEWLINE);
- return CMD_WARNING;
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
}
+}
- /* Multicast source address */
- source_str = argv[5]->arg;
- result = inet_pton(AF_INET, source_str, &source_addr);
- if (result <= 0) {
- vty_out(vty, "Bad source address %s: errno=%d: %s%s",
- source_str, errno, safe_strerror(errno), VTY_NEWLINE);
- return CMD_WARNING;
+static void
+ip_msdp_show_peers_detail(struct vty *vty, const char *peer, u_char uj)
+{
+ struct listnode *mpnode;
+ struct pim_msdp_peer *mp;
+ char peer_str[INET_ADDRSTRLEN];
+ char local_str[INET_ADDRSTRLEN];
+ char state_str[PIM_MSDP_STATE_STRLEN];
+ char timebuf[PIM_MSDP_UPTIME_STRLEN];
+ char katimer[PIM_MSDP_TIMER_STRLEN];
+ char crtimer[PIM_MSDP_TIMER_STRLEN];
+ char holdtimer[PIM_MSDP_TIMER_STRLEN];
+ int64_t now;
+ json_object *json = NULL;
+ json_object *json_row = NULL;
+
+ if (uj) {
+ json = json_object_new_object();
}
- /*
- Tweak IP header
- */
- ip_hdr = (struct ip *) buf;
- ip_hdr->ip_p = PIM_IP_PROTO_PIM;
- ip_hlen = PIM_IP_HEADER_MIN_LEN; /* ip header length in bytes */
- ip_hdr->ip_hl = ip_hlen >> 2; /* ip header length in 4-byte words */
- ip_hdr->ip_src = neigh_src_addr;
- ip_hdr->ip_dst = qpim_all_pim_routers_addr;
+ for (ALL_LIST_ELEMENTS_RO(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;
- /*
- Build PIM message
- */
- pim_msg = buf + ip_hlen;
-
- /* skip room for pim header */
- pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN;
-
- remain = buf_pastend - pim_msg_curr;
- pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr,
- remain,
- neigh_dst_addr);
- if (!pim_msg_curr) {
- vty_out(vty, "Failure encoding destination address %s: space left=%d%s",
- neigh_dst_str, remain, VTY_NEWLINE);
- return CMD_WARNING;
+ if (mp->state == PIM_MSDP_ESTABLISHED) {
+ now = pim_time_monotonic_sec();
+ pim_time_uptime(timebuf, sizeof(timebuf), now - mp->uptime);
+ } else {
+ strcpy(timebuf, "-");
+ }
+ pim_inet4_dump("<local?>", mp->local, local_str, sizeof(local_str));
+ pim_msdp_state_dump(mp->state, state_str, sizeof(state_str));
+ pim_time_timer_to_hhmmss(katimer, sizeof(katimer), mp->ka_timer);
+ pim_time_timer_to_hhmmss(crtimer, sizeof(crtimer), mp->cr_timer);
+ pim_time_timer_to_hhmmss(holdtimer, sizeof(holdtimer), mp->hold_timer);
+
+ if (uj) {
+ json_row = json_object_new_object();
+ json_object_string_add(json_row, "peer", peer_str);
+ json_object_string_add(json_row, "local", local_str);
+ json_object_string_add(json_row, "meshGroupName", mp->mesh_group_name);
+ json_object_string_add(json_row, "state", state_str);
+ json_object_string_add(json_row, "upTime", timebuf);
+ json_object_string_add(json_row, "keepAliveTimer", katimer);
+ json_object_string_add(json_row, "connRetryTimer", crtimer);
+ json_object_string_add(json_row, "holdTimer", holdtimer);
+ json_object_string_add(json_row, "lastReset", mp->last_reset);
+ json_object_int_add(json_row, "connAttempts", mp->conn_attempts);
+ json_object_int_add(json_row, "establishedChanges", mp->est_flaps);
+ json_object_int_add(json_row, "saCount", mp->sa_cnt);
+ json_object_int_add(json_row, "kaSent", mp->ka_tx_cnt);
+ json_object_int_add(json_row, "kaRcvd", mp->ka_rx_cnt);
+ json_object_int_add(json_row, "saSent", mp->sa_tx_cnt);
+ json_object_int_add(json_row, "saRcvd", mp->sa_rx_cnt);
+ json_object_object_add(json, peer_str, json_row);
+ } else {
+ vty_out(vty, "Peer : %s%s", peer_str, VTY_NEWLINE);
+ vty_out(vty, " Local : %s%s", local_str, VTY_NEWLINE);
+ vty_out(vty, " Mesh Group : %s%s", mp->mesh_group_name, VTY_NEWLINE);
+ vty_out(vty, " State : %s%s", state_str, VTY_NEWLINE);
+ vty_out(vty, " Uptime : %s%s", timebuf, VTY_NEWLINE);
+
+ vty_out(vty, " Keepalive Timer : %s%s", katimer, VTY_NEWLINE);
+ vty_out(vty, " Conn Retry Timer : %s%s", crtimer, VTY_NEWLINE);
+ vty_out(vty, " Hold Timer : %s%s", holdtimer, VTY_NEWLINE);
+ vty_out(vty, " Last Reset : %s%s", mp->last_reset, VTY_NEWLINE);
+ vty_out(vty, " Conn Attempts : %d%s", mp->conn_attempts, VTY_NEWLINE);
+ vty_out(vty, " Established Changes : %d%s", mp->est_flaps, VTY_NEWLINE);
+ vty_out(vty, " SA Count : %d%s", mp->sa_cnt, VTY_NEWLINE);
+ vty_out(vty, " Statistics :%s", VTY_NEWLINE);
+ vty_out(vty, " Sent Rcvd%s", VTY_NEWLINE);
+ vty_out(vty, " Keepalives : %10d %10d%s",
+ mp->ka_tx_cnt, mp->ka_rx_cnt, VTY_NEWLINE);
+ vty_out(vty, " SAs : %10d %10d%s",
+ mp->sa_tx_cnt, mp->sa_rx_cnt, VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
}
- remain = buf_pastend - pim_msg_curr;
- if (remain < 4) {
- vty_out(vty, "Group will not fit: space left=%d%s",
- remain, VTY_NEWLINE);
- return CMD_WARNING;
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
}
+}
- *pim_msg_curr = 0; /* reserved */
- ++pim_msg_curr;
- *pim_msg_curr = 1; /* number of groups */
- ++pim_msg_curr;
- *((uint16_t *) pim_msg_curr) = htons(neigh_holdtime);
- ++pim_msg_curr;
- ++pim_msg_curr;
-
- remain = buf_pastend - pim_msg_curr;
- pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr,
- remain,
- group_addr);
- if (!pim_msg_curr) {
- vty_out(vty, "Failure encoding group address %s: space left=%d%s",
- group_str, remain, VTY_NEWLINE);
- return CMD_WARNING;
+DEFUN (show_ip_msdp_peer_detail,
+ show_ip_msdp_peer_detail_cmd,
+ "show ip msdp peer [detail|A.B.C.D] [json]",
+ SHOW_STR
+ IP_STR
+ MSDP_STR
+ "MSDP peer information\n"
+ "Detailed output\n"
+ "peer ip address\n"
+ "JavaScript Object Notation\n")
+{
+ u_char uj = use_json(argc, argv);
+ if (argv[4]->arg)
+ ip_msdp_show_peers_detail(vty, argv[4]->arg, uj);
+ else
+ ip_msdp_show_peers(vty, uj);
+
+ return CMD_SUCCESS;
+}
+
+static void
+ip_msdp_show_sa(struct vty *vty, u_char uj)
+{
+ struct listnode *sanode;
+ struct pim_msdp_sa *sa;
+ char src_str[INET_ADDRSTRLEN];
+ char grp_str[INET_ADDRSTRLEN];
+ char rp_str[INET_ADDRSTRLEN];
+ char timebuf[PIM_MSDP_UPTIME_STRLEN];
+ char spt_str[8];
+ char local_str[8];
+ int64_t now;
+ 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, "Source Group RP Local SPT Uptime%s", VTY_NEWLINE);
}
- remain = buf_pastend - pim_msg_curr;
- if (remain < 4) {
- vty_out(vty, "Sources will not fit: space left=%d%s",
- remain, VTY_NEWLINE);
- return CMD_WARNING;
+ for (ALL_LIST_ELEMENTS_RO(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));
+ pim_inet4_dump("<grp?>", sa->sg.grp, grp_str, sizeof(grp_str));
+ if (sa->flags & PIM_MSDP_SAF_PEER) {
+ pim_inet4_dump("<rp?>", sa->rp, rp_str, sizeof(rp_str));
+ if (sa->up) {
+ strcpy(spt_str, "yes");
+ } else {
+ strcpy(spt_str, "no");
+ }
+ } else {
+ strcpy(rp_str, "-");
+ strcpy(spt_str, "-");
+ }
+ if (sa->flags & PIM_MSDP_SAF_LOCAL) {
+ strcpy(local_str, "yes");
+ } else {
+ strcpy(local_str, "no");
+ }
+ if (uj) {
+ json_object_object_get_ex(json, grp_str, &json_group);
+
+ if (!json_group) {
+ json_group = json_object_new_object();
+ json_object_object_add(json, grp_str, json_group);
+ }
+
+ json_row = json_object_new_object();
+ json_object_string_add(json_row, "source", src_str);
+ json_object_string_add(json_row, "group", grp_str);
+ json_object_string_add(json_row, "rp", rp_str);
+ json_object_string_add(json_row, "local", local_str);
+ json_object_string_add(json_row, "sptSetup", spt_str);
+ json_object_string_add(json_row, "upTime", timebuf);
+ json_object_object_add(json_group, src_str, json_row);
+ } else {
+ vty_out(vty, "%-15s %15s %15s %5c %3c %8s%s",
+ src_str, grp_str, rp_str, local_str[0], spt_str[0], timebuf, VTY_NEWLINE);
+ }
}
- if (src_is_join) {
- num_joined = 1;
- num_pruned = 0;
+
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
}
- else {
- num_joined = 0;
- num_pruned = 1;
- }
-
- /* number of joined sources */
- *((uint16_t *) pim_msg_curr) = htons(num_joined);
- ++pim_msg_curr;
- ++pim_msg_curr;
-
- /* number of pruned sources */
- *((uint16_t *) pim_msg_curr) = htons(num_pruned);
- ++pim_msg_curr;
- ++pim_msg_curr;
-
- remain = buf_pastend - pim_msg_curr;
- pim_msg_curr = pim_msg_addr_encode_ipv4_source(pim_msg_curr,
- remain,
- source_addr);
- if (!pim_msg_curr) {
- vty_out(vty, "Failure encoding source address %s: space left=%d%s",
- source_str, remain, VTY_NEWLINE);
- return CMD_WARNING;
+}
+
+static void
+ip_msdp_show_sa_entry_detail(struct pim_msdp_sa *sa, const char *src_str,
+ const char *grp_str, struct vty *vty,
+ u_char uj, json_object *json)
+{
+ char rp_str[INET_ADDRSTRLEN];
+ char peer_str[INET_ADDRSTRLEN];
+ char timebuf[PIM_MSDP_UPTIME_STRLEN];
+ char spt_str[8];
+ char local_str[8];
+ char statetimer[PIM_MSDP_TIMER_STRLEN];
+ int64_t now;
+ json_object *json_group = NULL;
+ json_object *json_row = NULL;
+
+ now = pim_time_monotonic_sec();
+ pim_time_uptime(timebuf, sizeof(timebuf), now - sa->uptime);
+ if (sa->flags & PIM_MSDP_SAF_PEER) {
+ pim_inet4_dump("<rp?>", sa->rp, rp_str, sizeof(rp_str));
+ pim_inet4_dump("<peer?>", sa->peer, peer_str, sizeof(peer_str));
+ if (sa->up) {
+ strcpy(spt_str, "yes");
+ } else {
+ strcpy(spt_str, "no");
+ }
+ } else {
+ strcpy(rp_str, "-");
+ strcpy(peer_str, "-");
+ strcpy(spt_str, "-");
+ }
+ if (sa->flags & PIM_MSDP_SAF_LOCAL) {
+ strcpy(local_str, "yes");
+ } else {
+ strcpy(local_str, "no");
}
+ pim_time_timer_to_hhmmss(statetimer, sizeof(statetimer), sa->sa_state_timer);
+ if (uj) {
+ json_object_object_get_ex(json, grp_str, &json_group);
- /* Add PIM header */
+ if (!json_group) {
+ json_group = json_object_new_object();
+ json_object_object_add(json, grp_str, json_group);
+ }
- pim_msg_size = pim_msg_curr - pim_msg;
+ json_row = json_object_new_object();
+ json_object_string_add(json_row, "source", src_str);
+ json_object_string_add(json_row, "group", grp_str);
+ json_object_string_add(json_row, "rp", rp_str);
+ json_object_string_add(json_row, "local", local_str);
+ json_object_string_add(json_row, "sptSetup", spt_str);
+ json_object_string_add(json_row, "upTime", timebuf);
+ json_object_string_add(json_row, "stateTimer", statetimer);
+ json_object_object_add(json_group, src_str, json_row);
+ } else {
+ vty_out(vty, "SA : %s%s", sa->sg_str, VTY_NEWLINE);
+ vty_out(vty, " RP : %s%s", rp_str, VTY_NEWLINE);
+ vty_out(vty, " Peer : %s%s", peer_str, VTY_NEWLINE);
+ vty_out(vty, " Local : %s%s", local_str, VTY_NEWLINE);
+ vty_out(vty, " SPT Setup : %s%s", spt_str, VTY_NEWLINE);
+ vty_out(vty, " Uptime : %s%s", timebuf, VTY_NEWLINE);
+ vty_out(vty, " State Timer : %s%s", statetimer, VTY_NEWLINE);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
+}
- pim_msg_build_header(pim_msg, pim_msg_size,
- PIM_MSG_TYPE_JOIN_PRUNE);
+static void
+ip_msdp_show_sa_detail(struct vty *vty, u_char uj)
+{
+ struct listnode *sanode;
+ struct pim_msdp_sa *sa;
+ char src_str[INET_ADDRSTRLEN];
+ char grp_str[INET_ADDRSTRLEN];
+ json_object *json = NULL;
- /*
- "Receive" message
- */
+ if (uj) {
+ json = json_object_new_object();
+ }
- ip_msg_len = ip_hlen + pim_msg_size;
- result = pim_pim_packet(ifp, buf, ip_msg_len);
- if (result) {
- vty_out(vty, "pim_pim_packet(len=%d) returned failure: %d%s",
- ip_msg_len, result, VTY_NEWLINE);
- return CMD_WARNING;
+ for (ALL_LIST_ELEMENTS_RO(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, json);
}
- return CMD_SUCCESS;
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
+ }
}
-DEFUN (test_pim_receive_join,
- test_pim_receive_join_cmd,
- "test pim receive join INTERFACE (0-65535) A.B.C.D A.B.C.D A.B.C.D A.B.C.D",
- "Test\n"
- "Test PIM protocol\n"
- "Test PIM message reception\n"
- "Test PIM join reception from neighbor\n"
- "Interface\n"
- "Neighbor holdtime\n"
- "Upstream neighbor unicast destination address\n"
- "Downstream neighbor unicast source address\n"
- "Multicast group address\n"
- "Unicast source address\n")
-{
- return recv_joinprune(vty, argv, 1 /* src_is_join=true */);
-}
-
-DEFUN (test_pim_receive_prune,
- test_pim_receive_prune_cmd,
- "test pim receive prune INTERFACE (0-65535) A.B.C.D A.B.C.D A.B.C.D A.B.C.D",
- "Test\n"
- "Test PIM protocol\n"
- "Test PIM message reception\n"
- "Test PIM prune reception from neighbor\n"
- "Interface\n"
- "Neighbor holdtime\n"
- "Upstream neighbor unicast destination address\n"
- "Downstream neighbor unicast source address\n"
- "Multicast group address\n"
- "Unicast source address\n")
-{
- return recv_joinprune(vty, argv, 0 /* src_is_join=false */);
-}
-
-DEFUN (test_pim_receive_upcall,
- test_pim_receive_upcall_cmd,
- "test pim receive upcall <nocache|wrongvif|wholepkt> (0-65535) A.B.C.D A.B.C.D",
- "Test\n"
- "Test PIM protocol\n"
- "Test PIM message reception\n"
- "Test reception of kernel upcall\n"
- "NOCACHE kernel upcall\n"
- "WRONGVIF kernel upcall\n"
- "WHOLEPKT kernel upcall\n"
- "Input interface vif index\n"
- "Multicast group address\n"
- "Multicast source address\n")
-{
- int idx_type = 4;
- int idx_number = 5;
- int idx_ipv4 = 6;
- int idx_ipv4_2 = 7;
- struct igmpmsg msg;
- const char *upcall_type;
- const char *group_str;
- const char *source_str;
- int result;
+DEFUN (show_ip_msdp_sa_detail,
+ show_ip_msdp_sa_detail_cmd,
+ "show ip msdp sa detail [json]",
+ SHOW_STR
+ IP_STR
+ MSDP_STR
+ "MSDP active-source information\n"
+ "Detailed output\n"
+ "JavaScript Object Notation\n")
+{
+ u_char uj = use_json(argc, argv);
+ ip_msdp_show_sa_detail(vty, uj);
+
+ return CMD_SUCCESS;
+}
- upcall_type = argv[idx_type]->arg;
+static void
+ip_msdp_show_sa_addr(struct vty *vty, const char *addr, u_char uj)
+{
+ struct listnode *sanode;
+ struct pim_msdp_sa *sa;
+ char src_str[INET_ADDRSTRLEN];
+ char grp_str[INET_ADDRSTRLEN];
+ json_object *json = NULL;
- if (upcall_type[0] == 'n')
- msg.im_msgtype = IGMPMSG_NOCACHE;
- else if (upcall_type[1] == 'r')
- msg.im_msgtype = IGMPMSG_WRONGVIF;
- else if (upcall_type[1] == 'h')
- msg.im_msgtype = IGMPMSG_WHOLEPKT;
- else {
- vty_out(vty, "Unknown kernel upcall type: %s%s",
- upcall_type, VTY_NEWLINE);
- return CMD_WARNING;
+ if (uj) {
+ json = json_object_new_object();
}
- msg.im_vif = atoi(argv[idx_number]->arg);
+ for (ALL_LIST_ELEMENTS_RO(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)) {
+ ip_msdp_show_sa_entry_detail(sa, src_str, grp_str, vty, uj, json);
+ }
+ }
- /* Group address */
- group_str = argv[idx_ipv4]->arg;
- result = inet_pton(AF_INET, group_str, &msg.im_dst);
- if (result <= 0) {
- vty_out(vty, "Bad group address %s: errno=%d: %s%s",
- group_str, errno, safe_strerror(errno), VTY_NEWLINE);
- return CMD_WARNING;
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
}
+}
- /* Source address */
- source_str = argv[idx_ipv4_2]->arg;
- result = inet_pton(AF_INET, source_str, &msg.im_src);
- if (result <= 0) {
- vty_out(vty, "Bad source address %s: errno=%d: %s%s",
- source_str, errno, safe_strerror(errno), VTY_NEWLINE);
- return CMD_WARNING;
+static void
+ip_msdp_show_sa_sg(struct vty *vty, const char *src, const char *grp, u_char uj)
+{
+ struct listnode *sanode;
+ struct pim_msdp_sa *sa;
+ char src_str[INET_ADDRSTRLEN];
+ char grp_str[INET_ADDRSTRLEN];
+ json_object *json = NULL;
+
+ if (uj) {
+ json = json_object_new_object();
}
- msg.im_mbz = 0; /* Must be zero */
+ for (ALL_LIST_ELEMENTS_RO(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)) {
+ ip_msdp_show_sa_entry_detail(sa, src_str, grp_str, vty, uj, json);
+ }
+ }
- result = pim_mroute_msg(-1, (char *) &msg, sizeof(msg));
- if (result) {
- vty_out(vty, "pim_mroute_msg(len=%zu) returned failure: %d%s",
- sizeof(msg), result, VTY_NEWLINE);
- return CMD_WARNING;
+ if (uj) {
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
}
+}
+
+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_STR
+ IP_STR
+ MSDP_STR
+ "MSDP active-source information\n"
+ "source or group ip\n"
+ "group ip\n"
+ "JavaScript Object Notation\n")
+{
+ u_char uj = use_json(argc, argv);
+ if (argv[5]->arg)
+ ip_msdp_show_sa_sg(vty, argv[4]->arg, argv[5]->arg, uj);
+ else if (argv[4]->arg)
+ ip_msdp_show_sa_addr(vty, argv[4]->arg, uj);
+ else
+ ip_msdp_show_sa(vty, uj);
return CMD_SUCCESS;
}
@@ -4759,17 +5964,33 @@ void pim_cmd_init()
install_node (&interface_node, pim_interface_config_write); /* INTERFACE_NODE */
if_cmd_init ();
+ install_node (&debug_node, pim_debug_config_write);
+
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 (CONFIG_NODE, &no_ip_pim_rp_cmd);
+ install_element (CONFIG_NODE, &ip_pim_rp_prefix_list_cmd);
+ install_element (CONFIG_NODE, &no_ip_pim_rp_prefix_list_cmd);
+ install_element (CONFIG_NODE, &ip_pim_register_suppress_cmd);
+ install_element (CONFIG_NODE, &no_ip_pim_register_suppress_cmd);
+ install_element (CONFIG_NODE, &ip_pim_joinprune_time_cmd);
+ install_element (CONFIG_NODE, &no_ip_pim_joinprune_time_cmd);
+ install_element (CONFIG_NODE, &ip_pim_keep_alive_cmd);
+ install_element (CONFIG_NODE, &no_ip_pim_keep_alive_cmd);
+ install_element (CONFIG_NODE, &ip_pim_packets_cmd);
+ install_element (CONFIG_NODE, &no_ip_pim_packets_cmd);
install_element (CONFIG_NODE, &ip_ssmpingd_cmd);
install_element (CONFIG_NODE, &no_ip_ssmpingd_cmd);
+ install_element (CONFIG_NODE, &ip_msdp_peer_cmd);
+ install_element (CONFIG_NODE, &no_ip_msdp_peer_cmd);
install_element (INTERFACE_NODE, &interface_ip_igmp_cmd);
install_element (INTERFACE_NODE, &interface_no_ip_igmp_cmd);
install_element (INTERFACE_NODE, &interface_ip_igmp_join_cmd);
install_element (INTERFACE_NODE, &interface_no_ip_igmp_join_cmd);
+ install_element (INTERFACE_NODE, &interface_ip_igmp_version_cmd);
+ install_element (INTERFACE_NODE, &interface_no_ip_igmp_version_cmd);
install_element (INTERFACE_NODE, &interface_ip_igmp_query_interval_cmd);
install_element (INTERFACE_NODE, &interface_no_ip_igmp_query_interval_cmd);
install_element (INTERFACE_NODE, &interface_ip_igmp_query_max_response_time_cmd);
@@ -4793,29 +6014,25 @@ void pim_cmd_init()
install_element (VIEW_NODE, &show_ip_igmp_interface_cmd);
install_element (VIEW_NODE, &show_ip_igmp_join_cmd);
- install_element (VIEW_NODE, &show_ip_igmp_parameters_cmd);
install_element (VIEW_NODE, &show_ip_igmp_groups_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_igmp_querier_cmd);
install_element (VIEW_NODE, &show_ip_pim_assert_cmd);
install_element (VIEW_NODE, &show_ip_pim_assert_internal_cmd);
install_element (VIEW_NODE, &show_ip_pim_assert_metric_cmd);
install_element (VIEW_NODE, &show_ip_pim_assert_winner_metric_cmd);
- install_element (VIEW_NODE, &show_ip_pim_dr_cmd);
- install_element (VIEW_NODE, &show_ip_pim_hello_cmd);
install_element (VIEW_NODE, &show_ip_pim_interface_cmd);
install_element (VIEW_NODE, &show_ip_pim_join_cmd);
- install_element (VIEW_NODE, &show_ip_pim_jp_override_interval_cmd);
- install_element (VIEW_NODE, &show_ip_pim_lan_prune_delay_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_rpf_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_upstream_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_multicast_cmd);
install_element (VIEW_NODE, &show_ip_mroute_cmd);
install_element (VIEW_NODE, &show_ip_mroute_count_cmd);
@@ -4823,22 +6040,12 @@ void pim_cmd_init()
install_element (VIEW_NODE, &show_ip_ssmpingd_cmd);
install_element (VIEW_NODE, &show_debugging_pim_cmd);
- install_element (ENABLE_NODE, &show_ip_pim_address_cmd);
-
install_element (ENABLE_NODE, &clear_ip_interfaces_cmd);
install_element (ENABLE_NODE, &clear_ip_igmp_interfaces_cmd);
install_element (ENABLE_NODE, &clear_ip_mroute_cmd);
install_element (ENABLE_NODE, &clear_ip_pim_interfaces_cmd);
install_element (ENABLE_NODE, &clear_ip_pim_oil_cmd);
- install_element (ENABLE_NODE, &test_igmp_receive_report_cmd);
- install_element (ENABLE_NODE, &test_pim_receive_assert_cmd);
- install_element (ENABLE_NODE, &test_pim_receive_dump_cmd);
- install_element (ENABLE_NODE, &test_pim_receive_hello_cmd);
- install_element (ENABLE_NODE, &test_pim_receive_join_cmd);
- install_element (ENABLE_NODE, &test_pim_receive_prune_cmd);
- install_element (ENABLE_NODE, &test_pim_receive_upcall_cmd);
-
install_element (ENABLE_NODE, &debug_igmp_cmd);
install_element (ENABLE_NODE, &no_debug_igmp_cmd);
install_element (ENABLE_NODE, &debug_igmp_events_cmd);
@@ -4848,7 +6055,9 @@ void pim_cmd_init()
install_element (ENABLE_NODE, &debug_igmp_trace_cmd);
install_element (ENABLE_NODE, &no_debug_igmp_trace_cmd);
install_element (ENABLE_NODE, &debug_mroute_cmd);
+ install_element (ENABLE_NODE, &debug_mroute_detail_cmd);
install_element (ENABLE_NODE, &no_debug_mroute_cmd);
+ install_element (ENABLE_NODE, &no_debug_mroute_detail_cmd);
install_element (ENABLE_NODE, &debug_static_cmd);
install_element (ENABLE_NODE, &no_debug_static_cmd);
install_element (ENABLE_NODE, &debug_pim_cmd);
@@ -4856,9 +6065,7 @@ void pim_cmd_init()
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, &debug_pim_packets_filter_cmd);
install_element (ENABLE_NODE, &no_debug_pim_packets_cmd);
- install_element (ENABLE_NODE, &no_debug_pim_packets_filter_cmd);
install_element (ENABLE_NODE, &debug_pim_packetdump_send_cmd);
install_element (ENABLE_NODE, &no_debug_pim_packetdump_send_cmd);
install_element (ENABLE_NODE, &debug_pim_packetdump_recv_cmd);
@@ -4869,6 +6076,15 @@ void pim_cmd_init()
install_element (ENABLE_NODE, &no_debug_ssmpingd_cmd);
install_element (ENABLE_NODE, &debug_pim_zebra_cmd);
install_element (ENABLE_NODE, &no_debug_pim_zebra_cmd);
+ install_element (ENABLE_NODE, &debug_msdp_cmd);
+ install_element (ENABLE_NODE, &no_debug_msdp_cmd);
+ install_element (ENABLE_NODE, &undebug_msdp_cmd);
+ install_element (ENABLE_NODE, &debug_msdp_events_cmd);
+ install_element (ENABLE_NODE, &no_debug_msdp_events_cmd);
+ install_element (ENABLE_NODE, &undebug_msdp_events_cmd);
+ install_element (ENABLE_NODE, &debug_msdp_packets_cmd);
+ install_element (ENABLE_NODE, &no_debug_msdp_packets_cmd);
+ install_element (ENABLE_NODE, &undebug_msdp_packets_cmd);
install_element (CONFIG_NODE, &debug_igmp_cmd);
install_element (CONFIG_NODE, &no_debug_igmp_cmd);
@@ -4879,7 +6095,9 @@ void pim_cmd_init()
install_element (CONFIG_NODE, &debug_igmp_trace_cmd);
install_element (CONFIG_NODE, &no_debug_igmp_trace_cmd);
install_element (CONFIG_NODE, &debug_mroute_cmd);
+ install_element (CONFIG_NODE, &debug_mroute_detail_cmd);
install_element (CONFIG_NODE, &no_debug_mroute_cmd);
+ install_element (CONFIG_NODE, &no_debug_mroute_detail_cmd);
install_element (CONFIG_NODE, &debug_static_cmd);
install_element (CONFIG_NODE, &no_debug_static_cmd);
install_element (CONFIG_NODE, &debug_pim_cmd);
@@ -4887,13 +6105,30 @@ void pim_cmd_init()
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, &debug_pim_packets_filter_cmd);
install_element (CONFIG_NODE, &no_debug_pim_packets_cmd);
- install_element (CONFIG_NODE, &no_debug_pim_packets_filter_cmd);
install_element (CONFIG_NODE, &debug_pim_trace_cmd);
install_element (CONFIG_NODE, &no_debug_pim_trace_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, &no_debug_pim_zebra_cmd);
+ install_element (CONFIG_NODE, &debug_msdp_cmd);
+ install_element (CONFIG_NODE, &no_debug_msdp_cmd);
+ install_element (CONFIG_NODE, &undebug_msdp_cmd);
+ install_element (CONFIG_NODE, &debug_msdp_events_cmd);
+ install_element (CONFIG_NODE, &no_debug_msdp_events_cmd);
+ install_element (CONFIG_NODE, &undebug_msdp_events_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 (CONFIG_NODE, &no_ip_msdp_mesh_group_member_cmd);
+ install_element (CONFIG_NODE, &ip_msdp_mesh_group_source_cmd);
+ install_element (CONFIG_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_sa_detail_cmd);
+ install_element (VIEW_NODE, &show_ip_msdp_sa_sg_cmd);
+ install_element (VIEW_NODE, &show_ip_msdp_mesh_group_cmd);
+ install_element (INTERFACE_NODE, &interface_pim_use_source_cmd);
+ install_element (INTERFACE_NODE, &interface_no_pim_use_source_cmd);
}
diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h
index 34f350e36b..e08cefb29b 100644
--- a/pimd/pim_cmd.h
+++ b/pimd/pim_cmd.h
@@ -47,6 +47,7 @@
#define DEBUG_PIM_PACKETS_STR "PIM protocol packets\n"
#define DEBUG_PIM_HELLO_PACKETS_STR "PIM Hello protocol packets\n"
#define DEBUG_PIM_J_P_PACKETS_STR "PIM Join/Prune protocol packets\n"
+#define DEBUG_PIM_PIM_REG_PACKETS_STR "PIM Register/Reg-Stop protocol packets\n"
#define DEBUG_PIM_PACKETDUMP_STR "PIM packet dump\n"
#define DEBUG_PIM_PACKETDUMP_SEND_STR "Dump sent packets\n"
#define DEBUG_PIM_PACKETDUMP_RECV_STR "Dump received packets\n"
@@ -57,6 +58,12 @@
#define CLEAR_IP_PIM_STR "PIM clear commands\n"
#define MROUTE_STR "IP multicast routing table\n"
#define RIB_STR "IP unicast routing table\n"
+#define CFG_MSDP_STR "Configure multicast source discovery protocol\n"
+#define MSDP_STR "MSDP information\n"
+#define DEBUG_MSDP_STR "MSDP protocol activity\n"
+#define DEBUG_MSDP_EVENTS_STR "MSDP protocol events\n"
+#define DEBUG_MSDP_INTERNAL_STR "MSDP protocol internal\n"
+#define DEBUG_MSDP_PACKETS_STR "MSDP protocol packets\n"
void pim_cmd_init(void);
diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c
index 1cd44f2539..3d7ae4ad22 100644
--- a/pimd/pim_hello.c
+++ b/pimd/pim_hello.c
@@ -37,7 +37,7 @@ static void on_trace(const char *label,
struct interface *ifp, struct in_addr src)
{
if (PIM_DEBUG_PIM_TRACE) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
zlog_debug("%s: from %s on %s",
label, src_str, ifp->name);
@@ -49,7 +49,7 @@ static void tlv_trace_bool(const char *label, const char *tlv_name,
int isset, int value)
{
if (isset) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: PIM hello option from %s on interface %s: %s=%d",
label,
@@ -63,7 +63,7 @@ static void tlv_trace_uint16(const char *label, const char *tlv_name,
int isset, uint16_t value)
{
if (isset) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u",
label,
@@ -77,7 +77,7 @@ static void tlv_trace_uint32(const char *label, const char *tlv_name,
int isset, uint32_t value)
{
if (isset) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u",
label,
@@ -91,7 +91,7 @@ static void tlv_trace_uint32_hex(const char *label, const char *tlv_name,
int isset, uint32_t value)
{
if (isset) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: PIM hello option from %s on interface %s: %s=%08x",
label,
@@ -106,7 +106,7 @@ static void tlv_trace(const char *label, const char *tlv_name,
int isset)
{
if (isset) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: PIM hello option from %s on interface %s: %s",
label,
@@ -121,7 +121,7 @@ static void tlv_trace_list(const char *label, const char *tlv_name,
int isset, struct list *addr_list)
{
if (isset) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: PIM hello option from %s on interface %s: %s size=%d list=%p",
label,
@@ -181,7 +181,7 @@ int pim_hello_recv(struct interface *ifp,
if (remain < PIM_TLV_MIN_SIZE) {
if (PIM_DEBUG_PIM_HELLO) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: short PIM hello TLV size=%d < min=%d from %s on interface %s",
__PRETTY_FUNCTION__,
@@ -198,7 +198,7 @@ int pim_hello_recv(struct interface *ifp,
if ((tlv_curr + option_len) > tlv_pastend) {
if (PIM_DEBUG_PIM_HELLO) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: long PIM hello TLV type=%d length=%d > left=%td from %s on interface %s",
__PRETTY_FUNCTION__,
@@ -209,7 +209,7 @@ int pim_hello_recv(struct interface *ifp,
}
if (PIM_DEBUG_PIM_HELLO) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: parse left_size=%d: PIM hello TLV type=%d length=%d from %s on %s",
__PRETTY_FUNCTION__,
@@ -267,7 +267,7 @@ int pim_hello_recv(struct interface *ifp,
break;
case PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH:
if (PIM_DEBUG_PIM_HELLO) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: ignoring PIM hello dense-mode state refresh TLV option type=%d length=%d from %s on interface %s",
__PRETTY_FUNCTION__,
@@ -277,7 +277,7 @@ int pim_hello_recv(struct interface *ifp,
break;
default:
if (PIM_DEBUG_PIM_HELLO) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: ignoring unknown PIM hello TLV type=%d length=%d from %s on interface %s",
__PRETTY_FUNCTION__,
@@ -326,7 +326,7 @@ int pim_hello_recv(struct interface *ifp,
if (!PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) {
if (PIM_DEBUG_PIM_HELLO) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: PIM hello missing holdtime from %s on interface %s",
__PRETTY_FUNCTION__,
@@ -349,10 +349,11 @@ int pim_hello_recv(struct interface *ifp,
hello_option_override_interval,
hello_option_dr_priority,
hello_option_generation_id,
- hello_option_addr_list);
+ hello_option_addr_list,
+ PIM_NEIGHBOR_SEND_DELAY);
if (!neigh) {
if (PIM_DEBUG_PIM_HELLO) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: failure creating PIM neighbor %s on interface %s",
__PRETTY_FUNCTION__,
@@ -373,15 +374,10 @@ int pim_hello_recv(struct interface *ifp,
/* GenID mismatch ? */
if (!PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_GENERATION_ID) ||
(hello_option_generation_id != neigh->generation_id)) {
-
- /* GenID changed */
-
- pim_upstream_rpf_genid_changed(neigh->source_addr);
-
/* GenID mismatch, then replace neighbor */
if (PIM_DEBUG_PIM_HELLO) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: GenId mismatch new=%08x old=%08x: replacing neighbor %s on %s",
__PRETTY_FUNCTION__,
@@ -400,10 +396,11 @@ int pim_hello_recv(struct interface *ifp,
hello_option_override_interval,
hello_option_dr_priority,
hello_option_generation_id,
- hello_option_addr_list);
+ hello_option_addr_list,
+ PIM_NEIGHBOR_SEND_NOW);
if (!neigh) {
if (PIM_DEBUG_PIM_HELLO) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: failure re-creating PIM neighbor %s on interface %s",
__PRETTY_FUNCTION__,
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index bac9692caa..cc4f4f3dce 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -25,6 +25,8 @@
#include "memory.h"
#include "prefix.h"
#include "vrf.h"
+#include "linklist.h"
+#include "plist.h"
#include "pimd.h"
#include "pim_iface.h"
@@ -38,14 +40,26 @@
#include "pim_sock.h"
#include "pim_time.h"
#include "pim_ssmpingd.h"
+#include "pim_rp.h"
struct interface *pim_regiface = NULL;
+struct list *pim_ifchannel_list = NULL;
static void pim_if_igmp_join_del_all(struct interface *ifp);
-void pim_if_init()
+void
+pim_if_init (void)
{
vrf_iflist_create(VRF_DEFAULT);
+ pim_ifchannel_list = list_new();
+ pim_ifchannel_list->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
+}
+
+void
+pim_if_terminate (void)
+{
+ if (pim_ifchannel_list)
+ list_free (pim_ifchannel_list);
}
static void *if_list_clean(struct pim_interface *pim_ifp)
@@ -78,15 +92,16 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
zassert(ifp);
zassert(!ifp->info);
- pim_ifp = XMALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
+ pim_ifp = XCALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
if (!pim_ifp) {
- zlog_err("PIM XMALLOC(%zu) failure", sizeof(*pim_ifp));
+ zlog_err("PIM XCALLOC(%zu) failure", sizeof(*pim_ifp));
return 0;
}
pim_ifp->options = 0;
pim_ifp->mroute_vif_index = -1;
+ pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
pim_ifp->igmp_default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
pim_ifp->igmp_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL;
pim_ifp->igmp_query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC;
@@ -104,15 +119,12 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
if (igmp)
PIM_IF_DO_IGMP(pim_ifp->options);
-#if 0
- /* FIXME: Should join? */
PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options);
-#endif
- pim_ifp->igmp_join_list = 0;
- pim_ifp->igmp_socket_list = 0;
- pim_ifp->pim_neighbor_list = 0;
- pim_ifp->pim_ifchannel_list = 0;
+ pim_ifp->igmp_join_list = NULL;
+ pim_ifp->igmp_socket_list = NULL;
+ pim_ifp->pim_neighbor_list = NULL;
+ pim_ifp->pim_ifchannel_list = NULL;
pim_ifp->pim_generation_id = 0;
/* list of struct igmp_sock */
@@ -141,6 +153,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
return if_list_clean(pim_ifp);
}
pim_ifp->pim_ifchannel_list->del = (void (*)(void *)) pim_ifchannel_free;
+ pim_ifp->pim_ifchannel_list->cmp = (int (*)(void *, void *)) pim_ifchannel_compare;
ifp->info = pim_ifp;
@@ -164,16 +177,11 @@ void pim_if_delete(struct interface *ifp)
if (pim_ifp->igmp_join_list) {
pim_if_igmp_join_del_all(ifp);
}
- zassert(!pim_ifp->igmp_join_list);
-
- zassert(pim_ifp->igmp_socket_list);
- zassert(!listcount(pim_ifp->igmp_socket_list));
- zassert(pim_ifp->pim_neighbor_list);
- zassert(!listcount(pim_ifp->pim_neighbor_list));
+ pim_ifchannel_delete_all (ifp);
+ igmp_sock_delete_all (ifp);
- zassert(pim_ifp->pim_ifchannel_list);
- zassert(!listcount(pim_ifp->pim_ifchannel_list));
+ pim_neighbor_delete_all (ifp, "Interface removed from configuration");
if (PIM_MROUTE_IS_ENABLED) {
pim_if_del_vif(ifp);
@@ -185,7 +193,7 @@ void pim_if_delete(struct interface *ifp)
XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
- ifp->info = 0;
+ ifp->info = NULL;
}
void pim_if_update_could_assert(struct interface *ifp)
@@ -258,14 +266,10 @@ static int detect_primary_address_change(struct interface *ifp,
int force_prim_as_any,
const char *caller)
{
- struct pim_interface *pim_ifp;
+ struct pim_interface *pim_ifp = ifp->info;
struct in_addr new_prim_addr;
int changed;
- pim_ifp = ifp->info;
- if (!pim_ifp)
- return 0;
-
if (force_prim_as_any)
new_prim_addr = qpim_inaddr_any;
else
@@ -274,8 +278,8 @@ static int detect_primary_address_change(struct interface *ifp,
changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr;
if (PIM_DEBUG_ZEBRA) {
- char new_prim_str[100];
- char old_prim_str[100];
+ char new_prim_str[INET_ADDRSTRLEN];
+ char old_prim_str[INET_ADDRSTRLEN];
pim_inet4_dump("<new?>", new_prim_addr, new_prim_str, sizeof(new_prim_str));
pim_inet4_dump("<old?>", pim_ifp->primary_address, old_prim_str, sizeof(old_prim_str));
zlog_debug("%s: old=%s new=%s on interface %s: %s",
@@ -286,57 +290,230 @@ static int detect_primary_address_change(struct interface *ifp,
if (changed) {
pim_ifp->primary_address = new_prim_addr;
+ }
- if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
- return changed;
+ 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 (ntohl(sec1->addr.s_addr) < ntohl(sec2->addr.s_addr))
+ return -1;
+
+ if (ntohl(sec1->addr.s_addr) > ntohl(sec2->addr.s_addr))
+ return 1;
+
+ 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 in_addr 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 (sec_addr->addr.s_addr == addr.s_addr) {
+ return sec_addr;
}
+ }
- pim_addr_change(ifp);
+ return NULL;
+}
+
+static void pim_sec_addr_del(struct pim_interface *pim_ifp,
+ struct pim_secondary_addr *sec_addr)
+{
+ listnode_delete(pim_ifp->sec_addr_list, sec_addr);
+ pim_sec_addr_free(sec_addr);
+}
+
+static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct in_addr addr)
+{
+ int changed = 0;
+ struct pim_secondary_addr *sec_addr;
+
+ sec_addr = pim_sec_addr_find(pim_ifp, addr);
+ if (sec_addr) {
+ sec_addr->flags &= ~PIM_SEC_ADDRF_STALE;
+ 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;
+ }
+ return changed;
+ }
+
+ changed = 1;
+ sec_addr->addr = addr;
+ listnode_add_sort(pim_ifp->sec_addr_list, sec_addr);
+
+ return changed;
+}
+
+static int pim_sec_addr_del_all(struct pim_interface *pim_ifp)
+{
+ int changed = 0;
+
+ if (!pim_ifp->sec_addr_list) {
+ return changed;
+ }
+ if (!list_isempty(pim_ifp->sec_addr_list)) {
+ changed = 1;
+ /* remove all nodes and free up the list itself */
+ list_delete_all_node(pim_ifp->sec_addr_list);
+ list_free(pim_ifp->sec_addr_list);
+ pim_ifp->sec_addr_list = NULL;
+ }
+
+ return changed;
+}
+
+static int pim_sec_addr_update(struct interface *ifp)
+{
+ struct pim_interface *pim_ifp = ifp->info;
+ struct connected *ifc;
+ struct listnode *node;
+ struct listnode *nextnode;
+ 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(ifp->connected, node, ifc)) {
+ struct prefix *p = ifc->address;
+
+ if (p->family != AF_INET) {
+ continue;
+ }
+
+ if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
+ continue;
+ }
+
+ if (pim_ifp->primary_address.s_addr == p->u.prefix4.s_addr) {
+ /* don't add the primary address into the secondary address list */
+ continue;
+ }
+
+ if (pim_sec_addr_add(pim_ifp, p->u.prefix4)) {
+ changed = 1;
+ }
+ }
+
+ 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;
+ }
}
return changed;
}
-static void detect_secondary_address_change(struct interface *ifp,
+static int detect_secondary_address_change(struct interface *ifp,
+ int force_prim_as_any,
const char *caller)
{
+ struct pim_interface *pim_ifp = ifp->info;
+ int changed = 0;
+
+ if (force_prim_as_any) {
+ /* if primary address is being forced to zero just flush the
+ * secondary address list */
+ changed = pim_sec_addr_del_all(pim_ifp);
+ } else {
+ /* re-evaluate the secondary address list */
+ changed = pim_sec_addr_update(ifp);
+ }
+
+ return changed;
+}
+
+static void detect_address_change(struct interface *ifp,
+ int force_prim_as_any,
+ const char *caller)
+{
+ int changed = 0;
struct pim_interface *pim_ifp;
- int changed;
pim_ifp = ifp->info;
if (!pim_ifp)
return;
- changed = 1; /* true */
- if (PIM_DEBUG_ZEBRA)
- zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change",
- __PRETTY_FUNCTION__, ifp->name);
+ if (detect_primary_address_change(ifp, force_prim_as_any, caller)) {
+ changed = 1;
+ }
- if (!changed) {
- return;
+ if (detect_secondary_address_change(ifp, force_prim_as_any, caller)) {
+ changed = 1;
}
- if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
- return;
+
+ if (changed) {
+ if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
+ return;
+ }
+
+ pim_addr_change(ifp);
}
- pim_addr_change(ifp);
+ /* XXX: if we have unnumbered interfaces we need to run detect address
+ * address change on all of them when the lo address changes */
}
-static void detect_address_change(struct interface *ifp,
- int force_prim_as_any,
- const char *caller)
+int pim_update_source_set(struct interface *ifp, struct in_addr source)
{
- int prim_changed;
+ struct pim_interface *pim_ifp = ifp->info;
- prim_changed = detect_primary_address_change(ifp, force_prim_as_any, caller);
- if (prim_changed) {
- /* no need to detect secondary change because
- the reaction would be the same */
- return;
+ if (!pim_ifp) {
+ return PIM_IFACE_NOT_FOUND;
}
- detect_secondary_address_change(ifp, caller);
+ if (pim_ifp->update_source.s_addr == source.s_addr) {
+ return PIM_UPDATE_SOURCE_DUP;
+ }
+
+ pim_ifp->update_source = source;
+ detect_address_change(ifp, 0 /* force_prim_as_any */,
+ __PRETTY_FUNCTION__);
+
+ return PIM_SUCCESS;
}
void pim_if_addr_add(struct connected *ifc)
@@ -406,6 +583,7 @@ void pim_if_addr_add(struct connected *ifc)
if (pim_ifp->mroute_vif_index < 0) {
pim_if_add_vif(ifp);
}
+ pim_ifchannel_scan_forward_start (ifp);
}
}
@@ -496,19 +674,59 @@ void pim_if_addr_add_all(struct interface *ifp)
struct connected *ifc;
struct listnode *node;
struct listnode *nextnode;
+ int v4_addrs = 0;
+ int v6_addrs = 0;
+ struct pim_interface *pim_ifp = ifp->info;
+
/* PIM/IGMP enabled ? */
- if (!ifp->info)
+ if (!pim_ifp)
return;
for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
struct prefix *p = ifc->address;
if (p->family != AF_INET)
- continue;
+ {
+ v6_addrs++;
+ continue;
+ }
+ v4_addrs++;
pim_if_addr_add(ifc);
}
+
+ if (!v4_addrs && v6_addrs && !if_is_loopback (ifp))
+ {
+ if (PIM_IF_TEST_PIM(pim_ifp->options)) {
+
+ /* Interface has a valid primary address ? */
+ if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
+
+ /* Interface has a valid socket ? */
+ if (pim_ifp->pim_sock_fd < 0) {
+ if (pim_sock_add(ifp)) {
+ zlog_warn("Failure creating PIM socket for interface %s",
+ ifp->name);
+ }
+ }
+
+ }
+ } /* pim */
+ }
+ if (PIM_MROUTE_IS_ENABLED) {
+ /*
+ * PIM or IGMP is enabled on interface, and there is at least one
+ * address assigned, then try to create a vif_index.
+ */
+ if (pim_ifp->mroute_vif_index < 0) {
+ pim_if_add_vif(ifp);
+ }
+ pim_ifchannel_scan_forward_start (ifp);
+ }
+
+ pim_rp_setup();
+ pim_rp_check_on_if_add(pim_ifp);
}
void pim_if_addr_del_all(struct interface *ifp)
@@ -529,6 +747,9 @@ void pim_if_addr_del_all(struct interface *ifp)
pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */);
}
+
+ pim_rp_setup();
+ pim_i_am_rp_re_evaluate();
}
void pim_if_addr_del_all_igmp(struct interface *ifp)
@@ -571,17 +792,28 @@ void pim_if_addr_del_all_pim(struct interface *ifp)
}
}
-static struct in_addr find_first_nonsec_addr(struct interface *ifp)
+struct in_addr
+pim_find_primary_addr (struct interface *ifp)
{
struct connected *ifc;
struct listnode *node;
struct in_addr addr;
+ int v4_addrs = 0;
+ int v6_addrs = 0;
+ struct pim_interface *pim_ifp = ifp->info;
+
+ if (pim_ifp && PIM_INADDR_ISNOT_ANY(pim_ifp->update_source)) {
+ return pim_ifp->update_source;
+ }
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
struct prefix *p = ifc->address;
-
+
if (p->family != AF_INET)
- continue;
+ {
+ v6_addrs++;
+ continue;
+ }
if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
zlog_warn("%s: null IPv4 address connected to interface %s",
@@ -589,22 +821,33 @@ static struct in_addr find_first_nonsec_addr(struct interface *ifp)
continue;
}
+ v4_addrs++;
+
if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
continue;
return p->u.prefix4;
}
+ /*
+ * If we have no v4_addrs and v6 is configured
+ * We probably are using unnumbered
+ * So let's grab the loopbacks v4 address
+ * and use that as the primary address
+ */
+ if (!v4_addrs && v6_addrs && !if_is_loopback (ifp))
+ {
+ struct interface *lo_ifp;
+ lo_ifp = if_lookup_by_name_vrf ("lo", VRF_DEFAULT);
+ if (lo_ifp)
+ return pim_find_primary_addr (lo_ifp);
+ }
+
addr.s_addr = PIM_NET_INADDR_ANY;
return addr;
}
-struct in_addr pim_find_primary_addr(struct interface *ifp)
-{
- return find_first_nonsec_addr(ifp);
-}
-
static int pim_iface_vif_index = 0;
static int
@@ -800,9 +1043,9 @@ int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex)
struct interface *ifp;
ifp = if_lookup_by_index_vrf (ifindex, VRF_DEFAULT);
- pim_ifp = ifp->info;
- if (!pim_ifp)
+ if (!ifp || !ifp->info)
return -1;
+ pim_ifp = ifp->info;
return pim_ifp->mroute_vif_index;
}
@@ -899,14 +1142,14 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
}
if (PIM_DEBUG_PIM_TRACE) {
- char addr_str[100];
+ char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s: neighbor not found for address %s on interface %s",
__PRETTY_FUNCTION__,
addr_str, ifp->name);
}
- return 0;
+ return NULL;
}
long pim_if_t_suppressed_msec(struct interface *ifp)
@@ -985,8 +1228,8 @@ static struct igmp_join *igmp_join_new(struct interface *ifp,
join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr, source_addr);
if (join_fd < 0) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
@@ -995,13 +1238,13 @@ static struct igmp_join *igmp_join_new(struct interface *ifp,
return 0;
}
- ij = XMALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
+ ij = XCALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
if (!ij) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
- zlog_err("%s: XMALLOC(%zu) failure for IGMP group %s source %s on interface %s",
+ zlog_err("%s: XCALLOC(%zu) failure for IGMP group %s source %s on interface %s",
__PRETTY_FUNCTION__,
sizeof(*ij), group_str, source_str, ifp->name);
close(join_fd);
@@ -1045,8 +1288,8 @@ int pim_if_igmp_join_add(struct interface *ifp,
ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
if (ij) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s",
@@ -1057,8 +1300,8 @@ int pim_if_igmp_join_add(struct interface *ifp,
ij = igmp_join_new(ifp, group_addr, source_addr);
if (!ij) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
@@ -1068,8 +1311,8 @@ int pim_if_igmp_join_add(struct interface *ifp,
}
if (PIM_DEBUG_IGMP_EVENTS) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
@@ -1106,8 +1349,8 @@ int pim_if_igmp_join_del(struct interface *ifp,
ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
if (!ij) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: could not find IGMP group %s source %s on interface %s",
@@ -1117,14 +1360,13 @@ int pim_if_igmp_join_del(struct interface *ifp,
}
if (close(ij->sock_fd)) {
- int e = errno;
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
__PRETTY_FUNCTION__,
- ij->sock_fd, group_str, source_str, ifp->name, e, safe_strerror(e));
+ ij->sock_fd, group_str, source_str, ifp->name, errno, safe_strerror(errno));
/* warning only */
}
listnode_delete(pim_ifp->igmp_join_list, ij);
@@ -1249,3 +1491,40 @@ void pim_if_create_pimreg (void)
pim_if_new(pim_regiface, 0, 0);
}
}
+
+int
+pim_if_connected_to_source (struct interface *ifp, struct in_addr src)
+{
+ struct listnode *cnode;
+ struct connected *c;
+ struct prefix p;
+
+ p.family = AF_INET;
+ p.u.prefix4 = src;
+ p.prefixlen = IPV4_MAX_BITLEN;
+
+ for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
+ {
+ if ((c->address->family == AF_INET) &&
+ prefix_match (CONNECTED_PREFIX (c), &p))
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+struct interface *
+pim_if_lookup_address_vrf (struct in_addr src, vrf_id_t vrf_id)
+{
+ struct listnode *ifnode;
+ struct interface *ifp;
+
+ for (ALL_LIST_ELEMENTS_RO (vrf_iflist(vrf_id), ifnode, ifp))
+ {
+ if (pim_if_connected_to_source (ifp, src) && ifp->info)
+ return ifp;
+ }
+ return NULL;
+}
diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h
index e56559ca46..244de598db 100644
--- a/pimd/pim_iface.h
+++ b/pimd/pim_iface.h
@@ -16,7 +16,7 @@
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_IFACE_H
#define PIM_IFACE_H
@@ -58,12 +58,26 @@ enum pim_interface_type {
PIM_INTERFACE_SM
};
+enum pim_secondary_addr_flags {
+ PIM_SEC_ADDRF_NONE = 0,
+ PIM_SEC_ADDRF_STALE = (1 << 0)
+};
+
+struct pim_secondary_addr {
+ struct in_addr addr;
+ enum pim_secondary_addr_flags flags;
+};
+
struct pim_interface {
enum pim_interface_type itype;
uint32_t options; /* bit vector */
ifindex_t mroute_vif_index;
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
+ * address of the interface */
+ int igmp_version; /* IGMP version */
int igmp_default_robustness_variable; /* IGMPv3 QRV */
int igmp_default_query_interval; /* IGMPv3 secs between general queries */
int igmp_query_max_response_time_dsec; /* IGMPv3 Max Response Time in dsecs for general queries */
@@ -106,6 +120,7 @@ struct pim_interface {
};
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
@@ -116,6 +131,7 @@ extern struct interface *pim_regiface;
((pim_ifp)->pim_default_holdtime))
void pim_if_init(void);
+void pim_if_terminate (void);
struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim);
void pim_if_delete(struct interface *ifp);
@@ -126,6 +142,8 @@ void pim_if_addr_del_all(struct interface *ifp);
void pim_if_addr_del_all_igmp(struct interface *ifp);
void pim_if_addr_del_all_pim(struct interface *ifp);
+struct interface *pim_if_lookup_address_vrf (struct in_addr src, vrf_id_t vrf_id);
+
int pim_if_add_vif(struct interface *ifp);
int pim_if_del_vif(struct interface *ifp);
void pim_if_add_vif_all(void);
@@ -166,4 +184,8 @@ void pim_if_update_join_desired(struct pim_interface *pim_ifp);
void pim_if_update_assert_tracking_desired(struct interface *ifp);
void pim_if_create_pimreg(void);
+
+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);
+
#endif /* PIM_IFACE_H */
diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c
index 7afb7a5bdf..07318791e7 100644
--- a/pimd/pim_ifchannel.c
+++ b/pimd/pim_ifchannel.c
@@ -24,6 +24,7 @@
#include "thread.h"
#include "memory.h"
#include "if.h"
+#include "vrf.h"
#include "pimd.h"
#include "pim_str.h"
@@ -36,13 +37,100 @@
#include "pim_join.h"
#include "pim_rpf.h"
#include "pim_macro.h"
+#include "pim_oil.h"
+#include "pim_upstream.h"
-void pim_ifchannel_free(struct pim_ifchannel *ch)
+int
+pim_ifchannel_compare (struct pim_ifchannel *ch1, struct pim_ifchannel *ch2)
+{
+ struct pim_interface *pim_ifp1;
+ struct pim_interface *pim_ifp2;
+
+ if (ntohl(ch1->sg.grp.s_addr) < ntohl(ch2->sg.grp.s_addr))
+ return -1;
+
+ if (ntohl(ch1->sg.grp.s_addr) > ntohl(ch2->sg.grp.s_addr))
+ return 1;
+
+ if (ntohl(ch1->sg.src.s_addr) < ntohl(ch2->sg.src.s_addr))
+ return -1;
+
+ if (ntohl(ch1->sg.src.s_addr) > ntohl(ch2->sg.src.s_addr))
+ return 1;
+
+ pim_ifp1 = ch1->interface->info;
+ pim_ifp2 = ch2->interface->info;
+ if (ntohl(pim_ifp1->primary_address.s_addr) < ntohl(pim_ifp2->primary_address.s_addr))
+ return -1;
+
+ if (ntohl(pim_ifp1->primary_address.s_addr) > ntohl(pim_ifp2->primary_address.s_addr))
+ return 1;
+
+ if (pim_ifp1->mroute_vif_index < pim_ifp2->mroute_vif_index)
+ return -1;
+
+ if (pim_ifp1->mroute_vif_index > pim_ifp2->mroute_vif_index)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * A (*,G) or a (*,*) is going away
+ * remove the parent pointer from
+ * those pointing at us
+ */
+static void
+pim_ifchannel_remove_children (struct pim_ifchannel *ch)
{
- zassert(!ch->t_ifjoin_expiry_timer);
- zassert(!ch->t_ifjoin_prune_pending_timer);
- zassert(!ch->t_ifassert_timer);
+ struct pim_ifchannel *child;
+
+ if (!ch->sources)
+ return;
+
+ while (!list_isempty (ch->sources))
+ {
+ child = listnode_head (ch->sources);
+ child->parent = NULL;
+ listnode_delete (ch->sources, child);
+ }
+}
+
+/*
+ * A (*,G) or a (*,*) is being created
+ * find all the children that would point
+ * at us.
+ */
+static void
+pim_ifchannel_find_new_children (struct pim_ifchannel *ch)
+{
+ struct pim_interface *pim_ifp = ch->interface->info;
+ struct pim_ifchannel *child;
+ struct listnode *ch_node;
+
+ // Basic Sanity that we are not being silly
+ if ((ch->sg.src.s_addr != INADDR_ANY) &&
+ (ch->sg.grp.s_addr != INADDR_ANY))
+ return;
+
+ 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))
+ {
+ if ((ch->sg.grp.s_addr != INADDR_ANY) &&
+ (child->sg.grp.s_addr == ch->sg.grp.s_addr) &&
+ (child != ch))
+ {
+ child->parent = ch;
+ listnode_add_sort (ch->sources, child);
+ }
+ }
+}
+
+void pim_ifchannel_free(struct pim_ifchannel *ch)
+{
XFREE(MTYPE_PIM_IFCHANNEL, ch);
}
@@ -51,48 +139,87 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch)
struct pim_interface *pim_ifp;
pim_ifp = ch->interface->info;
- zassert(pim_ifp);
+
+ if (ch->upstream->channel_oil)
+ {
+ pim_channel_del_oif (ch->upstream->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_PIM);
+ /*
+ * Do we have any S,G's that are inheriting?
+ * Nuke from on high too.
+ */
+ if (ch->upstream->sources)
+ {
+ struct pim_upstream *child;
+ struct listnode *up_node;
+
+ for (ALL_LIST_ELEMENTS_RO (ch->upstream->sources, up_node, child))
+ pim_channel_del_oif (child->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_PIM);
+ }
+ }
+
+ /*
+ * When this channel is removed
+ * we need to find all our children
+ * and make sure our pointers are fixed
+ */
+ pim_ifchannel_remove_children (ch);
+
+ if (ch->sources)
+ list_delete (ch->sources);
if (ch->ifjoin_state != PIM_IFJOIN_NOINFO) {
pim_upstream_update_join_desired(ch->upstream);
}
- pim_upstream_del(ch->upstream);
+ pim_upstream_del(ch->upstream, __PRETTY_FUNCTION__);
+ ch->upstream = NULL;
THREAD_OFF(ch->t_ifjoin_expiry_timer);
THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
THREAD_OFF(ch->t_ifassert_timer);
+ if (ch->parent)
+ {
+ 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);
+ listnode_delete(pim_ifchannel_list, ch);
pim_ifchannel_free(ch);
}
-#define IFCHANNEL_NOINFO(ch) \
- ( \
- ((ch)->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO) \
- && \
- ((ch)->ifjoin_state == PIM_IFJOIN_NOINFO) \
- && \
- ((ch)->ifassert_state == PIM_IFASSERT_NOINFO) \
- )
+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;
+
+ 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);
+ }
+}
static void delete_on_noinfo(struct pim_ifchannel *ch)
{
- if (IFCHANNEL_NOINFO(ch)) {
-
- /* In NOINFO state, timers should have been cleared */
- zassert(!ch->t_ifjoin_expiry_timer);
- zassert(!ch->t_ifjoin_prune_pending_timer);
- zassert(!ch->t_ifassert_timer);
-
+ if (ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO &&
+ ch->ifjoin_state == PIM_IFJOIN_NOINFO &&
+ ch->t_ifjoin_expiry_timer == NULL)
pim_ifchannel_delete(ch);
- }
+
}
void pim_ifchannel_ifjoin_switch(const char *caller,
@@ -101,6 +228,14 @@ void pim_ifchannel_ifjoin_switch(const char *caller,
{
enum pim_ifjoin_state old_state = ch->ifjoin_state;
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_debug ("PIM_IFCHANNEL(%s): %s is switching from %s to %s",
+ ch->interface->name,
+ ch->sg_str,
+ pim_ifchannel_ifjoin_name (ch->ifjoin_state),
+ pim_ifchannel_ifjoin_name (new_state));
+
+
if (old_state == new_state) {
if (PIM_DEBUG_PIM_EVENTS) {
zlog_debug("%s calledby %s: non-transition on state %d (%s)",
@@ -110,25 +245,68 @@ void pim_ifchannel_ifjoin_switch(const char *caller,
return;
}
- zassert(old_state != new_state);
-
ch->ifjoin_state = new_state;
+ if (ch->sg.src.s_addr == INADDR_ANY)
+ {
+ struct pim_upstream *up = ch->upstream;
+ struct pim_upstream *child;
+ struct listnode *up_node;
+
+ if (up)
+ {
+ if (ch->ifjoin_state == PIM_IFJOIN_NOINFO)
+ {
+ for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
+ {
+ struct channel_oil *c_oil = child->channel_oil;
+ struct pim_interface *pim_ifp = ch->interface->info;
+
+ if (PIM_DEBUG_PIM_TRACE)
+ zlog_debug("%s %s: Prune(S,G)=%s from %s",
+ __FILE__, __PRETTY_FUNCTION__,
+ child->sg_str, up->sg_str);
+ if (!c_oil)
+ continue;
+
+ if (!pim_upstream_evaluate_join_desired (child))
+ pim_channel_del_oif (c_oil, ch->interface, PIM_OIF_FLAG_PROTO_PIM);
+
+ /*
+ * If the S,G has no if channel and the c_oil still
+ * has output here then the *,G was supplying the implied
+ * if channel. So remove it.
+ */
+ if (!ch && c_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index])
+ pim_channel_del_oif (c_oil, ch->interface, PIM_OIF_FLAG_PROTO_PIM);
+ }
+ }
+ if (ch->ifjoin_state == PIM_IFJOIN_JOIN)
+ {
+ for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
+ {
+ if (PIM_DEBUG_PIM_TRACE)
+ zlog_debug("%s %s: Join(S,G)=%s from %s",
+ __FILE__, __PRETTY_FUNCTION__,
+ child->sg_str, up->sg_str);
+
+ if (pim_upstream_evaluate_join_desired (child))
+ {
+ pim_channel_add_oif (child->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_PIM);
+ pim_upstream_switch (child, PIM_UPSTREAM_JOINED);
+ }
+ }
+ }
+ }
+ }
/* Transition to/from NOINFO ? */
- if (
- (old_state == PIM_IFJOIN_NOINFO)
- ||
- (new_state == PIM_IFJOIN_NOINFO)
- ) {
+ if ((old_state == PIM_IFJOIN_NOINFO) ||
+ (new_state == PIM_IFJOIN_NOINFO)) {
if (PIM_DEBUG_PIM_EVENTS) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- zlog_debug("PIM_IFCHANNEL_%s: (S,G)=(%s,%s) on interface %s",
+ zlog_debug("PIM_IFCHANNEL_%s: (S,G)=%s on interface %s",
((new_state == PIM_IFJOIN_NOINFO) ? "DOWN" : "UP"),
- src_str, grp_str, ch->interface->name);
+ ch->sg_str, ch->interface->name);
}
/*
@@ -145,9 +323,12 @@ void pim_ifchannel_ifjoin_switch(const char *caller,
const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state)
{
switch (ifjoin_state) {
- case PIM_IFJOIN_NOINFO: return "NOINFO";
- case PIM_IFJOIN_JOIN: return "JOIN";
- case PIM_IFJOIN_PRUNE_PENDING: return "PRUNEP";
+ case PIM_IFJOIN_NOINFO: return "NOINFO";
+ case PIM_IFJOIN_JOIN: return "JOIN";
+ case PIM_IFJOIN_PRUNE: return "PRUNE";
+ case PIM_IFJOIN_PRUNE_PENDING: return "PRUNEP";
+ case PIM_IFJOIN_PRUNE_TMP: return "PRUNET";
+ case PIM_IFJOIN_PRUNE_PENDING_TMP: return "PRUNEPT";
}
return "ifjoin_bad_state";
@@ -180,77 +361,8 @@ void reset_ifassert_state(struct pim_ifchannel *ch)
qpim_infinite_assert_metric);
}
-static struct pim_ifchannel *pim_ifchannel_new(struct interface *ifp,
- struct in_addr source_addr,
- struct in_addr group_addr)
-{
- struct pim_ifchannel *ch;
- struct pim_interface *pim_ifp;
- struct pim_upstream *up;
-
- pim_ifp = ifp->info;
- zassert(pim_ifp);
-
- up = pim_upstream_add(source_addr, group_addr, NULL);
- if (!up) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
- zlog_err("%s: could not attach upstream (S,G)=(%s,%s) on interface %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str, ifp->name);
- return 0;
- }
-
- ch = XMALLOC(MTYPE_PIM_IFCHANNEL, sizeof(*ch));
- if (!ch) {
- zlog_err("%s: PIM XMALLOC(%zu) failure",
- __PRETTY_FUNCTION__, sizeof(*ch));
- return 0;
- }
-
- ch->flags = 0;
- ch->upstream = up;
- ch->interface = ifp;
- ch->source_addr = source_addr;
- ch->group_addr = group_addr;
- ch->local_ifmembership = PIM_IFMEMBERSHIP_NOINFO;
-
- ch->ifjoin_state = PIM_IFJOIN_NOINFO;
- ch->t_ifjoin_expiry_timer = 0;
- ch->t_ifjoin_prune_pending_timer = 0;
- ch->ifjoin_creation = 0;
-
- ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch);
- ch->ifassert_winner_metric = pim_macro_ch_my_assert_metric_eval (ch);
-
- ch->ifassert_winner.s_addr = 0;
-
- /* Assert state */
- ch->t_ifassert_timer = 0;
- reset_ifassert_state(ch);
- if (pim_macro_ch_could_assert_eval(ch))
- PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags);
- else
- PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags);
-
- if (pim_macro_assert_tracking_desired_eval(ch))
- PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags);
- else
- PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags);
-
- /* Attach to list */
- listnode_add(pim_ifp->pim_ifchannel_list, ch);
-
- zassert(IFCHANNEL_NOINFO(ch));
-
- return ch;
-}
-
struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp,
- struct in_addr source_addr,
- struct in_addr group_addr)
+ struct prefix_sg *sg)
{
struct pim_interface *pim_ifp;
struct listnode *ch_node;
@@ -261,21 +373,17 @@ struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp,
pim_ifp = ifp->info;
if (!pim_ifp) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
- zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s",
+ zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
__PRETTY_FUNCTION__,
- src_str, grp_str,
+ pim_str_sg_dump (sg),
ifp->name);
return 0;
}
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
if (
- (source_addr.s_addr == ch->source_addr.s_addr) &&
- (group_addr.s_addr == ch->group_addr.s_addr)
+ (sg->src.s_addr == ch->sg.src.s_addr) &&
+ (sg->grp.s_addr == ch->sg.grp.s_addr)
) {
return ch;
}
@@ -291,13 +399,9 @@ static void ifmembership_set(struct pim_ifchannel *ch,
return;
if (PIM_DEBUG_PIM_EVENTS) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- zlog_debug("%s: (S,G)=(%s,%s) membership now is %s on interface %s",
+ zlog_debug("%s: (S,G)=%s membership now is %s on interface %s",
__PRETTY_FUNCTION__,
- src_str, grp_str,
+ ch->sg_str,
membership == PIM_IFMEMBERSHIP_INCLUDE ? "INCLUDE" : "NOINFO",
ch->interface->name);
}
@@ -339,29 +443,110 @@ void pim_ifchannel_delete_on_noinfo(struct interface *ifp)
}
}
-struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
- struct in_addr source_addr,
- struct in_addr group_addr)
+/*
+ * For a given Interface, if we are given a S,G
+ * Find the *,G (If we have it).
+ * If we are passed a *,G, find the *,* ifchannel
+ * if we have it.
+ */
+static struct pim_ifchannel *
+pim_ifchannel_find_parent (struct pim_ifchannel *ch)
+{
+ struct prefix_sg parent_sg = ch->sg;
+ struct pim_ifchannel *parent = NULL;
+
+ // (S,G)
+ if ((parent_sg.src.s_addr != INADDR_ANY) &&
+ (parent_sg.grp.s_addr != INADDR_ANY))
+ {
+ parent_sg.src.s_addr = INADDR_ANY;
+ parent = pim_ifchannel_find (ch->interface, &parent_sg);
+
+ if (parent)
+ listnode_add (parent->sources, ch);
+ return parent;
+ }
+
+ return NULL;
+}
+
+struct pim_ifchannel *
+pim_ifchannel_add(struct interface *ifp,
+ struct prefix_sg *sg, int flags)
{
+ struct pim_interface *pim_ifp;
struct pim_ifchannel *ch;
- char src_str[100];
- char grp_str[100];
+ struct pim_upstream *up;
- ch = pim_ifchannel_find(ifp, source_addr, group_addr);
+ ch = pim_ifchannel_find(ifp, sg);
if (ch)
return ch;
- ch = pim_ifchannel_new(ifp, source_addr, group_addr);
- if (ch)
- return ch;
-
- pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
- zlog_warn("%s: pim_ifchannel_new() failure for (S,G)=(%s,%s) on interface %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str, ifp->name);
+ pim_ifp = ifp->info;
- return 0;
+ 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 = XMALLOC(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__);
+ return NULL;
+ }
+
+ ch->flags = 0;
+ ch->upstream = up;
+ ch->interface = ifp;
+ ch->sg = *sg;
+ pim_str_sg_set (sg, ch->sg_str);
+ ch->parent = pim_ifchannel_find_parent (ch);
+ if (ch->sg.src.s_addr == INADDR_ANY)
+ {
+ ch->sources = list_new ();
+ ch->sources->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
+ }
+ else
+ ch->sources = NULL;
+
+ pim_ifchannel_find_new_children (ch);
+ ch->local_ifmembership = PIM_IFMEMBERSHIP_NOINFO;
+
+ ch->ifjoin_state = PIM_IFJOIN_NOINFO;
+ ch->t_ifjoin_expiry_timer = NULL;
+ ch->t_ifjoin_prune_pending_timer = NULL;
+ ch->ifjoin_creation = 0;
+
+ ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch);
+ ch->ifassert_winner_metric = pim_macro_ch_my_assert_metric_eval (ch);
+
+ ch->ifassert_winner.s_addr = 0;
+
+ /* Assert state */
+ ch->t_ifassert_timer = NULL;
+ reset_ifassert_state(ch);
+ if (pim_macro_ch_could_assert_eval(ch))
+ PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags);
+ else
+ PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags);
+
+ if (pim_macro_assert_tracking_desired_eval(ch))
+ PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags);
+ else
+ PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags);
+
+ /* Attach to list */
+ listnode_add_sort(pim_ifp->pim_ifchannel_list, ch);
+ listnode_add_sort(pim_ifchannel_list, ch);
+
+ return ch;
}
static void ifjoin_to_noinfo(struct pim_ifchannel *ch)
@@ -375,13 +560,9 @@ static int on_ifjoin_expiry_timer(struct thread *t)
{
struct pim_ifchannel *ch;
- zassert(t);
ch = THREAD_ARG(t);
- zassert(ch);
- ch->t_ifjoin_expiry_timer = 0;
-
- zassert(ch->ifjoin_state == PIM_IFJOIN_JOIN);
+ ch->t_ifjoin_expiry_timer = NULL;
ifjoin_to_noinfo(ch);
/* ch may have been deleted */
@@ -389,64 +570,37 @@ static int on_ifjoin_expiry_timer(struct thread *t)
return 0;
}
-static void prune_echo(struct interface *ifp,
- struct in_addr source_addr,
- struct in_addr group_addr)
-{
- struct pim_interface *pim_ifp;
- struct in_addr neigh_dst_addr;
-
- pim_ifp = ifp->info;
- zassert(pim_ifp);
-
- neigh_dst_addr = pim_ifp->primary_address;
-
- if (PIM_DEBUG_PIM_EVENTS) {
- char source_str[100];
- char group_str[100];
- char neigh_dst_str[100];
- pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
- pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
- pim_inet4_dump("<neigh?>", neigh_dst_addr, neigh_dst_str, sizeof(neigh_dst_str));
- zlog_debug("%s: sending PruneEcho(S,G)=(%s,%s) to upstream=%s on interface %s",
- __PRETTY_FUNCTION__, source_str, group_str, neigh_dst_str, ifp->name);
- }
-
- pim_joinprune_send(ifp, neigh_dst_addr, source_addr, group_addr,
- 0 /* boolean: send_join=false (prune) */);
-}
-
static int on_ifjoin_prune_pending_timer(struct thread *t)
{
struct pim_ifchannel *ch;
int send_prune_echo; /* boolean */
struct interface *ifp;
struct pim_interface *pim_ifp;
- struct in_addr ch_source;
- struct in_addr ch_group;
- zassert(t);
ch = THREAD_ARG(t);
- zassert(ch);
-
- ch->t_ifjoin_prune_pending_timer = 0;
-
- zassert(ch->ifjoin_state == PIM_IFJOIN_PRUNE_PENDING);
- /* Send PruneEcho(S,G) ? */
- ifp = ch->interface;
- pim_ifp = ifp->info;
- send_prune_echo = (listcount(pim_ifp->pim_neighbor_list) > 1);
+ ch->t_ifjoin_prune_pending_timer = NULL;
- /* Save (S,G) */
- ch_source = ch->source_addr;
- ch_group = ch->group_addr;
+ if (ch->ifjoin_state == PIM_IFJOIN_PRUNE_PENDING)
+ {
+ /* Send PruneEcho(S,G) ? */
+ ifp = ch->interface;
+ pim_ifp = ifp->info;
+ send_prune_echo = (listcount(pim_ifp->pim_neighbor_list) > 1);
- ifjoin_to_noinfo(ch);
- /* from here ch may have been deleted */
+ ifjoin_to_noinfo(ch);
+ /* from here ch may have been deleted */
- if (send_prune_echo)
- prune_echo(ifp, ch_source, ch_group);
+ if (send_prune_echo)
+ pim_joinprune_send (ifp, pim_ifp->primary_address,
+ ch->upstream, 0);
+ }
+ else
+ {
+ zlog_warn("%s: IFCHANNEL%s Prune Pending Timer Popped while in %s state",
+ __PRETTY_FUNCTION__, pim_str_sg_dump (&ch->sg),
+ pim_ifchannel_ifjoin_name (ch->ifjoin_state));
+ }
return 0;
}
@@ -454,15 +608,14 @@ static int on_ifjoin_prune_pending_timer(struct thread *t)
static void check_recv_upstream(int is_join,
struct interface *recv_ifp,
struct in_addr upstream,
- struct in_addr source_addr,
- struct in_addr group_addr,
+ struct prefix_sg *sg,
uint8_t source_flags,
int holdtime)
{
struct pim_upstream *up;
/* Upstream (S,G) in Joined state ? */
- up = pim_upstream_find(source_addr, group_addr);
+ up = pim_upstream_find(sg);
if (!up)
return;
if (up->join_state != PIM_UPSTREAM_JOINED)
@@ -470,31 +623,23 @@ static void check_recv_upstream(int is_join,
/* Upstream (S,G) in Joined state */
- if (PIM_INADDR_IS_ANY(up->rpf.rpf_addr)) {
+ if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
/* RPF'(S,G) not found */
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
- zlog_warn("%s %s: RPF'(%s,%s) not found",
+ zlog_warn("%s %s: RPF'%s not found",
__FILE__, __PRETTY_FUNCTION__,
- src_str, grp_str);
+ up->sg_str);
return;
}
/* upstream directed to RPF'(S,G) ? */
- if (upstream.s_addr != up->rpf.rpf_addr.s_addr) {
- char src_str[100];
- char grp_str[100];
- char up_str[100];
- char rpf_str[100];
- pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
+ if (upstream.s_addr != up->rpf.rpf_addr.u.prefix4.s_addr) {
+ char up_str[INET_ADDRSTRLEN];
+ char rpf_str[PREFIX_STRLEN];
pim_inet4_dump("<up?>", upstream, up_str, sizeof(up_str));
- pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_str, sizeof(rpf_str));
- zlog_warn("%s %s: (S,G)=(%s,%s) upstream=%s not directed to RPF'(S,G)=%s on interface %s",
+ pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str, sizeof(rpf_str));
+ zlog_warn("%s %s: (S,G)=%s upstream=%s not directed to RPF'(S,G)=%s on interface %s",
__FILE__, __PRETTY_FUNCTION__,
- src_str, grp_str,
+ up->sg_str,
up_str, rpf_str, recv_ifp->name);
return;
}
@@ -502,7 +647,7 @@ static void check_recv_upstream(int is_join,
if (is_join) {
/* Join(S,G) to RPF'(S,G) */
- pim_upstream_join_suppress(up, up->rpf.rpf_addr, holdtime);
+ pim_upstream_join_suppress(up, up->rpf.rpf_addr.u.prefix4, holdtime);
return;
}
@@ -512,26 +657,25 @@ static void check_recv_upstream(int is_join,
if (source_flags & PIM_WILDCARD_BIT_MASK) {
/* Prune(*,G) to RPF'(S,G) */
pim_upstream_join_timer_decrease_to_t_override("Prune(*,G)",
- up, up->rpf.rpf_addr);
+ up, up->rpf.rpf_addr.u.prefix4);
return;
}
/* Prune(S,G,rpt) to RPF'(S,G) */
pim_upstream_join_timer_decrease_to_t_override("Prune(S,G,rpt)",
- up, up->rpf.rpf_addr);
+ up, up->rpf.rpf_addr.u.prefix4);
return;
}
/* Prune(S,G) to RPF'(S,G) */
pim_upstream_join_timer_decrease_to_t_override("Prune(S,G)", up,
- up->rpf.rpf_addr);
+ up->rpf.rpf_addr.u.prefix4);
}
static int nonlocal_upstream(int is_join,
struct interface *recv_ifp,
struct in_addr upstream,
- struct in_addr source_addr,
- struct in_addr group_addr,
+ struct prefix_sg *sg,
uint8_t source_flags,
uint16_t holdtime)
{
@@ -543,17 +687,13 @@ static int nonlocal_upstream(int is_join,
is_local = (upstream.s_addr == recv_pim_ifp->primary_address.s_addr);
- if (PIM_DEBUG_PIM_TRACE) {
- char up_str[100];
- char src_str[100];
- char grp_str[100];
+ if (PIM_DEBUG_PIM_TRACE_DETAIL) {
+ char up_str[INET_ADDRSTRLEN];
pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
- pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
- zlog_warn("%s: recv %s (S,G)=(%s,%s) to %s upstream=%s on %s",
+ zlog_warn("%s: recv %s (S,G)=%s to %s upstream=%s on %s",
__PRETTY_FUNCTION__,
is_join ? "join" : "prune",
- src_str, grp_str,
+ pim_str_sg_dump (sg),
is_local ? "local" : "non-local",
up_str, recv_ifp->name);
}
@@ -565,7 +705,7 @@ static int nonlocal_upstream(int is_join,
Since recv upstream addr was not directed to our primary
address, check if we should react to it in any way.
*/
- check_recv_upstream(is_join, recv_ifp, upstream, source_addr, group_addr,
+ check_recv_upstream(is_join, recv_ifp, upstream, sg,
source_flags, holdtime);
return 1; /* non-local */
@@ -574,8 +714,7 @@ static int nonlocal_upstream(int is_join,
void pim_ifchannel_join_add(struct interface *ifp,
struct in_addr neigh_addr,
struct in_addr upstream,
- struct in_addr source_addr,
- struct in_addr group_addr,
+ struct prefix_sg *sg,
uint8_t source_flags,
uint16_t holdtime)
{
@@ -583,11 +722,11 @@ void pim_ifchannel_join_add(struct interface *ifp,
struct pim_ifchannel *ch;
if (nonlocal_upstream(1 /* join */, ifp, upstream,
- source_addr, group_addr, source_flags, holdtime)) {
+ sg, source_flags, holdtime)) {
return;
}
- ch = pim_ifchannel_add(ifp, source_addr, group_addr);
+ ch = pim_ifchannel_add(ifp, sg, PIM_UPSTREAM_FLAG_MASK_SRC_PIM);
if (!ch)
return;
@@ -608,15 +747,11 @@ void pim_ifchannel_join_add(struct interface *ifp,
address of the join message is our primary address.
*/
if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
- char src_str[100];
- char grp_str[100];
- char neigh_str[100];
- pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", group_addr, grp_str, sizeof(grp_str));
+ char neigh_str[INET_ADDRSTRLEN];
pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str));
- zlog_warn("%s: Assert Loser recv Join(%s,%s) from %s on %s",
+ zlog_warn("%s: Assert Loser recv Join%s from %s on %s",
__PRETTY_FUNCTION__,
- src_str, grp_str, neigh_str, ifp->name);
+ ch->sg_str, neigh_str, ifp->name);
assert_action_a5(ch);
}
@@ -628,6 +763,7 @@ void pim_ifchannel_join_add(struct interface *ifp,
case PIM_IFJOIN_NOINFO:
pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_JOIN);
if (pim_macro_chisin_oiflist(ch)) {
+ pim_upstream_inherited_olist (ch->upstream);
pim_forward_start(ch);
}
break;
@@ -660,16 +796,26 @@ void pim_ifchannel_join_add(struct interface *ifp,
}
THREAD_OFF(ch->t_ifjoin_expiry_timer);
break;
+ case PIM_IFJOIN_PRUNE:
+ if (source_flags & PIM_ENCODE_RPT_BIT)
+ pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_NOINFO);
+ break;
case PIM_IFJOIN_PRUNE_PENDING:
- zassert(!ch->t_ifjoin_expiry_timer);
- zassert(ch->t_ifjoin_prune_pending_timer);
THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
- pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_JOIN);
+ if (source_flags & PIM_ENCODE_RPT_BIT)
+ {
+ THREAD_OFF(ch->t_ifjoin_expiry_timer);
+ pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_NOINFO);
+ }
+ else
+ pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_JOIN);
+ break;
+ case PIM_IFJOIN_PRUNE_TMP:
+ break;
+ case PIM_IFJOIN_PRUNE_PENDING_TMP:
break;
}
- zassert(!IFCHANNEL_NOINFO(ch));
-
if (holdtime != 0xFFFF) {
THREAD_TIMER_ON(master, ch->t_ifjoin_expiry_timer,
on_ifjoin_expiry_timer,
@@ -679,66 +825,112 @@ void pim_ifchannel_join_add(struct interface *ifp,
void pim_ifchannel_prune(struct interface *ifp,
struct in_addr upstream,
- struct in_addr source_addr,
- struct in_addr group_addr,
+ struct prefix_sg *sg,
uint8_t source_flags,
uint16_t holdtime)
{
struct pim_ifchannel *ch;
+ struct pim_interface *pim_ifp;
int jp_override_interval_msec;
if (nonlocal_upstream(0 /* prune */, ifp, upstream,
- source_addr, group_addr, source_flags, holdtime)) {
+ sg, source_flags, holdtime)) {
return;
}
- ch = pim_ifchannel_add(ifp, source_addr, group_addr);
+ ch = pim_ifchannel_find (ifp, sg);
+ if (!ch && !(source_flags & PIM_ENCODE_RPT_BIT))
+ {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: Received prune with no relevant ifchannel %s(%s) state: %d",
+ __PRETTY_FUNCTION__, ifp->name, pim_str_sg_dump (sg), source_flags);
+ return;
+ }
+
+ ch = pim_ifchannel_add(ifp, sg, PIM_UPSTREAM_FLAG_MASK_SRC_PIM);
if (!ch)
return;
+ pim_ifp = ifp->info;
+
switch (ch->ifjoin_state) {
case PIM_IFJOIN_NOINFO:
+ if (source_flags & PIM_ENCODE_RPT_BIT)
+ {
+ PIM_IF_FLAG_SET_S_G_RPT(ch->flags);
+ ch->ifjoin_state = PIM_IFJOIN_PRUNE_PENDING;
+ if (listcount(pim_ifp->pim_neighbor_list) > 1)
+ jp_override_interval_msec = pim_if_jp_override_interval_msec(ifp);
+ else
+ jp_override_interval_msec = 0; /* schedule to expire immediately */
+ /* If we called ifjoin_prune() directly instead, care should
+ be taken not to use "ch" afterwards since it would be
+ deleted. */
+
+ THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
+ THREAD_OFF(ch->t_ifjoin_expiry_timer);
+ THREAD_TIMER_MSEC_ON(master, ch->t_ifjoin_prune_pending_timer,
+ on_ifjoin_prune_pending_timer,
+ ch, jp_override_interval_msec);
+ THREAD_TIMER_ON(master, ch->t_ifjoin_expiry_timer,
+ on_ifjoin_expiry_timer,
+ ch, holdtime);
+ }
+ break;
case PIM_IFJOIN_PRUNE_PENDING:
/* nothing to do */
break;
case PIM_IFJOIN_JOIN:
- {
- struct pim_interface *pim_ifp;
-
- pim_ifp = ifp->info;
+ THREAD_OFF(ch->t_ifjoin_expiry_timer);
- zassert(ch->t_ifjoin_expiry_timer);
- zassert(!ch->t_ifjoin_prune_pending_timer);
+ pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_PRUNE_PENDING);
- THREAD_OFF(ch->t_ifjoin_expiry_timer);
-
- pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_PRUNE_PENDING);
-
- if (listcount(pim_ifp->pim_neighbor_list) > 1) {
- jp_override_interval_msec = pim_if_jp_override_interval_msec(ifp);
+ if (listcount(pim_ifp->pim_neighbor_list) > 1)
+ jp_override_interval_msec = pim_if_jp_override_interval_msec(ifp);
+ else
+ jp_override_interval_msec = 0; /* schedule to expire immediately */
+ /* If we called ifjoin_prune() directly instead, care should
+ be taken not to use "ch" afterwards since it would be
+ deleted. */
+ THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
+ THREAD_TIMER_MSEC_ON(master, ch->t_ifjoin_prune_pending_timer,
+ on_ifjoin_prune_pending_timer,
+ ch, jp_override_interval_msec);
+ break;
+ case PIM_IFJOIN_PRUNE:
+ if (source_flags & PIM_ENCODE_RPT_BIT)
+ {
+ THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
+ THREAD_TIMER_ON(master, ch->t_ifjoin_expiry_timer,
+ on_ifjoin_expiry_timer,
+ ch, holdtime);
+ }
+ break;
+ case PIM_IFJOIN_PRUNE_TMP:
+ if (source_flags & PIM_ENCODE_RPT_BIT)
+ {
+ ch->ifjoin_state = PIM_IFJOIN_PRUNE;
+ THREAD_OFF(ch->t_ifjoin_expiry_timer);
+ THREAD_TIMER_ON(master, ch->t_ifjoin_expiry_timer,
+ on_ifjoin_expiry_timer,
+ ch, holdtime);
}
- else {
- jp_override_interval_msec = 0; /* schedule to expire immediately */
- /* If we called ifjoin_prune() directly instead, care should
- be taken not to use "ch" afterwards since it would be
- deleted. */
+ break;
+ case PIM_IFJOIN_PRUNE_PENDING_TMP:
+ if (source_flags & PIM_ENCODE_RPT_BIT)
+ {
+ ch->ifjoin_state = PIM_IFJOIN_PRUNE_PENDING;
+ THREAD_OFF(ch->t_ifjoin_expiry_timer);
+ THREAD_TIMER_ON(master, ch->t_ifjoin_expiry_timer,
+ on_ifjoin_expiry_timer,
+ ch, holdtime);
}
-
- THREAD_TIMER_MSEC_ON(master, ch->t_ifjoin_prune_pending_timer,
- on_ifjoin_prune_pending_timer,
- ch, jp_override_interval_msec);
-
- zassert(!ch->t_ifjoin_expiry_timer);
- zassert(ch->t_ifjoin_prune_pending_timer);
- }
break;
}
-
}
void pim_ifchannel_local_membership_add(struct interface *ifp,
- struct in_addr source_addr,
- struct in_addr group_addr)
+ struct prefix_sg *sg)
{
struct pim_ifchannel *ch;
struct pim_interface *pim_ifp;
@@ -750,19 +942,37 @@ void pim_ifchannel_local_membership_add(struct interface *ifp,
if (!PIM_IF_TEST_PIM(pim_ifp->options))
return;
- ch = pim_ifchannel_add(ifp, source_addr, group_addr);
+ ch = pim_ifchannel_add(ifp, sg, PIM_UPSTREAM_FLAG_MASK_SRC_IGMP);
if (!ch) {
return;
}
ifmembership_set(ch, PIM_IFMEMBERSHIP_INCLUDE);
- zassert(!IFCHANNEL_NOINFO(ch));
+ if (sg->src.s_addr == INADDR_ANY)
+ {
+ struct pim_upstream *up = pim_upstream_find (sg);
+ struct pim_upstream *child;
+ struct listnode *up_node;
+
+ for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
+ {
+ if (PIM_DEBUG_EVENTS)
+ zlog_debug("%s %s: IGMP (S,G)=%s(%s) from %s",
+ __FILE__, __PRETTY_FUNCTION__,
+ child->sg_str, ifp->name, up->sg_str);
+
+ if (pim_upstream_evaluate_join_desired (child))
+ {
+ pim_channel_add_oif (child->channel_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
+ pim_upstream_switch (child, PIM_UPSTREAM_JOINED);
+ }
+ }
+ }
}
void pim_ifchannel_local_membership_del(struct interface *ifp,
- struct in_addr source_addr,
- struct in_addr group_addr)
+ struct prefix_sg *sg)
{
struct pim_ifchannel *ch;
struct pim_interface *pim_ifp;
@@ -774,12 +984,41 @@ void pim_ifchannel_local_membership_del(struct interface *ifp,
if (!PIM_IF_TEST_PIM(pim_ifp->options))
return;
- ch = pim_ifchannel_find(ifp, source_addr, group_addr);
+ ch = pim_ifchannel_find(ifp, sg);
if (!ch)
return;
ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
+ if (sg->src.s_addr == INADDR_ANY)
+ {
+ struct pim_upstream *up = pim_upstream_find (sg);
+ struct pim_upstream *child;
+ struct listnode *up_node;
+
+ for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
+ {
+ struct channel_oil *c_oil = child->channel_oil;
+ struct pim_ifchannel *chchannel = pim_ifchannel_find (ifp, &child->sg);
+ struct pim_interface *pim_ifp = ifp->info;
+
+ if (PIM_DEBUG_EVENTS)
+ zlog_debug("%s %s: Prune(S,G)=%s(%s) from %s",
+ __FILE__, __PRETTY_FUNCTION__,
+ up->sg_str, ifp->name, child->sg_str);
+
+ if (c_oil && !pim_upstream_evaluate_join_desired (child))
+ pim_channel_del_oif (c_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
+
+ /*
+ * If the S,G has no if channel and the c_oil still
+ * has output here then the *,G was supplying the implied
+ * if channel. So remove it.
+ */
+ if (!chchannel && c_oil && c_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index])
+ pim_channel_del_oif (c_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
+ }
+ }
delete_on_noinfo(ch);
}
@@ -792,10 +1031,10 @@ void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch)
return;
if (PIM_DEBUG_PIM_EVENTS) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
+ char src_str[INET_ADDRSTRLEN];
+ char grp_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<src?>", ch->sg.src, src_str, sizeof(src_str));
+ pim_inet4_dump("<grp?>", ch->sg.grp, grp_str, sizeof(grp_str));
zlog_debug("%s: CouldAssert(%s,%s,%s) changed from %d to %d",
__PRETTY_FUNCTION__,
src_str, grp_str, ch->interface->name,
@@ -834,12 +1073,12 @@ void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch)
return;
if (PIM_DEBUG_PIM_EVENTS) {
- char src_str[100];
- char grp_str[100];
- char old_addr_str[100];
- char new_addr_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
+ char src_str[INET_ADDRSTRLEN];
+ char grp_str[INET_ADDRSTRLEN];
+ char old_addr_str[INET_ADDRSTRLEN];
+ char new_addr_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<src?>", ch->sg.src, src_str, sizeof(src_str));
+ pim_inet4_dump("<grp?>", ch->sg.grp, grp_str, sizeof(grp_str));
pim_inet4_dump("<old_addr?>", ch->ifassert_my_metric.ip_address, old_addr_str, sizeof(old_addr_str));
pim_inet4_dump("<new_addr?>", my_metric_new.ip_address, new_addr_str, sizeof(new_addr_str));
zlog_debug("%s: my_assert_metric(%s,%s,%s) changed from %u,%u,%u,%s to %u,%u,%u,%s",
@@ -872,10 +1111,10 @@ void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch)
return;
if (PIM_DEBUG_PIM_EVENTS) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
+ char src_str[INET_ADDRSTRLEN];
+ char grp_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<src?>", ch->sg.src, src_str, sizeof(src_str));
+ pim_inet4_dump("<grp?>", ch->sg.grp, grp_str, sizeof(grp_str));
zlog_debug("%s: AssertTrackingDesired(%s,%s,%s) changed from %d to %d",
__PRETTY_FUNCTION__,
src_str, grp_str, ch->interface->name,
@@ -895,3 +1134,88 @@ void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch)
}
}
}
+
+/*
+ * If we have a new pim interface, check to
+ * see if any of the pre-existing channels have
+ * their upstream out that way and turn on forwarding
+ * for that ifchannel then.
+ */
+void
+pim_ifchannel_scan_forward_start (struct interface *new_ifp)
+{
+ 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))
+ {
+ struct pim_interface *loop_pim_ifp = ifp->info;
+ struct listnode *ch_node;
+ struct pim_ifchannel *ch;
+
+ if (!loop_pim_ifp)
+ continue;
+
+ if (new_pim_ifp == loop_pim_ifp)
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO (loop_pim_ifp->pim_ifchannel_list, ch_node, ch))
+ {
+ if (ch->ifjoin_state == PIM_IFJOIN_JOIN)
+ {
+ struct pim_upstream *up = ch->upstream;
+ if ((!up->channel_oil) &&
+ (up->rpf.source_nexthop.interface == new_ifp))
+ pim_forward_start (ch);
+ }
+ }
+ }
+}
+
+/*
+ * Downstream per-interface (S,G,rpt) state machine
+ * states that we need to move (S,G,rpt) items
+ * into different states at the start of the
+ * reception of a *,G join as well, when
+ * we get End of Message
+ */
+void
+pim_ifchannel_set_star_g_join_state (struct pim_ifchannel *ch, int eom)
+{
+ struct pim_ifchannel *child;
+ struct listnode *ch_node;
+
+ if (PIM_DEBUG_PIM_TRACE)
+ zlog_debug ("%s: %s %s eom: %d", __PRETTY_FUNCTION__,
+ pim_ifchannel_ifjoin_name(ch->ifjoin_state),
+ ch->sg_str, eom);
+ if (!ch->sources)
+ return;
+
+ for (ALL_LIST_ELEMENTS_RO (ch->sources, ch_node, child))
+ {
+ if (!PIM_IF_FLAG_TEST_S_G_RPT(child->flags))
+ continue;
+
+ switch (child->ifjoin_state)
+ {
+ case PIM_IFJOIN_NOINFO:
+ case PIM_IFJOIN_JOIN:
+ break;
+ case PIM_IFJOIN_PRUNE:
+ if (!eom)
+ child->ifjoin_state = PIM_IFJOIN_PRUNE_TMP;
+ break;
+ case PIM_IFJOIN_PRUNE_PENDING:
+ if (!eom)
+ child->ifjoin_state = PIM_IFJOIN_PRUNE_PENDING_TMP;
+ break;
+ case PIM_IFJOIN_PRUNE_TMP:
+ case PIM_IFJOIN_PRUNE_PENDING_TMP:
+ if (eom)
+ child->ifjoin_state = PIM_IFJOIN_NOINFO;
+ break;
+ }
+ }
+}
diff --git a/pimd/pim_ifchannel.h b/pimd/pim_ifchannel.h
index ce753222ee..bfe632135c 100644
--- a/pimd/pim_ifchannel.h
+++ b/pimd/pim_ifchannel.h
@@ -24,6 +24,7 @@
#include <zebra.h>
#include "if.h"
+#include "prefix.h"
#include "pim_upstream.h"
@@ -35,7 +36,10 @@ enum pim_ifmembership {
enum pim_ifjoin_state {
PIM_IFJOIN_NOINFO,
PIM_IFJOIN_JOIN,
- PIM_IFJOIN_PRUNE_PENDING
+ PIM_IFJOIN_PRUNE,
+ PIM_IFJOIN_PRUNE_PENDING,
+ PIM_IFJOIN_PRUNE_TMP,
+ PIM_IFJOIN_PRUNE_PENDING_TMP,
};
enum pim_ifassert_state {
@@ -67,11 +71,21 @@ struct pim_assert_metric {
#define PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(flags) ((flags) &= ~PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED)
/*
+ * Flat to tell us if the ifchannel is (S,G,rpt)
+ */
+#define PIM_IF_FLAG_MASK_S_G_RPT (1 << 2)
+#define PIM_IF_FLAG_TEST_S_G_RPT(flags) ((flags) & PIM_IF_FLAG_MASK_S_G_RPT)
+#define PIM_IF_FLAG_SET_S_G_RPT(flags) ((flags) |= PIM_IF_FLAG_MASK_S_G_RPT)
+#define PIM_IF_FLAG_UNSET_S_G_RPT(flags) ((flags) &= ~PIM_IF_FLAG_MASK_S_G_RPT)
+
+/*
Per-interface (S,G) state
*/
struct pim_ifchannel {
- struct in_addr source_addr; /* (S,G) source key */
- struct in_addr group_addr; /* (S,G) group key */
+ struct pim_ifchannel *parent;
+ struct list *sources;
+ struct prefix_sg sg;
+ char sg_str[PIM_SG_LEN];
struct interface *interface; /* backpointer to interface */
uint32_t flags;
@@ -98,33 +112,28 @@ struct pim_ifchannel {
void pim_ifchannel_free(struct pim_ifchannel *ch);
void pim_ifchannel_delete(struct pim_ifchannel *ch);
+void pim_ifchannel_delete_all (struct interface *ifp);
void pim_ifchannel_membership_clear(struct interface *ifp);
void pim_ifchannel_delete_on_noinfo(struct interface *ifp);
struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp,
- struct in_addr source_addr,
- struct in_addr group_addr);
+ struct prefix_sg *sg);
struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
- struct in_addr source_addr,
- struct in_addr group_addr);
+ struct prefix_sg *sg, int flags);
void pim_ifchannel_join_add(struct interface *ifp,
struct in_addr neigh_addr,
struct in_addr upstream,
- struct in_addr source_addr,
- struct in_addr group_addr,
+ struct prefix_sg *sg,
uint8_t source_flags,
uint16_t holdtime);
void pim_ifchannel_prune(struct interface *ifp,
struct in_addr upstream,
- struct in_addr source_addr,
- struct in_addr group_addr,
+ struct prefix_sg *sg,
uint8_t source_flags,
uint16_t holdtime);
void pim_ifchannel_local_membership_add(struct interface *ifp,
- struct in_addr source_addr,
- struct in_addr group_addr);
+ struct prefix_sg *sg);
void pim_ifchannel_local_membership_del(struct interface *ifp,
- struct in_addr source_addr,
- struct in_addr group_addr);
+ struct prefix_sg *sg);
void pim_ifchannel_ifjoin_switch(const char *caller,
struct pim_ifchannel *ch,
@@ -140,4 +149,8 @@ void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch);
void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch);
void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch);
+void pim_ifchannel_scan_forward_start (struct interface *new_ifp);
+void pim_ifchannel_set_star_g_join_state (struct pim_ifchannel *ch, int eom);
+
+int pim_ifchannel_compare (struct pim_ifchannel *ch1, struct pim_ifchannel *ch2);
#endif /* PIM_IFCHANNEL_H */
diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c
index ef1b3cbac0..4a23e4f668 100644
--- a/pimd/pim_igmp.c
+++ b/pimd/pim_igmp.c
@@ -26,6 +26,7 @@
#include "pimd.h"
#include "pim_igmp.h"
+#include "pim_igmpv2.h"
#include "pim_igmpv3.h"
#include "pim_iface.h"
#include "pim_sock.h"
@@ -35,34 +36,31 @@
#include "pim_time.h"
#include "pim_zebra.h"
-#define IGMP_GRP_REC_TYPE_MODE_IS_INCLUDE (1)
-#define IGMP_GRP_REC_TYPE_MODE_IS_EXCLUDE (2)
-#define IGMP_GRP_REC_TYPE_CHANGE_TO_INCLUDE_MODE (3)
-#define IGMP_GRP_REC_TYPE_CHANGE_TO_EXCLUDE_MODE (4)
-#define IGMP_GRP_REC_TYPE_ALLOW_NEW_SOURCES (5)
-#define IGMP_GRP_REC_TYPE_BLOCK_OLD_SOURCES (6)
-
static void group_timer_off(struct igmp_group *group);
+/* This socket is used for TXing IGMP packets only, IGMP RX happens
+ * in pim_mroute_msg()
+ */
static int igmp_sock_open(struct in_addr ifaddr, ifindex_t ifindex, uint32_t pim_options)
{
int fd;
int join = 0;
struct in_addr group;
- fd = pim_socket_mcast(IPPROTO_IGMP, ifaddr, ifindex, 1 /* loop=true */);
+ fd = pim_socket_mcast(IPPROTO_IGMP, ifaddr, ifindex, 1);
+
if (fd < 0)
return -1;
if (PIM_IF_TEST_IGMP_LISTEN_ALLROUTERS(pim_options)) {
if (inet_aton(PIM_ALL_ROUTERS, &group)) {
if (!pim_socket_join(fd, group, ifaddr, ifindex))
- ++join;
+ ++join;
}
else {
zlog_warn("%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s",
- __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr),
- PIM_ALL_ROUTERS, errno, safe_strerror(errno));
+ __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr),
+ PIM_ALL_ROUTERS, errno, safe_strerror(errno));
}
}
@@ -76,8 +74,8 @@ static int igmp_sock_open(struct in_addr ifaddr, ifindex_t ifindex, uint32_t pim
}
else {
zlog_warn("%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s",
- __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr),
- PIM_ALL_SYSTEMS, errno, safe_strerror(errno));
+ __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr),
+ PIM_ALL_SYSTEMS, errno, safe_strerror(errno));
}
if (inet_aton(PIM_ALL_IGMP_ROUTERS, &group)) {
@@ -87,13 +85,13 @@ static int igmp_sock_open(struct in_addr ifaddr, ifindex_t ifindex, uint32_t pim
}
else {
zlog_warn("%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s",
- __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr),
- PIM_ALL_IGMP_ROUTERS, errno, safe_strerror(errno));
+ __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr),
+ PIM_ALL_IGMP_ROUTERS, errno, safe_strerror(errno));
}
if (!join) {
zlog_err("IGMP socket fd=%d could not join any group on interface address %s",
- fd, inet_ntoa(ifaddr));
+ fd, inet_ntoa(ifaddr));
close(fd);
fd = -1;
}
@@ -154,22 +152,20 @@ static int pim_igmp_other_querier_expire(struct thread *t)
{
struct igmp_sock *igmp;
- zassert(t);
igmp = THREAD_ARG(t);
- zassert(igmp);
zassert(igmp->t_other_querier_timer);
zassert(!igmp->t_igmp_query_timer);
if (PIM_DEBUG_IGMP_TRACE) {
- char ifaddr_str[100];
+ char ifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str));
zlog_debug("%s: Querier %s resuming",
__PRETTY_FUNCTION__,
ifaddr_str);
}
- igmp->t_other_querier_timer = 0;
+ igmp->t_other_querier_timer = NULL;
/*
We are the current querier, then
@@ -198,7 +194,7 @@ void pim_igmp_other_querier_timer_on(struct igmp_sock *igmp)
*/
if (PIM_DEBUG_IGMP_TRACE) {
- char ifaddr_str[100];
+ char ifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str));
zlog_debug("Querier %s resetting TIMER event for Other-Querier-Present",
ifaddr_str);
@@ -210,7 +206,7 @@ void pim_igmp_other_querier_timer_on(struct igmp_sock *igmp)
else {
/*
We are the current querier, then stop sending general queries:
- igmp->t_igmp_query_timer = 0;
+ igmp->t_igmp_query_timer = NULL;
*/
pim_igmp_general_query_off(igmp);
}
@@ -241,7 +237,7 @@ void pim_igmp_other_querier_timer_on(struct igmp_sock *igmp)
pim_ifp->igmp_query_max_response_time_dsec);
if (PIM_DEBUG_IGMP_TRACE) {
- char ifaddr_str[100];
+ char ifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str));
zlog_debug("Querier %s scheduling %ld.%03ld sec TIMER event for Other-Querier-Present",
ifaddr_str,
@@ -260,7 +256,7 @@ void pim_igmp_other_querier_timer_off(struct igmp_sock *igmp)
if (PIM_DEBUG_IGMP_TRACE) {
if (igmp->t_other_querier_timer) {
- char ifaddr_str[100];
+ char ifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str));
zlog_debug("IGMP querier %s fd=%d cancelling other-querier-present TIMER event on %s",
ifaddr_str, igmp->fd, igmp->interface->name);
@@ -270,31 +266,27 @@ void pim_igmp_other_querier_timer_off(struct igmp_sock *igmp)
zassert(!igmp->t_other_querier_timer);
}
-static int recv_igmp_query(struct igmp_sock *igmp, int query_version,
- int max_resp_code,
- struct in_addr from, const char *from_str,
- char *igmp_msg, int igmp_msg_len)
+static int
+igmp_recv_query(struct igmp_sock *igmp, int query_version,
+ int max_resp_code,
+ struct in_addr from, const char *from_str,
+ char *igmp_msg, int igmp_msg_len)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
- uint8_t resv_s_qrv = 0;
- uint8_t s_flag = 0;
- uint8_t qrv = 0;
struct in_addr group_addr;
uint16_t recv_checksum;
uint16_t checksum;
- int i;
- //group_addr = *(struct in_addr *)(igmp_msg + 4);
memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
ifp = igmp->interface;
pim_ifp = ifp->info;
- recv_checksum = *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET);
+ recv_checksum = *(uint16_t *) (igmp_msg + IGMP_CHECKSUM_OFFSET);
/* for computing checksum */
- *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = 0;
+ *(uint16_t *) (igmp_msg + IGMP_CHECKSUM_OFFSET) = 0;
checksum = in_cksum(igmp_msg, igmp_msg_len);
if (checksum != recv_checksum) {
@@ -303,12 +295,33 @@ static int recv_igmp_query(struct igmp_sock *igmp, int query_version,
return -1;
}
+ /* RFC 3376 defines some guidelines on operating in backwards compatibility
+ * with older versions of IGMP but there are some gaps in the logic:
+ *
+ * - once we drop from say version 3 to version 2 we will never go back to
+ * version 3 even if the node that TXed an IGMP v2 query upgrades to v3
+ *
+ * - The node with the lowest IP is the querier so we will only know to drop
+ * from v3 to v2 if the node that is the querier is also the one that is
+ * running igmp v2. If a non-querier only supports igmp v2 we will have
+ * no way of knowing.
+ *
+ * For now we will simplify things and inform the user that they need to
+ * configure all PIM routers to use the same version of IGMP.
+ */
+ if (query_version != pim_ifp->igmp_version) {
+ zlog_warn("Recv IGMP query v%d from %s on %s but we are using v%d, please "
+ "configure all PIM routers on this subnet to use the same "
+ "IGMP version",
+ query_version, from_str, ifp->name, pim_ifp->igmp_version);
+ return 0;
+ }
+
if (PIM_DEBUG_IGMP_PACKETS) {
- char group_str[100];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
- zlog_debug("Recv IGMP query v%d from %s on %s: size=%d checksum=%x group=%s",
- query_version, from_str, ifp->name,
- igmp_msg_len, checksum, group_str);
+ zlog_debug("Recv IGMP query v%d from %s on %s for group %s",
+ query_version, from_str, ifp->name, group_str);
}
/*
@@ -320,9 +333,9 @@ static int recv_igmp_query(struct igmp_sock *igmp, int query_version,
elected querier.
*/
if (ntohl(from.s_addr) < ntohl(igmp->ifaddr.s_addr)) {
-
+
if (PIM_DEBUG_IGMP_TRACE) {
- char ifaddr_str[100];
+ char ifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str));
zlog_debug("%s: local address %s (%u) lost querier election to %s (%u)",
ifp->name,
@@ -333,272 +346,11 @@ static int recv_igmp_query(struct igmp_sock *igmp, int query_version,
pim_igmp_other_querier_timer_on(igmp);
}
+ /* IGMP version 3 is the only one where we process the RXed query */
if (query_version == 3) {
- /*
- RFC 3376: 4.1.6. QRV (Querier's Robustness Variable)
-
- Routers adopt the QRV value from the most recently received Query
- as their own [Robustness Variable] value, unless that most
- recently received QRV was zero, in which case the receivers use
- the default [Robustness Variable] value specified in section 8.1
- or a statically configured value.
- */
- resv_s_qrv = igmp_msg[8];
- qrv = 7 & resv_s_qrv;
- igmp->querier_robustness_variable = qrv ? qrv : pim_ifp->igmp_default_robustness_variable;
+ igmp_v3_recv_query(igmp, from_str, igmp_msg);
}
- /*
- RFC 3376: 4.1.7. QQIC (Querier's Query Interval Code)
-
- Multicast routers that are not the current querier adopt the QQI
- value from the most recently received Query as their own [Query
- Interval] value, unless that most recently received QQI was zero,
- in which case the receiving routers use the default.
- */
- if (igmp->t_other_querier_timer && query_version == 3) {
- /* other querier present */
- uint8_t qqic;
- uint16_t qqi;
- qqic = igmp_msg[9];
- qqi = igmp_msg_decode8to16(qqic);
- igmp->querier_query_interval = qqi ? qqi : pim_ifp->igmp_default_query_interval;
-
- if (PIM_DEBUG_IGMP_TRACE) {
- char ifaddr_str[100];
- pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str));
- zlog_debug("Querier %s new query interval is %s QQI=%u sec (recv QQIC=%02x from %s)",
- ifaddr_str,
- qqi ? "recv-non-default" : "default",
- igmp->querier_query_interval,
- qqic,
- from_str);
- }
- }
-
- /*
- RFC 3376: 6.6.1. Timer Updates
-
- When a router sends or receives a query with a clear Suppress
- Router-Side Processing flag, it must update its timers to reflect
- the correct timeout values for the group or sources being queried.
-
- General queries don't trigger timer update.
- */
- if (query_version == 3) {
- s_flag = (1 << 3) & resv_s_qrv;
- }
- else {
- /* Neither V1 nor V2 have this field. Pimd should really go into
- * a compatibility mode here and run as V2 (or V1) but it doesn't
- * so for now, lets just set the flag to suppress these timer updates.
- */
- s_flag = 1;
- }
-
- if (!s_flag) {
- /* s_flag is clear */
-
- if (PIM_INADDR_IS_ANY(group_addr)) {
- /* this is a general query */
-
- /* log that general query should have the s_flag set */
- zlog_warn("General IGMP query v%d from %s on %s: Suppress Router-Side Processing flag is clear",
- query_version, from_str, ifp->name);
- }
- else {
- struct igmp_group *group;
-
- /* this is a non-general query: perform timer updates */
-
- group = find_group_by_addr(igmp, group_addr);
- if (group) {
- int recv_num_sources = ntohs(*(uint16_t *)(igmp_msg + IGMP_V3_NUMSOURCES_OFFSET));
-
- /*
- RFC 3376: 6.6.1. Timer Updates
- Query Q(G,A): Source Timer for sources in A are lowered to LMQT
- Query Q(G): Group Timer is lowered to LMQT
- */
- if (recv_num_sources < 1) {
- /* Query Q(G): Group Timer is lowered to LMQT */
-
- igmp_group_timer_lower_to_lmqt(group);
- }
- else {
- /* Query Q(G,A): Source Timer for sources in A are lowered to LMQT */
-
- /* Scan sources in query and lower their timers to LMQT */
- struct in_addr *sources = (struct in_addr *)(igmp_msg + IGMP_V3_SOURCES_OFFSET);
- for (i = 0; i < recv_num_sources; ++i) {
- //struct in_addr src_addr = sources[i];
- //struct igmp_source *src = igmp_find_source_by_addr(group, src_addr);
- struct in_addr src_addr;
- struct igmp_source *src;
- memcpy(&src_addr, sources + i, sizeof(struct in_addr));
- src = igmp_find_source_by_addr(group, src_addr);
- if (src) {
- igmp_source_timer_lower_to_lmqt(src);
- }
- }
- }
-
- }
- else {
- char group_str[100];
- pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
- zlog_warn("IGMP query v%d from %s on %s: could not find group %s for timer update",
- query_version, from_str, ifp->name, group_str);
- }
- }
- } /* s_flag is clear: timer updates */
-
- return 0;
-}
-
-static int igmp_v3_report(struct igmp_sock *igmp,
- struct in_addr from, const char *from_str,
- char *igmp_msg, int igmp_msg_len)
-{
- uint16_t recv_checksum;
- uint16_t checksum;
- int num_groups;
- uint8_t *group_record;
- uint8_t *report_pastend = (uint8_t *) igmp_msg + igmp_msg_len;
- struct interface *ifp = igmp->interface;
- int i;
- int local_ncb = 0;
-
- if (igmp_msg_len < IGMP_V3_MSG_MIN_SIZE) {
- zlog_warn("Recv IGMP report v3 from %s on %s: size=%d shorter than minimum=%d",
- from_str, ifp->name, igmp_msg_len, IGMP_V3_MSG_MIN_SIZE);
- return -1;
- }
-
- recv_checksum = *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET);
-
- /* for computing checksum */
- *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = 0;
-
- checksum = in_cksum(igmp_msg, igmp_msg_len);
- if (checksum != recv_checksum) {
- zlog_warn("Recv IGMP report v3 from %s on %s: checksum mismatch: received=%x computed=%x",
- from_str, ifp->name, recv_checksum, checksum);
- return -1;
- }
-
- num_groups = ntohs(*(uint16_t *) (igmp_msg + IGMP_V3_REPORT_NUMGROUPS_OFFSET));
- if (num_groups < 1) {
- zlog_warn("Recv IGMP report v3 from %s on %s: missing group records",
- from_str, ifp->name);
- return -1;
- }
-
- if (PIM_DEBUG_IGMP_PACKETS) {
- zlog_debug("Recv IGMP report v3 from %s on %s: size=%d checksum=%x groups=%d",
- from_str, ifp->name, igmp_msg_len, checksum, num_groups);
- }
-
- group_record = (uint8_t *) igmp_msg + IGMP_V3_REPORT_GROUPPRECORD_OFFSET;
-
- /* Scan groups */
- for (i = 0; i < num_groups; ++i) {
- struct in_addr rec_group;
- uint8_t *sources;
- uint8_t *src;
- int rec_type;
- int rec_auxdatalen;
- int rec_num_sources;
- int j;
- struct prefix lncb;
- struct prefix g;
-
- if ((group_record + IGMP_V3_GROUP_RECORD_MIN_SIZE) > report_pastend) {
- zlog_warn("Recv IGMP report v3 from %s on %s: group record beyond report end",
- from_str, ifp->name);
- return -1;
- }
-
- rec_type = group_record[IGMP_V3_GROUP_RECORD_TYPE_OFFSET];
- rec_auxdatalen = group_record[IGMP_V3_GROUP_RECORD_AUXDATALEN_OFFSET];
- rec_num_sources = ntohs(* (uint16_t *) (group_record + IGMP_V3_GROUP_RECORD_NUMSOURCES_OFFSET));
-
- //rec_group = *(struct in_addr *)(group_record + IGMP_V3_GROUP_RECORD_GROUP_OFFSET);
- memcpy(&rec_group, group_record + IGMP_V3_GROUP_RECORD_GROUP_OFFSET, sizeof(struct in_addr));
-
- if (PIM_DEBUG_IGMP_PACKETS) {
- zlog_debug("Recv IGMP report v3 from %s on %s: record=%d type=%d auxdatalen=%d sources=%d group=%s",
- from_str, ifp->name, i, rec_type, rec_auxdatalen, rec_num_sources, inet_ntoa(rec_group));
- }
-
- /* Scan sources */
-
- sources = group_record + IGMP_V3_GROUP_RECORD_SOURCE_OFFSET;
-
- for (j = 0, src = sources; j < rec_num_sources; ++j, src += 4) {
-
- if ((src + 4) > report_pastend) {
- zlog_warn("Recv IGMP report v3 from %s on %s: group source beyond report end",
- from_str, ifp->name);
- return -1;
- }
-
- if (PIM_DEBUG_IGMP_PACKETS) {
- char src_str[200];
-
- if (!inet_ntop(AF_INET, src, src_str , sizeof(src_str)))
- sprintf(src_str, "<source?>");
-
- zlog_debug("Recv IGMP report v3 from %s on %s: record=%d group=%s source=%s",
- from_str, ifp->name, i, inet_ntoa(rec_group), src_str);
- }
- } /* for (sources) */
-
-
- lncb.family = AF_INET;
- lncb.u.prefix4.s_addr = 0x000000E0;
- lncb.prefixlen = 24;
-
- g.family = AF_INET;
- g.u.prefix4 = rec_group;
- g.prefixlen = 32;
- /*
- * If we receive a igmp report with the group in 224.0.0.0/24
- * then we should ignore it
- */
- if (prefix_match(&lncb, &g))
- local_ncb = 1;
-
- if (!local_ncb)
- switch (rec_type) {
- case IGMP_GRP_REC_TYPE_MODE_IS_INCLUDE:
- igmpv3_report_isin(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
- break;
- case IGMP_GRP_REC_TYPE_MODE_IS_EXCLUDE:
- igmpv3_report_isex(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
- break;
- case IGMP_GRP_REC_TYPE_CHANGE_TO_INCLUDE_MODE:
- igmpv3_report_toin(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
- break;
- case IGMP_GRP_REC_TYPE_CHANGE_TO_EXCLUDE_MODE:
- igmpv3_report_toex(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
- break;
- case IGMP_GRP_REC_TYPE_ALLOW_NEW_SOURCES:
- igmpv3_report_allow(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
- break;
- case IGMP_GRP_REC_TYPE_BLOCK_OLD_SOURCES:
- igmpv3_report_block(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
- break;
- default:
- zlog_warn("Recv IGMP report v3 from %s on %s: unknown record type: type=%d",
- from_str, ifp->name, rec_type);
- }
-
- group_record += 8 + (rec_num_sources << 2) + (rec_auxdatalen << 2);
- local_ncb = 0;
-
- } /* for (group records) */
-
return 0;
}
@@ -606,73 +358,17 @@ static void on_trace(const char *label,
struct interface *ifp, struct in_addr from)
{
if (PIM_DEBUG_IGMP_TRACE) {
- char from_str[100];
+ char from_str[INET_ADDRSTRLEN];
pim_inet4_dump("<from?>", from, from_str, sizeof(from_str));
zlog_debug("%s: from %s on %s",
label, from_str, ifp->name);
}
}
-static int igmp_v2_report(struct igmp_sock *igmp,
- struct in_addr from, const char *from_str,
- char *igmp_msg, int igmp_msg_len)
-{
- struct interface *ifp = igmp->interface;
- struct igmp_group *group;
- struct in_addr group_addr;
-
- on_trace(__PRETTY_FUNCTION__, igmp->interface, from);
-
- if (igmp_msg_len != IGMP_V12_MSG_SIZE) {
- zlog_warn("Recv IGMP report v2 from %s on %s: size=%d other than correct=%d",
- from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE);
- return -1;
- }
-
- if (PIM_DEBUG_IGMP_TRACE) {
- zlog_warn("%s %s: FIXME WRITEME",
- __FILE__, __PRETTY_FUNCTION__);
- }
-
- //group_addr = *(struct in_addr *)(igmp_msg + 4);
- memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
-
- /* non-existant group is created as INCLUDE {empty} */
- group = igmp_add_group_by_addr(igmp, group_addr);
- if (!group) {
- return -1;
- }
-
- group->last_igmp_v2_report_dsec = pim_time_monotonic_dsec();
-
- return 0;
-}
-
-static int igmp_v2_leave(struct igmp_sock *igmp,
- struct in_addr from, const char *from_str,
- char *igmp_msg, int igmp_msg_len)
-{
- struct interface *ifp = igmp->interface;
-
- on_trace(__PRETTY_FUNCTION__, igmp->interface, from);
-
- if (igmp_msg_len != IGMP_V12_MSG_SIZE) {
- zlog_warn("Recv IGMP leave v2 from %s on %s: size=%d other than correct=%d",
- from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE);
- return -1;
- }
-
- if (PIM_DEBUG_IGMP_TRACE) {
- zlog_warn("%s %s: FIXME WRITEME",
- __FILE__, __PRETTY_FUNCTION__);
- }
-
- return 0;
-}
-
-static int igmp_v1_report(struct igmp_sock *igmp,
- struct in_addr from, const char *from_str,
- char *igmp_msg, int igmp_msg_len)
+static int
+igmp_v1_recv_report (struct igmp_sock *igmp,
+ struct in_addr from, const char *from_str,
+ char *igmp_msg, int igmp_msg_len)
{
struct interface *ifp = igmp->interface;
struct igmp_group *group;
@@ -691,7 +387,6 @@ static int igmp_v1_report(struct igmp_sock *igmp,
__FILE__, __PRETTY_FUNCTION__);
}
- //group_addr = *(struct in_addr *)(igmp_msg + 4);
memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
/* non-existant group is created as INCLUDE {empty} */
@@ -712,8 +407,8 @@ int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len)
char *igmp_msg;
int igmp_msg_len;
int msg_type;
- char from_str[100];
- char to_str[100];
+ char from_str[INET_ADDRSTRLEN];
+ char to_str[INET_ADDRSTRLEN];
if (len < sizeof(*ip_hdr)) {
zlog_warn("IGMP packet size=%zu shorter than minimum=%zu",
@@ -790,26 +485,26 @@ int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len)
return -1;
}
- return recv_igmp_query(igmp, query_version, max_resp_code,
+ return igmp_recv_query(igmp, query_version, max_resp_code,
ip_hdr->ip_src, from_str,
igmp_msg, igmp_msg_len);
}
case PIM_IGMP_V3_MEMBERSHIP_REPORT:
- return igmp_v3_report(igmp, ip_hdr->ip_src, from_str,
- igmp_msg, igmp_msg_len);
+ return igmp_v3_recv_report(igmp, ip_hdr->ip_src, from_str,
+ igmp_msg, igmp_msg_len);
case PIM_IGMP_V2_MEMBERSHIP_REPORT:
- return igmp_v2_report(igmp, ip_hdr->ip_src, from_str,
- igmp_msg, igmp_msg_len);
+ return igmp_v2_recv_report(igmp, ip_hdr->ip_src, from_str,
+ igmp_msg, igmp_msg_len);
case PIM_IGMP_V1_MEMBERSHIP_REPORT:
- return igmp_v1_report(igmp, ip_hdr->ip_src, from_str,
- igmp_msg, igmp_msg_len);
+ return igmp_v1_recv_report(igmp, ip_hdr->ip_src, from_str,
+ igmp_msg, igmp_msg_len);
case PIM_IGMP_V2_LEAVE_GROUP:
- return igmp_v2_leave(igmp, ip_hdr->ip_src, from_str,
- igmp_msg, igmp_msg_len);
+ return igmp_v2_recv_leave(igmp, ip_hdr->ip_src, from_str,
+ igmp_msg, igmp_msg_len);
}
zlog_warn("Ignoring unsupported IGMP message type: %d", msg_type);
@@ -825,9 +520,6 @@ void pim_igmp_general_query_on(struct igmp_sock *igmp)
int startup_mode;
int query_interval;
- zassert(igmp);
- zassert(igmp->interface);
-
/*
Since this socket is starting as querier,
there should not exist a timer for other-querier-present.
@@ -841,20 +533,31 @@ void pim_igmp_general_query_on(struct igmp_sock *igmp)
The Startup Query Interval is the interval between General Queries
sent by a Querier on startup. Default: 1/4 the Query Interval.
+ The first one should be sent out immediately instead of 125/4
+ seconds from now.
*/
startup_mode = igmp->startup_query_count > 0;
if (startup_mode) {
- --igmp->startup_query_count;
+ /*
+ * If this is the first time we are sending a query on a
+ * newly configured igmp interface send it out in 1 second
+ * just to give the entire world a tiny bit of time to settle
+ * else the query interval is:
+ * query_interval = pim_ifp->igmp_default_query_interval >> 2;
+ */
+ if (igmp->startup_query_count == igmp->querier_robustness_variable)
+ query_interval = 1;
+ else
+ query_interval = PIM_IGMP_SQI(pim_ifp->igmp_default_query_interval);
- /* query_interval = pim_ifp->igmp_default_query_interval >> 2; */
- query_interval = PIM_IGMP_SQI(pim_ifp->igmp_default_query_interval);
+ --igmp->startup_query_count;
}
else {
query_interval = igmp->querier_query_interval;
}
if (PIM_DEBUG_IGMP_TRACE) {
- char ifaddr_str[100];
+ char ifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str));
zlog_debug("Querier %s scheduling %d-second (%s) TIMER event for IGMP query on fd=%d",
ifaddr_str,
@@ -862,8 +565,7 @@ void pim_igmp_general_query_on(struct igmp_sock *igmp)
startup_mode ? "startup" : "non-startup",
igmp->fd);
}
- igmp->t_igmp_query_timer = 0;
- zassert(!igmp->t_igmp_query_timer);
+ igmp->t_igmp_query_timer = NULL;
THREAD_TIMER_ON(master, igmp->t_igmp_query_timer,
pim_igmp_general_query,
igmp, query_interval);
@@ -875,35 +577,39 @@ void pim_igmp_general_query_off(struct igmp_sock *igmp)
if (PIM_DEBUG_IGMP_TRACE) {
if (igmp->t_igmp_query_timer) {
- char ifaddr_str[100];
+ char ifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str));
zlog_debug("IGMP querier %s fd=%d cancelling query TIMER event on %s",
ifaddr_str, igmp->fd, igmp->interface->name);
}
}
THREAD_OFF(igmp->t_igmp_query_timer);
- zassert(!igmp->t_igmp_query_timer);
}
/* Issue IGMP general query */
static int pim_igmp_general_query(struct thread *t)
{
- char query_buf[PIM_IGMP_BUFSIZE_WRITE];
struct igmp_sock *igmp;
struct in_addr dst_addr;
struct in_addr group_addr;
struct pim_interface *pim_ifp;
-
- zassert(t);
+ int query_buf_size;
igmp = THREAD_ARG(t);
- zassert(igmp);
zassert(igmp->interface);
zassert(igmp->interface->info);
pim_ifp = igmp->interface->info;
+ if (pim_ifp->igmp_version == 3) {
+ query_buf_size = PIM_IGMP_BUFSIZE_WRITE;
+ } else {
+ query_buf_size = IGMP_V12_MSG_SIZE;
+ }
+
+ char query_buf[query_buf_size];
+
/*
RFC3376: 4.1.12. IP Destination Addresses for Queries
@@ -917,8 +623,8 @@ static int pim_igmp_general_query(struct thread *t)
group_addr.s_addr = PIM_NET_INADDR_ANY;
if (PIM_DEBUG_IGMP_TRACE) {
- char querier_str[100];
- char dst_str[100];
+ char querier_str[INET_ADDRSTRLEN];
+ char dst_str[INET_ADDRSTRLEN];
pim_inet4_dump("<querier?>", igmp->ifaddr, querier_str,
sizeof(querier_str));
pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
@@ -926,124 +632,25 @@ static int pim_igmp_general_query(struct thread *t)
querier_str, dst_str, igmp->interface->name);
}
- pim_igmp_send_membership_query(0 /* igmp_group */,
- igmp->fd,
- igmp->interface->name,
- query_buf,
- sizeof(query_buf),
- 0 /* num_sources */,
- dst_addr,
- group_addr,
- pim_ifp->igmp_query_max_response_time_dsec,
- 1 /* s_flag: always set for general queries */,
- igmp->querier_robustness_variable,
- igmp->querier_query_interval);
+ igmp_send_query (pim_ifp->igmp_version,
+ 0 /* igmp_group */,
+ igmp->fd,
+ igmp->interface->name,
+ query_buf,
+ sizeof(query_buf),
+ 0 /* num_sources */,
+ dst_addr,
+ group_addr,
+ pim_ifp->igmp_query_max_response_time_dsec,
+ 1 /* s_flag: always set for general queries */,
+ igmp->querier_robustness_variable,
+ igmp->querier_query_interval);
pim_igmp_general_query_on(igmp);
return 0;
}
-static int pim_igmp_read(struct thread *t);
-
-static void igmp_read_on(struct igmp_sock *igmp)
-{
- zassert(igmp);
-
- if (PIM_DEBUG_IGMP_TRACE_DETAIL) {
- zlog_debug("Scheduling READ event on IGMP socket fd=%d",
- igmp->fd);
- }
- igmp->t_igmp_read = 0;
- zassert(!igmp->t_igmp_read);
- THREAD_READ_ON(master, igmp->t_igmp_read, pim_igmp_read, igmp, igmp->fd);
-}
-
-static int pim_igmp_read(struct thread *t)
-{
- struct igmp_sock *igmp;
- int fd;
- struct sockaddr_in from;
- struct sockaddr_in to;
- socklen_t fromlen = sizeof(from);
- socklen_t tolen = sizeof(to);
- uint8_t buf[PIM_IGMP_BUFSIZE_READ];
- int len;
- ifindex_t ifindex = -1;
- int result = -1; /* defaults to bad */
-
- zassert(t);
-
- igmp = THREAD_ARG(t);
-
- zassert(igmp);
-
- fd = THREAD_FD(t);
-
- zassert(fd == igmp->fd);
-
- len = pim_socket_recvfromto(fd, buf, sizeof(buf),
- &from, &fromlen,
- &to, &tolen,
- &ifindex);
- if (len < 0) {
- zlog_warn("Failure receiving IP IGMP packet on fd=%d: errno=%d: %s",
- fd, errno, safe_strerror(errno));
- goto done;
- }
-
- if (PIM_DEBUG_IGMP_PACKETS) {
- char from_str[100];
- char to_str[100];
-
- 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?>");
-
- zlog_debug("Recv IP IGMP pkt size=%d from %s to %s on fd=%d on ifindex=%d (sock_ifindex=%d)",
- len, from_str, to_str, fd, ifindex, igmp->interface->ifindex);
- }
-
-#ifdef PIM_CHECK_RECV_IFINDEX_SANITY
- /* ifindex sanity check */
- if (ifindex != igmp->interface->ifindex) {
- char from_str[100];
- char to_str[100];
- struct interface *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?>");
-
- ifp = if_lookup_by_index(ifindex);
- if (ifp) {
- zassert(ifindex == ifp->ifindex);
- }
-
-#ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH
- zlog_warn("Interface mismatch: recv IGMP pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)",
- from_str, to_str, fd,
- ifindex, ifp ? ifp->name : "<if-notfound>",
- igmp->interface->ifindex, igmp->interface->name);
-#endif
- goto done;
- }
-#endif
-
- if (pim_igmp_packet(igmp, (char *)buf, len)) {
- goto done;
- }
-
- result = 0; /* good */
-
- done:
- igmp_read_on(igmp);
-
- return result;
-}
-
static void sock_close(struct igmp_sock *igmp)
{
pim_igmp_other_querier_timer_off(igmp);
@@ -1057,7 +664,6 @@ static void sock_close(struct igmp_sock *igmp)
}
}
THREAD_OFF(igmp->t_igmp_read);
- zassert(!igmp->t_igmp_read);
if (close(igmp->fd)) {
zlog_err("Failure closing IGMP socket %s fd=%d on interface %s: errno=%d: %s",
@@ -1106,7 +712,7 @@ static void igmp_group_delete(struct igmp_group *group)
struct igmp_source *src;
if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[100];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_debug("Deleting IGMP group %s from socket %d interface %s",
group_str,
@@ -1168,6 +774,22 @@ void igmp_sock_delete(struct igmp_sock *igmp)
igmp_sock_free(igmp);
}
+void
+igmp_sock_delete_all (struct interface *ifp)
+{
+ struct pim_interface *pim_ifp;
+ struct listnode *igmp_node, *igmp_nextnode;
+ struct igmp_sock *igmp;
+
+ pim_ifp = ifp->info;
+
+ for (ALL_LIST_ELEMENTS (pim_ifp->igmp_socket_list, igmp_node,
+ igmp_nextnode, igmp))
+ {
+ igmp_sock_delete(igmp);
+ }
+}
+
static struct igmp_sock *igmp_sock_new(int fd,
struct in_addr ifaddr,
struct interface *ifp)
@@ -1182,9 +804,9 @@ static struct igmp_sock *igmp_sock_new(int fd,
fd, inet_ntoa(ifaddr), ifp->name);
}
- igmp = XMALLOC(MTYPE_PIM_IGMP_SOCKET, sizeof(*igmp));
+ igmp = XCALLOC(MTYPE_PIM_IGMP_SOCKET, sizeof(*igmp));
if (!igmp) {
- zlog_warn("%s %s: XMALLOC() failure",
+ zlog_warn("%s %s: XCALLOC() failure",
__FILE__, __PRETTY_FUNCTION__);
return 0;
}
@@ -1200,9 +822,9 @@ static struct igmp_sock *igmp_sock_new(int fd,
igmp->fd = fd;
igmp->interface = ifp;
igmp->ifaddr = ifaddr;
- igmp->t_igmp_read = 0;
- igmp->t_igmp_query_timer = 0;
- igmp->t_other_querier_timer = 0; /* no other querier present */
+ igmp->t_igmp_read = NULL;
+ igmp->t_igmp_query_timer = NULL;
+ igmp->t_other_querier_timer = NULL; /* no other querier present */
igmp->querier_robustness_variable = pim_ifp->igmp_default_robustness_variable;
igmp->sock_creation = pim_time_monotonic_sec();
@@ -1212,13 +834,63 @@ static struct igmp_sock *igmp_sock_new(int fd,
igmp->querier_query_interval = pim_ifp->igmp_default_query_interval;
*/
igmp_startup_mode_on(igmp);
-
- igmp_read_on(igmp);
pim_igmp_general_query_on(igmp);
return igmp;
}
+static void igmp_read_on (struct igmp_sock *igmp);
+
+static int
+pim_igmp_read (struct thread *t)
+{
+ uint8_t buf[10000];
+ struct igmp_sock *igmp = (struct igmp_sock *)THREAD_ARG(t);
+ struct sockaddr_in from;
+ struct sockaddr_in to;
+ socklen_t fromlen = sizeof(from);
+ socklen_t tolen = sizeof(to);
+ ifindex_t ifindex = -1;
+ int cont = 1;
+ int len;
+
+ while (cont)
+ {
+ len = pim_socket_recvfromto(igmp->fd, buf, sizeof(buf),
+ &from, &fromlen,
+ &to, &tolen,
+ &ifindex);
+ if (len < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
+ {
+ cont = 0;
+ break;
+ }
+ goto done;
+ }
+ }
+
+ done:
+ igmp_read_on(igmp);
+ return 0;
+}
+
+static void
+igmp_read_on (struct igmp_sock *igmp)
+{
+
+ if (PIM_DEBUG_IGMP_TRACE_DETAIL) {
+ zlog_debug("Scheduling READ event on IGMP socket fd=%d",
+ igmp->fd);
+ }
+ igmp->t_igmp_read = NULL;
+ THREAD_READ_ON(master, igmp->t_igmp_read, pim_igmp_read, igmp, igmp->fd);
+
+}
+
struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list,
struct in_addr ifaddr,
struct interface *ifp)
@@ -1244,6 +916,8 @@ struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list,
return 0;
}
+ igmp_read_on (igmp);
+
listnode_add(igmp_sock_list, igmp);
#ifdef IGMP_SOCK_DUMP
@@ -1271,12 +945,10 @@ static int igmp_group_timer(struct thread *t)
{
struct igmp_group *group;
- zassert(t);
group = THREAD_ARG(t);
- zassert(group);
if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[100];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_debug("%s: Timer for group %s on interface %s",
__PRETTY_FUNCTION__,
@@ -1315,7 +987,7 @@ static void group_timer_off(struct igmp_group *group)
return;
if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[100];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_debug("Cancelling TIMER event for group %s on %s",
group_str, group->group_igmp_sock->interface->name);
@@ -1331,7 +1003,7 @@ void igmp_group_timer_on(struct igmp_group *group,
group_timer_off(group);
if (PIM_DEBUG_IGMP_EVENTS) {
- char group_str[100];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_debug("Scheduling %ld.%03ld sec TIMER event for group %s on %s",
interval_msec / 1000,
@@ -1377,6 +1049,19 @@ struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp,
return group;
}
+ if (!pim_is_group_224_4 (group_addr))
+ {
+ zlog_warn("%s: Group Specified is not part of 224.0.0.0/4",
+ __PRETTY_FUNCTION__);
+ return NULL;
+ }
+
+ if (pim_is_group_224_0_0_0_24 (group_addr))
+ {
+ zlog_warn("%s: Group specified is part of 224.0.0.0/24",
+ __PRETTY_FUNCTION__);
+ return NULL;
+ }
/*
Non-existant group is created as INCLUDE {empty}:
@@ -1390,11 +1075,11 @@ struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp,
of INCLUDE and an empty source list.
*/
- group = XMALLOC(MTYPE_PIM_IGMP_GROUP, sizeof(*group));
+ group = XCALLOC(MTYPE_PIM_IGMP_GROUP, sizeof(*group));
if (!group) {
- zlog_warn("%s %s: XMALLOC() failure",
+ zlog_warn("%s %s: XCALLOC() failure",
__FILE__, __PRETTY_FUNCTION__);
- return 0; /* error, not found, could not create */
+ return NULL; /* error, not found, could not create */
}
group->group_source_list = list_new();
@@ -1402,7 +1087,7 @@ struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp,
zlog_warn("%s %s: list_new() failure",
__FILE__, __PRETTY_FUNCTION__);
XFREE(MTYPE_PIM_IGMP_GROUP, group); /* discard group */
- return 0; /* error, not found, could not initialize */
+ return NULL; /* error, not found, could not initialize */
}
group->group_source_list->del = (void (*)(void *)) igmp_source_free;
@@ -1414,6 +1099,7 @@ struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp,
group->last_igmp_v1_report_dsec = -1;
group->last_igmp_v2_report_dsec = -1;
group->group_creation = pim_time_monotonic_sec();
+ group->igmp_version = IGMP_DEFAULT_VERSION;
/* initialize new group as INCLUDE {empty} */
group->group_filtermode_isexcl = 0; /* 0=INCLUDE, 1=EXCLUDE */
@@ -1421,7 +1107,7 @@ struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp,
listnode_add(igmp->igmp_group_list, group);
if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[100];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_debug("Creating new IGMP group %s on socket %d interface %s",
group_str, igmp->fd, igmp->interface->name);
@@ -1442,3 +1128,32 @@ struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp,
return group;
}
+
+void
+igmp_send_query (int igmp_version,
+ struct igmp_group *group,
+ int fd,
+ const char *ifname,
+ char *query_buf,
+ int query_buf_size,
+ int num_sources,
+ struct in_addr dst_addr,
+ struct in_addr group_addr,
+ int query_max_response_time_dsec,
+ uint8_t s_flag,
+ uint8_t querier_robustness_variable,
+ uint16_t querier_query_interval)
+{
+ if (igmp_version == 3) {
+ igmp_v3_send_query (group, fd, ifname, query_buf,
+ query_buf_size, num_sources,
+ dst_addr, group_addr,
+ query_max_response_time_dsec, s_flag,
+ querier_robustness_variable,
+ querier_query_interval);
+ } else if (igmp_version == 2) {
+ igmp_v2_send_query (group, fd, ifname, query_buf,
+ dst_addr, group_addr,
+ query_max_response_time_dsec);
+ }
+}
diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h
index eb0377ce8c..802f1ba471 100644
--- a/pimd/pim_igmp.h
+++ b/pimd/pim_igmp.h
@@ -51,6 +51,7 @@
#define IGMP_V3_GROUP_RECORD_NUMSOURCES_OFFSET (2)
#define IGMP_V3_GROUP_RECORD_GROUP_OFFSET (4)
#define IGMP_V3_GROUP_RECORD_SOURCE_OFFSET (8)
+#define IGMP_CHECKSUM_OFFSET (2)
/* RFC 3376: 8.1. Robustness Variable - Default: 2 */
#define IGMP_DEFAULT_ROBUSTNESS_VARIABLE (2)
@@ -64,6 +65,8 @@
/* RFC 3376: 8.8. Last Member Query Interval - Default: 10 deciseconds */
#define IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC (10)
+#define IGMP_DEFAULT_VERSION (3)
+
struct igmp_join {
struct in_addr group_addr;
struct in_addr source_addr;
@@ -97,7 +100,7 @@ struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list,
struct interface *ifp);
void igmp_sock_delete(struct igmp_sock *igmp);
void igmp_sock_free(struct igmp_sock *igmp);
-
+void igmp_sock_delete_all (struct interface *ifp);
int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len);
void pim_igmp_general_query_on(struct igmp_sock *igmp);
@@ -151,6 +154,9 @@ struct igmp_group {
since sources have their counters) */
int group_specific_query_retransmit_count;
+ /* compatibility mode - igmp v1, v2 or v3 */
+ int igmp_version;
+
struct in_addr group_addr;
int group_filtermode_isexcl; /* 0=INCLUDE, 1=EXCLUDE */
struct list *group_source_list; /* list of struct igmp_source */
@@ -175,4 +181,18 @@ void igmp_group_timer_on(struct igmp_group *group,
struct igmp_source *
source_new (struct igmp_group *group,
struct in_addr src_addr);
+
+void igmp_send_query(int igmp_version,
+ struct igmp_group *group,
+ int fd,
+ const char *ifname,
+ char *query_buf,
+ int query_buf_size,
+ int num_sources,
+ struct in_addr dst_addr,
+ struct in_addr group_addr,
+ int query_max_response_time_dsec,
+ uint8_t s_flag,
+ uint8_t querier_robustness_variable,
+ uint16_t querier_query_interval);
#endif /* PIM_IGMP_H */
diff --git a/pimd/pim_igmpv2.c b/pimd/pim_igmpv2.c
new file mode 100644
index 0000000000..ee4aa7bd9d
--- /dev/null
+++ b/pimd/pim_igmpv2.c
@@ -0,0 +1,190 @@
+/*
+ * PIM for Quagga
+ * Copyright (C) 2016 Cumulus Networks, Inc.
+ * Daniel Walton
+ *
+ * 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 "pimd.h"
+#include "pim_igmp.h"
+#include "pim_igmpv2.h"
+#include "pim_igmpv3.h"
+#include "pim_str.h"
+#include "pim_time.h"
+#include "pim_util.h"
+
+
+static void
+on_trace (const char *label,
+ struct interface *ifp, struct in_addr from)
+{
+ if (PIM_DEBUG_IGMP_TRACE) {
+ char from_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<from?>", from, from_str, sizeof(from_str));
+ zlog_debug("%s: from %s on %s",
+ label, from_str, ifp->name);
+ }
+}
+
+void
+igmp_v2_send_query (struct igmp_group *group,
+ int fd,
+ const char *ifname,
+ char *query_buf,
+ struct in_addr dst_addr,
+ struct in_addr group_addr,
+ int query_max_response_time_dsec)
+{
+ ssize_t msg_size = 8;
+ uint8_t max_resp_code;
+ ssize_t sent;
+ struct sockaddr_in to;
+ socklen_t tolen;
+ uint16_t checksum;
+
+ /* max_resp_code must be non-zero else this will look like an IGMP v1 query */
+ max_resp_code = igmp_msg_encode16to8(query_max_response_time_dsec);
+ zassert(max_resp_code > 0);
+
+ query_buf[0] = PIM_IGMP_MEMBERSHIP_QUERY;
+ query_buf[1] = max_resp_code;
+ *(uint16_t *)(query_buf + IGMP_CHECKSUM_OFFSET) = 0; /* for computing checksum */
+ memcpy(query_buf+4, &group_addr, sizeof(struct in_addr));
+
+ checksum = in_cksum(query_buf, msg_size);
+ *(uint16_t *)(query_buf + IGMP_CHECKSUM_OFFSET) = checksum;
+
+ if (PIM_DEBUG_IGMP_PACKETS) {
+ char dst_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
+ pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
+ zlog_debug("Send IGMPv2 QUERY to %s on %s for group %s",
+ dst_str, ifname, group_str);
+ }
+
+ memset(&to, 0, sizeof(to));
+ to.sin_family = AF_INET;
+ to.sin_addr = dst_addr;
+ tolen = sizeof(to);
+
+ sent = sendto(fd, query_buf, msg_size, MSG_DONTWAIT,
+ (struct sockaddr *)&to, tolen);
+ if (sent != (ssize_t) msg_size) {
+ char dst_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
+ pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
+ if (sent < 0) {
+ zlog_warn("Send IGMPv2 QUERY failed due to %s on %s: group=%s msg_size=%zd: errno=%d: %s",
+ dst_str, ifname, group_str, msg_size, errno, safe_strerror(errno));
+ }
+ else {
+ zlog_warn("Send IGMPv2 QUERY failed due to %s on %s: group=%s msg_size=%zd: sent=%zd",
+ dst_str, ifname, group_str, msg_size, sent);
+ }
+ return;
+ }
+}
+
+int
+igmp_v2_recv_report (struct igmp_sock *igmp,
+ struct in_addr from, const char *from_str,
+ char *igmp_msg, int igmp_msg_len)
+{
+ struct interface *ifp = igmp->interface;
+ struct in_addr group_addr;
+ char group_str[INET_ADDRSTRLEN];
+
+ on_trace(__PRETTY_FUNCTION__, igmp->interface, from);
+
+ if (igmp_msg_len != IGMP_V12_MSG_SIZE) {
+ zlog_warn("Recv IGMPv2 REPORT from %s on %s: size=%d other than correct=%d",
+ from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE);
+ return -1;
+ }
+
+ memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
+
+ if (PIM_DEBUG_IGMP_PACKETS) {
+ pim_inet4_dump("<dst?>", group_addr, group_str, sizeof(group_str));
+ zlog_debug("Recv IGMPv2 REPORT from %s on %s for %s",
+ from_str, ifp->name, group_str);
+ }
+
+ /*
+ * RFC 3376
+ * 7.3.2. In the Presence of Older Version Group Members
+ *
+ * When Group Compatibility Mode is IGMPv2, a router internally
+ * translates the following IGMPv2 messages for that group to their
+ * IGMPv3 equivalents:
+ *
+ * IGMPv2 Message IGMPv3 Equivalent
+ * -------------- -----------------
+ * Report IS_EX( {} )
+ * Leave TO_IN( {} )
+ */
+ igmpv3_report_isex (igmp, from, group_addr, 0, NULL, 1);
+
+ return 0;
+}
+
+int
+igmp_v2_recv_leave (struct igmp_sock *igmp,
+ struct in_addr from, const char *from_str,
+ char *igmp_msg, int igmp_msg_len)
+{
+ struct interface *ifp = igmp->interface;
+ struct in_addr group_addr;
+ char group_str[INET_ADDRSTRLEN];
+
+ on_trace(__PRETTY_FUNCTION__, igmp->interface, from);
+
+ if (igmp_msg_len != IGMP_V12_MSG_SIZE) {
+ zlog_warn("Recv IGMPv2 LEAVE from %s on %s: size=%d other than correct=%d",
+ from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE);
+ return -1;
+ }
+
+ memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
+
+ if (PIM_DEBUG_IGMP_PACKETS) {
+ pim_inet4_dump("<dst?>", group_addr, group_str, sizeof(group_str));
+ zlog_debug("Recv IGMPv2 LEAVE from %s on %s for %s",
+ from_str, ifp->name, group_str);
+ }
+
+ /*
+ * RFC 3376
+ * 7.3.2. In the Presence of Older Version Group Members
+ *
+ * When Group Compatibility Mode is IGMPv2, a router internally
+ * translates the following IGMPv2 messages for that group to their
+ * IGMPv3 equivalents:
+ *
+ * IGMPv2 Message IGMPv3 Equivalent
+ * -------------- -----------------
+ * Report IS_EX( {} )
+ * Leave TO_IN( {} )
+ */
+ igmpv3_report_toin (igmp, from, group_addr, 0, NULL);
+
+ return 0;
+}
diff --git a/pimd/pim_igmpv2.h b/pimd/pim_igmpv2.h
new file mode 100644
index 0000000000..10a2477724
--- /dev/null
+++ b/pimd/pim_igmpv2.h
@@ -0,0 +1,41 @@
+/*
+ * PIM for Quagga
+ * Copyright (C) 2016 Cumulus Networks, Inc.
+ * Daniel Walton
+ *
+ * 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_IGMPV2_H
+#define PIM_IGMPV2_H
+
+void igmp_v2_send_query (struct igmp_group *group,
+ int fd,
+ const char *ifname,
+ char *query_buf,
+ struct in_addr dst_addr,
+ struct in_addr group_addr,
+ int query_max_response_time_dsec);
+
+int igmp_v2_recv_report (struct igmp_sock *igmp,
+ struct in_addr from, const char *from_str,
+ char *igmp_msg, int igmp_msg_len);
+
+int igmp_v2_recv_leave (struct igmp_sock *igmp,
+ struct in_addr from, const char *from_str,
+ char *igmp_msg, int igmp_msg_len);
+
+#endif /* PIM_IGMPV2_H */
diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c
index bdaf2bb270..f7a6cbd0ce 100644
--- a/pimd/pim_igmpv3.c
+++ b/pimd/pim_igmpv3.c
@@ -46,8 +46,8 @@ static void on_trace(const char *label,
int num_sources, struct in_addr *sources)
{
if (PIM_DEBUG_IGMP_TRACE) {
- char from_str[100];
- char group_str[100];
+ char from_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<from?>", from, from_str, sizeof(from_str));
pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
@@ -57,50 +57,6 @@ static void on_trace(const char *label,
}
}
-int igmp_group_compat_mode(const struct igmp_sock *igmp,
- const struct igmp_group *group)
-{
- struct pim_interface *pim_ifp;
- int64_t now_dsec;
- long older_host_present_interval_dsec;
-
- zassert(igmp);
- zassert(igmp->interface);
- zassert(igmp->interface->info);
-
- pim_ifp = igmp->interface->info;
-
- /*
- RFC 3376: 8.13. Older Host Present Interval
-
- This value MUST be ((the Robustness Variable) times (the Query
- Interval)) plus (one Query Response Interval).
-
- older_host_present_interval_dsec = \
- igmp->querier_robustness_variable * \
- 10 * igmp->querier_query_interval + \
- pim_ifp->query_max_response_time_dsec;
- */
- older_host_present_interval_dsec =
- PIM_IGMP_OHPI_DSEC(igmp->querier_robustness_variable,
- igmp->querier_query_interval,
- pim_ifp->igmp_query_max_response_time_dsec);
-
- now_dsec = pim_time_monotonic_dsec();
- if (now_dsec < 1) {
- /* broken timer logged by pim_time_monotonic_dsec() */
- return 3;
- }
-
- if ((now_dsec - group->last_igmp_v1_report_dsec) < older_host_present_interval_dsec)
- return 1; /* IGMPv1 */
-
- if ((now_dsec - group->last_igmp_v2_report_dsec) < older_host_present_interval_dsec)
- return 2; /* IGMPv2 */
-
- return 3; /* IGMPv3 */
-}
-
void igmp_group_reset_gmi(struct igmp_group *group)
{
long group_membership_interval_msec;
@@ -132,7 +88,7 @@ void igmp_group_reset_gmi(struct igmp_group *group)
pim_ifp->igmp_query_max_response_time_dsec);
if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[100];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_debug("Resetting group %s timer to GMI=%ld.%03ld sec on %s",
group_str,
@@ -158,15 +114,13 @@ static int igmp_source_timer(struct thread *t)
struct igmp_source *source;
struct igmp_group *group;
- zassert(t);
source = THREAD_ARG(t);
- zassert(source);
group = source->source_group;
if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
zlog_debug("%s: Source timer expired for group %s source %s on %s",
@@ -176,7 +130,7 @@ static int igmp_source_timer(struct thread *t)
}
zassert(source->t_source_timer);
- source->t_source_timer = 0;
+ source->t_source_timer = NULL;
/*
RFC 3376: 6.3. IGMPv3 Source-Specific Forwarding Rules
@@ -230,8 +184,8 @@ static void source_timer_off(struct igmp_group *group,
return;
if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
zlog_debug("Cancelling TIMER event for group %s source %s on %s",
@@ -250,8 +204,8 @@ static void igmp_source_timer_on(struct igmp_group *group,
source_timer_off(group, source);
if (PIM_DEBUG_IGMP_EVENTS) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
zlog_debug("Scheduling %ld.%03ld sec TIMER event for group %s source %s on %s",
@@ -291,8 +245,8 @@ void igmp_source_reset_gmi(struct igmp_sock *igmp,
pim_ifp->igmp_query_max_response_time_dsec);
if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
@@ -383,7 +337,7 @@ static void source_channel_oil_detach(struct igmp_source *source)
{
if (source->source_channel_oil) {
pim_channel_oil_del(source->source_channel_oil);
- source->source_channel_oil = 0;
+ source->source_channel_oil = NULL;
}
}
@@ -398,8 +352,8 @@ void igmp_source_delete(struct igmp_source *source)
group = source->source_group;
if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
zlog_debug("Deleting IGMP source %s for group %s from socket %d interface %s",
@@ -413,8 +367,8 @@ void igmp_source_delete(struct igmp_source *source)
/* sanity check that forwarding has been disabled */
if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
zlog_warn("%s: forwarding=ON(!) IGMP source %s for group %s from socket %d interface %s",
@@ -483,8 +437,8 @@ source_new (struct igmp_group *group,
struct igmp_source *src;
if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", src_addr, source_str, sizeof(source_str));
zlog_debug("Creating new IGMP source %s for group %s on socket %d interface %s",
@@ -493,9 +447,9 @@ source_new (struct igmp_group *group,
group->group_igmp_sock->interface->name);
}
- src = XMALLOC(MTYPE_PIM_IGMP_GROUP_SOURCE, sizeof(*src));
+ src = XCALLOC(MTYPE_PIM_IGMP_GROUP_SOURCE, sizeof(*src));
if (!src) {
- zlog_warn("%s %s: XMALLOC() failure",
+ zlog_warn("%s %s: XCALLOC() failure",
__FILE__, __PRETTY_FUNCTION__);
return 0; /* error, not found, could not create */
}
@@ -646,8 +600,10 @@ static void isex_excl(struct igmp_group *group,
struct in_addr star = { .s_addr = INADDR_ANY };
source = igmp_find_source_by_addr (group, star);
if (source)
- IGMP_SOURCE_DONT_DELETE(source->source_flags);
- igmp_source_reset_gmi (group->group_igmp_sock, group, source);
+ {
+ IGMP_SOURCE_DONT_DELETE(source->source_flags);
+ igmp_source_reset_gmi (group->group_igmp_sock, group, source);
+ }
}
/* E.5: delete all sources marked with deletion flag: (X-A) and (Y-A) */
@@ -702,7 +658,8 @@ static void isex_incl(struct igmp_group *group,
void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from,
struct in_addr group_addr,
- int num_sources, struct in_addr *sources)
+ int num_sources, struct in_addr *sources,
+ int from_igmp_v2_report)
{
struct interface *ifp = igmp->interface;
struct igmp_group *group;
@@ -716,6 +673,10 @@ void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from,
return;
}
+ /* So we can display how we learned the group in our show command output */
+ if (from_igmp_v2_report)
+ group->igmp_version = 2;
+
if (group->group_filtermode_isexcl) {
/* EXCLUDE mode */
isex_excl(group, num_sources, sources);
@@ -932,6 +893,16 @@ static void toex_excl(struct igmp_group *group,
/* clear off SEND flag from all known sources (X,Y) */
source_clear_send_flag(group->group_source_list);
+ if (num_sources == 0)
+ {
+ struct igmp_source *source;
+ struct in_addr any = { .s_addr = INADDR_ANY };
+
+ source = igmp_find_source_by_addr (group, any);
+ if (source)
+ IGMP_SOURCE_DONT_DELETE(source->source_flags);
+ }
+
/* scan received sources (A) */
for (i = 0; i < num_sources; ++i) {
struct igmp_source *source;
@@ -1037,17 +1008,25 @@ void igmpv3_report_allow(struct igmp_sock *igmp, struct in_addr from,
*/
static void group_retransmit_group(struct igmp_group *group)
{
- char query_buf[PIM_IGMP_BUFSIZE_WRITE];
struct igmp_sock *igmp;
struct pim_interface *pim_ifp;
long lmqc; /* Last Member Query Count */
long lmqi_msec; /* Last Member Query Interval */
long lmqt_msec; /* Last Member Query Time */
int s_flag;
+ int query_buf_size;
igmp = group->group_igmp_sock;
pim_ifp = igmp->interface->info;
+ if (pim_ifp->igmp_version == 3) {
+ query_buf_size = PIM_IGMP_BUFSIZE_WRITE;
+ } else {
+ query_buf_size = IGMP_V12_MSG_SIZE;
+ }
+
+ char query_buf[query_buf_size];
+
lmqc = igmp->querier_robustness_variable;
lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec;
lmqt_msec = lmqc * lmqi_msec;
@@ -1062,7 +1041,7 @@ static void group_retransmit_group(struct igmp_group *group)
s_flag = igmp_group_timer_remain_msec(group) > lmqt_msec;
if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[100];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_debug("retransmit_group_specific_query: group %s on %s: s_flag=%d count=%d",
group_str, igmp->interface->name, s_flag,
@@ -1077,18 +1056,19 @@ static void group_retransmit_group(struct igmp_group *group)
interest.
*/
- pim_igmp_send_membership_query(group,
- igmp->fd,
- igmp->interface->name,
- query_buf,
- sizeof(query_buf),
- 0 /* num_sources_tosend */,
- group->group_addr /* dst_addr */,
- group->group_addr /* group_addr */,
- pim_ifp->igmp_specific_query_max_response_time_dsec,
- s_flag,
- igmp->querier_robustness_variable,
- igmp->querier_query_interval);
+ igmp_send_query(pim_ifp->igmp_version,
+ group,
+ igmp->fd,
+ igmp->interface->name,
+ query_buf,
+ sizeof(query_buf),
+ 0 /* num_sources_tosend */,
+ group->group_addr /* dst_addr */,
+ group->group_addr /* group_addr */,
+ pim_ifp->igmp_specific_query_max_response_time_dsec,
+ s_flag,
+ igmp->querier_robustness_variable,
+ igmp->querier_query_interval);
}
/*
@@ -1123,9 +1103,6 @@ static int group_retransmit_sources(struct igmp_group *group,
struct igmp_source *src;
int num_retransmit_sources_left = 0;
- query_buf1_max_sources = (sizeof(query_buf1) - IGMP_V3_SOURCES_OFFSET) >> 2;
- query_buf2_max_sources = (sizeof(query_buf2) - IGMP_V3_SOURCES_OFFSET) >> 2;
-
source_addr1 = (struct in_addr *)(query_buf1 + IGMP_V3_SOURCES_OFFSET);
source_addr2 = (struct in_addr *)(query_buf2 + IGMP_V3_SOURCES_OFFSET);
@@ -1163,7 +1140,7 @@ static int group_retransmit_sources(struct igmp_group *group,
num_sources_tosend2 = source_addr2 - (struct in_addr *)(query_buf2 + IGMP_V3_SOURCES_OFFSET);
if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[100];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_debug("retransmit_grp&src_specific_query: group %s on %s: srcs_with_sflag=%d srcs_wo_sflag=%d will_send_sflag=%d retransmit_src_left=%d",
group_str, igmp->interface->name,
@@ -1183,7 +1160,7 @@ static int group_retransmit_sources(struct igmp_group *group,
query_buf1_max_sources = (sizeof(query_buf1) - IGMP_V3_SOURCES_OFFSET) >> 2;
if (num_sources_tosend1 > query_buf1_max_sources) {
- char group_str[100];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_warn("%s: group %s on %s: s_flag=1 unable to fit %d sources into buf_size=%zu (max_sources=%d)",
__PRETTY_FUNCTION__, group_str, igmp->interface->name,
@@ -1198,19 +1175,19 @@ static int group_retransmit_sources(struct igmp_group *group,
interest.
*/
- pim_igmp_send_membership_query(group,
- igmp->fd,
- igmp->interface->name,
- query_buf1,
- sizeof(query_buf1),
- num_sources_tosend1,
- group->group_addr,
- group->group_addr,
- pim_ifp->igmp_specific_query_max_response_time_dsec,
- 1 /* s_flag */,
- igmp->querier_robustness_variable,
- igmp->querier_query_interval);
-
+ igmp_send_query(pim_ifp->igmp_version,
+ group,
+ igmp->fd,
+ igmp->interface->name,
+ query_buf1,
+ sizeof(query_buf1),
+ num_sources_tosend1,
+ group->group_addr,
+ group->group_addr,
+ pim_ifp->igmp_specific_query_max_response_time_dsec,
+ 1 /* s_flag */,
+ igmp->querier_robustness_variable,
+ igmp->querier_query_interval);
}
} /* send_with_sflag_set */
@@ -1225,7 +1202,7 @@ static int group_retransmit_sources(struct igmp_group *group,
query_buf2_max_sources = (sizeof(query_buf2) - IGMP_V3_SOURCES_OFFSET) >> 2;
if (num_sources_tosend2 > query_buf2_max_sources) {
- char group_str[100];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_warn("%s: group %s on %s: s_flag=0 unable to fit %d sources into buf_size=%zu (max_sources=%d)",
__PRETTY_FUNCTION__, group_str, igmp->interface->name,
@@ -1240,19 +1217,19 @@ static int group_retransmit_sources(struct igmp_group *group,
interest.
*/
- pim_igmp_send_membership_query(group,
- igmp->fd,
- igmp->interface->name,
- query_buf2,
- sizeof(query_buf2),
- num_sources_tosend2,
- group->group_addr,
- group->group_addr,
- pim_ifp->igmp_specific_query_max_response_time_dsec,
- 0 /* s_flag */,
- igmp->querier_robustness_variable,
- igmp->querier_query_interval);
-
+ igmp_send_query(pim_ifp->igmp_version,
+ group,
+ igmp->fd,
+ igmp->interface->name,
+ query_buf2,
+ sizeof(query_buf2),
+ num_sources_tosend2,
+ group->group_addr,
+ group->group_addr,
+ pim_ifp->igmp_specific_query_max_response_time_dsec,
+ 0 /* s_flag */,
+ igmp->querier_robustness_variable,
+ igmp->querier_query_interval);
}
}
@@ -1265,12 +1242,10 @@ static int igmp_group_retransmit(struct thread *t)
int num_retransmit_sources_left;
int send_with_sflag_set; /* boolean */
- zassert(t);
group = THREAD_ARG(t);
- zassert(group);
if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[100];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_debug("group_retransmit_timer: group %s on %s",
group_str, group->group_igmp_sock->interface->name);
@@ -1300,7 +1275,7 @@ static int igmp_group_retransmit(struct thread *t)
num_retransmit_sources_left = group_retransmit_sources(group,
send_with_sflag_set);
- group->t_group_query_retransmit_timer = 0;
+ group->t_group_query_retransmit_timer = NULL;
/*
Keep group retransmit timer running if there is any retransmit
@@ -1336,7 +1311,7 @@ static void group_retransmit_timer_on(struct igmp_group *group)
lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec;
if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[100];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_debug("Scheduling %ld.%03ld sec retransmit timer for group %s on %s",
lmqi_msec / 1000,
@@ -1565,7 +1540,7 @@ void igmp_group_timer_lower_to_lmqt(struct igmp_group *group)
lmqt_msec = PIM_IGMP_LMQT_MSEC(lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */
if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[100];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
zlog_debug("%s: group %s on %s: LMQC=%d LMQI=%d dsec LMQT=%d msec",
__PRETTY_FUNCTION__,
@@ -1600,8 +1575,8 @@ void igmp_source_timer_lower_to_lmqt(struct igmp_source *source)
lmqt_msec = PIM_IGMP_LMQT_MSEC(lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */
if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
zlog_debug("%s: group %s source %s on %s: LMQC=%d LMQI=%d dsec LMQT=%d msec",
@@ -1613,32 +1588,19 @@ void igmp_source_timer_lower_to_lmqt(struct igmp_source *source)
igmp_source_timer_on(group, source, lmqt_msec);
}
-/*
- Copy sources to message:
-
- struct in_addr *sources = (struct in_addr *)(query_buf + IGMP_V3_SOURCES_OFFSET);
- if (num_sources > 0) {
- struct listnode *node;
- struct igmp_source *src;
- int i = 0;
-
- for (ALL_LIST_ELEMENTS_RO(source_list, node, src)) {
- sources[i++] = src->source_addr;
- }
- }
-*/
-void pim_igmp_send_membership_query(struct igmp_group *group,
- int fd,
- const char *ifname,
- char *query_buf,
- int query_buf_size,
- int num_sources,
- struct in_addr dst_addr,
- struct in_addr group_addr,
- int query_max_response_time_dsec,
- uint8_t s_flag,
- uint8_t querier_robustness_variable,
- uint16_t querier_query_interval)
+void
+igmp_v3_send_query (struct igmp_group *group,
+ int fd,
+ const char *ifname,
+ char *query_buf,
+ int query_buf_size,
+ int num_sources,
+ struct in_addr dst_addr,
+ struct in_addr group_addr,
+ int query_max_response_time_dsec,
+ uint8_t s_flag,
+ uint8_t querier_robustness_variable,
+ uint16_t querier_query_interval)
{
ssize_t msg_size;
uint8_t max_resp_code;
@@ -1678,7 +1640,7 @@ void pim_igmp_send_membership_query(struct igmp_group *group,
query_buf[0] = PIM_IGMP_MEMBERSHIP_QUERY;
query_buf[1] = max_resp_code;
- *(uint16_t *)(query_buf + IGMP_V3_CHECKSUM_OFFSET) = 0; /* for computing checksum */
+ *(uint16_t *)(query_buf + IGMP_CHECKSUM_OFFSET) = 0; /* for computing checksum */
memcpy(query_buf+4, &group_addr, sizeof(struct in_addr));
query_buf[8] = (s_flag << 3) | querier_robustness_variable;
@@ -1686,18 +1648,17 @@ void pim_igmp_send_membership_query(struct igmp_group *group,
*(uint16_t *)(query_buf + IGMP_V3_NUMSOURCES_OFFSET) = htons(num_sources);
checksum = in_cksum(query_buf, msg_size);
- *(uint16_t *)(query_buf + IGMP_V3_CHECKSUM_OFFSET) = checksum;
+ *(uint16_t *)(query_buf + IGMP_CHECKSUM_OFFSET) = checksum;
if (PIM_DEBUG_IGMP_PACKETS) {
- char dst_str[100];
- char group_str[100];
+ char dst_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
- zlog_debug("%s: to %s on %s: group=%s sources=%d msg_size=%zd s_flag=%x QRV=%u QQI=%u QQIC=%02x checksum=%x",
- __PRETTY_FUNCTION__,
- dst_str, ifname, group_str, num_sources,
- msg_size, s_flag, querier_robustness_variable,
- querier_query_interval, qqic, checksum);
+ zlog_debug("Send IGMPv3 query to %s on %s for group %s, sources=%d msg_size=%zd s_flag=%x QRV=%u QQI=%u QQIC=%02x",
+ dst_str, ifname, group_str,
+ num_sources, msg_size, s_flag, querier_robustness_variable,
+ querier_query_interval, qqic);
}
memset(&to, 0, sizeof(to));
@@ -1708,22 +1669,17 @@ void pim_igmp_send_membership_query(struct igmp_group *group,
sent = sendto(fd, query_buf, msg_size, MSG_DONTWAIT,
(struct sockaddr *)&to, tolen);
if (sent != (ssize_t) msg_size) {
- int e = errno;
- char dst_str[100];
- char group_str[100];
+ char dst_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
if (sent < 0) {
- zlog_warn("%s: sendto() failure to %s on %s: group=%s msg_size=%zd: errno=%d: %s",
- __PRETTY_FUNCTION__,
- dst_str, ifname, group_str, msg_size,
- e, safe_strerror(e));
+ zlog_warn("Send IGMPv3 query failed due to %s on %s: group=%s msg_size=%zd: errno=%d: %s",
+ dst_str, ifname, group_str, msg_size, errno, safe_strerror(errno));
}
else {
- zlog_warn("%s: sendto() partial to %s on %s: group=%s msg_size=%zd: sent=%zd",
- __PRETTY_FUNCTION__,
- dst_str, ifname, group_str,
- msg_size, sent);
+ zlog_warn("Send IGMPv3 query failed due to %s on %s: group=%s msg_size=%zd: sent=%zd",
+ dst_str, ifname, group_str, msg_size, sent);
}
return;
}
@@ -1742,8 +1698,8 @@ void pim_igmp_send_membership_query(struct igmp_group *group,
if (!s_flag) {
/* general query? */
if (PIM_INADDR_IS_ANY(group_addr)) {
- char dst_str[100];
- char group_str[100];
+ char dst_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
zlog_warn("%s: to %s on %s: group=%s sources=%d: s_flag is clear for general query!",
@@ -1751,5 +1707,268 @@ void pim_igmp_send_membership_query(struct igmp_group *group,
dst_str, ifname, group_str, num_sources);
}
}
+}
+
+void
+igmp_v3_recv_query (struct igmp_sock *igmp, const char *from_str, char *igmp_msg)
+{
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ struct in_addr group_addr;
+ uint8_t resv_s_qrv = 0;
+ uint8_t s_flag = 0;
+ uint8_t qrv = 0;
+ int i;
+
+ memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
+ ifp = igmp->interface;
+ pim_ifp = ifp->info;
+
+ /*
+ * RFC 3376: 4.1.6. QRV (Querier's Robustness Variable)
+ *
+ * Routers adopt the QRV value from the most recently received Query
+ * as their own [Robustness Variable] value, unless that most
+ * recently received QRV was zero, in which case the receivers use
+ * the default [Robustness Variable] value specified in section 8.1
+ * or a statically configured value.
+ */
+ resv_s_qrv = igmp_msg[8];
+ qrv = 7 & resv_s_qrv;
+ igmp->querier_robustness_variable = qrv ? qrv : pim_ifp->igmp_default_robustness_variable;
+
+ /*
+ * RFC 3376: 4.1.7. QQIC (Querier's Query Interval Code)
+ *
+ * Multicast routers that are not the current querier adopt the QQI
+ * value from the most recently received Query as their own [Query
+ * Interval] value, unless that most recently received QQI was zero,
+ * in which case the receiving routers use the default.
+ */
+ if (igmp->t_other_querier_timer) {
+ /* other querier present */
+ uint8_t qqic;
+ uint16_t qqi;
+ qqic = igmp_msg[9];
+ qqi = igmp_msg_decode8to16(qqic);
+ igmp->querier_query_interval = qqi ? qqi : pim_ifp->igmp_default_query_interval;
+
+ if (PIM_DEBUG_IGMP_TRACE) {
+ char ifaddr_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str));
+ zlog_debug("Querier %s new query interval is %s QQI=%u sec (recv QQIC=%02x from %s)",
+ ifaddr_str,
+ qqi ? "recv-non-default" : "default",
+ igmp->querier_query_interval,
+ qqic,
+ from_str);
+ }
+ }
+
+ /*
+ * RFC 3376: 6.6.1. Timer Updates
+ *
+ * When a router sends or receives a query with a clear Suppress
+ * Router-Side Processing flag, it must update its timers to reflect
+ * the correct timeout values for the group or sources being queried.
+ *
+ * General queries don't trigger timer update.
+ */
+ s_flag = (1 << 3) & resv_s_qrv;
+
+ if (!s_flag) {
+ /* s_flag is clear */
+
+ if (PIM_INADDR_IS_ANY(group_addr)) {
+ /* this is a general query */
+ /* log that general query should have the s_flag set */
+ zlog_warn("General IGMP query v3 from %s on %s: Suppress Router-Side Processing flag is clear",
+ from_str, ifp->name);
+ } else {
+ struct igmp_group *group;
+
+ /* this is a non-general query: perform timer updates */
+
+ group = find_group_by_addr(igmp, group_addr);
+ if (group) {
+ int recv_num_sources = ntohs(*(uint16_t *)(igmp_msg + IGMP_V3_NUMSOURCES_OFFSET));
+
+ /*
+ * RFC 3376: 6.6.1. Timer Updates
+ * Query Q(G,A): Source Timer for sources in A are lowered to LMQT
+ * Query Q(G): Group Timer is lowered to LMQT
+ */
+ if (recv_num_sources < 1) {
+ /* Query Q(G): Group Timer is lowered to LMQT */
+
+ igmp_group_timer_lower_to_lmqt(group);
+ } else {
+ /* Query Q(G,A): Source Timer for sources in A are lowered to LMQT */
+
+ /* Scan sources in query and lower their timers to LMQT */
+ struct in_addr *sources = (struct in_addr *)(igmp_msg + IGMP_V3_SOURCES_OFFSET);
+ for (i = 0; i < recv_num_sources; ++i) {
+ struct in_addr src_addr;
+ struct igmp_source *src;
+ memcpy(&src_addr, sources + i, sizeof(struct in_addr));
+ src = igmp_find_source_by_addr(group, src_addr);
+ if (src) {
+ igmp_source_timer_lower_to_lmqt(src);
+ }
+ }
+ }
+ } else {
+ char group_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
+ zlog_warn("IGMP query v3 from %s on %s: could not find group %s for timer update",
+ from_str, ifp->name, group_str);
+ }
+ }
+ } /* s_flag is clear: timer updates */
+}
+
+int
+igmp_v3_recv_report (struct igmp_sock *igmp,
+ struct in_addr from, const char *from_str,
+ char *igmp_msg, int igmp_msg_len)
+{
+ uint16_t recv_checksum;
+ uint16_t checksum;
+ int num_groups;
+ uint8_t *group_record;
+ uint8_t *report_pastend = (uint8_t *) igmp_msg + igmp_msg_len;
+ struct interface *ifp = igmp->interface;
+ int i;
+ int local_ncb = 0;
+
+ if (igmp_msg_len < IGMP_V3_MSG_MIN_SIZE) {
+ zlog_warn("Recv IGMP report v3 from %s on %s: size=%d shorter than minimum=%d",
+ from_str, ifp->name, igmp_msg_len, IGMP_V3_MSG_MIN_SIZE);
+ return -1;
+ }
+
+ recv_checksum = *(uint16_t *) (igmp_msg + IGMP_CHECKSUM_OFFSET);
+
+ /* for computing checksum */
+ *(uint16_t *) (igmp_msg + IGMP_CHECKSUM_OFFSET) = 0;
+
+ checksum = in_cksum(igmp_msg, igmp_msg_len);
+ if (checksum != recv_checksum) {
+ zlog_warn("Recv IGMP report v3 from %s on %s: checksum mismatch: received=%x computed=%x",
+ from_str, ifp->name, recv_checksum, checksum);
+ return -1;
+ }
+ num_groups = ntohs(*(uint16_t *) (igmp_msg + IGMP_V3_REPORT_NUMGROUPS_OFFSET));
+ if (num_groups < 1) {
+ zlog_warn("Recv IGMP report v3 from %s on %s: missing group records",
+ from_str, ifp->name);
+ return -1;
+ }
+
+ if (PIM_DEBUG_IGMP_PACKETS) {
+ zlog_debug("Recv IGMP report v3 from %s on %s: size=%d checksum=%x groups=%d",
+ from_str, ifp->name, igmp_msg_len, checksum, num_groups);
+ }
+
+ group_record = (uint8_t *) igmp_msg + IGMP_V3_REPORT_GROUPPRECORD_OFFSET;
+
+ /* Scan groups */
+ for (i = 0; i < num_groups; ++i) {
+ struct in_addr rec_group;
+ uint8_t *sources;
+ uint8_t *src;
+ int rec_type;
+ int rec_auxdatalen;
+ int rec_num_sources;
+ int j;
+ struct prefix lncb;
+ struct prefix g;
+
+ if ((group_record + IGMP_V3_GROUP_RECORD_MIN_SIZE) > report_pastend) {
+ zlog_warn("Recv IGMP report v3 from %s on %s: group record beyond report end",
+ from_str, ifp->name);
+ return -1;
+ }
+
+ rec_type = group_record[IGMP_V3_GROUP_RECORD_TYPE_OFFSET];
+ rec_auxdatalen = group_record[IGMP_V3_GROUP_RECORD_AUXDATALEN_OFFSET];
+ rec_num_sources = ntohs(* (uint16_t *) (group_record + IGMP_V3_GROUP_RECORD_NUMSOURCES_OFFSET));
+
+ memcpy(&rec_group, group_record + IGMP_V3_GROUP_RECORD_GROUP_OFFSET, sizeof(struct in_addr));
+
+ if (PIM_DEBUG_IGMP_PACKETS) {
+ zlog_debug("Recv IGMP report v3 from %s on %s: record=%d type=%d auxdatalen=%d sources=%d group=%s",
+ from_str, ifp->name, i, rec_type, rec_auxdatalen, rec_num_sources, inet_ntoa(rec_group));
+ }
+
+ /* Scan sources */
+
+ sources = group_record + IGMP_V3_GROUP_RECORD_SOURCE_OFFSET;
+
+ for (j = 0, src = sources; j < rec_num_sources; ++j, src += 4) {
+
+ if ((src + 4) > report_pastend) {
+ zlog_warn("Recv IGMP report v3 from %s on %s: group source beyond report end",
+ from_str, ifp->name);
+ return -1;
+ }
+
+ if (PIM_DEBUG_IGMP_PACKETS) {
+ char src_str[200];
+
+ if (!inet_ntop(AF_INET, src, src_str , sizeof(src_str)))
+ sprintf(src_str, "<source?>");
+
+ zlog_debug("Recv IGMP report v3 from %s on %s: record=%d group=%s source=%s",
+ from_str, ifp->name, i, inet_ntoa(rec_group), src_str);
+ }
+ } /* for (sources) */
+
+
+ lncb.family = AF_INET;
+ lncb.u.prefix4.s_addr = 0x000000E0;
+ lncb.prefixlen = 24;
+
+ g.family = AF_INET;
+ g.u.prefix4 = rec_group;
+ g.prefixlen = 32;
+ /*
+ * If we receive a igmp report with the group in 224.0.0.0/24
+ * then we should ignore it
+ */
+ if (prefix_match(&lncb, &g))
+ local_ncb = 1;
+
+ if (!local_ncb)
+ switch (rec_type) {
+ case IGMP_GRP_REC_TYPE_MODE_IS_INCLUDE:
+ igmpv3_report_isin(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
+ break;
+ case IGMP_GRP_REC_TYPE_MODE_IS_EXCLUDE:
+ igmpv3_report_isex(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources, 0);
+ break;
+ case IGMP_GRP_REC_TYPE_CHANGE_TO_INCLUDE_MODE:
+ igmpv3_report_toin(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
+ break;
+ case IGMP_GRP_REC_TYPE_CHANGE_TO_EXCLUDE_MODE:
+ igmpv3_report_toex(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
+ break;
+ case IGMP_GRP_REC_TYPE_ALLOW_NEW_SOURCES:
+ igmpv3_report_allow(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
+ break;
+ case IGMP_GRP_REC_TYPE_BLOCK_OLD_SOURCES:
+ igmpv3_report_block(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
+ break;
+ default:
+ zlog_warn("Recv IGMP report v3 from %s on %s: unknown record type: type=%d",
+ from_str, ifp->name, rec_type);
+ }
+
+ group_record += 8 + (rec_num_sources << 2) + (rec_auxdatalen << 2);
+ local_ncb = 0;
+
+ } /* for (group records) */
+
+ return 0;
}
diff --git a/pimd/pim_igmpv3.h b/pimd/pim_igmpv3.h
index db7895f9be..3a4a81d97e 100644
--- a/pimd/pim_igmpv3.h
+++ b/pimd/pim_igmpv3.h
@@ -30,6 +30,13 @@
#define IGMP_V3_NUMSOURCES_OFFSET (10)
#define IGMP_V3_SOURCES_OFFSET (12)
+#define IGMP_GRP_REC_TYPE_MODE_IS_INCLUDE (1)
+#define IGMP_GRP_REC_TYPE_MODE_IS_EXCLUDE (2)
+#define IGMP_GRP_REC_TYPE_CHANGE_TO_INCLUDE_MODE (3)
+#define IGMP_GRP_REC_TYPE_CHANGE_TO_EXCLUDE_MODE (4)
+#define IGMP_GRP_REC_TYPE_ALLOW_NEW_SOURCES (5)
+#define IGMP_GRP_REC_TYPE_BLOCK_OLD_SOURCES (6)
+
/* GMI: Group Membership Interval */
#define PIM_IGMP_GMI_MSEC(qrv,qqi,qri_dsec) ((qrv) * (1000 * (qqi)) + 100 * (qri_dsec))
@@ -54,15 +61,13 @@ void igmp_source_free(struct igmp_source *source);
void igmp_source_delete(struct igmp_source *source);
void igmp_source_delete_expired(struct list *source_list);
-int igmp_group_compat_mode(const struct igmp_sock *igmp,
- const struct igmp_group *group);
-
void igmpv3_report_isin(struct igmp_sock *igmp, struct in_addr from,
struct in_addr group_addr,
int num_sources, struct in_addr *sources);
void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from,
struct in_addr group_addr,
- int num_sources, struct in_addr *sources);
+ int num_sources, struct in_addr *sources,
+ int from_igmp_v2_report);
void igmpv3_report_toin(struct igmp_sock *igmp, struct in_addr from,
struct in_addr group_addr,
int num_sources, struct in_addr *sources);
@@ -82,17 +87,24 @@ void igmp_source_timer_lower_to_lmqt(struct igmp_source *source);
struct igmp_source *igmp_find_source_by_addr(struct igmp_group *group,
struct in_addr src_addr);
-void pim_igmp_send_membership_query(struct igmp_group *group,
- int fd,
- const char *ifname,
- char *query_buf,
- int query_buf_size,
- int num_sources,
- struct in_addr dst_addr,
- struct in_addr group_addr,
- int query_max_response_time_dsec,
- uint8_t s_flag,
- uint8_t querier_robustness_variable,
- uint16_t querier_query_interval);
+void igmp_v3_send_query (struct igmp_group *group,
+ int fd,
+ const char *ifname,
+ char *query_buf,
+ int query_buf_size,
+ int num_sources,
+ struct in_addr dst_addr,
+ struct in_addr group_addr,
+ int query_max_response_time_dsec,
+ uint8_t s_flag,
+ uint8_t querier_robustness_variable,
+ uint16_t querier_query_interval);
+
+void igmp_v3_recv_query (struct igmp_sock *igmp, const char *from_str,
+ char *igmp_msg);
+
+int igmp_v3_recv_report (struct igmp_sock *igmp,
+ struct in_addr from, const char *from_str,
+ char *igmp_msg, int igmp_msg_len);
#endif /* PIM_IGMPV3_H */
diff --git a/pimd/pim_join.c b/pimd/pim_join.c
index 6a5fb851d6..028f77f532 100644
--- a/pimd/pim_join.c
+++ b/pimd/pim_join.c
@@ -23,6 +23,8 @@
#include "log.h"
#include "prefix.h"
#include "if.h"
+#include "vty.h"
+#include "plist.h"
#include "pimd.h"
#include "pim_str.h"
@@ -30,15 +32,19 @@
#include "pim_msg.h"
#include "pim_pim.h"
#include "pim_join.h"
+#include "pim_oil.h"
#include "pim_iface.h"
#include "pim_hello.h"
#include "pim_ifchannel.h"
+#include "pim_rpf.h"
+#include "pim_rp.h"
-static void on_trace(const char *label,
- struct interface *ifp, struct in_addr src)
+static void
+on_trace (const char *label,
+ struct interface *ifp, struct in_addr src)
{
if (PIM_DEBUG_PIM_TRACE) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
zlog_debug("%s: from %s on %s",
label, src_str, ifp->name);
@@ -49,58 +55,81 @@ static void recv_join(struct interface *ifp,
struct pim_neighbor *neigh,
uint16_t holdtime,
struct in_addr upstream,
- struct in_addr group,
- struct in_addr source,
+ struct prefix_sg *sg,
uint8_t source_flags)
{
if (PIM_DEBUG_PIM_TRACE) {
- char up_str[100];
- char src_str[100];
- char grp_str[100];
- char neigh_str[100];
+ char up_str[INET_ADDRSTRLEN];
+ char neigh_str[INET_ADDRSTRLEN];
pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
- pim_inet4_dump("<src?>", source, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", group, grp_str, sizeof(grp_str));
pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
- zlog_warn("%s: join (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
+ zlog_warn("%s: join (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
__PRETTY_FUNCTION__,
- src_str, grp_str,
+ pim_str_sg_dump (sg),
source_flags & PIM_RPT_BIT_MASK,
source_flags & PIM_WILDCARD_BIT_MASK,
up_str, holdtime, neigh_str, ifp->name);
}
-
+
+ /*
+ * If the RPT and WC are set it's a (*,G)
+ * and the source is the RP
+ */
+ if ((source_flags & PIM_RPT_BIT_MASK) &&
+ (source_flags & PIM_WILDCARD_BIT_MASK))
+ {
+ struct pim_rpf *rp = RP (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)
+ return;
+
+ sg->src.s_addr = INADDR_ANY;
+ }
+
/* Restart join expiry timer */
pim_ifchannel_join_add(ifp, neigh->source_addr, upstream,
- source, group, source_flags, holdtime);
+ sg, source_flags, holdtime);
+
}
static void recv_prune(struct interface *ifp,
struct pim_neighbor *neigh,
uint16_t holdtime,
struct in_addr upstream,
- struct in_addr group,
- struct in_addr source,
+ struct prefix_sg *sg,
uint8_t source_flags)
{
if (PIM_DEBUG_PIM_TRACE) {
- char up_str[100];
- char src_str[100];
- char grp_str[100];
- char neigh_str[100];
+ char up_str[INET_ADDRSTRLEN];
+ char neigh_str[INET_ADDRSTRLEN];
pim_inet4_dump("<upstream?>", upstream, up_str, sizeof(up_str));
- pim_inet4_dump("<src?>", source, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", group, grp_str, sizeof(grp_str));
pim_inet4_dump("<neigh?>", neigh->source_addr, neigh_str, sizeof(neigh_str));
- zlog_warn("%s: prune (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
+ zlog_warn("%s: prune (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
__PRETTY_FUNCTION__,
- src_str, grp_str,
+ pim_str_sg_dump (sg),
source_flags & PIM_RPT_BIT_MASK,
source_flags & PIM_WILDCARD_BIT_MASK,
up_str, holdtime, neigh_str, ifp->name);
}
-
- pim_ifchannel_prune(ifp, upstream, source, group, source_flags, holdtime);
+
+ if ((source_flags & PIM_RPT_BIT_MASK) &&
+ (source_flags & PIM_WILDCARD_BIT_MASK))
+ {
+ struct pim_rpf *rp = RP (sg->grp);
+
+ // Ignoring Prune *,G's at the moment.
+ if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr)
+ return;
+
+ sg->src.s_addr = INADDR_ANY;
+ }
+
+ pim_ifchannel_prune(ifp, upstream, sg, source_flags, holdtime);
+
}
int pim_joinprune_recv(struct interface *ifp,
@@ -117,8 +146,6 @@ int pim_joinprune_recv(struct interface *ifp,
int remain;
int group;
- on_trace(__PRETTY_FUNCTION__, ifp, src_addr);
-
buf = tlv_buf;
pastend = tlv_buf + tlv_buf_size;
@@ -128,7 +155,7 @@ int pim_joinprune_recv(struct interface *ifp,
addr_offset = pim_parse_addr_ucast (&msg_upstream_addr,
buf, pastend - buf);
if (addr_offset < 1) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
__PRETTY_FUNCTION__,
@@ -141,8 +168,8 @@ int pim_joinprune_recv(struct interface *ifp,
Check upstream address family
*/
if (msg_upstream_addr.family != AF_INET) {
- if (PIM_DEBUG_PIM_TRACE) {
- char src_str[100];
+ if (PIM_DEBUG_PIM_J_P) {
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s",
__PRETTY_FUNCTION__,
@@ -153,7 +180,7 @@ int pim_joinprune_recv(struct interface *ifp,
remain = pastend - buf;
if (remain < 4) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s",
__PRETTY_FUNCTION__,
@@ -168,28 +195,29 @@ int pim_joinprune_recv(struct interface *ifp,
++buf;
++buf;
- if (PIM_DEBUG_PIM_TRACE) {
- char src_str[100];
- char upstream_str[100];
+ if (PIM_DEBUG_PIM_J_P) {
+ char src_str[INET_ADDRSTRLEN];
+ char upstream_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
upstream_str, sizeof(upstream_str));
- zlog_warn("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s",
- __PRETTY_FUNCTION__,
- upstream_str, msg_num_groups, msg_holdtime,
- src_str, ifp->name);
+ zlog_debug ("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s",
+ __PRETTY_FUNCTION__,
+ upstream_str, msg_num_groups, msg_holdtime,
+ src_str, ifp->name);
}
/* Scan groups */
for (group = 0; group < msg_num_groups; ++group) {
- struct prefix msg_group_addr;
- struct prefix msg_source_addr;
+ struct prefix_sg sg;
uint8_t msg_source_flags;
uint16_t msg_num_joined_sources;
uint16_t msg_num_pruned_sources;
int source;
+ struct pim_ifchannel *ch = NULL;
- addr_offset = pim_parse_addr_group (&msg_group_addr,
+ memset (&sg, 0, sizeof (struct prefix_sg));
+ addr_offset = pim_parse_addr_group (&sg,
buf, pastend - buf);
if (addr_offset < 1) {
return -5;
@@ -198,7 +226,7 @@ int pim_joinprune_recv(struct interface *ifp,
remain = pastend - buf;
if (remain < 4) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s",
__PRETTY_FUNCTION__,
@@ -211,25 +239,25 @@ int pim_joinprune_recv(struct interface *ifp,
msg_num_pruned_sources = ntohs(*(const uint16_t *) buf);
buf += 2;
- if (PIM_DEBUG_PIM_TRACE) {
- char src_str[100];
- char upstream_str[100];
- char group_str[100];
+ if (PIM_DEBUG_PIM_J_P) {
+ char src_str[INET_ADDRSTRLEN];
+ char upstream_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
pim_inet4_dump("<addr?>", msg_upstream_addr.u.prefix4,
upstream_str, sizeof(upstream_str));
- pim_inet4_dump("<grp?>", msg_group_addr.u.prefix4,
+ pim_inet4_dump("<grp?>", sg.grp,
group_str, sizeof(group_str));
- zlog_warn("%s: join/prune upstream=%s group=%s/%d join_src=%d prune_src=%d from %s on %s",
+ zlog_warn("%s: join/prune upstream=%s group=%s/32 join_src=%d prune_src=%d from %s on %s",
__PRETTY_FUNCTION__,
- upstream_str, group_str, msg_group_addr.prefixlen,
+ upstream_str, group_str,
msg_num_joined_sources, msg_num_pruned_sources,
src_str, ifp->name);
}
/* Scan joined sources */
for (source = 0; source < msg_num_joined_sources; ++source) {
- addr_offset = pim_parse_addr_source (&msg_source_addr,
+ addr_offset = pim_parse_addr_source (&sg,
&msg_source_flags,
buf, pastend - buf);
if (addr_offset < 1) {
@@ -240,14 +268,20 @@ int pim_joinprune_recv(struct interface *ifp,
recv_join(ifp, neigh, msg_holdtime,
msg_upstream_addr.u.prefix4,
- msg_group_addr.u.prefix4,
- msg_source_addr.u.prefix4,
+ &sg,
msg_source_flags);
+
+ if (sg.src.s_addr == INADDR_ANY)
+ {
+ ch = pim_ifchannel_find (ifp, &sg);
+ if (ch)
+ pim_ifchannel_set_star_g_join_state (ch, 0);
+ }
}
/* Scan pruned sources */
for (source = 0; source < msg_num_pruned_sources; ++source) {
- addr_offset = pim_parse_addr_source (&msg_source_addr,
+ addr_offset = pim_parse_addr_source (&sg,
&msg_source_flags,
buf, pastend - buf);
if (addr_offset < 1) {
@@ -258,11 +292,12 @@ int pim_joinprune_recv(struct interface *ifp,
recv_prune(ifp, neigh, msg_holdtime,
msg_upstream_addr.u.prefix4,
- msg_group_addr.u.prefix4,
- msg_source_addr.u.prefix4,
+ &sg,
msg_source_flags);
}
-
+ if (ch)
+ pim_ifchannel_set_star_g_join_state (ch, 1);
+ ch = NULL;
} /* scan groups */
return 0;
@@ -270,16 +305,14 @@ int pim_joinprune_recv(struct interface *ifp,
int pim_joinprune_send(struct interface *ifp,
struct in_addr upstream_addr,
- struct in_addr source_addr,
- struct in_addr group_addr,
+ struct pim_upstream *up,
int send_join)
{
struct pim_interface *pim_ifp;
- uint8_t pim_msg[1000];
- const uint8_t *pastend = pim_msg + sizeof(pim_msg);
- uint8_t *pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* room for pim header */
+ uint8_t pim_msg[9000];
int pim_msg_size;
- int remain;
+
+ on_trace (__PRETTY_FUNCTION__, ifp, upstream_addr);
zassert(ifp);
@@ -292,31 +325,23 @@ int pim_joinprune_send(struct interface *ifp,
return -1;
}
- if (PIM_DEBUG_PIM_TRACE) {
- char source_str[100];
- char group_str[100];
- char dst_str[100];
- pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
- pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
+ if (PIM_DEBUG_PIM_J_P) {
+ char dst_str[INET_ADDRSTRLEN];
pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
- zlog_debug("%s: sending %s(S,G)=(%s,%s) to upstream=%s on interface %s",
+ zlog_debug("%s: sending %s(S,G)=%s to upstream=%s on interface %s",
__PRETTY_FUNCTION__,
send_join ? "Join" : "Prune",
- source_str, group_str, dst_str, ifp->name);
+ up->sg_str, dst_str, ifp->name);
}
if (PIM_INADDR_IS_ANY(upstream_addr)) {
- if (PIM_DEBUG_PIM_TRACE) {
- char source_str[100];
- char group_str[100];
- char dst_str[100];
- pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
- pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
+ if (PIM_DEBUG_PIM_J_P) {
+ char dst_str[INET_ADDRSTRLEN];
pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
- zlog_debug("%s: %s(S,G)=(%s,%s): upstream=%s is myself on interface %s",
+ zlog_debug("%s: %s(S,G)=%s: upstream=%s is myself on interface %s",
__PRETTY_FUNCTION__,
send_join ? "Join" : "Prune",
- source_str, group_str, dst_str, ifp->name);
+ up->sg_str, dst_str, ifp->name);
}
return 0;
}
@@ -335,83 +360,14 @@ int pim_joinprune_send(struct interface *ifp,
/*
Build PIM message
*/
+ pim_msg_size = pim_msg_join_prune_encode (pim_msg, 9000, send_join,
+ up, upstream_addr, PIM_JP_HOLDTIME);
- remain = pastend - pim_msg_curr;
- pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr,
- remain,
- upstream_addr);
- if (!pim_msg_curr) {
- char dst_str[100];
- pim_inet4_dump("<dst?>", upstream_addr, dst_str, sizeof(dst_str));
- zlog_warn("%s: failure encoding destination address %s: space left=%d",
- __PRETTY_FUNCTION__, dst_str, remain);
- return -3;
- }
-
- remain = pastend - pim_msg_curr;
- if (remain < 4) {
- zlog_warn("%s: group will not fit: space left=%d",
- __PRETTY_FUNCTION__, remain);
- return -4;
- }
-
- *pim_msg_curr = 0; /* reserved */
- ++pim_msg_curr;
- *pim_msg_curr = 1; /* number of groups */
- ++pim_msg_curr;
- *((uint16_t *) pim_msg_curr) = htons(PIM_JP_HOLDTIME);
- ++pim_msg_curr;
- ++pim_msg_curr;
-
- remain = pastend - pim_msg_curr;
- pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr,
- remain,
- group_addr);
- if (!pim_msg_curr) {
- char group_str[100];
- pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
- zlog_warn("%s: failure encoding group address %s: space left=%d",
- __PRETTY_FUNCTION__, group_str, remain);
- return -5;
- }
-
- remain = pastend - pim_msg_curr;
- if (remain < 4) {
- zlog_warn("%s: sources will not fit: space left=%d",
- __PRETTY_FUNCTION__, remain);
- return -6;
- }
-
- /* number of joined sources */
- *((uint16_t *) pim_msg_curr) = htons(send_join ? 1 : 0);
- ++pim_msg_curr;
- ++pim_msg_curr;
-
- /* number of pruned sources */
- *((uint16_t *) pim_msg_curr) = htons(send_join ? 0 : 1);
- ++pim_msg_curr;
- ++pim_msg_curr;
-
- remain = pastend - pim_msg_curr;
- pim_msg_curr = pim_msg_addr_encode_ipv4_source(pim_msg_curr,
- remain,
- source_addr);
- if (!pim_msg_curr) {
- char source_str[100];
- pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
- zlog_warn("%s: failure encoding source address %s: space left=%d",
- __PRETTY_FUNCTION__, source_str, remain);
- return -7;
- }
-
- /* Add PIM header */
-
- pim_msg_size = pim_msg_curr - pim_msg;
-
- pim_msg_build_header(pim_msg, pim_msg_size,
- PIM_MSG_TYPE_JOIN_PRUNE);
+ if (pim_msg_size < 0)
+ return pim_msg_size;
if (pim_msg_send(pim_ifp->pim_sock_fd,
+ pim_ifp->primary_address,
qpim_all_pim_routers_addr,
pim_msg,
pim_msg_size,
diff --git a/pimd/pim_join.h b/pimd/pim_join.h
index dcdca00359..1eeeef756f 100644
--- a/pimd/pim_join.h
+++ b/pimd/pim_join.h
@@ -34,8 +34,7 @@ int pim_joinprune_recv(struct interface *ifp,
int pim_joinprune_send(struct interface *ifp,
struct in_addr upstream_addr,
- struct in_addr source_addr,
- struct in_addr group_addr,
+ struct pim_upstream *up,
int send_join);
#endif /* PIM_JOIN_H */
diff --git a/pimd/pim_macro.c b/pimd/pim_macro.c
index 622bef4439..127e0f6252 100644
--- a/pimd/pim_macro.c
+++ b/pimd/pim_macro.c
@@ -21,22 +21,39 @@
#include <zebra.h>
#include "log.h"
+#include "prefix.h"
+#include "vty.h"
+#include "plist.h"
-#include "pim_macro.h"
#include "pimd.h"
-#include "pim_str.h"
+#include "pim_macro.h"
#include "pim_iface.h"
#include "pim_ifchannel.h"
+#include "pim_rp.h"
/*
DownstreamJPState(S,G,I) is the per-interface state machine for
receiving (S,G) Join/Prune messages.
- DownstreamJPState(S,G,I) is either Join or Prune-Pending ?
+ DownstreamJPState(S,G,I) is either Join or Prune-Pending
+ DownstreamJPState(*,G,I) is either Join or Prune-Pending
*/
static int downstream_jpstate_isjoined(const struct pim_ifchannel *ch)
{
- return ch->ifjoin_state != PIM_IFJOIN_NOINFO;
+ switch (ch->ifjoin_state)
+ {
+ case PIM_IFJOIN_NOINFO:
+ case PIM_IFJOIN_PRUNE:
+ case PIM_IFJOIN_PRUNE_TMP:
+ case PIM_IFJOIN_PRUNE_PENDING_TMP:
+ return 0;
+ break;
+ case PIM_IFJOIN_JOIN:
+ case PIM_IFJOIN_PRUNE_PENDING:
+ return 1;
+ break;
+ }
+ return 0;
}
/*
@@ -100,13 +117,9 @@ int pim_macro_ch_lost_assert(const struct pim_ifchannel *ch)
ifp = ch->interface;
if (!ifp) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- zlog_warn("%s: (S,G)=(%s,%s): null interface",
+ zlog_warn("%s: (S,G)=%s: null interface",
__PRETTY_FUNCTION__,
- src_str, grp_str);
+ ch->sg_str);
return 0; /* false */
}
@@ -116,13 +129,9 @@ int pim_macro_ch_lost_assert(const struct pim_ifchannel *ch)
pim_ifp = ifp->info;
if (!pim_ifp) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s",
+ zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
__PRETTY_FUNCTION__,
- src_str, grp_str, ifp->name);
+ ch->sg_str, ifp->name);
return 0; /* false */
}
@@ -157,13 +166,9 @@ int pim_macro_chisin_pim_include(const struct pim_ifchannel *ch)
struct pim_interface *pim_ifp = ch->interface->info;
if (!pim_ifp) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s",
+ zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
__PRETTY_FUNCTION__,
- src_str, grp_str, ch->interface->name);
+ ch->sg_str, ch->interface->name);
return 0; /* false */
}
@@ -225,13 +230,8 @@ int pim_macro_ch_could_assert_eval(const struct pim_ifchannel *ch)
ifp = ch->interface;
if (!ifp) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- zlog_warn("%s: (S,G)=(%s,%s): null interface",
- __PRETTY_FUNCTION__,
- src_str, grp_str);
+ zlog_warn("%s: (S,G)=%s: null interface",
+ __PRETTY_FUNCTION__, ch->sg_str);
return 0; /* false */
}
@@ -350,7 +350,7 @@ static int pim_macro_chisin_inherited_olist(const struct pim_ifchannel *ch)
*/
int pim_macro_chisin_oiflist(const struct pim_ifchannel *ch)
{
- if (ch->upstream->join_state != PIM_UPSTREAM_JOINED) {
+ if (ch->upstream->join_state == PIM_UPSTREAM_NOTJOINED) {
/* oiflist is NULL */
return 0; /* false */
}
@@ -386,25 +386,15 @@ int pim_macro_assert_tracking_desired_eval(const struct pim_ifchannel *ch)
ifp = ch->interface;
if (!ifp) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- zlog_warn("%s: (S,G)=(%s,%s): null interface",
- __PRETTY_FUNCTION__,
- src_str, grp_str);
+ zlog_warn("%s: (S,G)=%s: null interface",
+ __PRETTY_FUNCTION__, ch->sg_str);
return 0; /* false */
}
pim_ifp = ifp->info;
if (!pim_ifp) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
- zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s",
- __PRETTY_FUNCTION__,
- src_str, grp_str, ch->interface->name);
+ zlog_warn("%s: (S,G)=%s: multicast not enabled on interface %s",
+ __PRETTY_FUNCTION__, ch->sg_str, ch->interface->name);
return 0; /* false */
}
diff --git a/pimd/pim_main.c b/pimd/pim_main.c
index ed8f69b517..0749d60b05 100644
--- a/pimd/pim_main.c
+++ b/pimd/pim_main.c
@@ -43,10 +43,9 @@
#include "pim_version.h"
#include "pim_signals.h"
#include "pim_zebra.h"
-
-#ifdef PIM_ZCLIENT_DEBUG
-extern int zclient_debug;
-#endif
+#include "pim_msdp.h"
+#include "pim_iface.h"
+#include "pim_rp.h"
extern struct host host;
@@ -70,6 +69,7 @@ zebra_capabilities_t _caps_p [] =
ZCAP_NET_ADMIN,
ZCAP_SYS_ADMIN,
ZCAP_NET_RAW,
+ ZCAP_BIND,
};
/* pimd privileges to run with */
@@ -104,18 +104,9 @@ Daemon which manages PIM.\n\n\
-A, --vty_addr Set vty's bind address\n\
-P, --vty_port Set vty's port number\n\
-v, --version Print program version\n\
-"
-
-#ifdef PIM_ZCLIENT_DEBUG
-"\
--Z, --debug_zclient Enable zclient debugging\n\
-"
-#endif
-
-"\
-h, --help Display this help and exit\n\
\n\
-Report bugs to %s\n", progname, PIMD_BUG_ADDRESS);
+Report bugs to %s\n", progname, PACKAGE_BUGREPORT);
}
exit (status);
@@ -177,11 +168,6 @@ int main(int argc, char** argv, char** envp) {
print_version(progname);
exit (0);
break;
-#ifdef PIM_ZCLIENT_DEBUG
- case 'Z':
- zclient_debug = 1;
- break;
-#endif
case 'h':
usage (0);
break;
@@ -206,8 +192,12 @@ int main(int argc, char** argv, char** envp) {
vrf_init ();
access_list_init();
prefix_list_init ();
+ prefix_list_add_hook (pim_rp_prefix_list_update);
+ prefix_list_delete_hook (pim_rp_prefix_list_update);
+
pim_route_map_init ();
pim_init();
+ pim_msdp_init (master);
/*
* Initialize zclient "update" and "lookup" sockets
@@ -254,11 +244,6 @@ int main(int argc, char** argv, char** envp) {
PIM_DO_DEBUG_ZEBRA;
#endif
-#ifdef PIM_ZCLIENT_DEBUG
- zlog_notice("PIM_ZCLIENT_DEBUG: zclient debugging is supported, mode is %s (see option -Z)",
- zclient_debug ? "ON" : "OFF");
-#endif
-
#ifdef PIM_CHECK_RECV_IFINDEX_SANITY
zlog_notice("PIM_CHECK_RECV_IFINDEX_SANITY: will match sock/recv ifindex");
#ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH
diff --git a/pimd/pim_memory.c b/pimd/pim_memory.c
index 6014725020..ccd0fa81ac 100644
--- a/pimd/pim_memory.c
+++ b/pimd/pim_memory.c
@@ -39,3 +39,11 @@ DEFINE_MTYPE(PIMD, PIM_UPSTREAM, "PIM upstream (S,G) state")
DEFINE_MTYPE(PIMD, PIM_SSMPINGD, "PIM sspimgd socket")
DEFINE_MTYPE(PIMD, PIM_STATIC_ROUTE, "PIM Static Route")
DEFINE_MTYPE(PIMD, PIM_BR, "PIM Bridge Router info")
+DEFINE_MTYPE(PIMD, PIM_RP, "PIM RP info")
+DEFINE_MTYPE(PIMD, PIM_FILTER_NAME, "PIM RP filter info")
+DEFINE_MTYPE(PIMD, PIM_MSDP_PEER, "PIM MSDP peer")
+DEFINE_MTYPE(PIMD, PIM_MSDP_MG_NAME, "PIM MSDP mesh-group name")
+DEFINE_MTYPE(PIMD, PIM_MSDP_SA, "PIM MSDP source-active cache")
+DEFINE_MTYPE(PIMD, PIM_MSDP_MG, "PIM MSDP mesh group")
+DEFINE_MTYPE(PIMD, PIM_MSDP_MG_MBR, "PIM MSDP mesh group mbr")
+DEFINE_MTYPE(PIMD, PIM_SEC_ADDR, "PIM secondary address")
diff --git a/pimd/pim_memory.h b/pimd/pim_memory.h
index 81841e58b6..b6b9b23239 100644
--- a/pimd/pim_memory.h
+++ b/pimd/pim_memory.h
@@ -38,5 +38,13 @@ DECLARE_MTYPE(PIM_UPSTREAM)
DECLARE_MTYPE(PIM_SSMPINGD)
DECLARE_MTYPE(PIM_STATIC_ROUTE)
DECLARE_MTYPE(PIM_BR)
+DECLARE_MTYPE(PIM_RP)
+DECLARE_MTYPE(PIM_FILTER_NAME)
+DECLARE_MTYPE(PIM_MSDP_PEER)
+DECLARE_MTYPE(PIM_MSDP_MG_NAME)
+DECLARE_MTYPE(PIM_MSDP_SA)
+DECLARE_MTYPE(PIM_MSDP_MG)
+DECLARE_MTYPE(PIM_MSDP_MG_MBR)
+DECLARE_MTYPE(PIM_SEC_ADDR)
#endif /* _QUAGGA_PIM_MEMORY_H */
diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c
index 3fbed88800..dfd22b7022 100644
--- a/pimd/pim_mroute.c
+++ b/pimd/pim_mroute.c
@@ -23,8 +23,11 @@
#include "privs.h"
#include "if.h"
#include "prefix.h"
+#include "vty.h"
+#include "plist.h"
#include "pimd.h"
+#include "pim_rpf.h"
#include "pim_mroute.h"
#include "pim_oil.h"
#include "pim_str.h"
@@ -34,10 +37,14 @@
#include "pim_rp.h"
#include "pim_oil.h"
#include "pim_register.h"
+#include "pim_ifchannel.h"
+#include "pim_zlookup.h"
/* GLOBAL VARS */
extern struct zebra_privs_t pimd_privs;
+static struct thread *qpim_mroute_socket_reader = NULL;
+
static void mroute_read_on(void);
static int pim_mroute_set(int fd, int enable)
@@ -45,62 +52,75 @@ static int pim_mroute_set(int fd, int enable)
int err;
int opt = enable ? MRT_INIT : MRT_DONE;
socklen_t opt_len = sizeof(opt);
+ int rcvbuf = 1024 * 1024 * 8;
+ long flags;
err = setsockopt(fd, IPPROTO_IP, opt, &opt, opt_len);
if (err) {
- int e = errno;
zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
__FILE__, __PRETTY_FUNCTION__,
- fd, enable ? "MRT_INIT" : "MRT_DONE", opt, e, safe_strerror(e));
- errno = e;
+ fd, enable ? "MRT_INIT" : "MRT_DONE", opt, errno, safe_strerror(errno));
return -1;
}
-#if 0
- zlog_info("%s %s: setsockopt(fd=%d,IPPROTO_IP,MRT_INIT,opt=%d): ok",
- __FILE__, __PRETTY_FUNCTION__,
- fd, opt);
-#endif
-
- return 0;
-}
-
-static int
-pim_mroute_connected_to_source (struct interface *ifp, struct in_addr src)
-{
- struct listnode *cnode;
- struct connected *c;
- struct prefix p;
-
- p.family = AF_INET;
- p.u.prefix4 = src;
- p.prefixlen = IPV4_MAX_BITLEN;
+ 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));
+ }
- for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
+ flags = fcntl(fd, 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);
+ return -1;
+ }
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
{
- if ((c->address->family == AF_INET) &&
- prefix_match (CONNECTED_PREFIX (c), &p))
- {
- return 1;
- }
+ zlog_warn("Could not set O_NONBLOCK on socket fd:%d %d %s",
+ fd, errno, safe_strerror(errno));
+ close(fd);
+ return -1;
}
+ if (enable)
+ {
+#if defined linux
+ int upcalls = IGMPMSG_WRVIFWHOLE;
+ opt = MRT_PIM;
+
+ err = setsockopt (fd, IPPROTO_IP, opt, &upcalls, sizeof (upcalls));
+ if (err)
+ {
+ zlog_warn ("Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
+ errno, safe_strerror (errno));
+ return -1;
+ }
+#else
+ zlog_warn ("PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall");
+#endif
+ }
+
return 0;
}
-static const char *igmpmsgtype2str[IGMPMSG_WHOLEPKT + 1] = {
+static const char *igmpmsgtype2str[IGMPMSG_WRVIFWHOLE + 1] = {
"<unknown_upcall?>",
"NOCACHE",
"WRONGVIF",
- "WHOLEPKT", };
+ "WHOLEPKT",
+ "WRVIFWHOLE" };
static int
-pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg,
- const char *src_str, const char *grp_str)
+pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg)
{
struct pim_interface *pim_ifp = ifp->info;
struct pim_upstream *up;
struct pim_rpf *rpg;
+ struct prefix_sg sg;
+ struct channel_oil *oil;
rpg = RP(msg->im_dst);
/*
@@ -108,108 +128,131 @@ pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg
* the Interface type is SSM we don't need to
* do anything here
*/
- if ((rpg->rpf_addr.s_addr == INADDR_NONE) ||
+ if ((pim_rpf_addr_is_inaddr_none (rpg)) ||
(!pim_ifp) ||
(!(PIM_I_am_DR(pim_ifp))) ||
(pim_ifp->itype == PIM_INTERFACE_SSM))
- return 0;
+ {
+ if (PIM_DEBUG_MROUTE_DETAIL)
+ zlog_debug ("%s: Interface is not configured correctly to handle incoming packet: Could be !DR, !pim_ifp, !SM, !RP",
+ __PRETTY_FUNCTION__);
+ return 0;
+ }
/*
* If we've received a multicast packet that isn't connected to
* us
*/
- if (!pim_mroute_connected_to_source (ifp, msg->im_src))
+ if (!pim_if_connected_to_source (ifp, msg->im_src))
{
- if (PIM_DEBUG_PIM_TRACE)
- zlog_debug ("%s: Received incoming packet that does originate on our seg",
+ if (PIM_DEBUG_MROUTE_DETAIL)
+ zlog_debug ("%s: Received incoming packet that doesn't originate on our seg",
__PRETTY_FUNCTION__);
return 0;
}
- if (PIM_DEBUG_PIM_TRACE) {
- zlog_debug("%s: Adding a Route for %s from %s for WHOLEPKT consumption",
- __PRETTY_FUNCTION__, grp_str, src_str);
- }
+ memset (&sg, 0, sizeof (struct prefix_sg));
+ sg.src = msg->im_src;
+ sg.grp = msg->im_dst;
- up = pim_upstream_add(msg->im_src, msg->im_dst, ifp);
- if (!up) {
- if (PIM_DEBUG_PIM_TRACE) {
- zlog_debug("%s: Failure to add upstream information for (%s,%s)",
+ oil = pim_channel_oil_add (&sg, pim_ifp->mroute_vif_index);
+ if (!oil) {
+ if (PIM_DEBUG_MROUTE) {
+ zlog_debug("%s: Failure to add channel oil for %s",
__PRETTY_FUNCTION__,
- src_str, grp_str);
+ pim_str_sg_dump (&sg));
}
return 0;
}
- pim_upstream_keep_alive_timer_start (up, PIM_KEEPALIVE_PERIOD);
-
- up->channel_oil = pim_channel_oil_add(msg->im_dst,
- msg->im_src,
- pim_ifp->mroute_vif_index);
- if (!up->channel_oil) {
- if (PIM_DEBUG_PIM_TRACE) {
- zlog_debug("%s: Failure to add channel oil for (%s,%s)",
+ up = pim_upstream_add (&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR, __PRETTY_FUNCTION__);
+ if (!up) {
+ if (PIM_DEBUG_MROUTE) {
+ zlog_debug("%s: Failure to add upstream information for %s",
__PRETTY_FUNCTION__,
- src_str, grp_str);
+ pim_str_sg_dump (&sg));
}
return 0;
}
- up->channel_oil->cc.pktcnt++;
- pim_channel_add_oif(up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_SOURCE);
+ /*
+ * I moved this debug till after the actual add because
+ * I want to take advantage of the up->sg_str being filled in.
+ */
+ if (PIM_DEBUG_MROUTE) {
+ zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
+ __PRETTY_FUNCTION__, up->sg_str);
+ }
+
+ PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
+ pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
+
+ up->channel_oil = oil;
+ up->channel_oil->cc.pktcnt++;
+ PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
+ pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
+ up->join_state = PIM_UPSTREAM_JOINED;
return 0;
}
static int
-pim_mroute_msg_wholepkt (int fd, struct interface *ifp, const char *buf,
- const char *src_str, const char *grp_str)
+pim_mroute_msg_wholepkt (int fd, struct interface *ifp, const char *buf)
{
struct pim_interface *pim_ifp;
- struct in_addr group;
- struct in_addr src;
+ struct prefix_sg sg;
struct pim_rpf *rpg;
const struct ip *ip_hdr;
struct pim_upstream *up;
ip_hdr = (const struct ip *)buf;
- src = ip_hdr->ip_src;
- group = ip_hdr->ip_dst;
+ memset (&sg, 0, sizeof (struct prefix_sg));
+ sg.src = ip_hdr->ip_src;
+ sg.grp = ip_hdr->ip_dst;
- up = pim_upstream_find(src, group);
+ up = pim_upstream_find(&sg);
if (!up) {
- if (PIM_DEBUG_PIM_TRACE) {
- zlog_debug("%s: Unable to find upstream channel WHOLEPKT(%s,%s)",
- __PRETTY_FUNCTION__, src_str, grp_str);
+ if (PIM_DEBUG_MROUTE_DETAIL) {
+ zlog_debug("%s: Unable to find upstream channel WHOLEPKT%s",
+ __PRETTY_FUNCTION__, pim_str_sg_dump (&sg));
}
return 0;
}
pim_ifp = up->rpf.source_nexthop.interface->info;
- rpg = RP(group);
+ rpg = RP(sg.grp);
- if ((rpg->rpf_addr.s_addr == INADDR_NONE) ||
+ if ((pim_rpf_addr_is_inaddr_none (rpg)) ||
(!pim_ifp) ||
(!(PIM_I_am_DR(pim_ifp))) ||
(pim_ifp->itype == PIM_INTERFACE_SSM)) {
- if (PIM_DEBUG_PIM_TRACE) {
+ if (PIM_DEBUG_MROUTE) {
zlog_debug("%s: Failed Check send packet", __PRETTY_FUNCTION__);
}
return 0;
}
- pim_register_send((const struct ip *)(buf + sizeof(struct ip)), rpg);
+ /*
+ * If we've received a register suppress
+ */
+ if (!up->t_rs_timer)
+ pim_register_send((uint8_t *)buf + sizeof(struct ip), ntohs (ip_hdr->ip_len),
+ pim_ifp->primary_address, rpg, 0, up);
return 0;
}
static int
-pim_mroute_msg_wrongvif (int fd, struct interface *ifp, const struct igmpmsg *msg,
- const char *src_str, const char *grp_str)
+pim_mroute_msg_wrongvif (int fd, struct interface *ifp, const struct igmpmsg *msg)
{
struct pim_ifchannel *ch;
struct pim_interface *pim_ifp;
+ struct prefix_sg sg;
+
+ memset (&sg, 0, sizeof (struct prefix_sg));
+ sg.src = msg->im_src;
+ sg.grp = msg->im_dst;
/*
Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
@@ -223,32 +266,39 @@ pim_mroute_msg_wrongvif (int fd, struct interface *ifp, const struct igmpmsg *ms
*/
if (!ifp) {
- if (PIM_DEBUG_PIM_TRACE) {
- zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) could not find input interface for input_vif_index=%d",
+ if (PIM_DEBUG_MROUTE)
+ zlog_debug("%s: WRONGVIF (S,G)=%s could not find input interface for input_vif_index=%d",
__PRETTY_FUNCTION__,
- src_str, grp_str, msg->im_vif);
- }
+ pim_str_sg_dump (&sg), msg->im_vif);
return -1;
}
pim_ifp = ifp->info;
if (!pim_ifp) {
- if (PIM_DEBUG_PIM_TRACE) {
- zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) multicast not enabled on interface %s",
+ if (PIM_DEBUG_MROUTE)
+ zlog_debug("%s: WRONGVIF (S,G)=%s multicast not enabled on interface %s",
__PRETTY_FUNCTION__,
- src_str, grp_str, ifp->name);
- }
+ pim_str_sg_dump (&sg), ifp->name);
return -2;
}
- ch = pim_ifchannel_find(ifp, msg->im_src, msg->im_dst);
+ ch = pim_ifchannel_find(ifp, &sg);
if (!ch) {
- if (PIM_DEBUG_PIM_TRACE) {
- zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) could not find channel on interface %s",
+ struct prefix_sg star_g = sg;
+ if (PIM_DEBUG_MROUTE)
+ zlog_debug("%s: WRONGVIF (S,G)=%s could not find channel on interface %s",
__PRETTY_FUNCTION__,
- src_str, grp_str, ifp->name);
+ pim_str_sg_dump(&sg), ifp->name);
+
+ star_g.src.s_addr = INADDR_ANY;
+ ch = pim_ifchannel_find(ifp, &star_g);
+ if (!ch) {
+ if (PIM_DEBUG_MROUTE)
+ zlog_debug("%s: WRONGVIF (*,G)=%s could not find channel on interface %s",
+ __PRETTY_FUNCTION__,
+ pim_str_sg_dump(&star_g), ifp->name);
+ return -3;
}
- return -3;
}
/*
@@ -266,28 +316,28 @@ pim_mroute_msg_wrongvif (int fd, struct interface *ifp, const struct igmpmsg *ms
*/
if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
- if (PIM_DEBUG_PIM_TRACE) {
- zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) channel is not on Assert NoInfo state for interface %s",
+ if (PIM_DEBUG_MROUTE) {
+ zlog_debug("%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
__PRETTY_FUNCTION__,
- src_str, grp_str, ifp->name);
+ ch->sg_str, ifp->name);
}
return -4;
}
if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
- if (PIM_DEBUG_PIM_TRACE) {
- zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) interface %s is not downstream for channel",
+ if (PIM_DEBUG_MROUTE) {
+ zlog_debug("%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
__PRETTY_FUNCTION__,
- src_str, grp_str, ifp->name);
+ ch->sg_str, ifp->name);
}
return -5;
}
if (assert_action_a1(ch)) {
- if (PIM_DEBUG_PIM_TRACE) {
- zlog_debug("%s: WRONGVIF (S,G)=(%s,%s) assert_action_a1 failure on interface %s",
+ if (PIM_DEBUG_MROUTE) {
+ zlog_debug("%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
__PRETTY_FUNCTION__,
- src_str, grp_str, ifp->name);
+ ch->sg_str, ifp->name);
}
return -6;
}
@@ -295,107 +345,250 @@ pim_mroute_msg_wrongvif (int fd, struct interface *ifp, const struct igmpmsg *ms
return 0;
}
+static int
+pim_mroute_msg_wrvifwhole (int fd, struct interface *ifp, const char *buf)
+{
+ const struct ip *ip_hdr = (const struct ip *)buf;
+ struct pim_interface *pim_ifp;
+ struct pim_ifchannel *ch;
+ struct pim_upstream *up;
+ //struct prefix_sg star_g;
+ struct prefix_sg sg;
+ struct channel_oil *oil;
+
+ memset (&sg, 0, sizeof (struct prefix_sg));
+ sg.src = ip_hdr->ip_src;
+ sg.grp = ip_hdr->ip_dst;
+
+ ch = pim_ifchannel_find(ifp, &sg);
+ if (ch)
+ {
+ if (PIM_DEBUG_MROUTE)
+ zlog_debug ("WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
+ ch->sg_str, ifp->name);
+ return -1;
+ }
+#if 0
+ star_g = sg;
+ star_g.src.s_addr = INADDR_ANY;
+ ch = pim_ifchannel_find(ifp, &star_g);
+ if (ch)
+ {
+ if (PIM_DEBUG_MROUTE)
+ zlog_debug ("WRVIFWHOLE (*,G)=%s found ifchannel on interface %s",
+ pim_str_sg_dump (&star_g), ifp->name);
+ return -1;
+ }
+#endif
+
+ up = pim_upstream_find (&sg);
+ if (up)
+ {
+ struct pim_nexthop source;
+ struct pim_rpf *rpf = RP (sg.grp);
+ if (!rpf || !rpf->source_nexthop.interface)
+ return 0;
+
+ pim_ifp = rpf->source_nexthop.interface->info;
+
+ memset (&source, 0, sizeof (source));
+ /*
+ * If we are the fhr that means we are getting a callback during
+ * the pimreg period, so I believe we can ignore this packet
+ */
+ 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)
+ pim_register_stop_send(source.interface, &sg, pim_ifp->primary_address, up->upstream_register);
+ if (!up->channel_oil)
+ up->channel_oil = pim_channel_oil_add (&sg, pim_ifp->mroute_vif_index);
+ pim_upstream_inherited_olist (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, 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;
+ }
+ pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
+ pim_upstream_inherited_olist (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);
+ 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__);
+ if (!up)
+ {
+ if (PIM_DEBUG_MROUTE)
+ zlog_debug ("%s: WRONGVIF%s unable to create upstream on interface",
+ pim_str_sg_dump (&sg), ifp->name);
+ return -2;
+ }
+ PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
+ pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
+ up->channel_oil = oil;
+ up->channel_oil->cc.pktcnt++;
+ pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
+ up->join_state = PIM_UPSTREAM_JOINED;
+ pim_upstream_inherited_olist (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)
{
struct interface *ifp;
+ struct pim_interface *pim_ifp;
const struct ip *ip_hdr;
const struct igmpmsg *msg;
- char src_str[100] = "<src?>";
- char grp_str[100] = "<grp?>";
+ char ip_src_str[INET_ADDRSTRLEN] = "";
+ char ip_dst_str[INET_ADDRSTRLEN] = "";
+ char src_str[INET_ADDRSTRLEN] = "<src?>";
+ char grp_str[INET_ADDRSTRLEN] = "<grp?>";
+ struct in_addr ifaddr;
+ struct igmp_sock *igmp;
ip_hdr = (const struct ip *) buf;
- /* kernel upcall must have protocol=0 */
- if (ip_hdr->ip_p) {
- /* this is not a kernel upcall */
- if (PIM_DEBUG_PIM_TRACE) {
- pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", ip_hdr->ip_dst, grp_str, sizeof(grp_str));
- zlog_debug("%s: not a kernel upcall proto=%d src: %s dst: %s msg_size=%d",
- __PRETTY_FUNCTION__, ip_hdr->ip_p, src_str, grp_str, buf_size);
+ if (ip_hdr->ip_p == IPPROTO_IGMP) {
+
+ /* We have the IP packet but we do not know which interface this packet was
+ * received on. Find the interface that is on the same subnet as 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));
+
+ zlog_warn("%s: igmp kernel upcall could not find usable interface for %s -> %s",
+ __PRETTY_FUNCTION__,
+ ip_src_str,
+ ip_dst_str);
+ }
+ return 0;
}
- return 0;
- }
+ pim_ifp = ifp->info;
+ ifaddr = pim_find_primary_addr(ifp);
+ igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list, ifaddr);
- msg = (const struct igmpmsg *) buf;
-
- ifp = pim_if_find_by_vif_index(msg->im_vif);
-
- if (PIM_DEBUG_PIM_TRACE) {
- pim_inet4_dump("<src?>", msg->im_src, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", msg->im_dst, grp_str, sizeof(grp_str));
- zlog_warn("%s: kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d",
- __PRETTY_FUNCTION__,
- igmpmsgtype2str[msg->im_msgtype],
- msg->im_msgtype,
- ip_hdr->ip_p,
- fd,
- src_str,
- grp_str,
- ifp ? ifp->name : "<ifname?>",
- msg->im_vif);
- }
+ if (PIM_DEBUG_MROUTE) {
+ 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));
- switch (msg->im_msgtype) {
- case IGMPMSG_WRONGVIF:
- return pim_mroute_msg_wrongvif(fd, ifp, msg, src_str, grp_str);
- break;
- case IGMPMSG_NOCACHE:
- return pim_mroute_msg_nocache(fd, ifp, msg, src_str, grp_str);
- break;
- case IGMPMSG_WHOLEPKT:
- return pim_mroute_msg_wholepkt(fd, ifp, (const char *)msg, src_str, grp_str);
- break;
- default:
- break;
- }
+ zlog_warn("%s: igmp kernel upcall on %s(%p) for %s -> %s",
+ __PRETTY_FUNCTION__, ifp->name, igmp, ip_src_str, ip_dst_str);
+ }
+ if (igmp)
+ pim_igmp_packet(igmp, (char *)buf, buf_size);
- return 0;
-}
+ } else if (ip_hdr->ip_p) {
+ if (PIM_DEBUG_MROUTE_DETAIL) {
+ pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str, sizeof(src_str));
+ pim_inet4_dump("<grp?>", ip_hdr->ip_dst, grp_str, sizeof(grp_str));
+ zlog_debug("%s: no kernel upcall proto=%d src: %s dst: %s msg_size=%d",
+ __PRETTY_FUNCTION__, ip_hdr->ip_p, src_str, grp_str, buf_size);
+ }
-static int mroute_read_msg(int fd)
-{
- const int msg_min_size = MAX(sizeof(struct ip), sizeof(struct igmpmsg));
- char buf[1000];
- int rd;
+ } else {
+ msg = (const struct igmpmsg *) buf;
- if (((int) sizeof(buf)) < msg_min_size) {
- zlog_err("%s: fd=%d: buf size=%zu lower than msg_min=%d",
- __PRETTY_FUNCTION__, fd, sizeof(buf), msg_min_size);
- return -1;
- }
+ ifp = pim_if_find_by_vif_index(msg->im_vif);
- rd = read(fd, buf, sizeof(buf));
- if (rd < 0) {
- zlog_warn("%s: failure reading fd=%d: errno=%d: %s",
- __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno));
- return -2;
- }
+ if (!ifp)
+ return 0;
+ if (PIM_DEBUG_MROUTE) {
+ pim_inet4_dump("<src?>", msg->im_src, src_str, sizeof(src_str));
+ pim_inet4_dump("<grp?>", msg->im_dst, grp_str, sizeof(grp_str));
+ zlog_warn("%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);
+ }
- if (rd < msg_min_size) {
- zlog_warn("%s: short message reading fd=%d: read=%d msg_min=%d",
- __PRETTY_FUNCTION__, fd, rd, msg_min_size);
- return -3;
+ switch (msg->im_msgtype) {
+ case IGMPMSG_WRONGVIF:
+ return pim_mroute_msg_wrongvif(fd, ifp, msg);
+ break;
+ case IGMPMSG_NOCACHE:
+ return pim_mroute_msg_nocache(fd, ifp, msg);
+ break;
+ case IGMPMSG_WHOLEPKT:
+ return pim_mroute_msg_wholepkt(fd, ifp, (const char *)msg);
+ break;
+ case IGMPMSG_WRVIFWHOLE:
+ return pim_mroute_msg_wrvifwhole (fd, ifp, (const char *)msg);
+ break;
+ default:
+ break;
+ }
}
- return pim_mroute_msg(fd, buf, rd);
+ return 0;
}
static int mroute_read(struct thread *t)
{
+ static long long count;
+ char buf[10000];
+ int result = 0;
+ int cont = 1;
int fd;
- int result;
-
- zassert(t);
- zassert(!THREAD_ARG(t));
+ int rd;
fd = THREAD_FD(t);
- zassert(fd == qpim_mroute_socket_fd);
-
- result = mroute_read_msg(fd);
+ while (cont)
+ {
+ rd = read(fd, buf, sizeof(buf));
+ if (rd < 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
+ {
+ cont = 0;
+ break;
+ }
+ if (PIM_DEBUG_MROUTE)
+ zlog_warn("%s: failure reading fd=%d: errno=%d: %s",
+ __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno));
+ goto done;
+ }
+
+ result = pim_mroute_msg(fd, buf, rd);
+
+ count++;
+ if (count % qpim_packet_process == 0)
+ cont = 0;
+ }
/* Keep reading */
- qpim_mroute_socket_reader = 0;
+ done:
+ qpim_mroute_socket_reader = NULL;
mroute_read_on();
return result;
@@ -450,8 +643,6 @@ int pim_mroute_socket_enable()
qpim_mroute_socket_creation = pim_time_monotonic_sec();
mroute_read_on();
- zassert(PIM_MROUTE_IS_ENABLED);
-
return 0;
}
@@ -475,8 +666,6 @@ int pim_mroute_socket_disable()
mroute_read_off();
qpim_mroute_socket_fd = -1;
- zassert(PIM_MROUTE_IS_DISABLED);
-
return 0;
}
@@ -521,16 +710,14 @@ int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr, unsigned ch
err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_VIF, (void*) &vc, sizeof(vc));
if (err) {
- char ifaddr_str[100];
- int e = errno;
+ char ifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", ifaddr, ifaddr_str, 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,
- e, safe_strerror(e));
- errno = e;
+ errno, safe_strerror(errno));
return -2;
}
@@ -553,22 +740,21 @@ int pim_mroute_del_vif(int vif_index)
err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_VIF, (void*) &vc, sizeof(vc));
if (err) {
- int e = errno;
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,
- e, safe_strerror(e));
- errno = e;
+ errno, safe_strerror(errno));
return -2;
}
return 0;
}
-int pim_mroute_add(struct channel_oil *c_oil)
+int pim_mroute_add(struct channel_oil *c_oil, const char *name)
{
int err;
int orig = 0;
+ int orig_iif_vif = 0;
qpim_mroute_add_last = pim_time_monotonic_sec();
++qpim_mroute_add_events;
@@ -589,27 +775,57 @@ int pim_mroute_add(struct channel_oil *c_oil)
c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = 1;
}
+ /*
+ * If we have an unresolved cache entry for the S,G
+ * it is owned by the pimreg for the incoming IIF
+ * So set pimreg as the IIF temporarily to cause
+ * the packets to be forwarded. Then set it
+ * to the correct IIF afterwords.
+ */
+ if (!c_oil->installed && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY &&
+ c_oil->oil.mfcc_parent != 0)
+ {
+ 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,
&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,
+ &c_oil->oil, sizeof (c_oil->oil));
+ }
+
if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = orig;
if (err) {
- int e = errno;
zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
__FILE__, __PRETTY_FUNCTION__,
qpim_mroute_socket_fd,
- e, safe_strerror(e));
- errno = e;
+ errno, safe_strerror(errno));
return -2;
}
+ if (PIM_DEBUG_MROUTE)
+ {
+ struct prefix_sg sg;
+
+ sg.src = c_oil->oil.mfcc_origin;
+ sg.grp = c_oil->oil.mfcc_mcastgrp;
+
+ zlog_debug("%s(%s), Added Route: %s to mroute table",
+ __PRETTY_FUNCTION__, name, pim_str_sg_dump(&sg));
+ }
+
c_oil->installed = 1;
return 0;
}
-int pim_mroute_del (struct channel_oil *c_oil)
+int pim_mroute_del (struct channel_oil *c_oil, const char *name)
{
int err;
@@ -624,15 +840,24 @@ int pim_mroute_del (struct channel_oil *c_oil)
err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_MFC, &c_oil->oil, sizeof(c_oil->oil));
if (err) {
- int e = errno;
- zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
- __FILE__, __PRETTY_FUNCTION__,
- qpim_mroute_socket_fd,
- e, safe_strerror(e));
- errno = e;
+ 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, safe_strerror(errno));
return -2;
}
+ if (PIM_DEBUG_MROUTE)
+ {
+ struct prefix_sg sg;
+
+ sg.src = c_oil->oil.mfcc_origin;
+ sg.grp = c_oil->oil.mfcc_mcastgrp;
+
+ zlog_debug("%s(%s), Deleted Route: %s from mroute table",
+ __PRETTY_FUNCTION__, name, pim_str_sg_dump(&sg));
+ }
c_oil->installed = 0;
return 0;
@@ -643,28 +868,46 @@ pim_mroute_update_counters (struct channel_oil *c_oil)
{
struct sioc_sg_req sgreq;
- memset (&sgreq, 0, sizeof(sgreq));
- sgreq.src = c_oil->oil.mfcc_origin;
- sgreq.grp = c_oil->oil.mfcc_mcastgrp;
-
c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
+ if (!c_oil->installed)
+ {
+ c_oil->cc.lastused = 100 * qpim_keep_alive_time;
+ if (PIM_DEBUG_MROUTE)
+ {
+ struct prefix_sg sg;
+
+ sg.src = c_oil->oil.mfcc_origin;
+ sg.grp = c_oil->oil.mfcc_mcastgrp;
+ if (PIM_DEBUG_MROUTE)
+ zlog_debug("Channel(%s) is not installed no need to collect data from kernel",
+ pim_str_sg_dump (&sg));
+ }
+ return;
+ }
+
+ memset (&sgreq, 0, sizeof(sgreq));
+ sgreq.src = c_oil->oil.mfcc_origin;
+ sgreq.grp = c_oil->oil.mfcc_mcastgrp;
+
+ pim_zlookup_sg_statistics (c_oil);
if (ioctl (qpim_mroute_socket_fd, SIOCGETSGCNT, &sgreq))
{
- char group_str[100];
- char source_str[100];
-
- pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
-
- zlog_warn ("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s,%s): errno=%d: %s",
- (unsigned long)SIOCGETSGCNT,
- source_str,
- group_str,
- errno,
- safe_strerror(errno));
+ if (PIM_DEBUG_MROUTE)
+ {
+ struct prefix_sg sg;
+
+ sg.src = c_oil->oil.mfcc_origin;
+ sg.grp = c_oil->oil.mfcc_mcastgrp;
+
+ zlog_warn ("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s): errno=%d: %s",
+ (unsigned long)SIOCGETSGCNT,
+ pim_str_sg_dump (&sg),
+ errno,
+ safe_strerror(errno));
+ }
return;
}
diff --git a/pimd/pim_mroute.h b/pimd/pim_mroute.h
index f385ce09f4..3c15c800da 100644
--- a/pimd/pim_mroute.h
+++ b/pimd/pim_mroute.h
@@ -157,6 +157,10 @@ struct igmpmsg
#endif
#endif
+#ifndef IGMPMSG_WRVIFWHOLE
+#define IGMPMSG_WRVIFWHOLE 4 /* For PIM processing */
+#endif
+
/*
Above: from <linux/mroute.h>
*/
@@ -167,8 +171,8 @@ int pim_mroute_socket_disable(void);
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_add(struct channel_oil *c_oil);
-int pim_mroute_del(struct channel_oil *c_oil);
+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);
diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c
new file mode 100644
index 0000000000..93141f39de
--- /dev/null
+++ b/pimd/pim_msdp.c
@@ -0,0 +1,1606 @@
+/*
+ * IP MSDP for Quagga
+ * Copyright (C) 2016 Cumulus 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 <lib/hash.h>
+#include <lib/jhash.h>
+#include <lib/log.h>
+#include <lib/prefix.h>
+#include <lib/sockunion.h>
+#include <lib/stream.h>
+#include <lib/thread.h>
+#include <lib/vty.h>
+#include <lib/plist.h>
+
+#include "pimd.h"
+#include "pim_cmd.h"
+#include "pim_memory.h"
+#include "pim_iface.h"
+#include "pim_rp.h"
+#include "pim_str.h"
+#include "pim_time.h"
+#include "pim_upstream.h"
+
+#include "pim_msdp.h"
+#include "pim_msdp_packet.h"
+#include "pim_msdp_socket.h"
+
+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_ka_timer_setup(struct pim_msdp_peer *mp, bool start);
+static void pim_msdp_peer_hold_timer_setup(struct pim_msdp_peer *mp, bool start);
+static void pim_msdp_peer_free(struct pim_msdp_peer *mp);
+static void pim_msdp_enable(void);
+static void pim_msdp_sa_adv_timer_setup(bool start);
+static void pim_msdp_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);
+static void pim_msdp_mg_mbr_free(struct pim_msdp_mg_mbr *mbr);
+static void pim_msdp_mg_mbr_do_del(struct pim_msdp_mg *mg, struct pim_msdp_mg_mbr *mbr);
+
+/************************ SA cache management ******************************/
+static void
+pim_msdp_sa_timer_expiry_log(struct pim_msdp_sa *sa, const char *timer_str)
+{
+ zlog_debug("MSDP SA %s %s timer expired", sa->sg_str, timer_str);
+}
+
+/* RFC-3618:Sec-5.1 - global active source advertisement timer */
+static int
+pim_msdp_sa_adv_timer_cb(struct thread *t)
+{
+ msdp->sa_adv_timer = NULL;
+ 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();
+ return 0;
+}
+static void
+pim_msdp_sa_adv_timer_setup(bool start)
+{
+ THREAD_OFF(msdp->sa_adv_timer);
+ if (start) {
+ THREAD_TIMER_ON(msdp->master, msdp->sa_adv_timer,
+ pim_msdp_sa_adv_timer_cb, NULL, PIM_MSDP_SA_ADVERTISMENT_TIME);
+ }
+}
+
+/* RFC-3618:Sec-5.3 - SA cache state timer */
+static int
+pim_msdp_sa_state_timer_cb(struct thread *t)
+{
+ struct pim_msdp_sa *sa;
+
+ sa = THREAD_ARG(t);
+ sa->sa_state_timer = NULL;
+
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ pim_msdp_sa_timer_expiry_log(sa, "state");
+ }
+
+ pim_msdp_sa_deref(sa, PIM_MSDP_SAF_PEER);
+ return 0;
+}
+static void
+pim_msdp_sa_state_timer_setup(struct pim_msdp_sa *sa, bool start)
+{
+ THREAD_OFF(sa->sa_state_timer);
+ if (start) {
+ THREAD_TIMER_ON(msdp->master, sa->sa_state_timer,
+ pim_msdp_sa_state_timer_cb, sa, PIM_MSDP_SA_HOLD_TIME);
+ }
+}
+
+static void
+pim_msdp_sa_upstream_del(struct pim_msdp_sa *sa)
+{
+ struct pim_upstream *up = sa->up;
+ if (!up) {
+ return;
+ }
+
+ sa->up = NULL;
+ 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__);
+ sa->flags &= ~PIM_MSDP_SAF_UP_DEL_IN_PROG;
+ }
+
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ zlog_debug("MSDP SA %s de-referenced SPT", sa->sg_str);
+ }
+}
+
+static bool
+pim_msdp_sa_upstream_add_ok(struct pim_msdp_sa *sa, struct pim_upstream *xg_up)
+{
+ if (!(sa->flags & PIM_MSDP_SAF_PEER)) {
+ /* SA should have been rxed from a peer */
+ return false;
+ }
+ /* check if we are RP */
+ if (!I_am_RP(sa->sg.grp)) {
+ return false;
+ }
+
+ /* check if we have a (*, G) with a non-empty immediate OIL */
+ if (!xg_up) {
+ struct prefix_sg sg;
+
+ memset(&sg, 0, sizeof(sg));
+ sg.grp = sa->sg.grp;
+
+ xg_up = pim_upstream_find(&sg);
+ }
+ if (!xg_up || (xg_up->join_state != PIM_UPSTREAM_JOINED)) {
+ /* join desired will be true for such (*, G) entries so we will
+ * just look at join_state and let the PIM state machine do the rest of
+ * the magic */
+ return false;
+ }
+
+ return true;
+}
+
+/* Upstream add evaluation needs to happen everytime -
+ * 1. Peer reference is added or removed.
+ * 2. The RP for a group changes.
+ * 3. joinDesired for the associated (*, G) changes
+ * 4. associated (*, G) is removed - this seems like a bit redundant
+ * (considering #4); but just in case an entry gets nuked without
+ * upstream state transition
+ * */
+static void
+pim_msdp_sa_upstream_update(struct pim_msdp_sa *sa,
+ struct pim_upstream *xg_up, const char *ctx)
+{
+ struct pim_upstream *up;
+
+ if (!pim_msdp_sa_upstream_add_ok(sa, xg_up)) {
+ pim_msdp_sa_upstream_del(sa);
+ return;
+ }
+
+ if (sa->up) {
+ /* nothing to do */
+ return;
+ }
+
+ up = pim_upstream_find(&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;
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ zlog_debug("MSDP SA %s SPT reference missing", sa->sg_str);
+ }
+ return;
+ }
+
+ /* 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 */,
+ PIM_UPSTREAM_FLAG_MASK_SRC_MSDP,
+ __PRETTY_FUNCTION__);
+
+ sa->up = up;
+ if (up) {
+ /* update inherited oil */
+ pim_upstream_inherited_olist(up);
+ /* should we also start the kat in parallel? we will need it when the
+ * SA ages out */
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ zlog_debug("MSDP SA %s referenced SPT", sa->sg_str);
+ }
+ } else {
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ zlog_debug("MSDP SA %s SPT reference failed", sa->sg_str);
+ }
+ }
+}
+
+/* release all mem associated with a sa */
+static void
+pim_msdp_sa_free(struct pim_msdp_sa *sa)
+{
+ XFREE(MTYPE_PIM_MSDP_SA, sa);
+}
+
+static struct pim_msdp_sa *
+pim_msdp_sa_new(struct prefix_sg *sg, struct in_addr rp)
+{
+ struct pim_msdp_sa *sa;
+
+ sa = XCALLOC(MTYPE_PIM_MSDP_SA, sizeof(*sa));
+ if (!sa) {
+ zlog_err("%s: PIM XCALLOC(%zu) failure",
+ __PRETTY_FUNCTION__, sizeof(*sa));
+ return NULL;
+ }
+
+ 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);
+ 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);
+
+ 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)
+{
+ struct pim_msdp_sa lookup;
+
+ lookup.sg = *sg;
+ return hash_lookup(msdp->sa_hash, &lookup);
+}
+
+static struct pim_msdp_sa *
+pim_msdp_sa_add(struct prefix_sg *sg, struct in_addr rp)
+{
+ struct pim_msdp_sa *sa;
+
+ sa = pim_msdp_sa_find(sg);
+ if (sa) {
+ return sa;
+ }
+
+ return pim_msdp_sa_new(sg, rp);
+}
+
+static void
+pim_msdp_sa_del(struct pim_msdp_sa * sa)
+{
+ /* this is somewhat redundant - still want to be careful not to leave
+ * stale upstream references */
+ pim_msdp_sa_upstream_del(sa);
+
+ /* stop timers */
+ 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);
+
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ zlog_debug("MSDP SA %s deleted", sa->sg_str);
+ }
+
+ /* free up any associated memory */
+ pim_msdp_sa_free(sa);
+}
+
+static void
+pim_msdp_sa_peer_ip_set(struct pim_msdp_sa *sa, struct pim_msdp_peer *mp, struct in_addr rp)
+{
+ struct pim_msdp_peer *old_mp;
+
+ /* optimize the "no change" case as it will happen
+ * frequently/periodically */
+ if (mp && (sa->peer.s_addr == mp->peer.s_addr)) {
+ return;
+ }
+
+ /* 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);
+ if (old_mp && old_mp->sa_cnt) {
+ --old_mp->sa_cnt;
+ }
+ }
+
+ if (mp) {
+ ++mp->sa_cnt;
+ sa->peer = mp->peer;
+ } else {
+ sa->peer.s_addr = PIM_NET_INADDR_ANY;
+ }
+ sa->rp = rp;
+}
+
+/* When a local active-source is removed there is no way to withdraw the
+ * source from peers. We will simply remove it from the SA cache so it will
+ * not be sent in supsequent SA updates. Peers will consequently timeout the
+ * SA.
+ * Similarly a "peer-added" SA is never explicitly deleted. It is simply
+ * aged out overtime if not seen in the SA updates from the peers.
+ * XXX: should we provide a knob to drop entries learnt from a peer when the
+ * peer goes down? */
+static void
+pim_msdp_sa_deref(struct pim_msdp_sa *sa, enum pim_msdp_sa_flags flags)
+{
+ bool update_up = false;
+
+ if ((sa->flags &PIM_MSDP_SAF_LOCAL)) {
+ if (flags & PIM_MSDP_SAF_LOCAL) {
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ zlog_debug("MSDP SA %s local reference removed", sa->sg_str);
+ }
+ if (msdp->local_cnt)
+ --msdp->local_cnt;
+ }
+ }
+
+ if ((sa->flags &PIM_MSDP_SAF_PEER)) {
+ if (flags & PIM_MSDP_SAF_PEER) {
+ struct in_addr rp;
+
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ zlog_debug("MSDP SA %s peer reference removed", sa->sg_str);
+ }
+ pim_msdp_sa_state_timer_setup(sa, false /* start */);
+ rp.s_addr = INADDR_ANY;
+ pim_msdp_sa_peer_ip_set(sa, NULL /* mp */, rp);
+ /* if peer ref was removed we need to remove the msdp reference on the
+ * msdp entry */
+ update_up = true;
+ }
+ }
+
+ sa->flags &= ~flags;
+ if (update_up) {
+ pim_msdp_sa_upstream_update(sa, NULL /* xg_up */, "sa-deref");
+ }
+
+ if (!(sa->flags & PIM_MSDP_SAF_REF)) {
+ pim_msdp_sa_del(sa);
+ }
+}
+
+void
+pim_msdp_sa_ref(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);
+ if (!sa) {
+ return;
+ }
+
+ /* reference it */
+ if (mp) {
+ if (!(sa->flags & PIM_MSDP_SAF_PEER)) {
+ sa->flags |= PIM_MSDP_SAF_PEER;
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ zlog_debug("MSDP SA %s added by peer", sa->sg_str);
+ }
+ }
+ pim_msdp_sa_peer_ip_set(sa, mp, rp);
+ /* start/re-start the state timer to prevent cache expiry */
+ pim_msdp_sa_state_timer_setup(sa, true /* start */);
+ /* We re-evaluate SA "SPT-trigger" everytime we hear abt it from a
+ * peer. XXX: If this becomes too much of a periodic overhead we
+ * can make it event based */
+ pim_msdp_sa_upstream_update(sa, NULL /* xg_up */, "peer-ref");
+ } else {
+ if (!(sa->flags & PIM_MSDP_SAF_LOCAL)) {
+ sa->flags |= PIM_MSDP_SAF_LOCAL;
+ ++msdp->local_cnt;
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ zlog_debug("MSDP SA %s added locally", sa->sg_str);
+ }
+ /* send an immediate SA update to peers */
+ pim_msdp_pkt_sa_tx_one(sa);
+ }
+ sa->flags &= ~PIM_MSDP_SAF_STALE;
+ }
+}
+
+/* The following criteria must be met to originate an SA from the MSDP
+ * speaker -
+ * 1. KAT must be running i.e. source is active.
+ * 2. We must be RP for the group.
+ * 3. Source must be registrable to the RP (this is where the RFC is vague
+ * and especially ambiguous in CLOS networks; with anycast RP all sources
+ * are potentially registrable to all RPs in the domain). We assume #3 is
+ * satisfied if -
+ * a. We are also the FHR-DR for the source (OR)
+ * b. We rxed a pim register (null or data encapsulated) within the last
+ * (3 * (1.5 * register_suppression_timer))).
+ */
+static bool
+pim_msdp_sa_local_add_ok(struct pim_upstream *up)
+{
+ if (!(msdp->flags & PIM_MSDPF_ENABLE)) {
+ return false;
+ }
+
+ if (!up->t_ka_timer) {
+ /* stream is not active */
+ return false;
+ }
+
+ if (!I_am_RP(up->sg.grp)) {
+ /* we are not RP for the group */
+ return false;
+ }
+
+ /* we are the FHR-DR for this stream or we are RP and have seen registers
+ * from a FHR for this source */
+ if (PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) || up->t_msdp_reg_timer) {
+ return true;
+ }
+
+ return false;
+}
+
+static void
+pim_msdp_sa_local_add(struct prefix_sg *sg)
+{
+ struct in_addr rp;
+ rp.s_addr = 0;
+ pim_msdp_sa_ref(NULL /* mp */, sg, rp);
+}
+
+void
+pim_msdp_sa_local_del(struct prefix_sg *sg)
+{
+ struct pim_msdp_sa *sa;
+
+ sa = pim_msdp_sa_find(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)
+{
+ struct pim_msdp_sa *sa;
+
+ sa = pim_msdp_sa_find(sg);
+ if (sa) {
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP local sa %s del on up del", sa->sg_str);
+ }
+
+ /* if there is no local reference escape */
+ if (!(sa->flags & PIM_MSDP_SAF_LOCAL)) {
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP local sa %s del; no local ref", sa->sg_str);
+ }
+ return;
+ }
+
+ if (sa->flags & PIM_MSDP_SAF_UP_DEL_IN_PROG) {
+ /* MSDP is the one that triggered the upstream del. if this happens
+ * we most certainly have a bug in the PIM upstream state machine. We
+ * will not have a local reference unless the KAT is running. And if the
+ * KAT is running there MUST be an additional source-stream reference to
+ * the flow. Accounting for such cases requires lot of changes; perhaps
+ * address this in the next release? - XXX */
+ zlog_err("MSDP sa %s SPT teardown is causing the local entry to be removed", sa->sg_str);
+ return;
+ }
+
+ /* we are dropping the sa on upstream del we should not have an
+ * upstream reference */
+ if (sa->up) {
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP local sa %s del; up non-NULL", sa->sg_str);
+ }
+ sa->up = NULL;
+ }
+ pim_msdp_sa_deref(sa, PIM_MSDP_SAF_LOCAL);
+ }
+}
+
+/* Local SA qualification needs to be re-evaluated when -
+ * 1. KAT is started or stopped
+ * 2. on RP changes
+ * 3. Whenever FHR status changes for a (S,G) - XXX - currently there
+ * is no clear path to transition an entry out of "MASK_FHR" need
+ * to discuss this with Donald. May result in some strangeness if the
+ * FHR is also the RP.
+ * 4. When msdp_reg timer is started or stopped
+ */
+void
+pim_msdp_sa_local_update(struct pim_upstream *up)
+{
+ if (pim_msdp_sa_local_add_ok(up)) {
+ pim_msdp_sa_local_add(&up->sg);
+ } else {
+ pim_msdp_sa_local_del(&up->sg);
+ }
+}
+
+static void
+pim_msdp_sa_local_setup(void)
+{
+ struct pim_upstream *up;
+ struct listnode *up_node;
+
+ 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)
+{
+ struct listnode *sanode;
+ struct listnode *nextnode;
+ struct pim_msdp_sa *sa;
+
+ if (!(msdp->flags & PIM_MSDPF_ENABLE)) {
+ /* if the feature is not enabled do nothing */
+ return;
+ }
+
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP i_am_rp changed");
+ }
+
+ /* mark all local entries as stale */
+ for (ALL_LIST_ELEMENTS_RO(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();
+
+ for (ALL_LIST_ELEMENTS(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 after
+ * "local-deref" */
+ sa->flags &= ~PIM_MSDP_SAF_STALE;
+ /* sa_deref can end up freeing the sa; so don't access contents after */
+ pim_msdp_sa_deref(sa, PIM_MSDP_SAF_LOCAL);
+ } else {
+ /* if the souce is still active check if we can influence SPT */
+ pim_msdp_sa_upstream_update(sa, NULL /* xg_up */, "rp-change");
+ }
+ }
+}
+
+/* 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)
+{
+ struct listnode *sanode;
+ struct pim_msdp_sa *sa;
+
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP join state changed for %s", xg_up->sg_str);
+ }
+
+ /* If this is not really an XG entry just move on */
+ if ((xg_up->sg.src.s_addr != INADDR_ANY) ||
+ (xg_up->sg.grp.s_addr == INADDR_ANY)) {
+ return;
+ }
+
+ /* XXX: Need to maintain SAs per-group to avoid all this unnecessary
+ * walking */
+ for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) {
+ if (sa->sg.grp.s_addr != xg_up->sg.grp.s_addr) {
+ continue;
+ }
+ pim_msdp_sa_upstream_update(sa, xg_up, "up-jp-change");
+ }
+}
+
+static void
+pim_msdp_up_xg_del(struct prefix_sg *sg)
+{
+ struct listnode *sanode;
+ struct pim_msdp_sa *sa;
+
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP %s del", pim_str_sg_dump(sg));
+ }
+
+ /* If this is not really an XG entry just move on */
+ if ((sg->src.s_addr != INADDR_ANY) ||
+ (sg->grp.s_addr == INADDR_ANY)) {
+ return;
+ }
+
+ /* XXX: Need to maintain SAs per-group to avoid all this unnecessary
+ * walking */
+ for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) {
+ if (sa->sg.grp.s_addr != sg->grp.s_addr) {
+ continue;
+ }
+ pim_msdp_sa_upstream_update(sa, NULL /* xg */, "up-jp-change");
+ }
+}
+
+void
+pim_msdp_up_del(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);
+ } else {
+ pim_msdp_sa_local_del_on_up_del(sg);
+ }
+}
+
+/* sa hash and peer list helpers */
+static unsigned int
+pim_msdp_sa_hash_key_make(void *p)
+{
+ struct pim_msdp_sa *sa = p;
+
+ return (jhash_2words(sa->sg.src.s_addr, sa->sg.grp.s_addr, 0));
+}
+
+static int
+pim_msdp_sa_hash_eq(const void *p1, const void *p2)
+{
+ const struct pim_msdp_sa *sa1 = p1;
+ const struct pim_msdp_sa *sa2 = p2;
+
+ return ((sa1->sg.src.s_addr == sa2->sg.src.s_addr) &&
+ (sa1->sg.grp.s_addr == sa2->sg.grp.s_addr));
+}
+
+static int
+pim_msdp_sa_comp(const void *p1, const void *p2)
+{
+ const struct pim_msdp_sa *sa1 = p1;
+ const struct pim_msdp_sa *sa2 = p2;
+
+ if (ntohl(sa1->sg.grp.s_addr) < ntohl(sa2->sg.grp.s_addr))
+ return -1;
+
+ if (ntohl(sa1->sg.grp.s_addr) > ntohl(sa2->sg.grp.s_addr))
+ return 1;
+
+ if (ntohl(sa1->sg.src.s_addr) < ntohl(sa2->sg.src.s_addr))
+ return -1;
+
+ if (ntohl(sa1->sg.src.s_addr) > ntohl(sa2->sg.src.s_addr))
+ return 1;
+
+ return 0;
+}
+
+/* RFC-3618:Sec-10.1.3 - Peer-RPF forwarding */
+/* XXX: this can use a bit of refining and extensions */
+bool
+pim_msdp_peer_rpf_check(struct pim_msdp_peer *mp, struct in_addr rp)
+{
+ if (mp->peer.s_addr == rp.s_addr) {
+ return true;
+ }
+
+ return false;
+}
+
+/************************ Peer session management **************************/
+char *
+pim_msdp_state_dump(enum pim_msdp_peer_state state, char *buf, int buf_size)
+{
+ switch (state) {
+ case PIM_MSDP_DISABLED:
+ snprintf(buf, buf_size, "%s", "disabled");
+ break;
+ case PIM_MSDP_INACTIVE:
+ snprintf(buf, buf_size, "%s", "inactive");
+ break;
+ case PIM_MSDP_LISTEN:
+ snprintf(buf, buf_size, "%s", "listen");
+ break;
+ case PIM_MSDP_CONNECTING:
+ snprintf(buf, buf_size, "%s", "connecting");
+ break;
+ case PIM_MSDP_ESTABLISHED:
+ snprintf(buf, buf_size, "%s", "established");
+ break;
+ default:
+ snprintf(buf, buf_size, "unk-%d", state);
+ }
+ return buf;
+}
+
+char *
+pim_msdp_peer_key_dump(struct pim_msdp_peer *mp, char *buf, int buf_size, bool long_format)
+{
+ char peer_str[INET_ADDRSTRLEN];
+ char local_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<peer?>", mp->peer, peer_str, sizeof(peer_str));
+ if (long_format) {
+ pim_inet4_dump("<local?>", mp->local, local_str, sizeof(local_str));
+ snprintf(buf, buf_size, "MSDP peer %s local %s mg %s",
+ peer_str, local_str, mp->mesh_group_name);
+ } else {
+ snprintf(buf, buf_size, "MSDP peer %s", peer_str);
+ }
+
+ return buf;
+}
+
+static void
+pim_msdp_peer_state_chg_log(struct pim_msdp_peer *mp)
+{
+ char state_str[PIM_MSDP_STATE_STRLEN];
+
+ pim_msdp_state_dump(mp->state, state_str, sizeof(state_str));
+ zlog_debug("MSDP peer %s state chg to %s", mp->key_str, state_str);
+}
+
+/* MSDP Connection State Machine actions (defined in RFC-3618:Sec-11.2) */
+/* 11.2.A2: active peer - start connect retry timer; when the timer fires
+ * a tcp connection will be made */
+static void
+pim_msdp_peer_connect(struct pim_msdp_peer *mp)
+{
+ mp->state = PIM_MSDP_CONNECTING;
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ pim_msdp_peer_state_chg_log(mp);
+ }
+
+ pim_msdp_peer_cr_timer_setup(mp, true /* start */);
+}
+
+/* 11.2.A3: passive peer - just listen for connections */
+static void
+pim_msdp_peer_listen(struct pim_msdp_peer *mp)
+{
+ mp->state = PIM_MSDP_LISTEN;
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ pim_msdp_peer_state_chg_log(mp);
+ }
+
+ /* this is interntionally asymmetric i.e. we set up listen-socket when the
+ * first listening peer is configured; but don't bother tearing it down when
+ * all the peers go down */
+ pim_msdp_sock_listen();
+}
+
+/* 11.2.A4 and 11.2.A5: transition active or passive peer to
+ * established state */
+void
+pim_msdp_peer_established(struct pim_msdp_peer *mp)
+{
+ if (mp->state != PIM_MSDP_ESTABLISHED) {
+ ++mp->est_flaps;
+ }
+
+ mp->state = PIM_MSDP_ESTABLISHED;
+ mp->uptime = pim_time_monotonic_sec();
+
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ pim_msdp_peer_state_chg_log(mp);
+ }
+
+ /* stop retry timer on active peers */
+ pim_msdp_peer_cr_timer_setup(mp, false /* start */);
+
+ /* send KA; start KA and hold timers */
+ pim_msdp_pkt_ka_tx(mp);
+ pim_msdp_peer_ka_timer_setup(mp, true /* start */);
+ pim_msdp_peer_hold_timer_setup(mp, true /* start */);
+
+ pim_msdp_pkt_sa_tx_to_one_peer(mp);
+
+ PIM_MSDP_PEER_WRITE_ON(mp);
+ PIM_MSDP_PEER_READ_ON(mp);
+}
+
+/* 11.2.A6, 11.2.A7 and 11.2.A8: shutdown the peer tcp connection */
+void
+pim_msdp_peer_stop_tcp_conn(struct pim_msdp_peer *mp, bool chg_state)
+{
+ if (chg_state) {
+ if (mp->state == PIM_MSDP_ESTABLISHED) {
+ ++mp->est_flaps;
+ }
+ mp->state = PIM_MSDP_INACTIVE;
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ pim_msdp_peer_state_chg_log(mp);
+ }
+ }
+
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP peer %s pim_msdp_peer_stop_tcp_conn", mp->key_str);
+ }
+ /* stop read and write threads */
+ PIM_MSDP_PEER_READ_OFF(mp);
+ PIM_MSDP_PEER_WRITE_OFF(mp);
+
+ /* reset buffers */
+ mp->packet_size = 0;
+ if (mp->ibuf)
+ stream_reset(mp->ibuf);
+ if (mp->obuf)
+ stream_fifo_clean(mp->obuf);
+
+ /* stop all peer timers */
+ pim_msdp_peer_ka_timer_setup(mp, false /* start */);
+ pim_msdp_peer_cr_timer_setup(mp, false /* start */);
+ pim_msdp_peer_hold_timer_setup(mp, false /* start */);
+
+ /* close connection */
+ if (mp->fd >= 0) {
+ close(mp->fd);
+ mp->fd = -1;
+ }
+}
+
+/* RFC-3618:Sec-5.6 - stop the peer tcp connection and startover */
+void
+pim_msdp_peer_reset_tcp_conn(struct pim_msdp_peer *mp, const char *rc_str)
+{
+ if (PIM_DEBUG_EVENTS) {
+ zlog_debug("MSDP peer %s tcp reset %s", mp->key_str, rc_str);
+ snprintf(mp->last_reset, sizeof(mp->last_reset), "%s", rc_str);
+ }
+
+ /* close the connection and transition to listening or connecting */
+ pim_msdp_peer_stop_tcp_conn(mp, true /* chg_state */);
+ if (PIM_MSDP_PEER_IS_LISTENER(mp)) {
+ pim_msdp_peer_listen(mp);
+ } else {
+ pim_msdp_peer_connect(mp);
+ }
+}
+
+static void
+pim_msdp_peer_timer_expiry_log(struct pim_msdp_peer *mp, const char *timer_str)
+{
+ zlog_debug("MSDP peer %s %s timer expired", mp->key_str, timer_str);
+}
+
+/* RFC-3618:Sec-5.4 - peer hold timer */
+static int
+pim_msdp_peer_hold_timer_cb(struct thread *t)
+{
+ struct pim_msdp_peer *mp;
+
+ mp = THREAD_ARG(t);
+ mp->hold_timer = NULL;
+
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ pim_msdp_peer_timer_expiry_log(mp, "hold");
+ }
+
+ if (mp->state != PIM_MSDP_ESTABLISHED) {
+ return 0;
+ }
+
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ pim_msdp_peer_state_chg_log(mp);
+ }
+ 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)
+{
+ THREAD_OFF(mp->hold_timer);
+ if (start) {
+ THREAD_TIMER_ON(msdp->master, mp->hold_timer,
+ pim_msdp_peer_hold_timer_cb, mp, PIM_MSDP_PEER_HOLD_TIME);
+ }
+}
+
+
+/* RFC-3618:Sec-5.5 - peer keepalive timer */
+static int
+pim_msdp_peer_ka_timer_cb(struct thread *t)
+{
+ struct pim_msdp_peer *mp;
+
+ mp = THREAD_ARG(t);
+ mp->ka_timer = NULL;
+
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ pim_msdp_peer_timer_expiry_log(mp, "ka");
+ }
+
+ pim_msdp_pkt_ka_tx(mp);
+ pim_msdp_peer_ka_timer_setup(mp, true /* start */);
+ return 0;
+}
+static void
+pim_msdp_peer_ka_timer_setup(struct pim_msdp_peer *mp, bool start)
+{
+ THREAD_OFF(mp->ka_timer);
+ if (start) {
+ THREAD_TIMER_ON(msdp->master, mp->ka_timer,
+ pim_msdp_peer_ka_timer_cb, mp, PIM_MSDP_PEER_KA_TIME);
+ }
+}
+
+static void
+pim_msdp_peer_active_connect(struct pim_msdp_peer *mp)
+{
+ int rc;
+ ++mp->conn_attempts;
+ rc = pim_msdp_sock_connect(mp);
+
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP peer %s pim_msdp_peer_active_connect: %d", mp->key_str, rc);
+ }
+
+ switch (rc) {
+ case connect_error:
+ case -1:
+ /* connect failed restart the connect-retry timer */
+ pim_msdp_peer_cr_timer_setup(mp, true /* start */);
+ break;
+
+ case connect_success:
+ /* connect was sucessful move to established */
+ pim_msdp_peer_established(mp);
+ break;
+
+ case connect_in_progress:
+ /* for NB content we need to wait till sock is readable or
+ * writeable */
+ PIM_MSDP_PEER_WRITE_ON(mp);
+ PIM_MSDP_PEER_READ_ON(mp);
+ /* also restart connect-retry timer to reset the socket if connect is
+ * not sucessful */
+ pim_msdp_peer_cr_timer_setup(mp, true /* start */);
+ break;
+ }
+}
+
+/* RFC-3618:Sec-5.6 - connection retry on active peer */
+static int
+pim_msdp_peer_cr_timer_cb(struct thread *t)
+{
+ struct pim_msdp_peer *mp;
+
+ mp = THREAD_ARG(t);
+ mp->cr_timer = NULL;
+
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ pim_msdp_peer_timer_expiry_log(mp, "connect-retry");
+ }
+
+ if (mp->state != PIM_MSDP_CONNECTING || PIM_MSDP_PEER_IS_LISTENER(mp)) {
+ return 0;
+ }
+
+ pim_msdp_peer_active_connect(mp);
+ return 0;
+}
+static void
+pim_msdp_peer_cr_timer_setup(struct pim_msdp_peer *mp, bool start)
+{
+ THREAD_OFF(mp->cr_timer);
+ if (start) {
+ THREAD_TIMER_ON(msdp->master, mp->cr_timer,
+ pim_msdp_peer_cr_timer_cb, mp, PIM_MSDP_PEER_CONNECT_RETRY_TIME);
+ }
+}
+
+/* if a valid packet is rxed from the peer we can restart hold timer */
+void
+pim_msdp_peer_pkt_rxed(struct pim_msdp_peer *mp)
+{
+ if (mp->state == PIM_MSDP_ESTABLISHED) {
+ pim_msdp_peer_hold_timer_setup(mp, true /* start */);
+ }
+}
+
+/* if a valid packet is txed to the peer we can restart ka timer and avoid
+ * unnecessary ka noise in the network */
+void
+pim_msdp_peer_pkt_txed(struct pim_msdp_peer *mp)
+{
+ if (mp->state == PIM_MSDP_ESTABLISHED) {
+ pim_msdp_peer_ka_timer_setup(mp, true /* start */);
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP ka timer restart on pkt tx to %s", mp->key_str);
+ }
+ }
+}
+
+static void pim_msdp_addr2su(union sockunion *su, struct in_addr addr)
+{
+ sockunion_init(su);
+ su->sin.sin_addr = addr;
+ su->sin.sin_family = AF_INET;
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+ su->sin.sin_len = sizeof(struct sockaddr_in);
+#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
+}
+
+/* 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, struct in_addr local_addr,
+ const char *mesh_group_name, struct pim_msdp_peer **mp_p)
+{
+ struct pim_msdp_peer *mp;
+
+ pim_msdp_enable();
+
+ mp = XCALLOC(MTYPE_PIM_MSDP_PEER, sizeof(*mp));
+ if (!mp) {
+ zlog_err("%s: PIM XCALLOC(%zu) failure",
+ __PRETTY_FUNCTION__, sizeof(*mp));
+ return PIM_MSDP_ERR_OOM;
+ }
+
+ 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_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->fd = -1;
+ strcpy(mp->last_reset, "-");
+ /* higher IP address is listener */
+ if (ntohl(mp->local.s_addr) > ntohl(mp->peer.s_addr)) {
+ mp->flags |= PIM_MSDP_PEERF_LISTENER;
+ }
+
+ /* setup packet buffers */
+ mp->ibuf = stream_new(PIM_MSDP_MAX_PACKET_SIZE);
+ 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);
+
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ zlog_debug("MSDP peer %s created", mp->key_str);
+
+ pim_msdp_peer_state_chg_log(mp);
+ }
+
+ /* fireup the connect state machine */
+ if (PIM_MSDP_PEER_IS_LISTENER(mp)) {
+ pim_msdp_peer_listen(mp);
+ } else {
+ pim_msdp_peer_connect(mp);
+ }
+ if (mp_p) {
+ *mp_p = mp;
+ }
+ return PIM_MSDP_ERR_NONE;
+}
+
+struct pim_msdp_peer *
+pim_msdp_peer_find(struct in_addr peer_addr)
+{
+ struct pim_msdp_peer lookup;
+
+ lookup.peer = peer_addr;
+ return hash_lookup(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, struct in_addr local_addr,
+ const char *mesh_group_name, struct pim_msdp_peer **mp_p)
+{
+ struct pim_msdp_peer *mp;
+
+ if (mp_p) {
+ *mp_p = NULL;
+ }
+
+ if (peer_addr.s_addr == local_addr.s_addr) {
+ /* skip session setup if config is invalid */
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ char peer_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<peer?>", peer_addr, peer_str, sizeof(peer_str));
+ zlog_debug("%s add skipped as DIP=SIP", peer_str);
+ }
+ return PIM_MSDP_ERR_SIP_EQ_DIP;
+ }
+
+ mp = pim_msdp_peer_find(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);
+}
+
+/* release all mem associated with a peer */
+static void
+pim_msdp_peer_free(struct pim_msdp_peer *mp)
+{
+ if (mp->ibuf) {
+ stream_free(mp->ibuf);
+ }
+
+ if (mp->obuf) {
+ stream_fifo_free(mp->obuf);
+ }
+
+ if (mp->mesh_group_name) {
+ XFREE(MTYPE_PIM_MSDP_MG_NAME, mp->mesh_group_name);
+ }
+ XFREE(MTYPE_PIM_MSDP_PEER, mp);
+}
+
+/* delete the peer config */
+static enum pim_msdp_err
+pim_msdp_peer_do_del(struct pim_msdp_peer *mp)
+{
+ /* stop the tcp connection and shutdown all timers */
+ 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);
+
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ zlog_debug("MSDP peer %s deleted", mp->key_str);
+ }
+
+ /* free up any associated memory */
+ pim_msdp_peer_free(mp);
+
+ return PIM_MSDP_ERR_NONE;
+}
+
+enum pim_msdp_err
+pim_msdp_peer_del(struct in_addr peer_addr)
+{
+ struct pim_msdp_peer *mp;
+
+ mp = pim_msdp_peer_find(peer_addr);
+ if (!mp) {
+ return PIM_MSDP_ERR_NO_PEER;
+ }
+
+ return pim_msdp_peer_do_del(mp);
+}
+
+/* peer hash and peer list helpers */
+static unsigned int
+pim_msdp_peer_hash_key_make(void *p)
+{
+ struct pim_msdp_peer *mp = p;
+ return (jhash_1word(mp->peer.s_addr, 0));
+}
+
+static int
+pim_msdp_peer_hash_eq(const void *p1, const void *p2)
+{
+ const struct pim_msdp_peer *mp1 = p1;
+ const struct pim_msdp_peer *mp2 = p2;
+
+ return (mp1->peer.s_addr == mp2->peer.s_addr);
+}
+
+static int
+pim_msdp_peer_comp(const void *p1, const void *p2)
+{
+ const struct pim_msdp_peer *mp1 = p1;
+ const struct pim_msdp_peer *mp2 = p2;
+
+ if (ntohl(mp1->peer.s_addr) < ntohl(mp2->peer.s_addr))
+ return -1;
+
+ if (ntohl(mp1->peer.s_addr) > ntohl(mp2->peer.s_addr))
+ return 1;
+
+ return 0;
+}
+
+/************************** Mesh group management **************************/
+static void
+pim_msdp_mg_free(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)) {
+ return;
+ }
+
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ zlog_debug("MSDP mesh-group %s deleted", mg->mesh_group_name);
+ }
+ if (mg->mesh_group_name)
+ XFREE(MTYPE_PIM_MSDP_MG_NAME, mg->mesh_group_name);
+
+ if (mg->mbr_list)
+ list_free(mg->mbr_list);
+
+ XFREE(MTYPE_PIM_MSDP_MG, mg);
+ msdp->mg = NULL;
+}
+
+static struct pim_msdp_mg *
+pim_msdp_mg_new(const char *mesh_group_name)
+{
+ struct pim_msdp_mg *mg;
+
+ mg = XCALLOC(MTYPE_PIM_MSDP_MG, sizeof(*mg));
+ if (!mg) {
+ zlog_err("%s: PIM XCALLOC(%zu) failure",
+ __PRETTY_FUNCTION__, sizeof(*mg));
+ return NULL;
+ }
+
+ mg->mesh_group_name = XSTRDUP(MTYPE_PIM_MSDP_MG_NAME, mesh_group_name);
+ mg->mbr_list = list_new();
+ mg->mbr_list->del = (void (*)(void *))pim_msdp_mg_mbr_free;
+ mg->mbr_list->cmp = (int (*)(void *, void *))pim_msdp_mg_mbr_comp;
+
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ zlog_debug("MSDP mesh-group %s created", mg->mesh_group_name);
+ }
+ return mg;
+}
+
+enum pim_msdp_err
+pim_msdp_mg_del(const char *mesh_group_name)
+{
+ struct pim_msdp_mg *mg = msdp->mg;
+ struct pim_msdp_mg_mbr *mbr;
+
+ if (!mg || strcmp(mg->mesh_group_name, mesh_group_name)) {
+ return PIM_MSDP_ERR_NO_MG;
+ }
+
+ /* delete all the mesh-group members */
+ while (!list_isempty(mg->mbr_list)) {
+ mbr = listnode_head(mg->mbr_list);
+ pim_msdp_mg_mbr_do_del(mg, mbr);
+ }
+
+ /* clear src ip */
+ mg->src_ip.s_addr = INADDR_ANY;
+
+ /* free up the mesh-group */
+ pim_msdp_mg_free(mg);
+ return PIM_MSDP_ERR_NONE;
+}
+
+static enum pim_msdp_err
+pim_msdp_mg_add(const char *mesh_group_name)
+{
+ if (msdp->mg) {
+ if (!strcmp(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) {
+ return PIM_MSDP_ERR_OOM;
+ }
+
+ return PIM_MSDP_ERR_NONE;
+}
+
+static int
+pim_msdp_mg_mbr_comp(const void *p1, const void *p2)
+{
+ const struct pim_msdp_mg_mbr *mbr1 = p1;
+ const struct pim_msdp_mg_mbr *mbr2 = p2;
+
+ if (ntohl(mbr1->mbr_ip.s_addr) < ntohl(mbr2->mbr_ip.s_addr))
+ return -1;
+
+ if (ntohl(mbr1->mbr_ip.s_addr) > ntohl(mbr2->mbr_ip.s_addr))
+ return 1;
+
+ return 0;
+}
+
+static void
+pim_msdp_mg_mbr_free(struct pim_msdp_mg_mbr *mbr)
+{
+ XFREE(MTYPE_PIM_MSDP_MG_MBR, mbr);
+}
+
+static struct pim_msdp_mg_mbr *
+pim_msdp_mg_mbr_find(struct in_addr mbr_ip)
+{
+ struct pim_msdp_mg_mbr *mbr;
+ struct listnode *mbr_node;
+
+ if (!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)) {
+ 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, 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);
+ if (rc != PIM_MSDP_ERR_NONE) {
+ return rc;
+ }
+
+ mg = msdp->mg;
+ mbr = pim_msdp_mg_mbr_find(mbr_ip);
+ if (mbr) {
+ return PIM_MSDP_ERR_MG_MBR_EXISTS;
+ }
+
+ mbr = XCALLOC(MTYPE_PIM_MSDP_MG_MBR, sizeof(*mbr));
+ if (!mbr) {
+ 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);
+ return PIM_MSDP_ERR_OOM;
+ }
+ mbr->mbr_ip = mbr_ip;
+ listnode_add_sort(mg->mbr_list, mbr);
+
+ /* 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,
+ &mbr->mp);
+ }
+
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ char ip_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<mbr?>", mbr->mbr_ip, ip_str, sizeof(ip_str));
+ zlog_debug("MSDP mesh-group %s mbr %s created", mg->mesh_group_name, ip_str);
+ }
+ ++mg->mbr_cnt;
+ return PIM_MSDP_ERR_NONE;
+}
+
+static void
+pim_msdp_mg_mbr_do_del(struct pim_msdp_mg *mg, struct pim_msdp_mg_mbr *mbr)
+{
+ /* Delete active peer session if any */
+ if (mbr->mp) {
+ pim_msdp_peer_do_del(mbr->mp);
+ }
+
+ listnode_delete(mg->mbr_list, mbr);
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ char ip_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<mbr?>", mbr->mbr_ip, ip_str, sizeof(ip_str));
+ zlog_debug("MSDP mesh-group %s mbr %s deleted", mg->mesh_group_name, ip_str);
+ }
+ pim_msdp_mg_mbr_free(mbr);
+ if (mg->mbr_cnt) {
+ --mg->mbr_cnt;
+ }
+}
+
+enum pim_msdp_err
+pim_msdp_mg_mbr_del(const char *mesh_group_name, struct in_addr mbr_ip)
+{
+ struct pim_msdp_mg_mbr *mbr;
+ struct pim_msdp_mg *mg = 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);
+ 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);
+
+ return PIM_MSDP_ERR_NONE;
+}
+
+static void
+pim_msdp_mg_src_do_del(void)
+{
+ struct pim_msdp_mg_mbr *mbr;
+ struct listnode *mbr_node;
+ struct pim_msdp_mg *mg = msdp->mg;
+
+ /* SIP is being removed - tear down all active peer sessions */
+ for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbr_node, mbr)) {
+ if (mbr->mp) {
+ pim_msdp_peer_do_del(mbr->mp);
+ mbr->mp = NULL;
+ }
+ }
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ zlog_debug("MSDP mesh-group %s src cleared", mg->mesh_group_name);
+ }
+}
+
+enum pim_msdp_err
+pim_msdp_mg_src_del(const char *mesh_group_name)
+{
+ struct pim_msdp_mg *mg = 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();
+ /* if there are no references to the mg free it */
+ pim_msdp_mg_free(mg);
+ }
+ return PIM_MSDP_ERR_NONE;
+}
+
+enum pim_msdp_err
+pim_msdp_mg_src_add(const char *mesh_group_name, struct in_addr src_ip)
+{
+ int rc;
+ struct pim_msdp_mg_mbr *mbr;
+ struct listnode *mbr_node;
+ struct pim_msdp_mg *mg;
+
+ if (src_ip.s_addr == INADDR_ANY) {
+ pim_msdp_mg_src_del(mesh_group_name);
+ return PIM_MSDP_ERR_NONE;
+ }
+
+ rc = pim_msdp_mg_add(mesh_group_name);
+ if (rc != PIM_MSDP_ERR_NONE) {
+ return rc;
+ }
+
+ mg = msdp->mg;
+ if (mg->src_ip.s_addr != INADDR_ANY) {
+ pim_msdp_mg_src_do_del();
+ }
+ 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,
+ &mbr->mp);
+ }
+
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ char ip_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<src?>", mg->src_ip, ip_str, sizeof(ip_str));
+ zlog_debug("MSDP mesh-group %s src %s set", mg->mesh_group_name, ip_str);
+ }
+ return PIM_MSDP_ERR_NONE;
+}
+
+/*********************** MSDP feature APIs *********************************/
+int
+pim_msdp_config_write(struct vty *vty)
+{
+ struct listnode *mbrnode;
+ struct pim_msdp_mg_mbr *mbr;
+ struct pim_msdp_mg *mg = msdp->mg;
+ char mbr_str[INET_ADDRSTRLEN];
+ char src_str[INET_ADDRSTRLEN];
+ int count = 0;
+
+ if (!mg) {
+ return count;
+ }
+
+ 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%s",
+ mg->mesh_group_name, src_str, VTY_NEWLINE);
+ ++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%s",
+ mg->mesh_group_name, mbr_str, VTY_NEWLINE);
+ ++count;
+ }
+ return count;
+}
+
+/* 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)
+{
+ if (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 */);
+ /* setup sa cache based on local sources */
+ pim_msdp_sa_local_setup();
+}
+
+/* MSDP init */
+void
+pim_msdp_init(struct thread_master *master)
+{
+ msdp->master = master;
+
+ msdp->peer_hash = hash_create(pim_msdp_peer_hash_key_make,
+ pim_msdp_peer_hash_eq);
+ 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;
+
+ msdp->sa_hash = hash_create(pim_msdp_sa_hash_key_make,
+ pim_msdp_sa_hash_eq);
+ 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;
+}
+
+/* counterpart to MSDP init; XXX: unused currently */
+void
+pim_msdp_exit(void)
+{
+ /* XXX: stop listener and delete all peer sessions */
+
+ if (msdp->peer_hash) {
+ hash_free(msdp->peer_hash);
+ msdp->peer_hash = NULL;
+ }
+
+ if (msdp->peer_list) {
+ list_free(msdp->peer_list);
+ msdp->peer_list = NULL;
+ }
+}
diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h
new file mode 100644
index 0000000000..33c1d88a45
--- /dev/null
+++ b/pimd/pim_msdp.h
@@ -0,0 +1,233 @@
+/*
+ * IP MSDP for Quagga
+ * Copyright (C) 2016 Cumulus 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 PIM_MSDP_H
+#define PIM_MSDP_H
+
+enum pim_msdp_peer_state {
+ PIM_MSDP_DISABLED,
+ PIM_MSDP_INACTIVE,
+ PIM_MSDP_LISTEN,
+ PIM_MSDP_CONNECTING,
+ PIM_MSDP_ESTABLISHED
+};
+
+/* SA and KA TLVs are processed; rest ignored */
+enum pim_msdp_tlv {
+ PIM_MSDP_V4_SOURCE_ACTIVE = 1,
+ PIM_MSDP_V4_SOURCE_ACTIVE_REQUEST,
+ PIM_MSDP_V4_SOURCE_ACTIVE_RESPONSE,
+ PIM_MSDP_KEEPALIVE,
+ PIM_MSDP_RESERVED,
+ PIM_MSDP_TRACEROUTE_PROGRESS,
+ PIM_MSDP_TRACEROUTE_REPLY,
+};
+
+/* MSDP error codes */
+enum pim_msdp_err {
+ PIM_MSDP_ERR_NONE = 0,
+ PIM_MSDP_ERR_OOM = -1,
+ PIM_MSDP_ERR_PEER_EXISTS = -2,
+ PIM_MSDP_ERR_MAX_MESH_GROUPS = -3,
+ PIM_MSDP_ERR_NO_PEER = -4,
+ PIM_MSDP_ERR_MG_MBR_EXISTS = -5,
+ PIM_MSDP_ERR_NO_MG = -6,
+ PIM_MSDP_ERR_NO_MG_MBR = -7,
+ PIM_MSDP_ERR_SIP_EQ_DIP = -8,
+};
+
+#define PIM_MSDP_STATE_STRLEN 16
+#define PIM_MSDP_UPTIME_STRLEN 80
+#define PIM_MSDP_TIMER_STRLEN 12
+#define PIM_MSDP_TCP_PORT 639
+#define PIM_MSDP_SOCKET_SNDBUF_SIZE 65536
+
+enum pim_msdp_sa_flags {
+ PIM_MSDP_SAF_NONE = 0,
+ /* There are two cases where we can pickup an active source locally -
+ * 1. We are RP and got a source-register from the FHR
+ * 2. We are RP and FHR and learnt a new directly connected source on a
+ * DR interface */
+ PIM_MSDP_SAF_LOCAL = (1 << 0),
+ /* We got this in the MSDP SA TLV from a peer (and this passed peer-RPF
+ * checks) */
+ 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 */
+ PIM_MSDP_SAF_UP_DEL_IN_PROG = (1 << 3)
+};
+
+struct pim_msdp_sa {
+ struct prefix_sg sg;
+ char sg_str[PIM_SG_LEN];
+ struct in_addr rp; /* Last RP address associated with this SA */
+ struct in_addr peer; /* last peer from who we heard this SA */
+ enum pim_msdp_sa_flags flags;
+
+ /* rfc-3618 is missing default value for SA-hold-down-Period. pulled
+ * this number from industry-standards */
+#define PIM_MSDP_SA_HOLD_TIME ((3*60)+30)
+ struct thread *sa_state_timer; // 5.6
+ int64_t uptime;
+
+ struct pim_upstream *up;
+};
+
+enum pim_msdp_peer_flags {
+ PIM_MSDP_PEERF_NONE = 0,
+ PIM_MSDP_PEERF_LISTENER = (1 << 0),
+#define PIM_MSDP_PEER_IS_LISTENER(mp) (mp->flags & PIM_MSDP_PEERF_LISTENER)
+ PIM_MSDP_PEERF_SA_JUST_SENT = (1 << 1)
+};
+
+struct pim_msdp_peer {
+ /* configuration */
+ struct in_addr local;
+ struct in_addr peer;
+ char *mesh_group_name;
+ char key_str[INET_ADDRSTRLEN];
+
+ /* state */
+ enum pim_msdp_peer_state state;
+ enum pim_msdp_peer_flags flags;
+
+ /* TCP socket info */
+ union sockunion su_local;
+ union sockunion su_peer;
+ int fd;
+
+ /* protocol timers */
+#define PIM_MSDP_PEER_HOLD_TIME 75
+ struct thread *hold_timer; // 5.4
+#define PIM_MSDP_PEER_KA_TIME 60
+ struct thread *ka_timer; // 5.5
+#define PIM_MSDP_PEER_CONNECT_RETRY_TIME 30
+ struct thread *cr_timer; // 5.6
+
+ /* packet thread and buffers */
+ uint32_t packet_size;
+ struct stream *ibuf;
+ struct stream_fifo *obuf;
+ struct thread *t_read;
+ struct thread *t_write;
+
+ /* stats */
+ uint32_t conn_attempts;
+ uint32_t est_flaps;
+ uint32_t sa_cnt; /* number of SAs attributed to this peer */
+#define PIM_MSDP_PEER_LAST_RESET_STR 20
+ char last_reset[PIM_MSDP_PEER_LAST_RESET_STR];
+
+ /* packet stats */
+ uint32_t ka_tx_cnt;
+ uint32_t sa_tx_cnt;
+ uint32_t ka_rx_cnt;
+ uint32_t sa_rx_cnt;
+ uint32_t unk_rx_cnt;
+
+ /* timestamps */
+ int64_t uptime;
+};
+
+struct pim_msdp_mg_mbr {
+ struct in_addr mbr_ip;
+ struct pim_msdp_peer *mp;
+};
+
+/* PIM MSDP mesh-group */
+struct pim_msdp_mg {
+ char *mesh_group_name;
+ struct in_addr src_ip;
+ uint32_t mbr_cnt;
+ struct list *mbr_list;
+};
+
+enum pim_msdp_flags {
+ PIM_MSDPF_NONE = 0,
+ PIM_MSDPF_ENABLE = (1 << 0),
+ PIM_MSDPF_LISTENER = (1 << 1)
+};
+
+struct pim_msdp_listener {
+ int fd;
+ union sockunion su;
+ struct thread *thread;
+};
+
+struct pim_msdp {
+ enum pim_msdp_flags flags;
+ struct thread_master *master;
+ struct pim_msdp_listener listener;
+ uint32_t rejected_accepts;
+
+ /* MSDP peer info */
+ struct hash *peer_hash;
+ struct list *peer_list;
+
+ /* MSDP active-source info */
+#define PIM_MSDP_SA_ADVERTISMENT_TIME 60
+ struct thread *sa_adv_timer; // 5.6
+ struct hash *sa_hash;
+ struct list *sa_list;
+ uint32_t local_cnt;
+
+ /* keep a scratch pad for building SA TLVs */
+ struct stream *work_obuf;
+
+ struct in_addr originator_id;
+
+ /* currently only one mesh-group is supported - so just stash it here */
+ struct pim_msdp_mg *mg;
+};
+
+#define PIM_MSDP_PEER_READ_ON(mp) THREAD_READ_ON(msdp->master, mp->t_read, pim_msdp_read, mp, mp->fd);
+#define PIM_MSDP_PEER_WRITE_ON(mp) THREAD_WRITE_ON(msdp->master, mp->t_write, pim_msdp_write, mp, mp->fd);
+
+#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, const char *mesh_group_name, struct pim_msdp_peer **mp_p);
+enum pim_msdp_err pim_msdp_peer_del(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);
+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);
+void pim_msdp_peer_reset_tcp_conn(struct pim_msdp_peer *mp, const char *rc_str);
+int pim_msdp_write(struct thread *thread);
+char *pim_msdp_peer_key_dump(struct pim_msdp_peer *mp, char *buf, int buf_size, bool long_format);
+int pim_msdp_config_write(struct vty *vty);
+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_local_update(struct pim_upstream *up);
+void pim_msdp_sa_local_del(struct prefix_sg *sg);
+void pim_msdp_i_am_rp_changed(void);
+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, struct in_addr mbr_ip);
+enum pim_msdp_err pim_msdp_mg_mbr_del(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, struct in_addr src_ip);
+enum pim_msdp_err pim_msdp_mg_del(const char *mesh_group_name);
+#endif
diff --git a/pimd/pim_msdp_packet.c b/pimd/pim_msdp_packet.c
new file mode 100644
index 0000000000..fbf34cd91c
--- /dev/null
+++ b/pimd/pim_msdp_packet.c
@@ -0,0 +1,696 @@
+/*
+ * IP MSDP packet helper
+ * Copyright (C) 2016 Cumulus 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 <lib/log.h>
+#include <lib/network.h>
+#include <lib/stream.h>
+#include <lib/thread.h>
+#include <lib/vty.h>
+
+#include "pimd.h"
+#include "pim_str.h"
+
+#include "pim_msdp.h"
+#include "pim_msdp_packet.h"
+#include "pim_msdp_socket.h"
+
+static char *
+pim_msdp_pkt_type_dump(enum pim_msdp_tlv type, char *buf, int buf_size)
+{
+ switch (type) {
+ case PIM_MSDP_V4_SOURCE_ACTIVE:
+ snprintf(buf, buf_size, "%s", "SA");
+ break;
+ case PIM_MSDP_V4_SOURCE_ACTIVE_REQUEST:
+ snprintf(buf, buf_size, "%s", "SA_REQ");
+ break;
+ case PIM_MSDP_V4_SOURCE_ACTIVE_RESPONSE:
+ snprintf(buf, buf_size, "%s", "SA_RESP");
+ break;
+ case PIM_MSDP_KEEPALIVE:
+ snprintf(buf, buf_size, "%s", "KA");
+ break;
+ case PIM_MSDP_RESERVED:
+ snprintf(buf, buf_size, "%s", "RSVD");
+ break;
+ case PIM_MSDP_TRACEROUTE_PROGRESS:
+ snprintf(buf, buf_size, "%s", "TRACE_PROG");
+ break;
+ case PIM_MSDP_TRACEROUTE_REPLY:
+ snprintf(buf, buf_size, "%s", "TRACE_REPLY");
+ break;
+ default:
+ snprintf(buf, buf_size, "UNK-%d", type);
+ }
+ return buf;
+}
+
+static void
+pim_msdp_pkt_sa_dump_one(struct stream *s)
+{
+ struct prefix_sg sg;
+
+ /* just throw away the three reserved bytes */
+ stream_get3(s);
+ /* throw away the prefix length also */
+ stream_getc(s);
+
+ memset(&sg, 0, sizeof (struct prefix_sg));
+ sg.grp.s_addr = stream_get_ipv4(s);
+ sg.src.s_addr = stream_get_ipv4(s);
+
+ zlog_debug(" sg %s", pim_str_sg_dump(&sg));
+}
+
+static void
+pim_msdp_pkt_sa_dump(struct stream *s)
+{
+ int entry_cnt;
+ int i;
+ struct in_addr rp; /* Last RP address associated with this SA */
+
+ entry_cnt = stream_getc(s);
+ rp.s_addr = stream_get_ipv4(s);
+
+ if (PIM_DEBUG_MSDP_PACKETS) {
+ char rp_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<rp?>", rp, rp_str, sizeof(rp_str));
+ zlog_debug(" entry_cnt %d rp %s", entry_cnt, rp_str);
+ }
+
+ /* dump SAs */
+ for (i = 0; i < entry_cnt; ++i) {
+ pim_msdp_pkt_sa_dump_one(s);
+ }
+}
+
+static void
+pim_msdp_pkt_dump(struct pim_msdp_peer *mp, int type, int len, bool rx,
+ struct stream *s)
+{
+ char type_str[PIM_MSDP_PKT_TYPE_STRLEN];
+
+ pim_msdp_pkt_type_dump(type, type_str, sizeof(type_str));
+
+ zlog_debug("MSDP peer %s pkt %s type %s len %d",
+ mp->key_str, rx?"rx":"tx", type_str, len);
+
+ if (!s) {
+ return;
+ }
+
+ switch(type) {
+ case PIM_MSDP_V4_SOURCE_ACTIVE:
+ pim_msdp_pkt_sa_dump(s);
+ break;
+ default:;
+ }
+}
+
+/* Check file descriptor whether connect is established. */
+static void
+pim_msdp_connect_check(struct pim_msdp_peer *mp)
+{
+ int status;
+ socklen_t slen;
+ int ret;
+
+ if (mp->state != PIM_MSDP_CONNECTING) {
+ /* if we are here it means we are not in a connecting or established state
+ * for now treat this as a fatal error */
+ pim_msdp_peer_reset_tcp_conn(mp, "invalid-state");
+ return;
+ }
+
+ PIM_MSDP_PEER_READ_OFF(mp);
+ PIM_MSDP_PEER_WRITE_OFF(mp);
+
+ /* Check file descriptor. */
+ slen = sizeof(status);
+ ret = getsockopt(mp->fd, SOL_SOCKET, SO_ERROR, (void *)&status, &slen);
+
+ /* If getsockopt is fail, this is fatal error. */
+ if (ret < 0) {
+ zlog_err("can't get sockopt for nonblocking connect");
+ pim_msdp_peer_reset_tcp_conn(mp, "connect-failed");
+ return;
+ }
+
+ /* When status is 0 then TCP connection is established. */
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP peer %s pim_connect_check %s", mp->key_str, status?"fail":"success");
+ }
+ if (status == 0) {
+ pim_msdp_peer_established(mp);
+ } else {
+ pim_msdp_peer_reset_tcp_conn(mp, "connect-failed");
+ }
+}
+
+static void
+pim_msdp_pkt_delete(struct pim_msdp_peer *mp)
+{
+ stream_free(stream_fifo_pop(mp->obuf));
+}
+
+static void
+pim_msdp_pkt_add(struct pim_msdp_peer *mp, struct stream *s)
+{
+ stream_fifo_push(mp->obuf, s);
+}
+
+static void
+pim_msdp_write_proceed_actions(struct pim_msdp_peer *mp)
+{
+ if (stream_fifo_head(mp->obuf)) {
+ PIM_MSDP_PEER_WRITE_ON(mp);
+ }
+}
+
+int
+pim_msdp_write(struct thread *thread)
+{
+ struct pim_msdp_peer *mp;
+ struct stream *s;
+ int num;
+ enum pim_msdp_tlv type;
+ int len;
+ int work_cnt = 0;
+ int work_max_cnt = 100;
+
+ mp = THREAD_ARG(thread);
+ mp->t_write = NULL;
+
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP peer %s pim_msdp_write", mp->key_str);
+ }
+ if (mp->fd < 0) {
+ return -1;
+ }
+
+ /* check if TCP connection is established */
+ if (mp->state != PIM_MSDP_ESTABLISHED) {
+ pim_msdp_connect_check(mp);
+ return 0;
+ }
+
+ s = stream_fifo_head(mp->obuf);
+ if (!s) {
+ pim_msdp_write_proceed_actions(mp);
+ return 0;
+ }
+
+ sockopt_cork(mp->fd, 1);
+
+ /* Nonblocking write until TCP output buffer is full */
+ do
+ {
+ int writenum;
+
+ /* Number of bytes to be sent */
+ writenum = stream_get_endp(s) - stream_get_getp(s);
+
+ /* Call write() system call */
+ num = write(mp->fd, STREAM_PNT(s), writenum);
+ if (num < 0) {
+ /* write failed either retry needed or error */
+ if (ERRNO_IO_RETRY(errno)) {
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP peer %s pim_msdp_write io retry", mp->key_str);
+ }
+ break;
+ }
+
+ pim_msdp_peer_reset_tcp_conn(mp, "pkt-tx-failed");
+ return 0;
+ }
+
+ if (num != writenum) {
+ /* Partial write */
+ stream_forward_getp(s, num);
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP peer %s pim_msdp_partial_write", mp->key_str);
+ }
+ break;
+ }
+
+ /* Retrieve msdp packet type. */
+ stream_set_getp(s,0);
+ type = stream_getc(s);
+ len = stream_getw(s);
+ switch (type)
+ {
+ case PIM_MSDP_KEEPALIVE:
+ mp->ka_tx_cnt++;
+ break;
+ case PIM_MSDP_V4_SOURCE_ACTIVE:
+ mp->sa_tx_cnt++;
+ break;
+ default:;
+ }
+ if (PIM_DEBUG_MSDP_PACKETS) {
+ pim_msdp_pkt_dump(mp, type, len, false /*rx*/, s);
+ }
+
+ /* packet sent delete it. */
+ pim_msdp_pkt_delete(mp);
+
+ ++work_cnt;
+ /* may need to pause if we have done too much work in this
+ * loop */
+ if (work_cnt >= work_max_cnt) {
+ break;
+ }
+ } while ((s = stream_fifo_head(mp->obuf)) != NULL);
+ pim_msdp_write_proceed_actions(mp);
+
+ sockopt_cork(mp->fd, 0);
+
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP peer %s pim_msdp_write wrote %d packets", mp->key_str, work_cnt);
+ }
+
+ return 0;
+}
+
+static void
+pim_msdp_pkt_send(struct pim_msdp_peer *mp, struct stream *s)
+{
+ /* Add packet to the end of list. */
+ pim_msdp_pkt_add(mp, s);
+
+ PIM_MSDP_PEER_WRITE_ON(mp);
+}
+
+void
+pim_msdp_pkt_ka_tx(struct pim_msdp_peer *mp)
+{
+ struct stream *s;
+
+ if (mp->state != PIM_MSDP_ESTABLISHED) {
+ /* don't tx anything unless a session is established */
+ return;
+ }
+ s = stream_new(PIM_MSDP_KA_TLV_MAX_SIZE);
+ stream_putc(s, PIM_MSDP_KEEPALIVE);
+ stream_putw(s, PIM_MSDP_KA_TLV_MAX_SIZE);
+
+ pim_msdp_pkt_send(mp, s);
+}
+
+static void
+pim_msdp_pkt_sa_push_to_one_peer(struct pim_msdp_peer *mp)
+{
+ struct stream *s;
+
+ if (mp->state != PIM_MSDP_ESTABLISHED) {
+ /* don't tx anything unless a session is established */
+ return;
+ }
+ s = stream_dup(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)
+{
+ struct listnode *mpnode;
+
+ if (mp) {
+ pim_msdp_pkt_sa_push_to_one_peer(mp);
+ } else {
+ for (ALL_LIST_ELEMENTS_RO(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);
+ }
+ }
+}
+
+static int
+pim_msdp_pkt_sa_fill_hdr(int local_cnt)
+{
+ int curr_tlv_ecnt;
+
+ stream_reset(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);
+
+ 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);
+}
+
+static void
+pim_msdp_pkt_sa_gen(struct pim_msdp_peer *mp)
+{
+ struct listnode *sanode;
+ struct pim_msdp_sa *sa;
+ int sa_count;
+ int local_cnt = 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);
+
+ for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) {
+ if (!(sa->flags & PIM_MSDP_SAF_LOCAL)) {
+ /* current implementation of MSDP is for anycast i.e. full mesh. so
+ * no re-forwarding of SAs that we learnt from other peers */
+ continue;
+ }
+ /* add sa into scratch pad */
+ pim_msdp_pkt_sa_fill_one(sa);
+ ++sa_count;
+ if (sa_count >= PIM_MSDP_SA_MAX_ENTRY_CNT) {
+ pim_msdp_pkt_sa_push(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);
+ }
+ }
+
+ if (sa_count) {
+ pim_msdp_pkt_sa_push(mp);
+ }
+ return;
+}
+
+static void
+pim_msdp_pkt_sa_tx_done(void)
+{
+ 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)) {
+ 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)
+{
+ pim_msdp_pkt_sa_gen(NULL /* mp */);
+ pim_msdp_pkt_sa_tx_done();
+}
+
+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_one(sa);
+ pim_msdp_pkt_sa_push(NULL);
+ pim_msdp_pkt_sa_tx_done();
+}
+
+/* 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();
+}
+
+static void
+pim_msdp_pkt_rxed_with_fatal_error(struct pim_msdp_peer *mp)
+{
+ pim_msdp_peer_reset_tcp_conn(mp, "invalid-pkt-rx");
+}
+
+static void
+pim_msdp_pkt_ka_rx(struct pim_msdp_peer *mp, int len)
+{
+ mp->ka_rx_cnt++;
+ if (len != PIM_MSDP_KA_TLV_MAX_SIZE) {
+ pim_msdp_pkt_rxed_with_fatal_error(mp);
+ return;
+ }
+ pim_msdp_peer_pkt_rxed(mp);
+}
+
+static void
+pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp)
+{
+ int prefix_len;
+ struct prefix_sg sg;
+
+ /* just throw away the three reserved bytes */
+ stream_get3(mp->ibuf);
+ prefix_len = stream_getc(mp->ibuf);
+
+ memset(&sg, 0, sizeof (struct prefix_sg));
+ sg.grp.s_addr = stream_get_ipv4(mp->ibuf);
+ sg.src.s_addr = stream_get_ipv4(mp->ibuf);
+
+ if (prefix_len != 32) {
+ /* ignore SA update if the prefix length is not 32 */
+ zlog_err("rxed sa update with invalid prefix length %d", prefix_len);
+ return;
+ }
+ if (PIM_DEBUG_MSDP_PACKETS) {
+ zlog_debug(" sg %s", pim_str_sg_dump(&sg));
+ }
+ pim_msdp_sa_ref(mp, &sg, rp);
+}
+
+static void
+pim_msdp_pkt_sa_rx(struct pim_msdp_peer *mp, int len)
+{
+ int entry_cnt;
+ int i;
+ struct in_addr rp; /* Last RP address associated with this SA */
+
+ mp->sa_rx_cnt++;
+
+ if (len < PIM_MSDP_SA_TLV_MIN_SIZE) {
+ pim_msdp_pkt_rxed_with_fatal_error(mp);
+ return;
+ }
+
+ entry_cnt = stream_getc(mp->ibuf);
+ /* some vendors include the actual multicast data in the tlv (at the end).
+ * we will ignore such data. in the future we may consider pushing it down
+ * the RPT */
+ if (len < PIM_MSDP_SA_ENTRY_CNT2SIZE(entry_cnt)) {
+ pim_msdp_pkt_rxed_with_fatal_error(mp);
+ return;
+ }
+ rp.s_addr = stream_get_ipv4(mp->ibuf);
+
+ if (PIM_DEBUG_MSDP_PACKETS) {
+ char rp_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<rp?>", rp, rp_str, sizeof(rp_str));
+ zlog_debug(" entry_cnt %d rp %s", entry_cnt, rp_str);
+ }
+
+ if (!pim_msdp_peer_rpf_check(mp, rp)) {
+ /* if peer-RPF check fails don't process the packet any further */
+ if (PIM_DEBUG_MSDP_PACKETS) {
+ zlog_debug(" peer RPF check failed");
+ }
+ return;
+ }
+
+ pim_msdp_peer_pkt_rxed(mp);
+
+ /* update SA cache */
+ for (i = 0; i < entry_cnt; ++i) {
+ pim_msdp_pkt_sa_rx_one(mp, rp);
+ }
+}
+
+static void
+pim_msdp_pkt_rx(struct pim_msdp_peer *mp)
+{
+ enum pim_msdp_tlv type;
+ int len;
+
+ /* re-read type and len */
+ type = stream_getc_from(mp->ibuf, 0);
+ len = stream_getw_from(mp->ibuf, 1);
+ if (len < PIM_MSDP_HEADER_SIZE) {
+ pim_msdp_pkt_rxed_with_fatal_error(mp);
+ return;
+ }
+
+ if (len > PIM_MSDP_SA_TLV_MAX_SIZE) {
+ /* if tlv size if greater than max just ignore the tlv */
+ return;
+ }
+
+ if (PIM_DEBUG_MSDP_PACKETS) {
+ pim_msdp_pkt_dump(mp, type, len, true /*rx*/, NULL /*s*/);
+ }
+
+ switch(type) {
+ case PIM_MSDP_KEEPALIVE:
+ pim_msdp_pkt_ka_rx(mp, len);
+ break;
+ case PIM_MSDP_V4_SOURCE_ACTIVE:
+ mp->sa_rx_cnt++;
+ pim_msdp_pkt_sa_rx(mp, len);
+ break;
+ default:
+ mp->unk_rx_cnt++;
+ }
+}
+
+/* pim msdp read utility function. */
+static int
+pim_msdp_read_packet(struct pim_msdp_peer *mp)
+{
+ int nbytes;
+ int readsize;
+ int old_endp;
+ int new_endp;
+
+ old_endp = stream_get_endp(mp->ibuf);
+ readsize = mp->packet_size - old_endp;
+ if (!readsize) {
+ return 0;
+ }
+
+ /* Read packet from fd */
+ nbytes = stream_read_try(mp->ibuf, mp->fd, readsize);
+ new_endp = stream_get_endp(mp->ibuf);
+ if (nbytes < 0) {
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP peer %s read failed %d", mp->key_str, nbytes);
+ }
+ if (nbytes == -2) {
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP peer %s pim_msdp_read io retry old_end: %d new_end: %d", mp->key_str, old_endp, new_endp);
+ }
+ /* transient error retry */
+ return -1;
+ }
+ pim_msdp_pkt_rxed_with_fatal_error(mp);
+ return -1;
+ }
+
+ if (!nbytes) {
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP peer %s read failed %d", mp->key_str, nbytes);
+ }
+ pim_msdp_peer_reset_tcp_conn(mp, "peer-down");
+ return -1;
+ }
+
+ /* We read partial packet. */
+ if (stream_get_endp(mp->ibuf) != mp->packet_size) {
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP peer %s read partial len %d old_endp %d new_endp %d", mp->key_str, mp->packet_size, old_endp, new_endp);
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+pim_msdp_read(struct thread *thread)
+{
+ struct pim_msdp_peer *mp;
+ int rc;
+ uint32_t len;
+
+ mp = THREAD_ARG(thread);
+ mp->t_read = NULL;
+
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP peer %s pim_msdp_read", mp->key_str);
+ }
+
+ if (mp->fd < 0) {
+ return -1;
+ }
+
+ /* check if TCP connection is established */
+ if (mp->state != PIM_MSDP_ESTABLISHED) {
+ pim_msdp_connect_check(mp);
+ return 0;
+ }
+
+ PIM_MSDP_PEER_READ_ON(mp);
+
+ if (!mp->packet_size) {
+ mp->packet_size = PIM_MSDP_HEADER_SIZE;
+ }
+
+ if (stream_get_endp(mp->ibuf) < PIM_MSDP_HEADER_SIZE) {
+ /* start by reading the TLV header */
+ rc = pim_msdp_read_packet(mp);
+ if (rc < 0) {
+ goto pim_msdp_read_end;
+ }
+
+ /* Find TLV type and len */
+ stream_getc(mp->ibuf);
+ len = stream_getw(mp->ibuf);
+ if (len < PIM_MSDP_HEADER_SIZE) {
+ pim_msdp_pkt_rxed_with_fatal_error(mp);
+ goto pim_msdp_read_end;
+ }
+ /* read complete TLV */
+ mp->packet_size = len;
+ }
+
+ rc = pim_msdp_read_packet(mp);
+ if (rc < 0) {
+ goto pim_msdp_read_end;
+ }
+
+ pim_msdp_pkt_rx(mp);
+
+ /* reset input buffers and get ready for the next packet */
+ mp->packet_size = 0;
+ stream_reset(mp->ibuf);
+
+pim_msdp_read_end:
+ return 0;
+}
diff --git a/pimd/pim_msdp_packet.h b/pimd/pim_msdp_packet.h
new file mode 100644
index 0000000000..f6fcfee6bb
--- /dev/null
+++ b/pimd/pim_msdp_packet.h
@@ -0,0 +1,72 @@
+/*
+ * IP MSDP packet helpers
+ * Copyright (C) 2016 Cumulus 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 PIM_MSDP_PACKET_H
+#define PIM_MSDP_PACKET_H
+
+/* type and length of a single tlv can be consider packet header */
+#define PIM_MSDP_HEADER_SIZE 3
+
+/* Keepalive TLV
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| 4 | 3 |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+#define PIM_MSDP_KA_TLV_MAX_SIZE PIM_MSDP_HEADER_SIZE
+
+/* Source-Active TLV (x=8, y=12xEntryCount)
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| 1 | x + y | Entry Count |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| RP Address |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Reserved | Sprefix Len | \
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ \
+| Group Address | ) z
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ /
+| Source Address | /
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+#define PIM_MSDP_SA_TLV_MAX_SIZE 9192
+#define PIM_MSDP_SA_X_SIZE 8
+#define PIM_MSDP_SA_ONE_ENTRY_SIZE 12
+#define PIM_MSDP_SA_Y_SIZE(entry_cnt) (PIM_MSDP_SA_ONE_ENTRY_SIZE * entry_cnt)
+#define PIM_MSDP_SA_ENTRY_CNT2SIZE(entry_cnt) (PIM_MSDP_SA_X_SIZE +\
+ PIM_MSDP_SA_Y_SIZE(entry_cnt))
+/* SA TLV has to have atleast only one entry in it so x=8 + y=12 */
+#define PIM_MSDP_SA_TLV_MIN_SIZE PIM_MSDP_SA_ENTRY_CNT2SIZE(1)
+/* XXX: theoretically we can fix a max of 255 but that may result in packet
+ * fragmentation */
+#define PIM_MSDP_SA_MAX_ENTRY_CNT 120
+
+#define PIM_MSDP_MAX_PACKET_SIZE max(PIM_MSDP_SA_TLV_MAX_SIZE, PIM_MSDP_KA_TLV_MAX_SIZE)
+
+#define PIM_MSDP_PKT_TYPE_STRLEN 16
+
+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_one(struct pim_msdp_sa *sa);
+void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp);
+
+#endif
diff --git a/pimd/pim_msdp_socket.c b/pimd/pim_msdp_socket.c
new file mode 100644
index 0000000000..bc9720f1f3
--- /dev/null
+++ b/pimd/pim_msdp_socket.c
@@ -0,0 +1,229 @@
+/*
+ * IP MSDP socket management
+ * Copyright (C) 2016 Cumulus 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 <lib/log.h>
+#include <lib/network.h>
+#include <lib/sockunion.h>
+#include <lib/thread.h>
+#include <lib/vty.h>
+
+#include "pimd.h"
+
+#include "pim_msdp.h"
+#include "pim_msdp_socket.h"
+
+extern struct zebra_privs_t pimd_privs;
+
+/* increase socket send buffer size */
+static void
+pim_msdp_update_sock_send_buffer_size (int fd)
+{
+ int size = PIM_MSDP_SOCKET_SNDBUF_SIZE;
+ int optval;
+ socklen_t optlen = sizeof(optval);
+
+ if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &optval, &optlen) < 0) {
+ zlog_err("getsockopt of SO_SNDBUF failed %s\n", safe_strerror(errno));
+ return;
+ }
+
+ if (optval < size) {
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) < 0) {
+ zlog_err("Couldn't increase send buffer: %s\n", safe_strerror(errno));
+ }
+ }
+}
+
+/* passive peer socket accept */
+static int
+pim_msdp_sock_accept(struct thread *thread)
+{
+ union sockunion su;
+ struct pim_msdp_listener *listener = THREAD_ARG(thread);
+ int accept_sock;
+ int msdp_sock;
+ struct pim_msdp_peer *mp;
+ char buf[SU_ADDRSTRLEN];
+
+ sockunion_init(&su);
+
+ /* re-register accept thread */
+ accept_sock = THREAD_FD(thread);
+ if (accept_sock < 0) {
+ zlog_err ("accept_sock is negative value %d", accept_sock);
+ return -1;
+ }
+ listener->thread = thread_add_read(master, pim_msdp_sock_accept,
+ listener, accept_sock);
+
+ /* accept client connection. */
+ msdp_sock = sockunion_accept(accept_sock, &su);
+ if (msdp_sock < 0) {
+ zlog_err ("pim_msdp_sock_accept failed (%s)", safe_strerror (errno));
+ return -1;
+ }
+
+ /* see if have peer config for this */
+ mp = pim_msdp_peer_find(su.sin.sin_addr);
+ if (!mp || !PIM_MSDP_PEER_IS_LISTENER(mp)) {
+ ++msdp->rejected_accepts;
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ zlog_err("msdp peer connection refused from %s",
+ sockunion2str(&su, buf, SU_ADDRSTRLEN));
+ }
+ close(msdp_sock);
+ return -1;
+ }
+
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP peer %s accept success%s", mp->key_str, mp->fd>=0?"(dup)":"");
+ }
+
+ /* if we have an existing connection we need to kill that one
+ * with this one */
+ if (mp->fd >= 0) {
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ zlog_err("msdp peer new connection from %s stop old connection",
+ sockunion2str(&su, buf, SU_ADDRSTRLEN));
+ }
+ pim_msdp_peer_stop_tcp_conn(mp, true /* chg_state */);
+ }
+ mp->fd = msdp_sock;
+ set_nonblocking(mp->fd);
+ pim_msdp_update_sock_send_buffer_size(mp->fd);
+ pim_msdp_peer_established(mp);
+ return 0;
+}
+
+/* global listener for the MSDP well know TCP port */
+int
+pim_msdp_sock_listen(void)
+{
+ int sock;
+ int socklen;
+ struct sockaddr_in sin;
+ int rc;
+ struct pim_msdp_listener *listener = &msdp->listener;
+
+ if (msdp->flags & PIM_MSDPF_LISTENER) {
+ /* listener already setup */
+ return 0;
+ }
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock < 0) {
+ zlog_err ("socket: %s", safe_strerror (errno));
+ return sock;
+ }
+
+ memset(&sin, 0, sizeof(struct sockaddr_in));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(PIM_MSDP_TCP_PORT);
+ socklen = sizeof(struct sockaddr_in);
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+ sin.sin_len = socklen;
+#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
+
+ sockopt_reuseaddr(sock);
+ sockopt_reuseport(sock);
+
+ if (pimd_privs.change(ZPRIVS_RAISE)) {
+ zlog_err ("pim_msdp_socket: could not raise privs, %s",
+ safe_strerror (errno));
+ }
+
+ /* bind to well known TCP port */
+ rc = bind(sock, (struct sockaddr *)&sin, socklen);
+
+ if (pimd_privs.change(ZPRIVS_LOWER)) {
+ zlog_err ("pim_msdp_socket: could not lower privs, %s",
+ safe_strerror (errno));
+ }
+
+ if (rc < 0) {
+ zlog_err ("pim_msdp_socket bind to port %d: %s", ntohs(sin.sin_port), safe_strerror (errno));
+ close(sock);
+ return rc;
+ }
+
+ rc = listen(sock, 3 /* backlog */);
+ if (rc < 0) {
+ zlog_err ("pim_msdp_socket listen: %s", safe_strerror (errno));
+ close(sock);
+ return rc;
+ }
+
+ /* add accept thread */
+ listener->fd = sock;
+ memcpy(&listener->su, &sin, socklen);
+ listener->thread = thread_add_read(msdp->master, pim_msdp_sock_accept, listener, sock);
+
+ msdp->flags |= PIM_MSDPF_LISTENER;
+ return 0;
+}
+
+/* active peer socket setup */
+int
+pim_msdp_sock_connect(struct pim_msdp_peer *mp)
+{
+ int rc;
+
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ zlog_debug("MSDP peer %s attempt connect%s", mp->key_str, mp->fd<0?"":"(dup)");
+ }
+
+ /* if we have an existing connection we need to kill that one
+ * with this one */
+ if (mp->fd >= 0) {
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ zlog_err("msdp duplicate connect to %s nuke old connection", mp->key_str);
+ }
+ pim_msdp_peer_stop_tcp_conn(mp, false /* chg_state */);
+ }
+
+ /* Make socket for the peer. */
+ mp->fd = sockunion_socket(&mp->su_peer);
+ if (mp->fd < 0) {
+ zlog_err ("pim_msdp_socket socket failure: %s", safe_strerror (errno));
+ return -1;
+ }
+
+ set_nonblocking(mp->fd);
+
+ /* Set socket send buffer size */
+ pim_msdp_update_sock_send_buffer_size(mp->fd);
+ sockopt_reuseaddr(mp->fd);
+ sockopt_reuseport(mp->fd);
+
+ /* source bind */
+ rc = sockunion_bind(mp->fd, &mp->su_local, 0, &mp->su_local);
+ if (rc < 0) {
+ zlog_err ("pim_msdp_socket connect bind failure: %s", safe_strerror (errno));
+ close(mp->fd);
+ mp->fd = -1;
+ return rc;
+ }
+
+ /* Connect to the remote mp. */
+ return (sockunion_connect(mp->fd, &mp->su_peer, htons(PIM_MSDP_TCP_PORT), 0));
+}
+
diff --git a/pimd/pim_msdp_socket.h b/pimd/pim_msdp_socket.h
new file mode 100644
index 0000000000..bf3d12ad2c
--- /dev/null
+++ b/pimd/pim_msdp_socket.h
@@ -0,0 +1,25 @@
+/*
+ * IP MSDP socket management for Quagga
+ * Copyright (C) 2016 Cumulus 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 PIM_MSDP_SOCKET_H
+#define PIM_MSDP_SOCKET_H
+
+int pim_msdp_sock_listen(void);
+int pim_msdp_sock_connect(struct pim_msdp_peer *mp);
+#endif
diff --git a/pimd/pim_msg.c b/pimd/pim_msg.c
index 9d0fc0ad8f..7ea7b1ad82 100644
--- a/pimd/pim_msg.c
+++ b/pimd/pim_msg.c
@@ -21,11 +21,20 @@
#include <zebra.h>
#include "if.h"
+#include "log.h"
+#include "prefix.h"
+#include "vty.h"
+#include "plist.h"
#include "pimd.h"
+#include "pim_vty.h"
#include "pim_pim.h"
#include "pim_msg.h"
#include "pim_util.h"
+#include "pim_str.h"
+#include "pim_iface.h"
+#include "pim_rp.h"
+#include "pim_rpf.h"
void pim_msg_build_header(uint8_t *pim_msg, int pim_msg_size,
uint8_t pim_msg_type)
@@ -86,9 +95,9 @@ uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf,
return buf + ENCODED_IPV4_GROUP_SIZE;
}
-uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf,
- int buf_size,
- struct in_addr addr)
+uint8_t *
+pim_msg_addr_encode_ipv4_source(uint8_t *buf, int buf_size,
+ struct in_addr addr, uint8_t bits)
{
const int ENCODED_IPV4_SOURCE_SIZE = 8;
@@ -98,9 +107,172 @@ uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf,
buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */
buf[1] = '\0'; /* native encoding */
- buf[2] = 4; /* reserved = 0 | S bit = 1 | W bit = 0 | R bit = 0 */
+ buf[2] = bits;
buf[3] = 32; /* mask len */
memcpy(buf+4, &addr, sizeof(struct in_addr));
return buf + ENCODED_IPV4_SOURCE_SIZE;
}
+
+int
+pim_msg_join_prune_encode (uint8_t *buf, int buf_size, int is_join,
+ struct pim_upstream *up,
+ struct in_addr upstream, int holdtime)
+{
+ uint8_t *pim_msg = buf;
+ uint8_t *pim_msg_curr = buf + PIM_MSG_HEADER_LEN;
+ uint8_t *end = buf + buf_size;
+ uint16_t *prunes = NULL;
+ uint16_t *joins = NULL;
+ struct in_addr stosend;
+ uint8_t bits;
+ int remain;
+
+ remain = end - pim_msg_curr;
+ pim_msg_curr = pim_msg_addr_encode_ipv4_ucast (pim_msg_curr, buf_size - PIM_MSG_HEADER_LEN, upstream);
+ if (!pim_msg_curr) {
+ char dst_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<dst?>", upstream, dst_str, sizeof(dst_str));
+ zlog_warn("%s: failure encoding destination address %s: space left=%d",
+ __PRETTY_FUNCTION__, dst_str, remain);
+ return -3;
+ }
+
+ remain = end - pim_msg_curr;
+ if (remain < 4) {
+ zlog_warn("%s: group will not fit: space left=%d",
+ __PRETTY_FUNCTION__, remain);
+ return -4;
+ }
+
+ *pim_msg_curr = 0; /* reserved */
+ ++pim_msg_curr;
+ *pim_msg_curr = 1; /* number of groups */
+ ++pim_msg_curr;
+
+ *((uint16_t *) pim_msg_curr) = htons(holdtime);
+ ++pim_msg_curr;
+ ++pim_msg_curr;
+
+ remain = end - pim_msg_curr;
+ pim_msg_curr = pim_msg_addr_encode_ipv4_group (pim_msg_curr, remain,
+ up->sg.grp);
+ if (!pim_msg_curr) {
+ char group_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<grp?>", up->sg.grp, group_str, sizeof(group_str));
+ zlog_warn("%s: failure encoding group address %s: space left=%d",
+ __PRETTY_FUNCTION__, group_str, remain);
+ return -5;
+ }
+
+ remain = end - pim_msg_curr;
+ if (remain < 4) {
+ zlog_warn("%s: sources will not fit: space left=%d",
+ __PRETTY_FUNCTION__, remain);
+ return -6;
+ }
+
+ /* number of joined sources */
+ joins = (uint16_t *)pim_msg_curr;
+ *joins = htons(is_join ? 1 : 0);
+ ++pim_msg_curr;
+ ++pim_msg_curr;
+
+ /* number of pruned sources */
+ prunes = (uint16_t *)pim_msg_curr;
+ *prunes = htons(is_join ? 0 : 1);
+ ++pim_msg_curr;
+ ++pim_msg_curr;
+
+ remain = end - pim_msg_curr;
+ if (up->sg.src.s_addr == INADDR_ANY)
+ {
+ struct pim_rpf *rpf = pim_rp_g (up->sg.grp);
+ bits = PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_WC_BIT | PIM_ENCODE_RPT_BIT;
+ stosend = rpf->rpf_addr.u.prefix4;
+ }
+ else
+ {
+ bits = PIM_ENCODE_SPARSE_BIT;
+ stosend = up->sg.src;
+ }
+ pim_msg_curr = pim_msg_addr_encode_ipv4_source (pim_msg_curr, remain, stosend, bits);
+ if (!pim_msg_curr) {
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<src?>", up->sg.src, source_str, sizeof(source_str));
+ zlog_warn("%s: failure encoding source address %s: space left=%d",
+ __PRETTY_FUNCTION__, source_str, remain);
+ return -7;
+ }
+ remain = pim_msg_curr - pim_msg;
+
+ /*
+ * This is not implemented correctly at this point in time
+ * Make it stop.
+ */
+#if 0
+ if (up->sg.src.s_addr == INADDR_ANY)
+ {
+ struct pim_upstream *child;
+ struct listnode *up_node;
+ int send_prune = 0;
+
+ zlog_debug ("%s: Considering (%s) children for (S,G,rpt) prune",
+ __PRETTY_FUNCTION__, up->sg_str);
+ for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
+ {
+ if (child->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
+ {
+ if (!pim_rpf_is_same(&up->rpf, &child->rpf))
+ {
+ send_prune = 1;
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug ("%s: SPT Bit and RPF'(%s) != RPF'(S,G): Add Prune (%s,rpt) to compound message",
+ __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
+ }
+ else
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug ("%s: SPT Bit and RPF'(%s) == RPF'(S,G): Not adding Prune for (%s,rpt)",
+ __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
+ }
+ else if (pim_upstream_is_sg_rpt (child))
+ {
+ if (pim_upstream_empty_inherited_olist (child))
+ {
+ send_prune = 1;
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug ("%s: inherited_olist(%s,rpt) is NULL, Add Prune to compound message",
+ __PRETTY_FUNCTION__, child->sg_str);
+ }
+ else if (!pim_rpf_is_same (&up->rpf, &child->rpf))
+ {
+ send_prune = 1;
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug ("%s: RPF'(%s) != RPF'(%s,rpt), Add Prune to compound message",
+ __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
+ }
+ else
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug ("%s: RPF'(%s) == RPF'(%s,rpt), Do not add Prune to compound message",
+ __PRETTY_FUNCTION__, up->sg_str, child->sg_str);
+ }
+ else
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug ("%s: SPT bit is not set for (%s)",
+ __PRETTY_FUNCTION__, child->sg_str);
+ if (send_prune)
+ {
+ pim_msg_curr = pim_msg_addr_encode_ipv4_source (pim_msg_curr, remain,
+ child->sg.src,
+ PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_RPT_BIT);
+ remain = pim_msg_curr - pim_msg;
+ *prunes = htons(ntohs(*prunes) + 1);
+ send_prune = 0;
+ }
+ }
+ }
+#endif
+ pim_msg_build_header (pim_msg, remain, PIM_MSG_TYPE_JOIN_PRUNE);
+
+ return remain;
+}
diff --git a/pimd/pim_msg.h b/pimd/pim_msg.h
index 96a89659e6..5229f85c72 100644
--- a/pimd/pim_msg.h
+++ b/pimd/pim_msg.h
@@ -43,8 +43,17 @@ uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf,
uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf,
int buf_size,
struct in_addr addr);
+
+#define PIM_ENCODE_SPARSE_BIT 0x04
+#define PIM_ENCODE_WC_BIT 0x02
+#define PIM_ENCODE_RPT_BIT 0x01
uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf,
int buf_size,
- struct in_addr addr);
+ struct in_addr addr,
+ uint8_t bits);
+
+int pim_msg_join_prune_encode (uint8_t *buf, int buf_size, int is_join,
+ struct pim_upstream *up,
+ struct in_addr upstream, int holdtime);
#endif /* PIM_MSG_H */
diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c
index 04792eb35e..346b911157 100644
--- a/pimd/pim_neighbor.c
+++ b/pimd/pim_neighbor.c
@@ -24,6 +24,8 @@
#include "prefix.h"
#include "memory.h"
#include "if.h"
+#include "vty.h"
+#include "plist.h"
#include "pimd.h"
#include "pim_neighbor.h"
@@ -33,6 +35,8 @@
#include "pim_pim.h"
#include "pim_upstream.h"
#include "pim_ifchannel.h"
+#include "pim_rp.h"
+#include "pim_zebra.h"
static void dr_election_by_addr(struct interface *ifp)
{
@@ -125,8 +129,8 @@ int pim_if_dr_election(struct interface *ifp)
if (old_dr_addr.s_addr != pim_ifp->pim_dr_addr.s_addr) {
if (PIM_DEBUG_PIM_EVENTS) {
- char dr_old_str[100];
- char dr_new_str[100];
+ char dr_old_str[INET_ADDRSTRLEN];
+ char dr_new_str[INET_ADDRSTRLEN];
pim_inet4_dump("<old_dr?>", old_dr_addr, dr_old_str, sizeof(dr_old_str));
pim_inet4_dump("<new_dr?>", pim_ifp->pim_dr_addr, dr_new_str, sizeof(dr_new_str));
zlog_debug("%s: DR was %s now is %s on interface %s",
@@ -207,20 +211,18 @@ static int on_neighbor_timer(struct thread *t)
struct interface *ifp;
char msg[100];
- zassert(t);
neigh = THREAD_ARG(t);
- zassert(neigh);
ifp = neigh->interface;
if (PIM_DEBUG_PIM_TRACE) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
zlog_debug("Expired %d sec holdtime for neighbor %s on interface %s",
neigh->holdtime, src_str, ifp->name);
}
- neigh->t_expire_timer = 0;
+ neigh->t_expire_timer = NULL;
snprintf(msg, sizeof(msg), "%d-sec holdtime expired", neigh->holdtime);
pim_neighbor_delete(ifp, neigh, msg);
@@ -237,26 +239,11 @@ static int on_neighbor_timer(struct thread *t)
return 0;
}
-static void neighbor_timer_off(struct pim_neighbor *neigh)
-{
- if (PIM_DEBUG_PIM_TRACE_DETAIL) {
- if (neigh->t_expire_timer) {
- char src_str[100];
- pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
- zlog_debug("%s: cancelling timer for neighbor %s on %s",
- __PRETTY_FUNCTION__,
- src_str, neigh->interface->name);
- }
- }
- THREAD_OFF(neigh->t_expire_timer);
- zassert(!neigh->t_expire_timer);
-}
-
void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime)
{
neigh->holdtime = holdtime;
- neighbor_timer_off(neigh);
+ THREAD_OFF(neigh->t_expire_timer);
/*
0xFFFF is request for no holdtime
@@ -266,7 +253,7 @@ void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime)
}
if (PIM_DEBUG_PIM_TRACE_DETAIL) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
zlog_debug("%s: starting %u sec timer for neighbor %s on %s",
__PRETTY_FUNCTION__,
@@ -290,15 +277,15 @@ static struct pim_neighbor *pim_neighbor_new(struct interface *ifp,
{
struct pim_interface *pim_ifp;
struct pim_neighbor *neigh;
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
zassert(ifp);
pim_ifp = ifp->info;
zassert(pim_ifp);
- neigh = XMALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh));
+ neigh = XCALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh));
if (!neigh) {
- zlog_err("%s: PIM XMALLOC(%zu) failure",
+ zlog_err("%s: PIM XCALLOC(%zu) failure",
__PRETTY_FUNCTION__, sizeof(*neigh));
return 0;
}
@@ -311,10 +298,18 @@ static struct pim_neighbor *pim_neighbor_new(struct interface *ifp,
neigh->dr_priority = dr_priority;
neigh->generation_id = generation_id;
neigh->prefix_list = addr_list;
- neigh->t_expire_timer = 0;
+ neigh->t_expire_timer = NULL;
neigh->interface = ifp;
pim_neighbor_timer_reset(neigh, holdtime);
+ /*
+ * The pim_ifstat_hello_sent variable is used to decide if
+ * we should expedite a hello out the interface. If we
+ * establish a new neighbor, we unfortunately need to
+ * reset the value so that we can know to hurry up and
+ * hello
+ */
+ pim_ifp->pim_ifstat_hello_sent = 0;
pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
@@ -391,7 +386,8 @@ struct pim_neighbor *pim_neighbor_find(struct interface *ifp,
struct pim_neighbor *neigh;
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ if (!pim_ifp)
+ return NULL;
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
if (source_addr.s_addr == neigh->source_addr.s_addr) {
@@ -399,7 +395,35 @@ struct pim_neighbor *pim_neighbor_find(struct interface *ifp,
}
}
- return 0;
+ return NULL;
+}
+
+/*
+ * Find the *one* interface out
+ * this interface. If more than
+ * one return NULL
+ */
+struct pim_neighbor *
+pim_neighbor_find_if (struct interface *ifp)
+{
+ struct pim_interface *pim_ifp = ifp->info;
+
+ if (!pim_ifp || pim_ifp->pim_neighbor_list->count != 1)
+ return NULL;
+
+ return listnode_head (pim_ifp->pim_neighbor_list);
+}
+
+/* rpf info associated with an upstream entry needs to be re-evaluated
+ * when an RPF neighbor comes or goes */
+static void
+pim_neighbor_rpf_update(void)
+{
+ /* XXX: for the time being piggyback on the timer used on rib changes
+ * to scan and update the rpf nexthop. This is expensive processing
+ * and we should be able to optimize neighbor changes differently than
+ * nexthop changes. */
+ sched_rpf_cache_refresh();
}
struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
@@ -410,7 +434,8 @@ struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
uint16_t override_interval,
uint32_t dr_priority,
uint32_t generation_id,
- struct list *addr_list)
+ struct list *addr_list,
+ int send_hello_now)
{
struct pim_interface *pim_ifp;
struct pim_neighbor *neigh;
@@ -449,9 +474,22 @@ struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
message with a new GenID is received from an existing neighbor, a
new Hello message should be sent on this interface after a
randomized delay between 0 and Triggered_Hello_Delay.
+
+ This is a bit silly to do it that way. If I get a new
+ genid we need to send the hello *now* because we've
+ lined up a bunch of join/prune messages to go out the
+ interface.
*/
- pim_hello_restart_triggered(neigh->interface);
+ if (send_hello_now)
+ pim_hello_restart_now (ifp);
+ else
+ pim_hello_restart_triggered(neigh->interface);
+
+ pim_upstream_find_new_rpf();
+ pim_rp_setup ();
+
+ pim_neighbor_rpf_update();
return neigh;
}
@@ -508,7 +546,7 @@ void pim_neighbor_delete(struct interface *ifp,
const char *delete_message)
{
struct pim_interface *pim_ifp;
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_ifp = ifp->info;
zassert(pim_ifp);
@@ -517,7 +555,7 @@ void pim_neighbor_delete(struct interface *ifp,
zlog_info("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s",
src_str, ifp->name, delete_message);
- neighbor_timer_off(neigh);
+ THREAD_OFF(neigh->t_expire_timer);
pim_if_assert_on_neighbor_down(ifp, neigh->source_addr);
@@ -564,6 +602,8 @@ void pim_neighbor_delete(struct interface *ifp,
listnode_delete(pim_ifp->pim_neighbor_list, neigh);
pim_neighbor_free(neigh);
+
+ pim_neighbor_rpf_update();
}
void pim_neighbor_delete_all(struct interface *ifp,
@@ -646,9 +686,9 @@ static void delete_from_neigh_addr(struct interface *ifp,
{
struct prefix *p = pim_neighbor_find_secondary(neigh, addr->u.prefix4);
if (p) {
- char addr_str[100];
- char this_neigh_str[100];
- char other_neigh_str[100];
+ char addr_str[INET_ADDRSTRLEN];
+ char this_neigh_str[INET_ADDRSTRLEN];
+ char other_neigh_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr->u.prefix4, addr_str, sizeof(addr_str));
pim_inet4_dump("<neigh1?>", neigh_addr, this_neigh_str, sizeof(this_neigh_str));
diff --git a/pimd/pim_neighbor.h b/pimd/pim_neighbor.h
index e023a7f1ef..211eda25c7 100644
--- a/pimd/pim_neighbor.h
+++ b/pimd/pim_neighbor.h
@@ -25,6 +25,7 @@
#include "if.h"
#include "linklist.h"
+#include "prefix.h"
#include "pim_tlv.h"
@@ -46,6 +47,12 @@ void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime);
void pim_neighbor_free(struct pim_neighbor *neigh);
struct pim_neighbor *pim_neighbor_find(struct interface *ifp,
struct in_addr source_addr);
+
+struct pim_neighbor *pim_neighbor_find_if (struct interface *ifp);
+
+
+#define PIM_NEIGHBOR_SEND_DELAY 0
+#define PIM_NEIGHBOR_SEND_NOW 1
struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
struct in_addr source_addr,
pim_hello_options hello_options,
@@ -54,7 +61,8 @@ struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
uint16_t override_interval,
uint32_t dr_priority,
uint32_t generation_id,
- struct list *addr_list);
+ struct list *addr_list,
+ int send_hello_now);
void pim_neighbor_delete(struct interface *ifp,
struct pim_neighbor *neigh,
const char *delete_message);
diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c
index ebbc6e19f9..0cebe47355 100644
--- a/pimd/pim_oil.c
+++ b/pimd/pim_oil.c
@@ -24,6 +24,8 @@
#include "memory.h"
#include "linklist.h"
#include "if.h"
+#include "hash.h"
+#include "jhash.h"
#include "pimd.h"
#include "pim_oil.h"
@@ -31,104 +33,162 @@
#include "pim_iface.h"
#include "pim_time.h"
+struct list *pim_channel_oil_list = NULL;
+struct hash *pim_channel_oil_hash = NULL;
+
+static int
+pim_channel_oil_compare (struct channel_oil *c1, struct channel_oil *c2)
+{
+ if (ntohl(c1->oil.mfcc_mcastgrp.s_addr) < ntohl(c2->oil.mfcc_mcastgrp.s_addr))
+ return -1;
+
+ if (ntohl(c1->oil.mfcc_mcastgrp.s_addr) > ntohl(c2->oil.mfcc_mcastgrp.s_addr))
+ return 1;
+
+ if (ntohl(c1->oil.mfcc_origin.s_addr) < ntohl(c2->oil.mfcc_origin.s_addr))
+ return -1;
+
+ if (ntohl(c1->oil.mfcc_origin.s_addr) > ntohl(c2->oil.mfcc_origin.s_addr))
+ return 1;
+
+ return 0;
+}
+
+static int
+pim_oil_equal (const void *arg1, const void *arg2)
+{
+ const struct channel_oil *c1 = (const struct channel_oil *)arg1;
+ const struct channel_oil *c2 = (const struct channel_oil *)arg2;
+
+ if ((c1->oil.mfcc_mcastgrp.s_addr == c2->oil.mfcc_mcastgrp.s_addr) &&
+ (c1->oil.mfcc_origin.s_addr == c2->oil.mfcc_origin.s_addr))
+ return 1;
+
+ return 0;
+}
+
+static unsigned int
+pim_oil_hash_key (void *arg)
+{
+ struct channel_oil *oil = (struct channel_oil *)arg;
+
+ return jhash_2words (oil->oil.mfcc_mcastgrp.s_addr, oil->oil.mfcc_origin.s_addr, 0);
+}
+
+void
+pim_oil_init (void)
+{
+ pim_channel_oil_hash = hash_create_size (8192, pim_oil_hash_key,
+ pim_oil_equal);
+
+ 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 = (int (*)(void *, void *)) pim_channel_oil_compare;
+}
+
+void
+pim_oil_terminate (void)
+{
+ if (pim_channel_oil_list)
+ list_free(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;
+}
+
void pim_channel_oil_free(struct channel_oil *c_oil)
{
XFREE(MTYPE_PIM_CHANNEL_OIL, c_oil);
}
-static void pim_channel_oil_delete(struct channel_oil *c_oil)
+static void
+pim_del_channel_oil (struct channel_oil *c_oil)
{
/*
notice that listnode_delete() can't be moved
into pim_channel_oil_free() because the later is
called by list_delete_all_node()
*/
- listnode_delete(qpim_channel_oil_list, c_oil);
+ listnode_delete(pim_channel_oil_list, c_oil);
+ hash_release (pim_channel_oil_hash, c_oil);
pim_channel_oil_free(c_oil);
}
-static struct channel_oil *channel_oil_new(struct in_addr group_addr,
- struct in_addr source_addr,
- int input_vif_index)
+static struct channel_oil *
+pim_add_channel_oil (struct prefix_sg *sg,
+ int input_vif_index)
{
struct channel_oil *c_oil;
- struct interface *ifp_in;
+ struct interface *ifp;
- ifp_in = pim_if_find_by_vif_index(input_vif_index);
- if (!ifp_in) {
+ ifp = pim_if_find_by_vif_index(input_vif_index);
+ if (!ifp) {
/* warning only */
- char group_str[100];
- char source_str[100];
- pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", source_addr, source_str, sizeof(source_str));
- zlog_warn("%s: (S,G)=(%s,%s) could not find input interface for input_vif_index=%d",
+ zlog_warn("%s: (S,G)=%s could not find input interface for input_vif_index=%d",
__PRETTY_FUNCTION__,
- source_str, group_str, input_vif_index);
+ pim_str_sg_dump (sg), input_vif_index);
}
c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil));
if (!c_oil) {
zlog_err("PIM XCALLOC(%zu) failure", sizeof(*c_oil));
- return 0;
+ return NULL;
}
- c_oil->oil.mfcc_mcastgrp = group_addr;
- c_oil->oil.mfcc_origin = source_addr;
+ 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->oil.mfcc_parent = input_vif_index;
c_oil->oil_ref_count = 1;
c_oil->installed = 0;
- zassert(c_oil->oil_size == 0);
+ listnode_add_sort(pim_channel_oil_list, c_oil);
return c_oil;
}
-static struct channel_oil *pim_add_channel_oil(struct in_addr group_addr,
- struct in_addr source_addr,
- int input_vif_index)
+static struct channel_oil *pim_find_channel_oil(struct prefix_sg *sg)
{
- struct channel_oil *c_oil;
+ struct channel_oil *c_oil = NULL;
+ struct channel_oil lookup;
- c_oil = channel_oil_new(group_addr, source_addr, input_vif_index);
- if (!c_oil) {
- zlog_warn("PIM XCALLOC(%zu) failure", sizeof(*c_oil));
- return 0;
- }
+ lookup.oil.mfcc_mcastgrp = sg->grp;
+ lookup.oil.mfcc_origin = sg->src;
- listnode_add(qpim_channel_oil_list, c_oil);
+ c_oil = hash_lookup (pim_channel_oil_hash, &lookup);
return c_oil;
}
-static struct channel_oil *pim_find_channel_oil(struct in_addr group_addr,
- struct in_addr source_addr)
-{
- struct listnode *node;
- struct channel_oil *c_oil;
-
- for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) {
- if ((group_addr.s_addr == c_oil->oil.mfcc_mcastgrp.s_addr) &&
- (source_addr.s_addr == c_oil->oil.mfcc_origin.s_addr))
- return c_oil;
- }
-
- return 0;
-}
-
-struct channel_oil *pim_channel_oil_add(struct in_addr group_addr,
- struct in_addr source_addr,
+struct channel_oil *pim_channel_oil_add(struct prefix_sg *sg,
int input_vif_index)
{
struct channel_oil *c_oil;
- c_oil = pim_find_channel_oil(group_addr, source_addr);
+ c_oil = pim_find_channel_oil(sg);
if (c_oil) {
+ if (c_oil->oil.mfcc_parent != input_vif_index)
+ {
+ c_oil->oil_inherited_rescan = 1;
+ if (PIM_DEBUG_MROUTE)
+ zlog_debug ("%s: Existing channel oil %s points to %d, modifying to point at %d",
+ __PRETTY_FUNCTION__, pim_str_sg_dump(sg), c_oil->oil.mfcc_parent, input_vif_index);
+ }
+ c_oil->oil.mfcc_parent = input_vif_index;
++c_oil->oil_ref_count;
return c_oil;
}
- return pim_add_channel_oil(group_addr, source_addr, input_vif_index);
+ return pim_add_channel_oil(sg, input_vif_index);
}
void pim_channel_oil_del(struct channel_oil *c_oil)
@@ -136,10 +196,96 @@ void pim_channel_oil_del(struct channel_oil *c_oil)
--c_oil->oil_ref_count;
if (c_oil->oil_ref_count < 1) {
- pim_channel_oil_delete(c_oil);
+ pim_del_channel_oil(c_oil);
}
}
+int
+pim_channel_del_oif (struct channel_oil *channel_oil,
+ struct interface *oif,
+ uint32_t proto_mask)
+{
+ struct pim_interface *pim_ifp;
+
+ zassert (channel_oil);
+ zassert (oif);
+
+ pim_ifp = oif->info;
+
+ /*
+ * Don't do anything if we've been asked to remove a source
+ * that is not actually on it.
+ */
+ if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask))
+ {
+ if (PIM_DEBUG_MROUTE)
+ {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
+ pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
+ zlog_debug("%s %s: no existing protocol mask %u(%u) for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
+ __FILE__, __PRETTY_FUNCTION__,
+ proto_mask, channel_oil->oif_flags[pim_ifp->mroute_vif_index],
+ oif->name, pim_ifp->mroute_vif_index,
+ channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
+ source_str, group_str);
+ }
+ return 0;
+ }
+
+ channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
+
+ if (channel_oil->oif_flags[pim_ifp->mroute_vif_index])
+ {
+ if (PIM_DEBUG_MROUTE)
+ {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
+ pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
+ zlog_debug("%s %s: other protocol masks remain for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
+ __FILE__, __PRETTY_FUNCTION__,
+ oif->name, pim_ifp->mroute_vif_index,
+ channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
+ source_str, group_str);
+ }
+ return 0;
+ }
+
+ channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
+
+ if (pim_mroute_add (channel_oil, __PRETTY_FUNCTION__)) {
+ if (PIM_DEBUG_MROUTE)
+ {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
+ pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
+ zlog_debug("%s %s: could not remove output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
+ __FILE__, __PRETTY_FUNCTION__,
+ oif->name, pim_ifp->mroute_vif_index,
+ source_str, group_str);
+ }
+ return -1;
+ }
+
+ if (PIM_DEBUG_MROUTE)
+ {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
+ pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
+ zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
+ __FILE__, __PRETTY_FUNCTION__,
+ source_str, group_str,
+ proto_mask, oif->name, pim_ifp->mroute_vif_index);
+ }
+
+ return 0;
+}
+
+
int pim_channel_add_oif(struct channel_oil *channel_oil,
struct interface *oif,
uint32_t proto_mask)
@@ -147,21 +293,18 @@ int pim_channel_add_oif(struct channel_oil *channel_oil,
struct pim_interface *pim_ifp;
int old_ttl;
- zassert(channel_oil);
+ /*
+ * If we've gotten here we've gone bad, but let's
+ * not take down pim
+ */
+ if (!channel_oil)
+ {
+ zlog_warn ("Attempt to Add OIF for non-existent channel oil");
+ return -1;
+ }
pim_ifp = oif->info;
- if (PIM_DEBUG_MROUTE) {
- char group_str[100];
- char source_str[100];
- pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
- zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
- __FILE__, __PRETTY_FUNCTION__,
- source_str, group_str,
- proto_mask, oif->name, pim_ifp->mroute_vif_index);
- }
-
#ifdef PIM_ENFORCE_LOOPFREE_MFC
/*
Prevent creating MFC entry with OIF=IIF.
@@ -175,10 +318,11 @@ int pim_channel_add_oif(struct channel_oil *channel_oil,
TODO T22.
*/
if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
+ channel_oil->oil_inherited_rescan = 1;
if (PIM_DEBUG_MROUTE)
{
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
@@ -195,8 +339,8 @@ int pim_channel_add_oif(struct channel_oil *channel_oil,
if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
if (PIM_DEBUG_MROUTE)
{
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
@@ -218,8 +362,8 @@ int pim_channel_add_oif(struct channel_oil *channel_oil,
if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
if (PIM_DEBUG_MROUTE)
{
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
@@ -238,8 +382,8 @@ int pim_channel_add_oif(struct channel_oil *channel_oil,
if (old_ttl > 0) {
if (PIM_DEBUG_MROUTE)
{
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
@@ -252,11 +396,11 @@ int pim_channel_add_oif(struct channel_oil *channel_oil,
channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL;
- if (pim_mroute_add(channel_oil)) {
+ if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) {
if (PIM_DEBUG_MROUTE)
{
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
@@ -274,8 +418,8 @@ int pim_channel_add_oif(struct channel_oil *channel_oil,
channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
if (PIM_DEBUG_MROUTE) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
@@ -286,3 +430,24 @@ int pim_channel_add_oif(struct channel_oil *channel_oil,
return 0;
}
+
+int
+pim_channel_oil_empty (struct channel_oil *c_oil)
+{
+ static uint32_t zero[MAXVIFS];
+ static int inited = 0;
+
+ if (!c_oil)
+ return 1;
+ /*
+ * Not sure that this is necessary, but I would rather ensure
+ * that this works.
+ */
+ if (!inited)
+ {
+ memset(&zero, 0, sizeof(uint32_t) * MAXVIFS);
+ inited = 1;
+ }
+
+ return !memcmp(c_oil->oif_flags, zero, MAXVIFS * sizeof(uint32_t));
+}
diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h
index 540acce3a3..143cfb7942 100644
--- a/pimd/pim_oil.h
+++ b/pimd/pim_oil.h
@@ -51,6 +51,7 @@
struct channel_counts
{
+ unsigned long long lastused;
unsigned long pktcnt;
unsigned long oldpktcnt;
unsigned long bytecnt;
@@ -69,6 +70,7 @@ struct channel_counts
struct channel_oil {
struct mfcctl oil;
int installed;
+ int oil_inherited_rescan;
int oil_size;
int oil_ref_count;
time_t oif_creation[MAXVIFS];
@@ -76,14 +78,22 @@ struct channel_oil {
struct channel_counts cc;
};
+extern struct list *pim_channel_oil_list;
+
+void pim_oil_init (void);
+void pim_oil_terminate (void);
+
void pim_channel_oil_free(struct channel_oil *c_oil);
-struct channel_oil *pim_channel_oil_add(struct in_addr group_addr,
- struct in_addr source_addr,
+struct channel_oil *pim_channel_oil_add(struct prefix_sg *sg,
int input_vif_index);
void pim_channel_oil_del(struct channel_oil *c_oil);
int pim_channel_add_oif(struct channel_oil *c_oil,
struct interface *oif,
uint32_t proto_mask);
+int pim_channel_del_oif (struct channel_oil *c_oil,
+ struct interface *oif,
+ uint32_t proto_mask);
+int pim_channel_oil_empty (struct channel_oil *c_oil);
#endif /* PIM_OIL_H */
diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c
index 0f41a43315..1dbbd7c655 100644
--- a/pimd/pim_pim.c
+++ b/pimd/pim_pim.c
@@ -44,6 +44,25 @@ static int on_pim_hello_send(struct thread *t);
static int pim_hello_send(struct interface *ifp,
uint16_t holdtime);
+static
+const char *pim_pim_msgtype2str (enum pim_msg_type type)
+{
+ switch (type)
+ {
+ case PIM_MSG_TYPE_HELLO: return "HELLO";
+ case PIM_MSG_TYPE_REGISTER: return "REGISTER";
+ case PIM_MSG_TYPE_REG_STOP: return "REGSTOP";
+ case PIM_MSG_TYPE_JOIN_PRUNE: return "JOINPRUNE";
+ case PIM_MSG_TYPE_BOOTSTRAP: return "BOOT";
+ case PIM_MSG_TYPE_ASSERT: return "ASSERT";
+ case PIM_MSG_TYPE_GRAFT: return "GRAFT";
+ case PIM_MSG_TYPE_GRAFT_ACK: return "GACK";
+ case PIM_MSG_TYPE_CANDIDATE: return "CANDIDATE";
+ }
+
+ return "UNKNOWN";
+}
+
static void sock_close(struct interface *ifp)
{
struct pim_interface *pim_ifp = ifp->info;
@@ -70,7 +89,10 @@ static void sock_close(struct interface *ifp)
pim_ifp->pim_sock_fd, ifp->name);
}
- if (close(pim_ifp->pim_sock_fd)) {
+ /*
+ * If the fd is already deleted no need to do anything here
+ */
+ if (pim_ifp->pim_sock_fd > 0 && close(pim_ifp->pim_sock_fd)) {
zlog_warn("Failure closing PIM socket fd=%d on interface %s: errno=%d: %s",
pim_ifp->pim_sock_fd, ifp->name,
errno, safe_strerror(errno));
@@ -78,11 +100,6 @@ static void sock_close(struct interface *ifp)
pim_ifp->pim_sock_fd = -1;
pim_ifp->pim_sock_creation = 0;
-
- zassert(pim_ifp->pim_sock_fd < 0);
- zassert(!pim_ifp->t_pim_sock_read);
- zassert(!pim_ifp->t_pim_hello_timer);
- zassert(!pim_ifp->pim_sock_creation);
}
void pim_sock_delete(struct interface *ifp, const char *delete_message)
@@ -114,67 +131,53 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
{
struct ip *ip_hdr;
size_t ip_hlen; /* ip header length in bytes */
- char src_str[100];
- char dst_str[100];
+ char src_str[INET_ADDRSTRLEN];
+ char dst_str[INET_ADDRSTRLEN];
uint8_t *pim_msg;
int pim_msg_len;
uint8_t pim_version;
- uint8_t pim_type;
+ enum pim_msg_type pim_type;
uint16_t pim_checksum; /* received checksum */
uint16_t checksum; /* computed checksum */
struct pim_neighbor *neigh;
- if (!ifp->info) {
- zlog_warn("%s: PIM not enabled on interface %s",
- __PRETTY_FUNCTION__, ifp->name);
- return -1;
- }
-
if (len < sizeof(*ip_hdr)) {
- zlog_warn("PIM packet size=%zu shorter than minimum=%zu",
- len, sizeof(*ip_hdr));
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug("PIM packet size=%zu shorter than minimum=%zu",
+ len, sizeof(*ip_hdr));
return -1;
}
ip_hdr = (struct ip *) buf;
-
- pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str, sizeof(src_str));
- pim_inet4_dump("<dst?>", ip_hdr->ip_dst, dst_str, sizeof(dst_str));
-
ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */
- if (PIM_DEBUG_PIM_PACKETS) {
- zlog_debug("Recv IP packet from %s to %s on %s: size=%zu ip_header_size=%zu ip_proto=%d",
- src_str, dst_str, ifp->name, len, ip_hlen, ip_hdr->ip_p);
- }
-
if (ip_hdr->ip_p != PIM_IP_PROTO_PIM) {
- zlog_warn("IP packet protocol=%d is not PIM=%d",
- ip_hdr->ip_p, PIM_IP_PROTO_PIM);
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug("IP packet protocol=%d is not PIM=%d",
+ ip_hdr->ip_p, PIM_IP_PROTO_PIM);
return -1;
}
if (ip_hlen < PIM_IP_HEADER_MIN_LEN) {
- zlog_warn("IP packet header size=%zu shorter than minimum=%d",
- ip_hlen, PIM_IP_HEADER_MIN_LEN);
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug("IP packet header size=%zu shorter than minimum=%d",
+ ip_hlen, PIM_IP_HEADER_MIN_LEN);
return -1;
}
if (ip_hlen > PIM_IP_HEADER_MAX_LEN) {
- zlog_warn("IP packet header size=%zu greater than maximum=%d",
- ip_hlen, PIM_IP_HEADER_MAX_LEN);
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug("IP packet header size=%zu greater than maximum=%d",
+ ip_hlen, PIM_IP_HEADER_MAX_LEN);
return -1;
}
pim_msg = buf + ip_hlen;
pim_msg_len = len - ip_hlen;
- if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
- pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_len);
- }
-
if (pim_msg_len < PIM_PIM_MIN_LEN) {
- zlog_warn("PIM message size=%d shorter than minimum=%d",
- pim_msg_len, PIM_PIM_MIN_LEN);
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug("PIM message size=%d shorter than minimum=%d",
+ pim_msg_len, PIM_PIM_MIN_LEN);
return -1;
}
@@ -182,8 +185,9 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
pim_type = PIM_MSG_HDR_GET_TYPE(pim_msg);
if (pim_version != PIM_PROTO_VERSION) {
- zlog_warn("Ignoring PIM pkt from %s with unsupported version: %d",
- ifp->name, pim_version);
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug("Ignoring PIM pkt from %s with unsupported version: %d",
+ ifp->name, pim_version);
return -1;
}
@@ -195,71 +199,79 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
checksum = in_cksum(pim_msg, pim_msg_len);
if (checksum != pim_checksum) {
- zlog_warn("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
- ifp->name, pim_checksum, checksum);
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x",
+ ifp->name, pim_checksum, checksum);
return -1;
}
if (PIM_DEBUG_PIM_PACKETS) {
- zlog_debug("Recv PIM packet from %s to %s on %s: ttl=%d pim_version=%d pim_type=%d pim_msg_size=%d checksum=%x",
- src_str, dst_str, ifp->name, ip_hdr->ip_ttl,
- pim_version, pim_type, pim_msg_len, checksum);
+ pim_inet4_dump("<src?>", ip_hdr->ip_src, src_str, sizeof(src_str));
+ pim_inet4_dump("<dst?>", ip_hdr->ip_dst, dst_str, sizeof(dst_str));
+ zlog_debug("Recv PIM %s packet from %s to %s on %s: ttl=%d pim_version=%d pim_msg_size=%d checksum=%x",
+ pim_pim_msgtype2str (pim_type), src_str, dst_str, ifp->name,
+ ip_hdr->ip_ttl, pim_version, pim_msg_len, checksum);
+ if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
+ pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_len);
+ }
}
- if (pim_type == PIM_MSG_TYPE_REG_STOP ||
- pim_type == PIM_MSG_TYPE_BOOTSTRAP ||
- pim_type == PIM_MSG_TYPE_GRAFT ||
- pim_type == PIM_MSG_TYPE_GRAFT_ACK ||
- pim_type == PIM_MSG_TYPE_CANDIDATE)
+ switch (pim_type)
{
+ case PIM_MSG_TYPE_HELLO:
+ return pim_hello_recv (ifp,
+ ip_hdr->ip_src,
+ pim_msg + PIM_MSG_HEADER_LEN,
+ pim_msg_len - PIM_MSG_HEADER_LEN);
+ break;
+ case PIM_MSG_TYPE_REGISTER:
+ return pim_register_recv (ifp,
+ ip_hdr->ip_dst,
+ ip_hdr->ip_src,
+ pim_msg + PIM_MSG_HEADER_LEN,
+ pim_msg_len - PIM_MSG_HEADER_LEN);
+ break;
+ case PIM_MSG_TYPE_REG_STOP:
+ return pim_register_stop_recv (pim_msg + PIM_MSG_HEADER_LEN,
+ pim_msg_len - PIM_MSG_HEADER_LEN);
+ break;
+ case PIM_MSG_TYPE_JOIN_PRUNE:
+ neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
+ if (!neigh) {
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
+ __FILE__, __PRETTY_FUNCTION__,
+ pim_type, src_str, ifp->name);
+ return -1;
+ }
+ pim_neighbor_timer_reset(neigh, neigh->holdtime);
+ return pim_joinprune_recv(ifp, neigh,
+ ip_hdr->ip_src,
+ pim_msg + PIM_MSG_HEADER_LEN,
+ pim_msg_len - PIM_MSG_HEADER_LEN);
+ break;
+ case PIM_MSG_TYPE_ASSERT:
+ neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
+ if (!neigh) {
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
+ __FILE__, __PRETTY_FUNCTION__,
+ pim_type, src_str, ifp->name);
+ return -1;
+ }
+ pim_neighbor_timer_reset(neigh, neigh->holdtime);
+ return pim_assert_recv(ifp, neigh,
+ ip_hdr->ip_src,
+ pim_msg + PIM_MSG_HEADER_LEN,
+ pim_msg_len - PIM_MSG_HEADER_LEN);
+ break;
+ default:
if (PIM_DEBUG_PIM_PACKETS) {
zlog_debug("Recv PIM packet type %d which is not currently understood",
pim_type);
}
return -1;
}
-
- if (pim_type == PIM_MSG_TYPE_HELLO) {
- return pim_hello_recv(ifp,
- ip_hdr->ip_src,
- pim_msg + PIM_MSG_HEADER_LEN,
- pim_msg_len - PIM_MSG_HEADER_LEN);
- } else if (pim_type == PIM_MSG_TYPE_REGISTER) {
- return pim_register_recv(ifp,
- ip_hdr->ip_dst,
- ip_hdr->ip_src,
- pim_msg + PIM_MSG_HEADER_LEN,
- pim_msg_len - PIM_MSG_HEADER_LEN);
- }
-
- neigh = pim_neighbor_find(ifp, ip_hdr->ip_src);
- if (!neigh) {
- zlog_warn("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s",
- __FILE__, __PRETTY_FUNCTION__,
- pim_type, src_str, ifp->name);
- return -1;
- }
-
- switch (pim_type) {
- case PIM_MSG_TYPE_JOIN_PRUNE:
- return pim_joinprune_recv(ifp, neigh,
- ip_hdr->ip_src,
- pim_msg + PIM_MSG_HEADER_LEN,
- pim_msg_len - PIM_MSG_HEADER_LEN);
- break;
- case PIM_MSG_TYPE_ASSERT:
- return pim_assert_recv(ifp, neigh,
- ip_hdr->ip_src,
- pim_msg + PIM_MSG_HEADER_LEN,
- pim_msg_len - PIM_MSG_HEADER_LEN);
- break;
- default:
- zlog_warn("%s %s: unsupported PIM message type=%d from %s on %s",
- __FILE__, __PRETTY_FUNCTION__,
- pim_type, src_str, ifp->name);
- break;
- }
-
return -1;
}
@@ -278,80 +290,73 @@ static int pim_sock_read(struct thread *t)
int len;
ifindex_t ifindex = -1;
int result = -1; /* defaults to bad */
-
- zassert(t);
+ static long long count = 0;
+ int cont = 1;
ifp = THREAD_ARG(t);
- zassert(ifp);
-
fd = THREAD_FD(t);
pim_ifp = ifp->info;
- zassert(pim_ifp);
-
- zassert(fd == pim_ifp->pim_sock_fd);
- len = pim_socket_recvfromto(fd, buf, sizeof(buf),
- &from, &fromlen,
- &to, &tolen,
- &ifindex);
- if (len < 0) {
- zlog_warn("Failure receiving IP PIM packet on fd=%d: errno=%d: %s",
- fd, errno, safe_strerror(errno));
- goto done;
- }
-
- if (PIM_DEBUG_PIM_PACKETS) {
- char from_str[100];
- char to_str[100];
-
- 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?>");
-
- zlog_debug("Recv IP PIM pkt size=%d from %s to %s on fd=%d on ifindex=%d (sock_ifindex=%d)",
- len, from_str, to_str, fd, ifindex, ifp->ifindex);
- }
-
- if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
- pim_pkt_dump(__PRETTY_FUNCTION__, buf, len);
- }
+ while (cont)
+ {
+ len = pim_socket_recvfromto(fd, buf, sizeof(buf),
+ &from, &fromlen,
+ &to, &tolen,
+ &ifindex);
+ if (len < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
+ {
+ cont = 0;
+ break;
+ }
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug ("Received errno: %d %s", errno, safe_strerror (errno));
+ goto done;
+ }
#ifdef PIM_CHECK_RECV_IFINDEX_SANITY
- /* ifindex sanity check */
- if (ifindex != (int) ifp->ifindex) {
- char from_str[100];
- char to_str[100];
- 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);
- if (recv_ifp) {
- zassert(ifindex == (int) recv_ifp->ifindex);
- }
+ /* 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);
+ 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);
+ 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
- goto done;
- }
+ goto done;
+ }
#endif
- int fail = pim_pim_packet(ifp, buf, len);
- if (fail) {
- if (PIM_DEBUG_PIM_PACKETS)
- zlog_debug("%s: pim_pim_packet() return=%d",
- __PRETTY_FUNCTION__, fail);
- goto done;
- }
+ int fail = pim_pim_packet(ifp, buf, len);
+ if (fail) {
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug("%s: pim_pim_packet() return=%d",
+ __PRETTY_FUNCTION__, fail);
+ goto done;
+ }
+
+ count++;
+ if (count % qpim_packet_process == 0)
+ cont = 0;
+ }
result = 0; /* good */
@@ -378,7 +383,7 @@ static void pim_sock_read_on(struct interface *ifp)
zlog_debug("Scheduling READ event on PIM socket fd=%d",
pim_ifp->pim_sock_fd);
}
- pim_ifp->t_pim_sock_read = 0;
+ pim_ifp->t_pim_sock_read = NULL;
zassert(!pim_ifp->t_pim_sock_read);
THREAD_READ_ON(master, pim_ifp->t_pim_sock_read, pim_sock_read, ifp,
pim_ifp->pim_sock_fd);
@@ -431,9 +436,9 @@ void pim_sock_reset(struct interface *ifp)
pim_ifp->pim_sock_fd = -1;
pim_ifp->pim_sock_creation = 0;
- pim_ifp->t_pim_sock_read = 0;
+ pim_ifp->t_pim_sock_read = NULL;
- pim_ifp->t_pim_hello_timer = 0;
+ pim_ifp->t_pim_hello_timer = NULL;
pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD;
pim_ifp->pim_default_holdtime = -1; /* unset: means 3.5 * pim_hello_period */
pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY;
@@ -462,18 +467,91 @@ void pim_sock_reset(struct interface *ifp)
pim_ifstat_reset(ifp);
}
-int pim_msg_send(int fd,
- struct in_addr dst,
- uint8_t *pim_msg,
- int pim_msg_size,
- const char *ifname)
+static uint16_t ip_id = 0;
+
+
+static int
+pim_msg_send_frame (int fd, char *buf, size_t len,
+ struct sockaddr *dst, size_t salen)
+{
+ struct ip *ip = (struct ip *)buf;
+
+ while (sendto (fd, buf, len, MSG_DONTWAIT, dst, salen) < 0)
+ {
+ char dst_str[INET_ADDRSTRLEN];
+
+ switch (errno)
+ {
+ case EMSGSIZE:
+ {
+ size_t hdrsize = sizeof (struct ip);
+ size_t newlen1 = ((len - hdrsize) / 2 ) & 0xFFF8;
+ size_t sendlen = newlen1 + hdrsize;
+ size_t offset = ntohs (ip->ip_off);
+
+ ip->ip_len = htons (sendlen);
+ ip->ip_off = htons (offset | IP_MF);
+ if (pim_msg_send_frame (fd, buf, sendlen, dst, salen) == 0)
+ {
+ struct ip *ip2 = (struct ip *)(buf + newlen1);
+ size_t newlen2 = len - sendlen;
+ sendlen = newlen2 + hdrsize;
+
+ memcpy (ip2, ip, hdrsize);
+ ip2->ip_len = htons (sendlen);
+ ip2->ip_off = htons (offset + (newlen1 >> 3));
+ return pim_msg_send_frame (fd, (char *)ip2, sendlen, dst, salen);
+ }
+ }
+
+ return -1;
+ break;
+ default:
+ if (PIM_DEBUG_PIM_PACKETS)
+ {
+ pim_inet4_dump ("<dst?>", ip->ip_dst, dst_str, sizeof (dst_str));
+ zlog_warn ("%s: sendto() failure to %s: fd=%d msg_size=%zd: errno=%d: %s",
+ __PRETTY_FUNCTION__,
+ dst_str, fd, len,
+ errno, safe_strerror(errno));
+ }
+ return -1;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int
+pim_msg_send(int fd, struct in_addr src,
+ struct in_addr dst, uint8_t *pim_msg,
+ int pim_msg_size, const char *ifname)
{
- ssize_t sent;
struct sockaddr_in to;
socklen_t tolen;
+ unsigned char buffer[10000];
+ unsigned char *msg_start;
+ struct ip *ip;
+
+ memset (buffer, 0, 10000);
+ int sendlen = sizeof (struct ip) + pim_msg_size;
+
+ msg_start = buffer + sizeof (struct ip);
+ memcpy (msg_start, pim_msg, pim_msg_size);
+
+ ip = (struct ip *)buffer;
+ ip->ip_id = htons (++ip_id);
+ ip->ip_hl = 5;
+ ip->ip_v = 4;
+ ip->ip_p = PIM_IP_PROTO_PIM;
+ ip->ip_src = src;
+ ip->ip_dst = dst;
+ ip->ip_ttl = MAXTTL;
+ ip->ip_len = htons (sendlen);
if (PIM_DEBUG_PIM_PACKETS) {
- char dst_str[100];
+ char dst_str[INET_ADDRSTRLEN];
pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x",
__PRETTY_FUNCTION__,
@@ -490,27 +568,8 @@ int pim_msg_send(int fd,
pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size);
}
- sent = sendto(fd, pim_msg, pim_msg_size, MSG_DONTWAIT,
- (struct sockaddr *)&to, tolen);
- if (sent != (ssize_t) pim_msg_size) {
- int e = errno;
- char dst_str[100];
- pim_inet4_dump("<dst?>", dst, dst_str, sizeof(dst_str));
- if (sent < 0) {
- zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s",
- __PRETTY_FUNCTION__,
- dst_str, ifname, fd, pim_msg_size,
- e, safe_strerror(e));
- }
- else {
- zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%zd",
- __PRETTY_FUNCTION__,
- dst_str, ifname, fd,
- pim_msg_size, sent);
- }
- return -1;
- }
-
+ pim_msg_send_frame (fd, (char *)buffer, sendlen,
+ (struct sockaddr *)&to, tolen);
return 0;
}
@@ -525,7 +584,7 @@ static int hello_send(struct interface *ifp,
pim_ifp = ifp->info;
if (PIM_DEBUG_PIM_HELLO) {
- char dst_str[100];
+ char dst_str[INET_ADDRSTRLEN];
pim_inet4_dump("<dst?>", qpim_all_pim_routers_addr, dst_str, sizeof(dst_str));
zlog_debug("%s: to %s on %s: holdt=%u prop_d=%u overr_i=%u dis_join_supp=%d dr_prio=%u gen_id=%08x addrs=%d",
__PRETTY_FUNCTION__,
@@ -560,6 +619,7 @@ static int hello_send(struct interface *ifp,
PIM_MSG_TYPE_HELLO);
if (pim_msg_send(pim_ifp->pim_sock_fd,
+ pim_ifp->primary_address,
qpim_all_pim_routers_addr,
pim_msg,
pim_msg_size,
@@ -627,16 +687,14 @@ static int on_pim_hello_send(struct thread *t)
struct pim_interface *pim_ifp;
struct interface *ifp;
- zassert(t);
ifp = THREAD_ARG(t);
- zassert(ifp);
pim_ifp = ifp->info;
/*
* Schedule next hello
*/
- pim_ifp->t_pim_hello_timer = 0;
+ pim_ifp->t_pim_hello_timer = NULL;
hello_resched(ifp);
/*
@@ -692,7 +750,20 @@ void pim_hello_restart_triggered(struct interface *ifp)
pim_ifp = ifp->info;
zassert(pim_ifp);
- triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay;
+ /*
+ * There exists situations where we have the a RPF out this
+ * interface, but we haven't formed a neighbor yet. This
+ * happens especially during interface flaps. While
+ * we would like to handle this more gracefully in other
+ * parts of the code. In order to get us up and running
+ * let's just send the hello immediate'ish
+ * This should be revisited when we get nexthop tracking
+ * in and when we have a better handle on safely
+ * handling the rpf information for upstreams that
+ * we cannot legally reach yet.
+ */
+ triggered_hello_delay_msec = 1;
+ //triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay;
if (pim_ifp->t_pim_hello_timer) {
long remain_msec = pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer);
@@ -703,11 +774,11 @@ void pim_hello_restart_triggered(struct interface *ifp)
}
THREAD_OFF(pim_ifp->t_pim_hello_timer);
- pim_ifp->t_pim_hello_timer = 0;
+ pim_ifp->t_pim_hello_timer = NULL;
}
- zassert(!pim_ifp->t_pim_hello_timer);
- random_msec = random() % (triggered_hello_delay_msec + 1);
+ random_msec = triggered_hello_delay_msec;
+ //random_msec = random() % (triggered_hello_delay_msec + 1);
if (PIM_DEBUG_PIM_HELLO) {
zlog_debug("Scheduling %d msec triggered hello on interface %s",
@@ -729,8 +800,9 @@ int pim_sock_add(struct interface *ifp)
zassert(pim_ifp);
if (pim_ifp->pim_sock_fd >= 0) {
- zlog_warn("Can't recreate existing PIM socket fd=%d for interface %s",
- pim_ifp->pim_sock_fd, ifp->name);
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug("Can't recreate existing PIM socket fd=%d for interface %s",
+ pim_ifp->pim_sock_fd, ifp->name);
return -1;
}
@@ -738,12 +810,15 @@ int pim_sock_add(struct interface *ifp)
pim_ifp->pim_sock_fd = pim_sock_open(ifaddr, ifp->ifindex);
if (pim_ifp->pim_sock_fd < 0) {
- zlog_warn("Could not open PIM socket on interface %s",
- ifp->name);
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug("Could not open PIM socket on interface %s",
+ ifp->name);
return -2;
}
- pim_ifp->t_pim_sock_read = 0;
+ pim_socket_ip_hdr (pim_ifp->pim_sock_fd);
+
+ pim_ifp->t_pim_sock_read = NULL;
pim_ifp->pim_sock_creation = pim_time_monotonic_sec();
/*
diff --git a/pimd/pim_pim.h b/pimd/pim_pim.h
index 5692a37938..00c5f9012e 100644
--- a/pimd/pim_pim.h
+++ b/pimd/pim_pim.h
@@ -28,8 +28,6 @@
#define PIM_PIM_BUFSIZE_READ (20000)
#define PIM_PIM_BUFSIZE_WRITE (20000)
-#define PIM_NEXTHOP_IFINDEX_TAB_SIZE (20)
-
#define PIM_DEFAULT_HELLO_PERIOD (30) /* seconds, RFC 4601: 4.11 */
#define PIM_DEFAULT_TRIGGERED_HELLO_DELAY (5) /* seconds, RFC 4601: 4.11 */
#define PIM_DEFAULT_DR_PRIORITY (1) /* RFC 4601: 4.3.1 */
@@ -38,15 +36,17 @@
#define PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION (0) /* boolean */
#define PIM_DEFAULT_T_PERIODIC (60) /* RFC 4601: 4.11. Timer Values */
-#define PIM_MSG_TYPE_HELLO (0)
-#define PIM_MSG_TYPE_REGISTER (1)
-#define PIM_MSG_TYPE_REG_STOP (2)
-#define PIM_MSG_TYPE_JOIN_PRUNE (3)
-#define PIM_MSG_TYPE_BOOTSTRAP (4)
-#define PIM_MSG_TYPE_ASSERT (5)
-#define PIM_MSG_TYPE_GRAFT (6)
-#define PIM_MSG_TYPE_GRAFT_ACK (7)
-#define PIM_MSG_TYPE_CANDIDATE (8)
+enum pim_msg_type {
+ PIM_MSG_TYPE_HELLO = 0,
+ PIM_MSG_TYPE_REGISTER,
+ PIM_MSG_TYPE_REG_STOP,
+ PIM_MSG_TYPE_JOIN_PRUNE,
+ PIM_MSG_TYPE_BOOTSTRAP,
+ PIM_MSG_TYPE_ASSERT,
+ PIM_MSG_TYPE_GRAFT,
+ PIM_MSG_TYPE_GRAFT_ACK,
+ PIM_MSG_TYPE_CANDIDATE
+};
#define PIM_MSG_HDR_OFFSET_VERSION(pim_msg) (pim_msg)
#define PIM_MSG_HDR_OFFSET_TYPE(pim_msg) (pim_msg)
@@ -67,6 +67,7 @@ void pim_hello_restart_triggered(struct interface *ifp);
int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len);
int pim_msg_send(int fd,
+ struct in_addr src,
struct in_addr dst,
uint8_t *pim_msg,
int pim_msg_size,
diff --git a/pimd/pim_register.c b/pimd/pim_register.c
index ce3ac1a433..490a05be37 100644
--- a/pimd/pim_register.c
+++ b/pimd/pim_register.c
@@ -24,6 +24,9 @@
#include "log.h"
#include "if.h"
#include "thread.h"
+#include "prefix.h"
+#include "vty.h"
+#include "plist.h"
#include "pimd.h"
#include "pim_mroute.h"
@@ -39,65 +42,150 @@
#include "pim_oil.h"
#include "pim_zebra.h"
#include "pim_join.h"
+#include "pim_util.h"
struct thread *send_test_packet_timer = NULL;
-/*
- * This seems stupidly expensive. A list lookup. Why is this
- * not a hash?
- */
-static int
-pim_check_is_my_ip_address (struct in_addr dest_addr)
+void
+pim_register_stop_send (struct interface *ifp, struct prefix_sg *sg,
+ struct in_addr src, struct in_addr originator)
{
- /*
- * 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(dest_addr) && (dest_addr.s_addr == qpim_rp.rpf_addr.s_addr))
- return 1;
+ struct pim_interface *pinfo;
+ unsigned char buffer[10000];
+ unsigned int b1length = 0;
+ unsigned int length;
+ uint8_t *b1;
+ struct prefix p;
+
+ if (PIM_DEBUG_PIM_REG)
+ {
+ zlog_debug ("Sending Register stop for %s to %s on %s",
+ pim_str_sg_dump (sg), inet_ntoa(originator), ifp->name);
+ }
- if (if_lookup_exact_address (&dest_addr, AF_INET))
- return 1;
+ memset (buffer, 0, 10000);
+ b1 = (uint8_t *)buffer + PIM_MSG_REGISTER_STOP_LEN;
- return 0;
+ length = pim_encode_addr_group (b1, AFI_IP, 0, 0, sg->grp);
+ b1length += length;
+ b1 += length;
+
+ p.family = AF_INET;
+ p.u.prefix4 = sg->src;
+ p.prefixlen = 32;
+ length = pim_encode_addr_ucast (b1, &p);
+ b1length += length;
+
+ pim_msg_build_header (buffer, b1length + PIM_MSG_REGISTER_STOP_LEN, PIM_MSG_TYPE_REG_STOP);
+
+ pinfo = (struct pim_interface *)ifp->info;
+ if (!pinfo)
+ {
+ if (PIM_DEBUG_PIM_TRACE)
+ zlog_debug ("%s: No pinfo!\n", __PRETTY_FUNCTION__);
+ return;
+ }
+ if (pim_msg_send (pinfo->pim_sock_fd, src, originator,
+ buffer, b1length + PIM_MSG_REGISTER_STOP_LEN,
+ ifp->name))
+ {
+ if (PIM_DEBUG_PIM_TRACE)
+ {
+ zlog_debug ("%s: could not send PIM register stop message on interface %s",
+ __PRETTY_FUNCTION__, ifp->name);
+ }
+ }
}
-static void
-pim_register_stop_send (struct in_addr src)
+int
+pim_register_stop_recv (uint8_t *buf, int buf_size)
{
- return;
+ struct pim_upstream *upstream = NULL;
+ struct prefix source;
+ struct prefix_sg sg;
+ int l;
+
+ memset (&sg, 0, sizeof (struct prefix_sg));
+ l = pim_parse_addr_group (&sg, buf, buf_size);
+ buf += l;
+ buf_size -= l;
+ pim_parse_addr_ucast (&source, buf, buf_size);
+ sg.src = source.u.prefix4;
+
+ upstream = pim_upstream_find (&sg);
+ if (!upstream)
+ {
+ return 0;
+ }
+
+ if (PIM_DEBUG_PIM_REG)
+ zlog_debug ("Received Register stop for %s",
+ upstream->sg_str);
+
+ switch (upstream->join_state)
+ {
+ case PIM_UPSTREAM_NOTJOINED:
+ case PIM_UPSTREAM_PRUNE:
+ return 0;
+ break;
+ case PIM_UPSTREAM_JOINED:
+ upstream->join_state = PIM_UPSTREAM_PRUNE;
+ pim_channel_del_oif (upstream->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
+ pim_upstream_start_register_stop_timer (upstream, 0);
+ case PIM_UPSTREAM_JOIN_PENDING:
+ upstream->join_state = PIM_UPSTREAM_PRUNE;
+ pim_upstream_start_register_stop_timer (upstream, 0);
+ return 0;
+ break;
+ }
+
+ return 0;
}
void
-pim_register_send (const struct ip *ip_hdr, struct pim_rpf *rpg)
+pim_register_send (const uint8_t *buf, int buf_size, struct in_addr src, struct pim_rpf *rpg, int null_register, struct pim_upstream *up)
{
- unsigned char buffer[3000];
+ unsigned char buffer[10000];
unsigned char *b1;
struct pim_interface *pinfo;
struct interface *ifp;
- uint32_t plen;
+
+ if (PIM_DEBUG_PIM_REG)
+ {
+ char rp_str[INET_ADDRSTRLEN];
+ strcpy (rp_str, inet_ntoa (rpg->rpf_addr.u.prefix4));
+ zlog_debug ("Sending %s %sRegister Packet to %s",
+ up->sg_str, null_register ? "NULL " : "", rp_str);
+ }
ifp = rpg->source_nexthop.interface;
+ if (!ifp)
+ {
+ if (PIM_DEBUG_PIM_REG)
+ zlog_debug ("%s: No interface to transmit register on", __PRETTY_FUNCTION__);
+ return;
+ }
pinfo = (struct pim_interface *)ifp->info;
if (!pinfo) {
- zlog_debug("%s: No pinfo!\n", __PRETTY_FUNCTION__);
+ if (PIM_DEBUG_PIM_REG)
+ zlog_debug("%s: Interface: %s not configured for pim to trasmit on!\n", __PRETTY_FUNCTION__, ifp->name);
return;
}
- memset(buffer, 0, 3000);
+ memset(buffer, 0, 10000);
+ b1 = buffer + PIM_MSG_HEADER_LEN;
+ *b1 |= null_register << 6;
b1 = buffer + PIM_MSG_REGISTER_LEN;
- plen = ntohs(ip_hdr->ip_len);
- memcpy(b1, (const unsigned char *)ip_hdr, plen);
+ memcpy(b1, (const unsigned char *)buf, buf_size);
- pim_msg_build_header(buffer, plen + PIM_MSG_REGISTER_LEN, PIM_MSG_TYPE_REGISTER);
+ pim_msg_build_header(buffer, buf_size + PIM_MSG_REGISTER_LEN, PIM_MSG_TYPE_REGISTER);
if (pim_msg_send(pinfo->pim_sock_fd,
- rpg->rpf_addr,
+ src,
+ rpg->rpf_addr.u.prefix4,
buffer,
- plen + PIM_MSG_REGISTER_LEN,
+ buf_size + PIM_MSG_REGISTER_LEN,
ifp->name)) {
if (PIM_DEBUG_PIM_TRACE) {
zlog_debug("%s: could not send PIM register message on interface %s",
@@ -159,15 +247,16 @@ pim_register_recv (struct interface *ifp,
{
int sentRegisterStop = 0;
struct ip *ip_hdr;
- //size_t hlen;
- struct in_addr group = { .s_addr = 0 };
- struct in_addr source = { .s_addr = 0 };
- //uint8_t *msg;
+ struct prefix_sg sg;
uint32_t *bits;
+ int i_am_rp = 0;
- if (!pim_check_is_my_ip_address (dest_addr)) {
- if (PIM_DEBUG_PIM_PACKETS) {
- char dest[100];
+#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_DEBUG_PIM_REG) {
+ char dest[INET_ADDRSTRLEN];
pim_inet4_dump ("<dst?>", dest_addr, dest, sizeof(dest));
zlog_debug ("%s: Received Register message for %s that I do not own", __func__,
@@ -176,7 +265,6 @@ pim_register_recv (struct interface *ifp,
return 0;
}
-#define inherited_olist(S,G) NULL
/*
* Please note this is not drawn to get the correct bit/data size
*
@@ -203,25 +291,33 @@ pim_register_recv (struct interface *ifp,
* Line above. So we need to add 4 bytes to get to the
* start of the actual Encapsulated data.
*/
-#define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4
- ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN);
- //hlen = (ip_hdr->ip_hl << 2) | PIM_MSG_REGISTER_LEN;
- //msg = (uint8_t *)tlv_buf + hlen;
- source = ip_hdr->ip_src;
- group = ip_hdr->ip_dst;
+ memset (&sg, 0, sizeof (struct prefix_sg));
+ sg.src = ip_hdr->ip_src;
+ sg.grp = ip_hdr->ip_dst;
- if (I_am_RP (group) && (dest_addr.s_addr == ((RP (group))->rpf_addr.s_addr))) {
+ i_am_rp = I_am_RP (sg.grp);
+
+ if (PIM_DEBUG_PIM_REG)
+ {
+ char src_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump ("<src?>", src_addr, src_str, sizeof (src_str));
+ zlog_debug ("Received Register message(%s) from %s on %s, rp: %d",
+ 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))) {
sentRegisterStop = 0;
if (*bits & PIM_REGISTER_BORDER_BIT) {
- struct in_addr pimbr = pim_br_get_pmbr (source, group);
+ struct in_addr pimbr = pim_br_get_pmbr (&sg);
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("%s: Received Register message with Border bit set", __func__);
if (pimbr.s_addr == pim_br_unknown.s_addr)
- pim_br_set_pmbr(source, group, src_addr);
+ pim_br_set_pmbr(&sg, src_addr);
else if (src_addr.s_addr != pimbr.s_addr) {
- pim_register_stop_send(src_addr);
+ pim_register_stop_send (ifp, &sg, dest_addr, src_addr);
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug("%s: Sending register-Stop to %s and dropping mr. packet",
__func__, "Sender");
@@ -230,83 +326,81 @@ pim_register_recv (struct interface *ifp,
}
}
- struct pim_upstream *upstream = pim_upstream_find (source, group);
+ struct pim_upstream *upstream = pim_upstream_find (&sg);
/*
* If we don't have a place to send ignore the packet
*/
if (!upstream)
- return 1;
+ {
+ upstream = pim_upstream_add (&sg, ifp,
+ PIM_UPSTREAM_FLAG_MASK_SRC_STREAM,
+ __PRETTY_FUNCTION__);
+ if (!upstream)
+ {
+ zlog_warn ("Failure to create upstream state");
+ return 1;
+ }
+ PIM_UPSTREAM_FLAG_SET_SRC_STREAM(upstream->flags);
+
+ upstream->upstream_register = src_addr;
+ pim_rp_set_upstream_addr (&upstream->upstream_addr, sg.src, sg.grp);
+ if (pim_nexthop_lookup (&upstream->rpf.source_nexthop,
+ upstream->upstream_addr, 1) != 0)
+ {
+ if (PIM_DEBUG_PIM_REG)
+ {
+ zlog_debug ("Received Register(%s), for which I have no path back", upstream->sg_str);
+ }
+ PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(upstream->flags);
+ pim_upstream_del (upstream, __PRETTY_FUNCTION__);
+ return 1;
+ }
+ upstream->sg.src = sg.src;
+ upstream->rpf.rpf_addr = upstream->rpf.source_nexthop.mrib_nexthop_addr;
+
+ upstream->join_state = PIM_UPSTREAM_PRUNE;
+
+ }
if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) ||
- ((SwitchToSptDesired(source, group)) &&
- (inherited_olist(source, group) == NULL))) {
- pim_register_stop_send(src_addr);
+ ((SwitchToSptDesired(&sg)) &&
+ pim_upstream_inherited_olist (upstream) == 0)) {
+ //pim_scan_individual_oil (upstream->channel_oil);
+ pim_register_stop_send (ifp, &sg, dest_addr, src_addr);
sentRegisterStop = 1;
+ } else {
+ if (PIM_DEBUG_PIM_REG)
+ zlog_debug ("(%s) sptbit: %d", upstream->sg_str, upstream->sptbit);
}
-
if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) ||
- (SwitchToSptDesired(source, group))) {
+ (SwitchToSptDesired(&sg))) {
if (sentRegisterStop) {
- pim_upstream_keep_alive_timer_start (upstream, PIM_RP_KEEPALIVE_PERIOD);
+ pim_upstream_keep_alive_timer_start (upstream, qpim_rp_keep_alive_time);
} else {
- pim_upstream_keep_alive_timer_start (upstream, PIM_KEEPALIVE_PERIOD);
+ pim_upstream_keep_alive_timer_start (upstream, qpim_keep_alive_time);
}
}
if (!(upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) &&
!(*bits & PIM_REGISTER_NR_BIT))
{
- pim_rp_set_upstream_addr (&upstream->upstream_addr, source);
- pim_nexthop_lookup (&upstream->rpf.source_nexthop,
- upstream->upstream_addr, NULL);
- upstream->rpf.source_nexthop.interface = ifp;
- upstream->source_addr.s_addr = source.s_addr;
- upstream->rpf.rpf_addr.s_addr = source.s_addr;
- upstream->channel_oil->oil.mfcc_origin = source;
- pim_scan_individual_oil (upstream->channel_oil);
- pim_joinprune_send(upstream->rpf.source_nexthop.interface,
- upstream->rpf.source_nexthop.mrib_nexthop_addr,
- upstream->source_addr,
- upstream->group_addr,
- 1);
-
//decapsulate and forward the iner packet to
//inherited_olist(S,G,rpt)
+ // This is taken care of by the kernel for us
}
+ pim_upstream_msdp_reg_timer_start(upstream);
} else {
- pim_register_stop_send(src_addr);
+ if (PIM_DEBUG_PIM_REG)
+ {
+ if (!i_am_rp)
+ zlog_debug ("Received Register packet for %s, Rejecting packet because I am not the RP configured for group",
+ pim_str_sg_dump (&sg));
+ else
+ zlog_debug ("Received Register packet for %s, Rejecting packet because the dst ip address is not the actual RP",
+ pim_str_sg_dump (&sg));
+ }
+ pim_register_stop_send (ifp, &sg, dest_addr, src_addr);
}
return 1;
}
-
-
-static int
-pim_register_send_test_packet (struct thread *t)
-{
- uint8_t *packet;
-
- packet = THREAD_ARG(t);
-
- *packet = 4;
-
- return 1;
-}
-
-/*
- * pim_register_send_test_packet
- *
- * Send a test packet to the RP from source, in group and pps packets per second
- */
-void
-pim_register_send_test_packet_start (struct in_addr source,
- struct in_addr group,
- uint32_t pps)
-{
- uint8_t *packet = NULL;
-
- THREAD_TIMER_MSEC_ON(master, send_test_packet_timer,
- pim_register_send_test_packet, packet, 1000/pps);
-
- return;
-}
diff --git a/pimd/pim_register.h b/pimd/pim_register.h
index 039c0006e0..42a908b225 100644
--- a/pimd/pim_register.h
+++ b/pimd/pim_register.h
@@ -31,15 +31,14 @@
#define PIM_MSG_REGISTER_LEN (8)
#define PIM_MSG_REGISTER_STOP_LEN (4)
-void pim_register_send_test_packet_start (struct in_addr source,
- struct in_addr group,
- uint32_t pps);
+int pim_register_stop_recv (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, int tlv_buf_size);
-void pim_register_send (const struct ip *msg, struct pim_rpf *rpg);
+void pim_register_send (const uint8_t *buf, int buf_size, struct in_addr src, struct pim_rpf *rpg, int null_register, struct pim_upstream *up);
+void pim_register_stop_send (struct interface *ifp, struct prefix_sg *sg, struct in_addr src, struct in_addr originator);
#endif
diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c
index 26d108bcaa..ba464e98c6 100644
--- a/pimd/pim_rp.c
+++ b/pimd/pim_rp.c
@@ -20,48 +20,597 @@
*/
#include <zebra.h>
+#include "lib/json.h"
#include "log.h"
#include "network.h"
#include "if.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "memory.h"
+#include "vty.h"
+#include "vrf.h"
+#include "plist.h"
#include "pimd.h"
+#include "pim_vty.h"
#include "pim_str.h"
+#include "pim_iface.h"
#include "pim_rp.h"
#include "pim_str.h"
#include "pim_rpf.h"
+#include "pim_sock.h"
+#include "pim_memory.h"
+#include "pim_iface.h"
+#include "pim_msdp.h"
-static int i_am_rp = 0;
+struct rp_info
+{
+ struct prefix group;
+ struct pim_rpf rp;
+ int i_am_rp;
+ char *plist;
+};
+
+static struct list *qpim_rp_list = NULL;
+static struct rp_info *tail = NULL;
+
+static void
+pim_rp_info_free (struct rp_info *rp_info)
+{
+ XFREE (MTYPE_PIM_RP, rp_info);
+}
+
+static int
+pim_rp_list_cmp (void *v1, void *v2)
+{
+ struct rp_info *rp1 = (struct rp_info *)v1;
+ struct rp_info *rp2 = (struct rp_info *)v2;
+
+ if (rp1 == rp2)
+ return 0;
+
+ if (!rp1 && rp2)
+ return -1;
+
+ if (rp1 && !rp2)
+ return 1;
+
+ /*
+ * Sort by RP IP address
+ */
+ if (rp1->rp.rpf_addr.u.prefix4.s_addr < rp2->rp.rpf_addr.u.prefix4.s_addr)
+ return -1;
+
+ if (rp1->rp.rpf_addr.u.prefix4.s_addr > rp2->rp.rpf_addr.u.prefix4.s_addr)
+ return 1;
+
+ /*
+ * Sort by group IP address
+ */
+ if (rp1->group.u.prefix4.s_addr < rp2->group.u.prefix4.s_addr)
+ return -1;
+
+ if (rp1->group.u.prefix4.s_addr > rp2->group.u.prefix4.s_addr)
+ return 1;
+
+ if (rp1 == tail)
+ return 1;
+
+ return -1;
+}
+
+void
+pim_rp_init (void)
+{
+ 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;
+
+ rp_info = XCALLOC (MTYPE_PIM_RP, sizeof (*rp_info));
+
+ if (!rp_info)
+ return;
+
+ str2prefix ("224.0.0.0/4", &rp_info->group);
+ rp_info->group.family = AF_INET;
+ rp_info->rp.rpf_addr.family = AF_INET;
+ rp_info->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE;
+ tail = rp_info;
+
+ listnode_add (qpim_rp_list, rp_info);
+}
+
+void
+pim_rp_free (void)
+{
+ if (qpim_rp_list)
+ list_free (qpim_rp_list);
+}
+
+/*
+ * 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, const char *plist)
+{
+ struct listnode *node;
+ struct rp_info *rp_info;
+
+ for (ALL_LIST_ELEMENTS_RO (qpim_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 NULL;
+}
+
+/*
+ * Return true if plist is used by any rp_info
+ */
+static int
+pim_rp_prefix_list_used (const char *plist)
+{
+ struct listnode *node;
+ struct rp_info *rp_info;
+
+ for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
+ {
+ if (rp_info->plist && strcmp(rp_info->plist, plist) == 0)
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
/*
- * Checks to see if we should elect ourself the actual RP
+ * 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, struct prefix *group)
+{
+ struct listnode *node;
+ struct rp_info *rp_info;
+
+ for (ALL_LIST_ELEMENTS_RO (qpim_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;
+ }
+
+ return NULL;
+}
+
+/*
+ * Given a group, return the rp_info for that group
+ */
+static struct rp_info *
+pim_rp_find_match_group (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))
+ {
+ if (rp_info->plist)
+ {
+ plist = prefix_list_lookup (AFI_IP, rp_info->plist);
+
+ if (plist && prefix_list_apply (plist, group) == PREFIX_PERMIT)
+ return rp_info;
+ }
+ else
+ {
+ if (prefix_match (&rp_info->group, group))
+ return rp_info;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * When the user makes "ip pim rp" configuration changes or if they change the
+ * prefix-list(s) used by these statements we must tickle the upstream state
+ * for each group to make them re-lookup who their RP should be.
+ *
+ * This is a placeholder function for now.
+ */
+static void
+pim_rp_refresh_group_to_rp_mapping()
+{
+ pim_msdp_i_am_rp_changed();
+}
+
void
-pim_rp_check_rp (struct in_addr old, struct in_addr new)
-{
- if (PIM_DEBUG_ZEBRA) {
- char sold[100];
- char snew[100];
- char rp[100];
- pim_inet4_dump("<rp?>", qpim_rp.rpf_addr, rp, sizeof(rp));
- pim_inet4_dump("<old?>", old, sold, sizeof(sold));
- pim_inet4_dump("<new?>", new, snew, sizeof(snew));
- zlog_debug("%s: %s for old %s new %s", __func__, rp, sold, snew );
+pim_rp_prefix_list_update (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))
+ {
+ if (rp_info->plist && strcmp(rp_info->plist, prefix_list_name (plist)) == 0)
+ {
+ refresh_needed = 1;
+ break;
+ }
+ }
+
+ if (refresh_needed)
+ pim_rp_refresh_group_to_rp_mapping();
+}
+
+static int
+pim_rp_check_interface_addrs(struct rp_info *rp_info,
+ struct pim_interface *pim_ifp)
+{
+ struct listnode *node;
+ struct pim_secondary_addr *sec_addr;
+
+ if (pim_ifp->primary_address.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr)
+ return 1;
+
+ if (!pim_ifp->sec_addr_list) {
+ return 0;
}
- if (qpim_rp.rpf_addr.s_addr == INADDR_NONE)
- return;
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
+ if (sec_addr->addr.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void
+pim_rp_check_interfaces (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))
+ {
+ struct pim_interface *pim_ifp = ifp->info;
+
+ if (!pim_ifp)
+ continue;
+
+ if (pim_rp_check_interface_addrs(rp_info, pim_ifp)) {
+ rp_info->i_am_rp = 1;
+ }
+ }
+}
+
+int
+pim_rp_new (const char *rp, const char *group_range, const char *plist)
+{
+ int result;
+ struct rp_info *rp_info;
+ struct rp_info *rp_all;
+ struct prefix group_all;
+ struct listnode *node, *nnode;
+ struct rp_info *tmp_rp_info;
+ char buffer[BUFSIZ];
+
+ rp_info = XCALLOC (MTYPE_PIM_RP, sizeof (*rp_info));
+ if (!rp_info)
+ return PIM_MALLOC_FAIL;
+
+ if (group_range == NULL)
+ result = str2prefix ("224.0.0.0/4", &rp_info->group);
+ else
+ result = str2prefix (group_range, &rp_info->group);
+
+ if (!result)
+ {
+ XFREE (MTYPE_PIM_RP, rp_info);
+ return PIM_GROUP_BAD_ADDRESS;
+ }
+
+ rp_info->rp.rpf_addr.family = AF_INET;
+ result = inet_pton (rp_info->rp.rpf_addr.family, rp, &rp_info->rp.rpf_addr.u.prefix4);
+
+ if (result <= 0)
+ {
+ XFREE (MTYPE_PIM_RP, rp_info);
+ return PIM_RP_BAD_ADDRESS;
+ }
+
+ if (plist)
+ {
+ /*
+ * Return if the prefix-list is already configured for this RP
+ */
+ if (pim_rp_find_prefix_list (rp_info->rp.rpf_addr.u.prefix4, 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))
+ {
+ 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, 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, tmp_rp_info->plist);
+ else
+ pim_rp_del (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);
+
+ /*
+ * Barf if group is a non-multicast subnet
+ */
+ if (! prefix_match (&rp_all->group, &rp_info->group))
+ {
+ XFREE (MTYPE_PIM_RP, rp_info);
+ return PIM_GROUP_BAD_ADDRESS;
+ }
- if (new.s_addr == qpim_rp.rpf_addr.s_addr)
+ /*
+ * Remove any prefix-list rp_info entries for this RP
+ */
+ for (ALL_LIST_ELEMENTS (qpim_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);
+ }
+ }
+
+ /*
+ * Take over the 224.0.0.0/4 group if the rp is INADDR_NONE
+ */
+ if (prefix_same (&rp_all->group, &rp_info->group) &&
+ pim_rpf_addr_is_inaddr_none (&rp_all->rp))
+ {
+ rp_all->rp.rpf_addr = rp_info->rp.rpf_addr;
+ XFREE (MTYPE_PIM_RP, rp_info);
+
+ if (pim_nexthop_lookup (&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();
+ 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, &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);
+
+ if (tmp_rp_info)
+ {
+ if (tmp_rp_info->plist)
+ {
+ XFREE (MTYPE_PIM_RP, rp_info);
+ return PIM_GROUP_PFXLIST_OVERLAP;
+ }
+ else
+ {
+ /*
+ * If the only RP that covers this group is an RP configured for
+ * 224.0.0.0/4 that is fine, ignore that one. For all others
+ * though we must return PIM_GROUP_OVERLAP
+ */
+ if (! prefix_same (&group_all, &tmp_rp_info->group))
+ {
+ XFREE (MTYPE_PIM_RP, rp_info);
+ return PIM_GROUP_OVERLAP;
+ }
+ }
+ }
+ }
+
+ listnode_add_sort (qpim_rp_list, rp_info);
+
+ if (pim_nexthop_lookup (&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();
+ return PIM_SUCCESS;
+}
+
+int
+pim_rp_del (const char *rp, const char *group_range, const char *plist)
+{
+ struct prefix group;
+ struct in_addr rp_addr;
+ struct prefix g_all;
+ struct rp_info *rp_info;
+ struct rp_info *rp_all;
+ int result;
+
+ if (group_range == NULL)
+ result = str2prefix ("224.0.0.0/4", &group);
+ else
+ result = str2prefix (group_range, &group);
+
+ if (!result)
+ return PIM_GROUP_BAD_ADDRESS;
+
+ result = inet_pton (AF_INET, rp, &rp_addr);
+ if (result <= 0)
+ return PIM_RP_BAD_ADDRESS;
+
+ if (plist)
+ rp_info = pim_rp_find_prefix_list (rp_addr, plist);
+ else
+ rp_info = pim_rp_find_exact (rp_addr, &group);
+
+ if (!rp_info)
+ return PIM_RP_NOT_FOUND;
+
+ if (rp_info->plist)
{
- i_am_rp = 1;
- return;
+ XFREE(MTYPE_PIM_FILTER_NAME, rp_info->plist);
+ rp_info->plist = NULL;
}
- if (old.s_addr == qpim_rp.rpf_addr.s_addr)
+ str2prefix ("224.0.0.0/4", &g_all);
+ rp_all = pim_rp_find_match_group (&g_all);
+
+ if (rp_all == rp_info)
{
- i_am_rp = 0;
- return;
+ rp_all->rp.rpf_addr.family = AF_INET;
+ rp_all->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE;
+ rp_all->i_am_rp = 0;
+ return PIM_SUCCESS;
+ }
+
+ listnode_delete (qpim_rp_list, rp_info);
+ pim_rp_refresh_group_to_rp_mapping();
+ return PIM_SUCCESS;
+}
+
+int
+pim_rp_setup (void)
+{
+ struct listnode *node;
+ struct rp_info *rp_info;
+ int ret = 0;
+
+ for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
+ {
+ if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE)
+ continue;
+
+ if (pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1) != 0)
+ {
+ if (PIM_DEBUG_PIM_TRACE)
+ zlog_debug ("Unable to lookup nexthop for rp specified");
+ ret++;
+ }
}
+
+ if (ret)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Checks to see if we should elect ourself the actual RP when new if
+ * addresses are added against an interface.
+ */
+void
+pim_rp_check_on_if_add(struct pim_interface *pim_ifp)
+{
+ struct listnode *node;
+ struct rp_info *rp_info;
+ bool i_am_rp_changed = false;
+
+ if (qpim_rp_list == NULL)
+ return;
+
+ for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info)) {
+ if (pim_rpf_addr_is_inaddr_none (&rp_info->rp))
+ continue;
+
+ /* if i_am_rp is already set nothing to be done (adding new addresses
+ * is not going to make a difference). */
+ if (rp_info->i_am_rp) {
+ continue;
+ }
+
+ if (pim_rp_check_interface_addrs(rp_info, pim_ifp)) {
+ i_am_rp_changed = true;
+ rp_info->i_am_rp = 1;
+ if (PIM_DEBUG_ZEBRA) {
+ char rp[PREFIX_STRLEN];
+ pim_addr_dump("<rp?>", &rp_info->rp.rpf_addr, rp, sizeof(rp));
+ zlog_debug("%s: %s: i am rp", __func__, rp);
+ }
+ }
+ }
+
+ if (i_am_rp_changed) {
+ pim_msdp_i_am_rp_changed();
+ }
+}
+
+/* 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)
+{
+ struct listnode *node;
+ struct rp_info *rp_info;
+ bool i_am_rp_changed = false;
+ int old_i_am_rp;
+
+ if (qpim_rp_list == NULL)
+ return;
+
+ for (ALL_LIST_ELEMENTS_RO(qpim_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);
+
+ if (old_i_am_rp != rp_info->i_am_rp) {
+ i_am_rp_changed = true;
+ if (PIM_DEBUG_ZEBRA) {
+ char rp[PREFIX_STRLEN];
+ pim_addr_dump("<rp?>", &rp_info->rp.rpf_addr, rp, sizeof(rp));
+ if (rp_info->i_am_rp) {
+ zlog_debug("%s: %s: i am rp", __func__, rp);
+ } else {
+ zlog_debug("%s: %s: i am no longer rp", __func__, rp);
+ }
+ }
+ }
+ }
+
+ if (i_am_rp_changed) {
+ pim_msdp_i_am_rp_changed();
+ }
}
/*
@@ -73,7 +622,20 @@ pim_rp_check_rp (struct in_addr old, struct in_addr new)
int
pim_rp_i_am_rp (struct in_addr group)
{
- return i_am_rp;
+ struct prefix g;
+ struct rp_info *rp_info;
+
+ memset (&g, 0, sizeof (g));
+ g.family = AF_INET;
+ g.prefixlen = 32;
+ g.u.prefix4 = group;
+
+ rp_info = pim_rp_find_match_group (&g);
+
+ if (rp_info)
+ return rp_info->i_am_rp;
+
+ return 0;
}
/*
@@ -84,11 +646,24 @@ pim_rp_i_am_rp (struct in_addr group)
struct pim_rpf *
pim_rp_g (struct in_addr group)
{
- /*
- * For staticly configured RP, it is always the qpim_rp
- */
- pim_nexthop_lookup(&qpim_rp.source_nexthop, qpim_rp.rpf_addr, NULL);
- return(&qpim_rp);
+ struct prefix g;
+ struct rp_info *rp_info;
+
+ memset (&g, 0, sizeof (g));
+ g.family = AF_INET;
+ g.prefixlen = 32;
+ g.u.prefix4 = group;
+
+ rp_info = pim_rp_find_match_group (&g);
+
+ if (rp_info)
+ {
+ pim_nexthop_lookup(&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1);
+ return (&rp_info->rp);
+ }
+
+ // About to Go Down
+ return NULL;
}
/*
@@ -100,16 +675,168 @@ pim_rp_g (struct in_addr group)
*
*/
int
-pim_rp_set_upstream_addr (struct in_addr *up, struct in_addr source)
+pim_rp_set_upstream_addr (struct in_addr *up, struct in_addr source, struct in_addr group)
{
- if ((qpim_rp.rpf_addr.s_addr == INADDR_NONE) && (source.s_addr == INADDR_ANY))
+ struct rp_info *rp_info;
+ struct prefix g;
+
+ memset (&g, 0, sizeof (g));
+ g.family = AF_INET;
+ g.prefixlen = 32;
+ g.u.prefix4 = group;
+
+ rp_info = pim_rp_find_match_group (&g);
+
+ if ((pim_rpf_addr_is_inaddr_none (&rp_info->rp)) && (source.s_addr == INADDR_ANY))
{
if (PIM_DEBUG_PIM_TRACE)
zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__);
return 0;
}
- *up = (source.s_addr == INADDR_ANY) ? qpim_rp.rpf_addr : source;
+ *up = (source.s_addr == INADDR_ANY) ? rp_info->rp.rpf_addr.u.prefix4 : source;
return 1;
}
+
+int
+pim_rp_config_write (struct vty *vty)
+{
+ struct listnode *node;
+ struct rp_info *rp_info;
+ char rp_buffer[32];
+ char group_buffer[32];
+ int count = 0;
+
+ for (ALL_LIST_ELEMENTS_RO (qpim_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%s",
+ inet_ntop(AF_INET, &rp_info->rp.rpf_addr.u.prefix4, rp_buffer, 32),
+ rp_info->plist, VTY_NEWLINE);
+ else
+ vty_out(vty, "ip pim rp %s %s%s",
+ inet_ntop(AF_INET, &rp_info->rp.rpf_addr.u.prefix4, rp_buffer, 32),
+ prefix2str(&rp_info->group, group_buffer, 32), VTY_NEWLINE);
+ count++;
+ }
+
+ return count;
+}
+
+int
+pim_rp_check_is_my_ip_address (struct in_addr group, struct in_addr dest_addr)
+{
+ struct rp_info *rp_info;
+ struct prefix g;
+
+ memset (&g, 0, sizeof (g));
+ g.family = AF_INET;
+ g.prefixlen = 32;
+ g.u.prefix4 = group;
+
+ rp_info = pim_rp_find_match_group (&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 (dest_addr.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr)
+ return 1;
+ }
+
+ if (if_lookup_exact_address (&dest_addr, AF_INET))
+ return 1;
+
+ return 0;
+}
+
+void
+pim_rp_show_information (struct vty *vty, u_char uj)
+{
+ struct rp_info *rp_info;
+ struct rp_info *prev_rp_info = NULL;
+ struct listnode *node;
+
+ json_object *json = NULL;
+ json_object *json_rp_rows = NULL;
+ json_object *json_row = NULL;
+
+ if (uj)
+ json = json_object_new_object();
+ else
+ vty_out (vty, "RP address group/prefix-list OIF I am RP%s", VTY_NEWLINE);
+
+ for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
+ {
+ if (!pim_rpf_addr_is_inaddr_none (&rp_info->rp))
+ {
+ char buf[48];
+
+ if (uj)
+ {
+ /*
+ * If we have moved on to a new RP then add the entry for the previous RP
+ */
+ if (prev_rp_info &&
+ prev_rp_info->rp.rpf_addr.u.prefix4.s_addr != rp_info->rp.rpf_addr.u.prefix4.s_addr)
+ {
+ json_object_object_add(json, inet_ntoa (prev_rp_info->rp.rpf_addr.u.prefix4), json_rp_rows);
+ json_rp_rows = NULL;
+ }
+
+ if (!json_rp_rows)
+ json_rp_rows = json_object_new_array();
+
+ json_row = json_object_new_object();
+ if (rp_info->rp.source_nexthop.interface)
+ json_object_string_add(json_row, "outboundInterface", rp_info->rp.source_nexthop.interface->name);
+
+ if (rp_info->i_am_rp)
+ json_object_boolean_true_add(json_row, "iAmRP");
+
+ if (rp_info->plist)
+ json_object_string_add(json_row, "prefixList", rp_info->plist);
+ else
+ json_object_string_add(json_row, "group", prefix2str(&rp_info->group, buf, 48));
+
+ json_object_array_add(json_rp_rows, json_row);
+ }
+ else
+ {
+ vty_out (vty, "%-15s ", inet_ntoa (rp_info->rp.rpf_addr.u.prefix4));
+
+ if (rp_info->plist)
+ vty_out (vty, "%-18s ", rp_info->plist);
+ else
+ vty_out (vty, "%-18s ", prefix2str(&rp_info->group, buf, 48));
+
+ if (rp_info->rp.source_nexthop.interface)
+ vty_out (vty, "%-10s ", rp_info->rp.source_nexthop.interface->name);
+ else
+ vty_out (vty, "%-10s ", "(Unknown)");
+
+ if (rp_info->i_am_rp)
+ vty_out (vty, "yes%s", VTY_NEWLINE);
+ else
+ vty_out (vty, "no%s", VTY_NEWLINE);
+ }
+
+ prev_rp_info = rp_info;
+ }
+ }
+
+ if (uj) {
+ if (prev_rp_info && json_rp_rows)
+ json_object_object_add(json, inet_ntoa (prev_rp_info->rp.rpf_addr.u.prefix4), json_rp_rows);
+
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
+ }
+}
diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h
index bb785e7efc..b32228ed49 100644
--- a/pimd/pim_rp.h
+++ b/pimd/pim_rp.h
@@ -21,11 +21,29 @@
#ifndef PIM_RP_H
#define PIM_RP_H
-void pim_rp_check_rp (struct in_addr old, struct in_addr new);
+void pim_rp_init (void);
+void pim_rp_free (void);
+
+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);
+
+int pim_rp_config_write (struct vty *vty);
+
+int pim_rp_setup (void);
+
int pim_rp_i_am_rp (struct in_addr group);
-int pim_rp_set_upstream_addr (struct in_addr *up, struct in_addr source);
+void pim_rp_check_on_if_add(struct pim_interface *pim_ifp);
+void pim_i_am_rp_re_evaluate(void);
+
+int pim_rp_check_is_my_ip_address (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);
+
struct pim_rpf *pim_rp_g (struct in_addr group);
#define I_am_RP(G) pim_rp_i_am_rp ((G))
#define RP(G) pim_rp_g ((G))
+
+void pim_rp_show_information (struct vty *vty, u_char uj);
#endif
diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c
index 8d6e7b70c1..ae00e347b5 100644
--- a/pimd/pim_rpf.c
+++ b/pimd/pim_rpf.c
@@ -33,108 +33,160 @@
#include "pim_iface.h"
#include "pim_zlookup.h"
#include "pim_ifchannel.h"
+#include "pim_time.h"
+
+static long long last_route_change_time = -1;
+long long nexthop_lookups_avoided = 0;
static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up);
-int pim_nexthop_lookup(struct pim_nexthop *nexthop,
- struct in_addr addr, struct interface *incoming)
+void
+pim_rpf_set_refresh_time (void)
{
- struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE];
- int num_ifindex;
- struct interface *ifp;
- int first_ifindex;
+ last_route_change_time = pim_time_monotonic_usec();
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: New last route change time: %lld",
+ __PRETTY_FUNCTION__, last_route_change_time);
+}
- memset (nexthop_tab, 0, sizeof (struct pim_zlookup_nexthop) * PIM_NEXTHOP_IFINDEX_TAB_SIZE);
+int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, int neighbor_needed)
+{
+ struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
+ int num_ifindex;
+ struct interface *ifp = NULL;
+ ifindex_t first_ifindex = 0;
+ int found = 0;
+ int i = 0;
- if (!incoming)
+ if ((nexthop->last_lookup.s_addr == addr.s_addr) &&
+ (nexthop->last_lookup_time > last_route_change_time))
{
- num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab,
- PIM_NEXTHOP_IFINDEX_TAB_SIZE,
- addr, PIM_NEXTHOP_LOOKUP_MAX);
- if (num_ifindex < 1) {
- char addr_str[100];
- 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;
- }
-
- first_ifindex = nexthop_tab[0].ifindex;
-
- if (num_ifindex > 1) {
- char addr_str[100];
- pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
- zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
- __FILE__, __PRETTY_FUNCTION__,
- num_ifindex, addr_str, first_ifindex);
- /* debug warning only, do not return */
- }
-
- ifp = if_lookup_by_index(first_ifindex);
- if (!ifp) {
- char addr_str[100];
- pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
- zlog_warn("%s %s: could not find interface for ifindex %d (address %s)",
- __FILE__, __PRETTY_FUNCTION__,
- first_ifindex, addr_str);
- return -2;
- }
+ if (PIM_DEBUG_TRACE)
+ {
+ char addr_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
+ zlog_debug ("%s: Using last lookup for %s at %lld, %lld",
+ __PRETTY_FUNCTION__,
+ addr_str,
+ nexthop->last_lookup_time,
+ last_route_change_time);
+ }
+ nexthop_lookups_avoided++;
+ return 0;
}
else
{
- ifp = incoming;
- first_ifindex = ifp->ifindex;
+ if (PIM_DEBUG_TRACE)
+ {
+ 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, %lld",
+ __PRETTY_FUNCTION__,
+ addr_str,
+ nexthop->last_lookup_time,
+ last_route_change_time);
+ }
}
- if (!ifp->info) {
- char addr_str[100];
+ 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);
+ if (num_ifindex < 1) {
+ char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
- zlog_warn("%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)",
- __PRETTY_FUNCTION__,
- ifp->name, first_ifindex, addr_str);
- /* debug warning only, do not return */
+ zlog_warn("%s %s: could not find nexthop ifindex for address %s",
+ __FILE__, __PRETTY_FUNCTION__,
+ addr_str);
+ return -1;
}
- if (PIM_DEBUG_PIM_TRACE) {
- char nexthop_str[100];
- char addr_str[100];
- pim_inet4_dump("<nexthop?>", nexthop_tab[0].nexthop_addr, nexthop_str, sizeof(nexthop_str));
- pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
- zlog_debug("%s %s: found nexthop %s for address %s: interface %s ifindex=%d metric=%d pref=%d",
- __FILE__, __PRETTY_FUNCTION__,
- nexthop_str, addr_str,
- ifp->name, first_ifindex,
- nexthop_tab[0].route_metric,
- nexthop_tab[0].protocol_distance);
- }
+ while (!found && (i < num_ifindex))
+ {
+ first_ifindex = nexthop_tab[i].ifindex;
- /* update nextop data */
- nexthop->interface = ifp;
- nexthop->mrib_nexthop_addr = nexthop_tab[0].nexthop_addr;
- nexthop->mrib_metric_preference = nexthop_tab[0].protocol_distance;
- nexthop->mrib_route_metric = nexthop_tab[0].route_metric;
+ ifp = if_lookup_by_index(first_ifindex);
+ if (!ifp)
+ {
+ if (PIM_DEBUG_ZEBRA)
+ {
+ 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)",
+ __FILE__, __PRETTY_FUNCTION__,
+ first_ifindex, addr_str);
+ }
+ i++;
+ continue;
+ }
+
+ if (!ifp->info)
+ {
+ if (PIM_DEBUG_ZEBRA)
+ {
+ 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)",
+ __PRETTY_FUNCTION__,
+ ifp->name, first_ifindex, addr_str);
+ }
+ i++;
+ }
+ else if (neighbor_needed && !pim_if_connected_to_source (ifp, addr))
+ {
+ struct pim_neighbor *nbr;
+
+ 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 (!nbr && !if_is_loopback (ifp))
+ i++;
+ else
+ found = 1;
+ }
+ else
+ found = 1;
+ }
- return 0;
+ if (found)
+ {
+ if (PIM_DEBUG_ZEBRA) {
+ char nexthop_str[PREFIX_STRLEN];
+ char addr_str[INET_ADDRSTRLEN];
+ pim_addr_dump("<nexthop?>", &nexthop_tab[i].nexthop_addr, nexthop_str, sizeof(nexthop_str));
+ pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
+ zlog_debug("%s %s: found nexthop %s for address %s: interface %s ifindex=%d metric=%d pref=%d",
+ __FILE__, __PRETTY_FUNCTION__,
+ nexthop_str, addr_str,
+ ifp->name, first_ifindex,
+ nexthop_tab[i].route_metric,
+ nexthop_tab[i].protocol_distance);
+ }
+ /* update nextop data */
+ nexthop->interface = ifp;
+ nexthop->mrib_nexthop_addr = nexthop_tab[i].nexthop_addr;
+ nexthop->mrib_metric_preference = nexthop_tab[i].protocol_distance;
+ nexthop->mrib_route_metric = nexthop_tab[i].route_metric;
+ nexthop->last_lookup = addr;
+ nexthop->last_lookup_time = pim_time_monotonic_usec();
+ return 0;
+ }
+ else
+ return -1;
}
static int nexthop_mismatch(const struct pim_nexthop *nh1,
const struct pim_nexthop *nh2)
{
- return (nh1->interface != nh2->interface)
- ||
- (nh1->mrib_nexthop_addr.s_addr != nh2->mrib_nexthop_addr.s_addr)
- ||
- (nh1->mrib_metric_preference != nh2->mrib_metric_preference)
- ||
+ return (nh1->interface != nh2->interface) ||
+ (nh1->mrib_nexthop_addr.u.prefix4.s_addr != nh2->mrib_nexthop_addr.u.prefix4.s_addr) ||
+ (nh1->mrib_metric_preference != nh2->mrib_metric_preference) ||
(nh1->mrib_route_metric != nh2->mrib_route_metric);
}
-enum pim_rpf_result pim_rpf_update(struct pim_upstream *up,
- struct in_addr *old_rpf_addr,
- struct interface *incoming)
+enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct in_addr *old_rpf_addr)
{
- struct in_addr save_rpf_addr;
+ struct prefix save_rpf_addr;
struct pim_nexthop save_nexthop;
struct pim_rpf *rpf = &up->rpf;
@@ -142,36 +194,31 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up,
save_rpf_addr = rpf->rpf_addr; /* detect change in RPF'(S,G) */
if (pim_nexthop_lookup(&rpf->source_nexthop,
- up->upstream_addr, incoming)) {
+ up->upstream_addr,
+ !PIM_UPSTREAM_FLAG_TEST_FHR (up->flags) &&
+ !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags))) {
return PIM_RPF_FAILURE;
}
- rpf->rpf_addr = pim_rpf_find_rpf_addr(up);
- if (PIM_INADDR_IS_ANY(rpf->rpf_addr) && PIM_DEBUG_PIM_EVENTS) {
+ rpf->rpf_addr.family = AF_INET;
+ rpf->rpf_addr.u.prefix4 = pim_rpf_find_rpf_addr(up);
+ if (pim_rpf_addr_is_inaddr_any(rpf) && PIM_DEBUG_ZEBRA) {
/* RPF'(S,G) not found */
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
- zlog_debug("%s %s: RPF'(%s,%s) not found: won't send join upstream",
+ zlog_debug("%s %s: RPF'%s not found: won't send join upstream",
__FILE__, __PRETTY_FUNCTION__,
- src_str, grp_str);
+ up->sg_str);
/* warning only */
}
/* detect change in pim_nexthop */
if (nexthop_mismatch(&rpf->source_nexthop, &save_nexthop)) {
- if (PIM_DEBUG_PIM_EVENTS) {
- char src_str[100];
- char grp_str[100];
- char nhaddr_str[100];
- pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
- pim_inet4_dump("<addr?>", rpf->source_nexthop.mrib_nexthop_addr, nhaddr_str, sizeof(nhaddr_str));
- zlog_debug("%s %s: (S,G)=(%s,%s) source nexthop now is: interface=%s address=%s pref=%d metric=%d",
+ if (PIM_DEBUG_ZEBRA) {
+ char nhaddr_str[PREFIX_STRLEN];
+ pim_addr_dump("<addr?>", &rpf->source_nexthop.mrib_nexthop_addr, nhaddr_str, sizeof(nhaddr_str));
+ zlog_debug("%s %s: (S,G)=%s source nexthop now is: interface=%s address=%s pref=%d metric=%d",
__FILE__, __PRETTY_FUNCTION__,
- src_str, grp_str,
+ up->sg_str,
rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "<ifname?>",
nhaddr_str,
rpf->source_nexthop.mrib_metric_preference,
@@ -186,14 +233,10 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up,
/* detect change in RPF_interface(S) */
if (save_nexthop.interface != rpf->source_nexthop.interface) {
- if (PIM_DEBUG_PIM_EVENTS) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
- zlog_debug("%s %s: (S,G)=(%s,%s) RPF_interface(S) changed from %s to %s",
+ if (PIM_DEBUG_ZEBRA) {
+ zlog_debug("%s %s: (S,G)=%s RPF_interface(S) changed from %s to %s",
__FILE__, __PRETTY_FUNCTION__,
- src_str, grp_str,
+ up->sg_str,
save_nexthop.interface ? save_nexthop.interface->name : "<oldif?>",
rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "<newif?>");
/* warning only */
@@ -203,11 +246,11 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up,
}
/* detect change in RPF'(S,G) */
- if (save_rpf_addr.s_addr != rpf->rpf_addr.s_addr) {
+ if (save_rpf_addr.u.prefix4.s_addr != rpf->rpf_addr.u.prefix4.s_addr) {
/* return old rpf to caller ? */
if (old_rpf_addr)
- *old_rpf_addr = save_rpf_addr;
+ *old_rpf_addr = save_rpf_addr.u.prefix4;
return PIM_RPF_CHANGED;
}
@@ -237,20 +280,16 @@ static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up)
struct in_addr rpf_addr;
if (!up->rpf.source_nexthop.interface) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
- zlog_warn("%s: missing RPF interface for upstream (S,G)=(%s,%s)",
+ zlog_warn("%s: missing RPF interface for upstream (S,G)=%s",
__PRETTY_FUNCTION__,
- src_str, grp_str);
+ up->sg_str);
rpf_addr.s_addr = PIM_NET_INADDR_ANY;
return rpf_addr;
}
rpf_ch = pim_ifchannel_find(up->rpf.source_nexthop.interface,
- up->source_addr, up->group_addr);
+ &up->sg);
if (rpf_ch) {
if (rpf_ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
return rpf_ch->ifassert_winner;
@@ -260,7 +299,7 @@ static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up)
/* return NBR( RPF_interface(S), MRIB.next_hop( S ) ) */
neigh = pim_if_find_neighbor(up->rpf.source_nexthop.interface,
- up->rpf.source_nexthop.mrib_nexthop_addr);
+ up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4);
if (neigh)
rpf_addr = neigh->source_addr;
else
@@ -268,3 +307,52 @@ static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up)
return rpf_addr;
}
+
+int
+pim_rpf_addr_is_inaddr_none (struct pim_rpf *rpf)
+{
+ switch (rpf->rpf_addr.family)
+ {
+ case AF_INET:
+ return rpf->rpf_addr.u.prefix4.s_addr == INADDR_NONE;
+ break;
+ case AF_INET6:
+ zlog_warn ("%s: v6 Unimplmeneted", __PRETTY_FUNCTION__);
+ return 1;
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ return 0;
+}
+
+int
+pim_rpf_addr_is_inaddr_any (struct pim_rpf *rpf)
+{
+ switch (rpf->rpf_addr.family)
+ {
+ case AF_INET:
+ return rpf->rpf_addr.u.prefix4.s_addr == INADDR_ANY;
+ break;
+ case AF_INET6:
+ zlog_warn ("%s: v6 Unimplmented", __PRETTY_FUNCTION__);
+ return 1;
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ return 0;
+}
+
+int
+pim_rpf_is_same (struct pim_rpf *rpf1, struct pim_rpf *rpf2)
+{
+ if (rpf1->source_nexthop.interface == rpf2->source_nexthop.interface)
+ return 1;
+
+ return 0;
+}
diff --git a/pimd/pim_rpf.h b/pimd/pim_rpf.h
index 4d55bd6881..bb77775324 100644
--- a/pimd/pim_rpf.h
+++ b/pimd/pim_rpf.h
@@ -26,10 +26,48 @@
#include "pim_upstream.h"
#include "pim_neighbor.h"
-int pim_nexthop_lookup(struct pim_nexthop *nexthop,
- struct in_addr addr, struct interface *incoming);
-enum pim_rpf_result pim_rpf_update(struct pim_upstream *up,
- struct in_addr *old_rpf_addr,
- struct interface *incoming);
+/*
+ RFC 4601:
+
+ Metric Preference
+ Preference value assigned to the unicast routing protocol that
+ provided the route to the multicast source or Rendezvous-Point.
+
+ Metric
+ The unicast routing table metric associated with the route used to
+ reach the multicast source or Rendezvous-Point. The metric is in
+ units applicable to the unicast routing protocol used.
+*/
+struct pim_nexthop {
+ struct in_addr last_lookup;
+ long long last_lookup_time;
+ struct interface *interface; /* RPF_interface(S) */
+ struct prefix mrib_nexthop_addr; /* MRIB.next_hop(S) */
+ uint32_t mrib_metric_preference; /* MRIB.pref(S) */
+ uint32_t mrib_route_metric; /* MRIB.metric(S) */
+};
+
+struct pim_rpf {
+ struct pim_nexthop source_nexthop;
+ struct prefix rpf_addr; /* RPF'(S,G) */
+};
+
+enum pim_rpf_result {
+ PIM_RPF_OK = 0,
+ PIM_RPF_CHANGED,
+ PIM_RPF_FAILURE
+};
+
+struct pim_upstream;
+
+extern long long nexthop_lookups_avoided;
+
+int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, int neighbor_needed);
+enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct in_addr *old_rpf_addr);
+
+int pim_rpf_addr_is_inaddr_none (struct pim_rpf *rpf);
+int pim_rpf_addr_is_inaddr_any (struct pim_rpf *rpf);
+int pim_rpf_is_same (struct pim_rpf *rpf1, struct pim_rpf *rpf2);
+void pim_rpf_set_refresh_time (void);
#endif /* PIM_RPF_H */
diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c
index 54816d126b..eda81c6571 100644
--- a/pimd/pim_sock.c
+++ b/pimd/pim_sock.c
@@ -44,7 +44,8 @@
/* GLOBAL VARS */
extern struct zebra_privs_t pimd_privs;
-int pim_socket_raw(int protocol)
+int
+pim_socket_raw (int protocol)
{
int fd;
@@ -67,8 +68,58 @@ int pim_socket_raw(int protocol)
return fd;
}
+int
+pim_socket_ip_hdr (int fd)
+{
+ const int on = 1;
+ int ret;
+
+ if (pimd_privs.change (ZPRIVS_RAISE))
+ zlog_err ("%s: could not raise privs, %s",
+ __PRETTY_FUNCTION__, safe_strerror (errno));
+
+ ret = setsockopt (fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on));
+
+ if (pimd_privs.change (ZPRIVS_LOWER))
+ zlog_err ("%s: could not lower privs, %s",
+ __PRETTY_FUNCTION__, safe_strerror (errno));
+
+ return ret;
+}
+
+/*
+ * Given a socket and a interface,
+ * Bind that socket to that interface
+ */
+int
+pim_socket_bind (int fd, struct interface *ifp)
+{
+ int ret = 0;
+#ifdef SO_BINDTODEVICE
+
+ if (pimd_privs.change (ZPRIVS_RAISE))
+ zlog_err ("%s: could not raise privs, %s",
+ __PRETTY_FUNCTION__, safe_strerror (errno));
+
+ ret = setsockopt (fd, SOL_SOCKET,
+ SO_BINDTODEVICE, ifp->name, strlen (ifp->name));
+
+ if (pimd_privs.change (ZPRIVS_LOWER))
+ zlog_err ("%s: could not lower privs, %s",
+ __PRETTY_FUNCTION__, safe_strerror (errno));
+
+#endif
+ return ret;
+}
+
int pim_socket_mcast(int protocol, struct in_addr ifaddr, int ifindex, u_char loop)
{
+ int rcvbuf = 1024 * 1024 * 8;
+#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
+ struct ip_mreqn mreq;
+#else
+ struct ip_mreq mreq;
+#endif
int fd;
fd = pim_socket_raw(protocol);
@@ -86,17 +137,7 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, int ifindex, u_char lo
ifp = if_lookup_by_index_vrf (ifindex, VRF_DEFAULT);
- if (pimd_privs.change (ZPRIVS_RAISE))
- zlog_err ("%s: could not raise privs, %s",
- __PRETTY_FUNCTION__, safe_strerror (errno));
-
- ret = setsockopt (fd, SOL_SOCKET,
- SO_BINDTODEVICE, ifp->name, strlen (ifp->name));
-
- if (pimd_privs.change (ZPRIVS_LOWER))
- zlog_err ("%s: could not lower privs, %s",
- __PRETTY_FUNCTION__, safe_strerror (errno));
-
+ ret = pim_socket_bind (fd, ifp);
if (ret)
{
zlog_warn("Could not set fd: %d for interface: %s to device",
@@ -180,14 +221,28 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, int ifindex, u_char lo
return PIM_SOCK_ERR_LOOP;
}
+ memset (&mreq, 0, sizeof (mreq));
+#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
+ mreq.imr_ifindex = ifindex;
+#else
+ /*
+ * I am not sure what to do here yet for *BSD
+ */
+ //mreq.imr_interface = ifindex;
+#endif
+
if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
- (void *) &ifaddr, sizeof(ifaddr))) {
+ (void *) &mreq, sizeof(mreq))) {
zlog_warn("Could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s",
fd, errno, safe_strerror(errno));
close(fd);
return PIM_SOCK_ERR_IFACE;
}
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)))
+ zlog_warn("%s: Failure to set buffer size to %d",
+ __PRETTY_FUNCTION__, rcvbuf);
+
{
long flags;
@@ -232,8 +287,8 @@ int pim_socket_join(int fd, struct in_addr group,
ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &opt, sizeof(opt));
if (ret) {
- char group_str[100];
- char ifaddr_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char ifaddr_str[INET_ADDRSTRLEN];
if (!inet_ntop(AF_INET, &group, group_str , sizeof(group_str)))
sprintf(group_str, "<group?>");
if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str , sizeof(ifaddr_str)))
@@ -245,8 +300,8 @@ int pim_socket_join(int fd, struct in_addr group,
}
if (PIM_DEBUG_TRACE) {
- char group_str[100];
- char ifaddr_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char ifaddr_str[INET_ADDRSTRLEN];
if (!inet_ntop(AF_INET, &group, group_str , sizeof(group_str)))
sprintf(group_str, "<group?>");
if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str , sizeof(ifaddr_str)))
@@ -265,15 +320,14 @@ int pim_socket_join_source(int fd, ifindex_t ifindex,
const char *ifname)
{
if (pim_igmp_join_source(fd, ifindex, group_addr, source_addr)) {
- int e = errno;
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s",
__PRETTY_FUNCTION__,
fd, group_str, source_str, ifindex, ifname,
- e, safe_strerror(e));
+ errno, safe_strerror(errno));
return -1;
}
@@ -298,17 +352,14 @@ int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
if (to) {
struct sockaddr_in si;
socklen_t si_len = sizeof(si);
-
- ((struct sockaddr_in *) to)->sin_family = AF_INET;
- if (pim_socket_getsockname(fd, (struct sockaddr *) &si, &si_len)) {
- ((struct sockaddr_in *) to)->sin_port = ntohs(0);
- ((struct sockaddr_in *) to)->sin_addr.s_addr = ntohl(0);
- }
- else {
- ((struct sockaddr_in *) to)->sin_port = si.sin_port;
- ((struct sockaddr_in *) to)->sin_addr = si.sin_addr;
- }
+ memset (&si, 0, sizeof (si));
+ to->sin_family = AF_INET;
+
+ pim_socket_getsockname(fd, (struct sockaddr *) &si, &si_len);
+
+ to->sin_port = si.sin_port;
+ to->sin_addr = si.sin_addr;
if (tolen)
*tolen = sizeof(si);
@@ -346,14 +397,6 @@ int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
if (ifindex)
*ifindex = i->ipi_ifindex;
- if (to && PIM_DEBUG_PACKETS) {
- char to_str[100];
- pim_inet4_dump("<to?>", to->sin_addr, to_str, sizeof(to_str));
- zlog_debug("%s: HAVE_IP_PKTINFO to=%s,%d",
- __PRETTY_FUNCTION__,
- to_str, ntohs(to->sin_port));
- }
-
break;
}
#endif
@@ -366,14 +409,6 @@ int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
if (tolen)
*tolen = sizeof(struct sockaddr_in);
- if (to && PIM_DEBUG_PACKETS) {
- char to_str[100];
- pim_inet4_dump("<to?>", to->sin_addr, to_str, sizeof(to_str));
- zlog_debug("%s: HAVE_IP_RECVDSTADDR to=%s,%d",
- __PRETTY_FUNCTION__,
- to_str, ntohs(to->sin_port));
- }
-
break;
}
#endif
diff --git a/pimd/pim_sock.h b/pimd/pim_sock.h
index f905c661dd..aaf82e862a 100644
--- a/pimd/pim_sock.h
+++ b/pimd/pim_sock.h
@@ -36,6 +36,8 @@
#define PIM_SOCK_ERR_NAME (-10) /* Socket name (getsockname) */
#define PIM_SOCK_ERR_BIND (-11) /* Can't bind to interface */
+int pim_socket_bind (int fd, struct interface *ifp);
+int pim_socket_ip_hdr (int fd);
int pim_socket_raw(int protocol);
int pim_socket_mcast(int protocol, struct in_addr ifaddr, int ifindex, u_char loop);
int pim_socket_join(int fd, struct in_addr group,
diff --git a/pimd/pim_ssmpingd.c b/pimd/pim_ssmpingd.c
index ece644a861..0354083332 100644
--- a/pimd/pim_ssmpingd.c
+++ b/pimd/pim_ssmpingd.c
@@ -25,11 +25,10 @@
#include "memory.h"
#include "sockopt.h"
+#include "pimd.h"
#include "pim_ssmpingd.h"
#include "pim_time.h"
#include "pim_sock.h"
-#include "pim_str.h"
-#include "pimd.h"
static const char * const PIM_SSMPINGD_REPLY_GROUP = "232.43.211.234";
@@ -96,7 +95,7 @@ static int ssmpingd_socket(struct in_addr addr, int port, int mttl)
sockaddr.sin_port = htons(port);
if (bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
- char addr_str[100];
+ char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_warn("%s: bind(fd=%d,addr=%s,port=%d,len=%zu) failure: errno=%d: %s",
__PRETTY_FUNCTION__,
@@ -195,12 +194,11 @@ static void ssmpingd_delete(struct ssmpingd_sock *ss)
THREAD_OFF(ss->t_sock_read);
if (close(ss->sock_fd)) {
- int e = errno;
- char source_str[100];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str));
zlog_warn("%s: failure closing ssmpingd sock_fd=%d for source %s: errno=%d: %s",
__PRETTY_FUNCTION__,
- ss->sock_fd, source_str, e, safe_strerror(e));
+ ss->sock_fd, source_str, errno, safe_strerror(errno));
/* warning only */
}
@@ -219,14 +217,13 @@ static void ssmpingd_sendto(struct ssmpingd_sock *ss,
sent = sendto(ss->sock_fd, buf, len, MSG_DONTWAIT,
(struct sockaddr *)&to, tolen);
if (sent != len) {
- int e = errno;
- char to_str[100];
+ char to_str[INET_ADDRSTRLEN];
pim_inet4_dump("<to?>", to.sin_addr, to_str, sizeof(to_str));
if (sent < 0) {
zlog_warn("%s: sendto() failure to %s,%d: fd=%d len=%d: errno=%d: %s",
__PRETTY_FUNCTION__,
to_str, ntohs(to.sin_port), ss->sock_fd, len,
- e, safe_strerror(e));
+ errno, safe_strerror(errno));
}
else {
zlog_warn("%s: sendto() partial to %s,%d: fd=%d len=%d: sent=%d",
@@ -255,7 +252,7 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss)
&to, &tolen,
&ifindex);
if (len < 0) {
- char source_str[100];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str));
zlog_warn("%s: failure receiving ssmping for source %s on fd=%d: errno=%d: %s",
__PRETTY_FUNCTION__, source_str, ss->sock_fd, errno, safe_strerror(errno));
@@ -265,9 +262,9 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss)
ifp = if_lookup_by_index(ifindex);
if (buf[0] != PIM_SSMPINGD_REQUEST) {
- char source_str[100];
- char from_str[100];
- char to_str[100];
+ char source_str[INET_ADDRSTRLEN];
+ char from_str[INET_ADDRSTRLEN];
+ char to_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str));
pim_inet4_dump("<from?>", from.sin_addr, from_str, sizeof(from_str));
pim_inet4_dump("<to?>", to.sin_addr, to_str, sizeof(to_str));
@@ -283,9 +280,9 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss)
}
if (PIM_DEBUG_SSMPINGD) {
- char source_str[100];
- char from_str[100];
- char to_str[100];
+ char source_str[INET_ADDRSTRLEN];
+ char from_str[INET_ADDRSTRLEN];
+ char to_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str));
pim_inet4_dump("<from?>", from.sin_addr, from_str, sizeof(from_str));
pim_inet4_dump("<to?>", to.sin_addr, to_str, sizeof(to_str));
@@ -316,10 +313,7 @@ static int ssmpingd_sock_read(struct thread *t)
int sock_fd;
int result;
- zassert(t);
-
ss = THREAD_ARG(t);
- zassert(ss);
sock_fd = THREAD_FD(t);
zassert(sock_fd == ss->sock_fd);
@@ -357,18 +351,18 @@ static struct ssmpingd_sock *ssmpingd_new(struct in_addr source_addr)
sock_fd = ssmpingd_socket(source_addr, /* port: */ 4321, /* mTTL: */ 64);
if (sock_fd < 0) {
- char source_str[100];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: ssmpingd_socket() failure for source %s",
__PRETTY_FUNCTION__, source_str);
return 0;
}
- ss = XMALLOC(MTYPE_PIM_SSMPINGD, sizeof(*ss));
+ ss = XCALLOC(MTYPE_PIM_SSMPINGD, sizeof(*ss));
if (!ss) {
- char source_str[100];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
- zlog_err("%s: XMALLOC(%zu) failure for ssmpingd source %s",
+ zlog_err("%s: XCALLOC(%zu) failure for ssmpingd source %s",
__PRETTY_FUNCTION__,
sizeof(*ss), source_str);
close(sock_fd);
@@ -399,7 +393,7 @@ int pim_ssmpingd_start(struct in_addr source_addr)
}
{
- char source_str[100];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_info("%s: starting ssmpingd for source %s",
__PRETTY_FUNCTION__, source_str);
@@ -407,7 +401,7 @@ int pim_ssmpingd_start(struct in_addr source_addr)
ss = ssmpingd_new(source_addr);
if (!ss) {
- char source_str[100];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: ssmpingd_new() failure for source %s",
__PRETTY_FUNCTION__, source_str);
@@ -423,7 +417,7 @@ int pim_ssmpingd_stop(struct in_addr source_addr)
ss = ssmpingd_find(source_addr);
if (!ss) {
- char source_str[100];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_warn("%s: could not find ssmpingd for source %s",
__PRETTY_FUNCTION__, source_str);
@@ -431,7 +425,7 @@ int pim_ssmpingd_stop(struct in_addr source_addr)
}
{
- char source_str[100];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
zlog_info("%s: stopping ssmpingd for source %s",
__PRETTY_FUNCTION__, source_str);
diff --git a/pimd/pim_static.c b/pimd/pim_static.c
index 565d6fe728..e1ccec387a 100644
--- a/pimd/pim_static.c
+++ b/pimd/pim_static.c
@@ -78,11 +78,11 @@ static struct static_route *static_route_new(unsigned int iif,
int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source)
{
- struct listnode *node = 0;
- struct static_route *s_route = 0;
- struct static_route *original_s_route = 0;
- struct pim_interface *pim_iif = iif ? iif->info : 0;
- struct pim_interface *pim_oif = oif ? oif->info : 0;
+ struct listnode *node = NULL;
+ struct static_route *s_route = NULL;
+ struct static_route *original_s_route = NULL;
+ struct pim_interface *pim_iif = iif ? iif->info : NULL;
+ struct pim_interface *pim_oif = oif ? oif->info : NULL;
ifindex_t iif_index = pim_iif ? pim_iif->mroute_vif_index : 0;
ifindex_t oif_index = pim_oif ? pim_oif->mroute_vif_index : 0;
@@ -110,8 +110,8 @@ int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr
s_route->source.s_addr == source.s_addr) {
if (s_route->iif == iif_index &&
s_route->oif_ttls[oif_index]) {
- char gifaddr_str[100];
- char sifaddr_str[100];
+ char gifaddr_str[INET_ADDRSTRLEN];
+ char sifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
zlog_warn("%s %s: Unable to add static route: Route already exists (iif=%d,oif=%d,group=%s,source=%s)",
@@ -174,10 +174,10 @@ int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr
listnode_add(qpim_static_route_list, s_route);
}
- if (pim_mroute_add(&s_route->c_oil))
+ if (pim_mroute_add(&s_route->c_oil, __PRETTY_FUNCTION__))
{
- char gifaddr_str[100];
- char sifaddr_str[100];
+ char gifaddr_str[INET_ADDRSTRLEN];
+ char sifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
zlog_warn("%s %s: Unable to add static route(iif=%d,oif=%d,group=%s,source=%s)",
@@ -209,8 +209,8 @@ int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr
}
if (PIM_DEBUG_STATIC) {
- char gifaddr_str[100];
- char sifaddr_str[100];
+ char gifaddr_str[INET_ADDRSTRLEN];
+ char sifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
zlog_debug("%s: Static route added(iif=%d,oif=%d,group=%s,source=%s)",
@@ -226,9 +226,9 @@ int pim_static_add(struct interface *iif, struct interface *oif, struct in_addr
int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr group, struct in_addr source)
{
- struct listnode *node = 0;
- struct listnode *nextnode = 0;
- struct static_route *s_route = 0;
+ struct listnode *node = NULL;
+ struct listnode *nextnode = NULL;
+ struct static_route *s_route = NULL;
struct pim_interface *pim_iif = iif ? iif->info : 0;
struct pim_interface *pim_oif = oif ? oif->info : 0;
ifindex_t iif_index = pim_iif ? pim_iif->mroute_vif_index : 0;
@@ -253,23 +253,23 @@ int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr
/* If there are no more outputs then delete the whole route, otherwise set the route with the new outputs */
if (s_route->c_oil.oil_ref_count <= 0 ?
- pim_mroute_del(&s_route->c_oil) : pim_mroute_add(&s_route->c_oil)) {
- char gifaddr_str[100];
- char sifaddr_str[100];
- pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
- pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
- zlog_warn("%s %s: Unable to remove static route(iif=%d,oif=%d,group=%s,source=%s)",
+ pim_mroute_del(&s_route->c_oil, __PRETTY_FUNCTION__) : pim_mroute_add(&s_route->c_oil, __PRETTY_FUNCTION__)) {
+ char gifaddr_str[INET_ADDRSTRLEN];
+ char sifaddr_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
+ pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
+ zlog_warn("%s %s: Unable to remove static route(iif=%d,oif=%d,group=%s,source=%s)",
__FILE__, __PRETTY_FUNCTION__,
iif_index,
oif_index,
gifaddr_str,
sifaddr_str);
- s_route->oif_ttls[oif_index] = 1;
- s_route->c_oil.oil.mfcc_ttls[oif_index] = 1;
- ++s_route->c_oil.oil_ref_count;
+ s_route->oif_ttls[oif_index] = 1;
+ s_route->c_oil.oil.mfcc_ttls[oif_index] = 1;
+ ++s_route->c_oil.oil_ref_count;
- return -1;
+ return -1;
}
s_route->c_oil.oif_creation[oif_index] = 0;
@@ -280,8 +280,8 @@ int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr
}
if (PIM_DEBUG_STATIC) {
- char gifaddr_str[100];
- char sifaddr_str[100];
+ char gifaddr_str[INET_ADDRSTRLEN];
+ char sifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
zlog_debug("%s: Static route removed(iif=%d,oif=%d,group=%s,source=%s)",
@@ -297,8 +297,8 @@ int pim_static_del(struct interface *iif, struct interface *oif, struct in_addr
}
if (!node) {
- char gifaddr_str[100];
- char sifaddr_str[100];
+ char gifaddr_str[INET_ADDRSTRLEN];
+ char sifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", group, gifaddr_str, sizeof(gifaddr_str));
pim_inet4_dump("<ifaddr?>", source, sifaddr_str, sizeof(sifaddr_str));
zlog_warn("%s %s: Unable to remove static route: Route does not exist(iif=%d,oif=%d,group=%s,source=%s)",
@@ -319,8 +319,8 @@ pim_static_write_mroute (struct vty *vty, struct interface *ifp)
struct listnode *node;
struct static_route *sroute;
int count = 0;
- char sbuf[100];
- char gbuf[100];
+ char sbuf[INET_ADDRSTRLEN];
+ char gbuf[INET_ADDRSTRLEN];
for (ALL_LIST_ELEMENTS_RO (qpim_static_route_list, node, sroute))
{
diff --git a/pimd/pim_str.c b/pimd/pim_str.c
index c817045697..83f2a635b3 100644
--- a/pimd/pim_str.c
+++ b/pimd/pim_str.c
@@ -28,17 +28,62 @@
#include "pim_str.h"
-void pim_inet4_dump(const char *onfail, struct in_addr addr, char *buf, int buf_size)
+void pim_addr_dump (const char *onfail, struct prefix *p, char *buf, int buf_size)
{
int save_errno = errno;
- if (!inet_ntop(AF_INET, &addr, buf, buf_size)) {
- int e = errno;
- zlog_warn("pim_inet4_dump: inet_ntop(AF_INET,buf_size=%d): errno=%d: %s",
- buf_size, e, safe_strerror(e));
+ if (!inet_ntop(p->family, &p->u.prefix, buf, buf_size)) {
+ zlog_warn("pim_addr_dump: inet_ntop(buf_size=%d): errno=%d: %s",
+ buf_size, errno, safe_strerror(errno));
if (onfail)
snprintf(buf, buf_size, "%s", onfail);
}
errno = save_errno;
}
+
+void pim_inet4_dump(const char *onfail, struct in_addr addr, char *buf, int buf_size)
+{
+ int save_errno = errno;
+
+ if (addr.s_addr == INADDR_ANY)
+ strcpy(buf, "*");
+ else
+ {
+ if (!inet_ntop(AF_INET, &addr, buf, buf_size)) {
+ zlog_warn("pim_inet4_dump: inet_ntop(AF_INET,buf_size=%d): errno=%d: %s",
+ buf_size, errno, safe_strerror(errno));
+ if (onfail)
+ snprintf(buf, buf_size, "%s", onfail);
+ }
+ }
+
+ errno = save_errno;
+}
+
+char *
+pim_str_sg_dump (const struct prefix_sg *sg)
+{
+ char src_str[INET_ADDRSTRLEN];
+ char grp_str[INET_ADDRSTRLEN];
+ static char sg_str[PIM_SG_LEN];
+
+ pim_inet4_dump ("<src?>", sg->src, src_str, sizeof(src_str));
+ pim_inet4_dump ("<grp?>", sg->grp, grp_str, sizeof(grp_str));
+ snprintf (sg_str, PIM_SG_LEN, "(%s,%s)", src_str, grp_str);
+
+ return sg_str;
+}
+
+char *
+pim_str_sg_set (const struct prefix_sg *sg, char *sg_str)
+{
+ char src_str[INET_ADDRSTRLEN];
+ char grp_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump ("<src?>", sg->src, src_str, sizeof(src_str));
+ pim_inet4_dump ("<grp?>", sg->grp, grp_str, sizeof(grp_str));
+ snprintf (sg_str, PIM_SG_LEN, "(%s,%s)", src_str, grp_str);
+
+ return sg_str;
+}
diff --git a/pimd/pim_str.h b/pimd/pim_str.h
index d2af0110a4..97263e6a37 100644
--- a/pimd/pim_str.h
+++ b/pimd/pim_str.h
@@ -25,6 +25,20 @@
#include <sys/socket.h>
#include <arpa/inet.h>
+#include <prefix.h>
+
+/*
+ * Longest possible length of a (S,G) string is 36 bytes
+ * 123.123.123.123 = 16 * 2
+ * (,) = 3
+ * NULL Character at end = 1
+ * (123.123.123.123,123,123,123,123)
+ */
+#define PIM_SG_LEN 36
+
+void pim_addr_dump (const char *onfail, struct prefix *p, char *buf, int buf_size);
void pim_inet4_dump(const char *onfail, struct in_addr addr, char *buf, int buf_size);
+char *pim_str_sg_dump (const struct prefix_sg *sg);
+char *pim_str_sg_set (const struct prefix_sg *sg, char *sg_str);
#endif
diff --git a/pimd/pim_time.c b/pimd/pim_time.c
index 75f767fef1..348793cd0b 100644
--- a/pimd/pim_time.c
+++ b/pimd/pim_time.c
@@ -82,6 +82,25 @@ int64_t pim_time_monotonic_dsec()
return now_dsec;
}
+int64_t
+pim_time_monotonic_usec (void)
+{
+ struct timeval now_tv;
+ int64_t now_dsec;
+
+ if (gettime_monotonic(&now_tv)) {
+ zlog_err("%s: gettime_monotonic() failure: errno=%d: %s",
+ __PRETTY_FUNCTION__,
+ errno, safe_strerror(errno));
+ return -1;
+ }
+
+ now_dsec = ((int64_t) now_tv.tv_sec) * 1000000 + ((int64_t) now_tv.tv_usec);
+
+ return now_dsec;
+
+}
+
int pim_time_mmss(char *buf, int buf_size, long sec)
{
long mm;
diff --git a/pimd/pim_time.h b/pimd/pim_time.h
index 8ccc6a9207..de304a9f71 100644
--- a/pimd/pim_time.h
+++ b/pimd/pim_time.h
@@ -28,6 +28,7 @@
int64_t pim_time_monotonic_sec(void);
int64_t pim_time_monotonic_dsec(void);
+int64_t pim_time_monotonic_usec(void);
int pim_time_mmss(char *buf, int buf_size, long sec);
void pim_time_timer_to_mmss(char *buf, int buf_size, struct thread *t);
void pim_time_timer_to_hhmmss(char *buf, int buf_size, struct thread *t);
diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c
index 546ceb86e1..5223f60e1b 100644
--- a/pimd/pim_tlv.c
+++ b/pimd/pim_tlv.c
@@ -95,8 +95,35 @@ uint8_t *pim_tlv_append_uint32(uint8_t *buf,
#define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
-static int
-pim_encode_unicast_address (uint8_t *buf, struct prefix *p)
+/*
+ * An Encoded-Unicast address takes the following format:
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Addr Family | Encoding Type | Unicast Address
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
+ *
+ * Addr Family
+ * The PIM address family of the 'Unicast Address' field of this
+ * address.
+ *
+ * Values 0-127 are as assigned by the IANA for Internet Address * Families in [7]. Values 128-250 are reserved to be assigned by
+ * the IANA for PIM-specific Address Families. Values 251 though
+ * 255 are designated for private use. As there is no assignment
+ * authority for this space, collisions should be expected.
+ *
+ * Encoding Type
+ * The type of encoding used within a specific Address Family. The
+ * value '0' is reserved for this field and represents the native
+ * encoding of the Address Family.
+ *
+ * Unicast Address
+ * The unicast address as represented by the given Address Family
+ * and Encoding Type.
+ */
+int
+pim_encode_addr_ucast (uint8_t *buf, struct prefix *p)
{
switch (p->family)
{
@@ -114,6 +141,79 @@ pim_encode_unicast_address (uint8_t *buf, struct prefix *p)
}
}
+#define group_ipv4_encoding_len (4 + sizeof (struct in_addr))
+
+/*
+ * Encoded-Group addresses take the following format:
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Addr Family | Encoding Type |B| Reserved |Z| Mask Len |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Group multicast Address
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
+ *
+ * Addr Family
+ * Described above.
+ *
+ * Encoding Type
+ * Described above.
+ *
+ * [B]idirectional PIM
+ * Indicates the group range should use Bidirectional PIM [13].
+ * For PIM-SM defined in this specification, this bit MUST be zero.
+ *
+ * Reserved
+ * Transmitted as zero. Ignored upon receipt.
+ *
+ * Admin Scope [Z]one
+ * indicates the group range is an admin scope zone. This is used
+ * in the Bootstrap Router Mechanism [11] only. For all other
+ * purposes, this bit is set to zero and ignored on receipt.
+ *
+ * Mask Len
+ * The Mask length field is 8 bits. The value is the number of
+ * contiguous one bits that are left justified and used as a mask;
+ * when combined with the group address, it describes a range of
+ * groups. It is less than or equal to the address length in bits
+ * for the given Address Family and Encoding Type. If the message
+ * is sent for a single group, then the Mask length must equal the
+ * address length in bits for the given Address Family and Encoding
+ * Type (e.g., 32 for IPv4 native encoding, 128 for IPv6 native
+ * encoding).
+ *
+ * Group multicast Address
+ * Contains the group address.
+ */
+int
+pim_encode_addr_group (uint8_t *buf, afi_t afi, int bidir, int scope, struct in_addr group)
+{
+ uint8_t flags = 0;
+
+ flags |= bidir << 8;
+ flags |= scope;
+
+ switch (afi)
+ {
+ case AFI_IP:
+ *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV4;
+ ++buf;
+ *(uint8_t *)buf = 0;
+ ++buf;
+ *(uint8_t *)buf = flags;
+ ++buf;
+ *(uint8_t *)buf = 32;
+ ++buf;
+ memcpy (buf, &group, sizeof (struct in_addr));
+ return group_ipv4_encoding_len;
+ break;
+ default:
+ return 0;
+ break;
+ }
+}
+
uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
const uint8_t *buf_pastend,
struct list *ifconnected)
@@ -143,7 +243,7 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
if ((curr + ucast_ipv4_encoding_len) > buf_pastend)
return 0;
- l_encode = pim_encode_unicast_address (curr, p);
+ l_encode = pim_encode_addr_ucast (curr, p);
curr += l_encode;
option_len += l_encode;
}
@@ -173,7 +273,7 @@ static int check_tlv_length(const char *label, const char *tlv_name,
int correct_len, int option_len)
{
if (option_len != correct_len) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s",
label, tlv_name,
@@ -192,7 +292,7 @@ static void check_tlv_redefinition_uint16(const char *label, const char *tlv_nam
uint16_t new, uint16_t old)
{
if (PIM_OPTION_IS_SET(options, opt_mask)) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
label, tlv_name,
@@ -208,7 +308,7 @@ static void check_tlv_redefinition_uint32(const char *label, const char *tlv_nam
uint32_t new, uint32_t old)
{
if (PIM_OPTION_IS_SET(options, opt_mask)) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
label, tlv_name,
@@ -224,7 +324,7 @@ static void check_tlv_redefinition_uint32_hex(const char *label, const char *tlv
uint32_t new, uint32_t old)
{
if (PIM_OPTION_IS_SET(options, opt_mask)) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s",
label, tlv_name,
@@ -408,7 +508,7 @@ pim_parse_addr_ucast (struct prefix *p,
}
int
-pim_parse_addr_group (struct prefix *p,
+pim_parse_addr_group (struct prefix_sg *sg,
const uint8_t *buf,
int buf_size)
{
@@ -450,17 +550,15 @@ pim_parse_addr_group (struct prefix *p,
return -3;
}
- p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
- memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
- p->prefixlen = mask_len;
+ memcpy(&sg->grp.s_addr, addr, sizeof(struct in_addr));
addr += sizeof(struct in_addr);
break;
default:
{
- zlog_warn("%s: unknown group address encoding family=%d from",
- __PRETTY_FUNCTION__, family);
+ zlog_warn("%s: unknown group address encoding family=%d mask_len=%d from",
+ __PRETTY_FUNCTION__, family, mask_len);
return -4;
}
}
@@ -469,7 +567,7 @@ pim_parse_addr_group (struct prefix *p,
}
int
-pim_parse_addr_source(struct prefix *p,
+pim_parse_addr_source(struct prefix_sg *sg,
uint8_t *flags,
const uint8_t *buf,
int buf_size)
@@ -513,9 +611,7 @@ pim_parse_addr_source(struct prefix *p,
return -3;
}
- p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
- memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
- p->prefixlen = mask_len;
+ memcpy(&sg->src, addr, sizeof(struct in_addr));
/*
RFC 4601: 4.9.1 Encoded Source and Group Address Formats
@@ -527,9 +623,9 @@ pim_parse_addr_source(struct prefix *p,
and 128 for IPv6 native). A router SHOULD ignore any messages
received with any other mask length.
*/
- if (p->prefixlen != 32) {
+ if (mask_len != 32) {
zlog_warn("%s: IPv4 bad source address mask: %d",
- __PRETTY_FUNCTION__, p->prefixlen);
+ __PRETTY_FUNCTION__, mask_len);
return -4;
}
@@ -582,7 +678,7 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
*/
addr_offset = pim_parse_addr_ucast(&tmp, addr, pastend - addr);
if (addr_offset < 1) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
__PRETTY_FUNCTION__,
@@ -599,8 +695,8 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
switch (tmp.family) {
case AF_INET:
{
- char addr_str[100];
- char src_str[100];
+ char addr_str[INET_ADDRSTRLEN];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", tmp.u.prefix4, addr_str, sizeof(addr_str));
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s",
@@ -612,7 +708,7 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
break;
default:
{
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s",
__PRETTY_FUNCTION__,
@@ -629,7 +725,7 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
*/
if (tmp.family == AF_INET) {
if (tmp.u.prefix4.s_addr == src_addr.s_addr) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
zlog_warn("%s: ignoring primary address in secondary list from %s on %s",
__PRETTY_FUNCTION__,
diff --git a/pimd/pim_tlv.h b/pimd/pim_tlv.h
index 16c5aa4b97..9c4ebc9f0f 100644
--- a/pimd/pim_tlv.h
+++ b/pimd/pim_tlv.h
@@ -109,13 +109,16 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
uint16_t option_len,
const uint8_t *tlv_curr);
+int pim_encode_addr_ucast (uint8_t *buf, struct prefix *p);
+int pim_encode_addr_group (uint8_t *buf, afi_t afi, int bidir, int scope, struct in_addr group);
+
int pim_parse_addr_ucast (struct prefix *p,
const uint8_t *buf,
int buf_size);
-int pim_parse_addr_group (struct prefix *p,
+int pim_parse_addr_group (struct prefix_sg *sg,
const uint8_t *buf,
int buf_size);
-int pim_parse_addr_source(struct prefix *p,
+int pim_parse_addr_source(struct prefix_sg *sg,
uint8_t *flags,
const uint8_t *buf,
int buf_size);
diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c
index 059de3b62e..fbb7d84a25 100644
--- a/pimd/pim_upstream.c
+++ b/pimd/pim_upstream.c
@@ -27,6 +27,11 @@
#include "memory.h"
#include "thread.h"
#include "linklist.h"
+#include "vty.h"
+#include "plist.h"
+#include "hash.h"
+#include "jhash.h"
+#include "wheel.h"
#include "pimd.h"
#include "pim_pim.h"
@@ -44,10 +49,95 @@
#include "pim_macro.h"
#include "pim_rp.h"
#include "pim_br.h"
+#include "pim_register.h"
+#include "pim_msdp.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_start(struct pim_upstream *up);
static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up);
+/*
+ * A (*,G) or a (*,*) is going away
+ * remove the parent pointer from
+ * those pointing at us
+ */
+static void
+pim_upstream_remove_children (struct pim_upstream *up)
+{
+ struct pim_upstream *child;
+
+ if (!up->sources)
+ return;
+
+ while (!list_isempty (up->sources))
+ {
+ child = listnode_head (up->sources);
+ child->parent = NULL;
+ listnode_delete (up->sources, child);
+ }
+}
+
+/*
+ * A (*,G) or a (*,*) is being created
+ * Find the children that would point
+ * at us.
+ */
+static void
+pim_upstream_find_new_children (struct pim_upstream *up)
+{
+ struct pim_upstream *child;
+ struct listnode *ch_node;
+
+ if ((up->sg.src.s_addr != INADDR_ANY) &&
+ (up->sg.grp.s_addr != INADDR_ANY))
+ return;
+
+ if ((up->sg.src.s_addr == INADDR_ANY) &&
+ (up->sg.grp.s_addr == INADDR_ANY))
+ return;
+
+ 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))
+ {
+ child->parent = up;
+ listnode_add_sort (up->sources, child);
+ }
+ }
+}
+
+/*
+ * If we have a (*,*) || (S,*) there is no parent
+ * 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)
+{
+ struct prefix_sg any = child->sg;
+ struct pim_upstream *up = NULL;
+
+ // (S,G)
+ 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);
+
+ if (up)
+ listnode_add (up->sources, child);
+
+ return up;
+ }
+
+ return NULL;
+}
+
void pim_upstream_free(struct pim_upstream *up)
{
XFREE(MTYPE_PIM_UPSTREAM, up);
@@ -61,48 +151,89 @@ static void upstream_channel_oil_detach(struct pim_upstream *up)
}
}
-void pim_upstream_delete(struct pim_upstream *up)
+void
+pim_upstream_del(struct pim_upstream *up, const char *name)
{
+ bool notify_msdp = false;
+
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s(%s): Delete %s ref count: %d",
+ __PRETTY_FUNCTION__, name, up->sg_str, up->ref_count);
+
+ --up->ref_count;
+
+ if (up->ref_count >= 1)
+ return;
+
THREAD_OFF(up->t_join_timer);
THREAD_OFF(up->t_ka_timer);
+ THREAD_OFF(up->t_rs_timer);
+ THREAD_OFF(up->t_msdp_reg_timer);
+
+ if (up->join_state == PIM_UPSTREAM_JOINED) {
+ pim_joinprune_send (up->rpf.source_nexthop.interface,
+ up->rpf.rpf_addr.u.prefix4,
+ up, 0);
+ if (up->sg.src.s_addr == INADDR_ANY) {
+ /* if a (*, G) entry in the joined state is being deleted we
+ * need to notify MSDP */
+ notify_msdp = true;
+ }
+ }
+
+ if (up->sg.src.s_addr != INADDR_ANY) {
+ wheel_remove_item (pim_upstream_sg_wheel, up);
+ notify_msdp = true;
+ }
+ pim_upstream_remove_children (up);
+ pim_mroute_del (up->channel_oil, __PRETTY_FUNCTION__);
upstream_channel_oil_detach(up);
+ if (up->sources)
+ list_delete (up->sources);
+ up->sources = NULL;
+
/*
notice that listnode_delete() can't be moved
into pim_upstream_free() because the later is
called by list_delete_all_node()
*/
- listnode_delete(qpim_upstream_list, up);
+ if (up->parent)
+ {
+ listnode_delete (up->parent->sources, up);
+ up->parent = NULL;
+ }
+ listnode_delete (pim_upstream_list, up);
+ hash_release (pim_upstream_hash, up);
+ if (notify_msdp) {
+ pim_msdp_up_del(&up->sg);
+ }
pim_upstream_free(up);
}
-static void send_join(struct pim_upstream *up)
+void
+pim_upstream_send_join (struct pim_upstream *up)
{
- zassert(up->join_state == PIM_UPSTREAM_JOINED);
-
-
- if (PIM_DEBUG_PIM_TRACE) {
- if (PIM_INADDR_IS_ANY(up->rpf.rpf_addr)) {
- char src_str[100];
- char grp_str[100];
- char rpf_str[100];
- pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
- pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_str, sizeof(rpf_str));
- zlog_warn("%s: can't send join upstream: RPF'(%s,%s)=%s",
- __PRETTY_FUNCTION__,
- src_str, grp_str, rpf_str);
+ if (PIM_DEBUG_TRACE) {
+ char rpf_str[PREFIX_STRLEN];
+ pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str, sizeof(rpf_str));
+ zlog_debug ("%s: RPF'%s=%s(%s) for Interface %s", __PRETTY_FUNCTION__,
+ up->sg_str, rpf_str, pim_upstream_state2str (up->join_state),
+ up->rpf.source_nexthop.interface->name);
+ if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
+ zlog_debug("%s: can't send join upstream: RPF'%s=%s",
+ __PRETTY_FUNCTION__,
+ up->sg_str, rpf_str);
/* warning only */
}
}
-
+
/* send Join(S,G) to the current upstream neighbor */
pim_joinprune_send(up->rpf.source_nexthop.interface,
- up->rpf.rpf_addr,
- up->source_addr,
- up->group_addr,
+ up->rpf.rpf_addr.u.prefix4,
+ up,
1 /* join */);
}
@@ -110,13 +241,23 @@ static int on_join_timer(struct thread *t)
{
struct pim_upstream *up;
- zassert(t);
up = THREAD_ARG(t);
- zassert(up);
-
- send_join(up);
up->t_join_timer = NULL;
+
+ /*
+ * In the case of a HFR we will not ahve anyone to send this to.
+ */
+ if (PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
+ return 0;
+
+ /*
+ * Don't send the join if the outgoing interface is a loopback
+ * But since this might change leave the join timer running
+ */
+ if (!if_is_loopback (up->rpf.source_nexthop.interface))
+ pim_upstream_send_join (up);
+
join_timer_start(up);
return 0;
@@ -125,18 +266,13 @@ static int on_join_timer(struct thread *t)
static void join_timer_start(struct pim_upstream *up)
{
if (PIM_DEBUG_PIM_EVENTS) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
- zlog_debug("%s: starting %d sec timer for upstream (S,G)=(%s,%s)",
+ zlog_debug("%s: starting %d sec timer for upstream (S,G)=%s",
__PRETTY_FUNCTION__,
qpim_t_periodic,
- src_str, grp_str);
+ up->sg_str);
}
- zassert(!up->t_join_timer);
-
+ THREAD_OFF (up->t_join_timer);
THREAD_TIMER_ON(master, up->t_join_timer,
on_join_timer,
up, qpim_t_periodic);
@@ -152,14 +288,10 @@ static void pim_upstream_join_timer_restart_msec(struct pim_upstream *up,
int interval_msec)
{
if (PIM_DEBUG_PIM_EVENTS) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
- zlog_debug("%s: restarting %d msec timer for upstream (S,G)=(%s,%s)",
+ zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
__PRETTY_FUNCTION__,
interval_msec,
- src_str, grp_str);
+ up->sg_str);
}
THREAD_OFF(up->t_join_timer);
@@ -180,29 +312,21 @@ void pim_upstream_join_suppress(struct pim_upstream *up,
join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
- if (PIM_DEBUG_PIM_TRACE) {
- char src_str[100];
- char grp_str[100];
- char rpf_str[100];
- pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
+ if (PIM_DEBUG_TRACE) {
+ char rpf_str[INET_ADDRSTRLEN];
pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
- zlog_debug("%s %s: detected Join(%s,%s) to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
+ zlog_debug("%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
__FILE__, __PRETTY_FUNCTION__,
- src_str, grp_str,
+ up->sg_str,
rpf_str,
join_timer_remain_msec, t_joinsuppress_msec);
}
if (join_timer_remain_msec < t_joinsuppress_msec) {
- if (PIM_DEBUG_PIM_TRACE) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
- zlog_debug("%s %s: suppressing Join(S,G)=(%s,%s) for %ld msec",
+ if (PIM_DEBUG_TRACE) {
+ zlog_debug("%s %s: suppressing Join(S,G)=%s for %ld msec",
__FILE__, __PRETTY_FUNCTION__,
- src_str, grp_str, t_joinsuppress_msec);
+ up->sg_str, t_joinsuppress_msec);
}
pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec);
@@ -219,28 +343,20 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
t_override_msec = pim_if_t_override_msec(up->rpf.source_nexthop.interface);
- if (PIM_DEBUG_PIM_TRACE) {
- char src_str[100];
- char grp_str[100];
- char rpf_str[100];
- pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
+ if (PIM_DEBUG_TRACE) {
+ char rpf_str[INET_ADDRSTRLEN];
pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
- zlog_debug("%s: to RPF'(%s,%s)=%s: join_timer=%ld msec t_override=%d msec",
+ zlog_debug("%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
debug_label,
- src_str, grp_str, rpf_str,
+ up->sg_str, rpf_str,
join_timer_remain_msec, t_override_msec);
}
if (join_timer_remain_msec > t_override_msec) {
- if (PIM_DEBUG_PIM_TRACE) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
- zlog_debug("%s: decreasing (S,G)=(%s,%s) join timer to t_override=%d msec",
+ if (PIM_DEBUG_TRACE) {
+ zlog_debug("%s: decreasing (S,G)=%s join timer to t_override=%d msec",
debug_label,
- src_str, grp_str,
+ up->sg_str,
t_override_msec);
}
@@ -250,196 +366,327 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
static void forward_on(struct pim_upstream *up)
{
- struct listnode *ifnode;
- struct listnode *ifnextnode;
struct listnode *chnode;
struct listnode *chnextnode;
- struct interface *ifp;
struct pim_interface *pim_ifp;
struct pim_ifchannel *ch;
- /* scan all interfaces */
- for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
- pim_ifp = ifp->info;
+ /* scan (S,G) state */
+ for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
+ pim_ifp = ch->interface->info;
if (!pim_ifp)
continue;
- /* scan per-interface (S,G) state */
- for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
-
- if (ch->upstream != up)
- continue;
+ if (ch->upstream != up)
+ continue;
- if (pim_macro_chisin_oiflist(ch))
- pim_forward_start(ch);
+ if (pim_macro_chisin_oiflist(ch))
+ pim_forward_start(ch);
- } /* scan iface channel list */
- } /* scan iflist */
+ } /* scan iface channel list */
}
static void forward_off(struct pim_upstream *up)
{
- struct listnode *ifnode;
- struct listnode *ifnextnode;
struct listnode *chnode;
struct listnode *chnextnode;
- struct interface *ifp;
struct pim_interface *pim_ifp;
struct pim_ifchannel *ch;
- /* scan all interfaces */
- for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
- pim_ifp = ifp->info;
+ /* scan per-interface (S,G) state */
+ for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
+ pim_ifp = ch->interface->info;
if (!pim_ifp)
continue;
- /* scan per-interface (S,G) state */
- for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
+ if (ch->upstream != up)
+ continue;
- if (ch->upstream != up)
- continue;
+ pim_forward_stop(ch);
- pim_forward_stop(ch);
+ } /* scan iface channel list */
+}
- } /* scan iface channel list */
- } /* scan iflist */
+static int
+pim_upstream_could_register (struct pim_upstream *up)
+{
+ struct pim_interface *pim_ifp = up->rpf.source_nexthop.interface->info;
+
+ if (pim_ifp && PIM_I_am_DR (pim_ifp) &&
+ pim_if_connected_to_source (up->rpf.source_nexthop.interface, up->sg.src))
+ return 1;
+
+ return 0;
}
-static void pim_upstream_switch(struct pim_upstream *up,
- enum pim_upstream_state new_state)
+void
+pim_upstream_switch(struct pim_upstream *up,
+ enum pim_upstream_state new_state)
{
enum pim_upstream_state old_state = up->join_state;
- zassert(old_state != new_state);
-
- up->join_state = new_state;
- up->state_transition = pim_time_monotonic_sec();
-
if (PIM_DEBUG_PIM_EVENTS) {
- char src_str[100];
- char grp_str[100];
- pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
- zlog_debug("%s: PIM_UPSTREAM_%s: (S,G)=(%s,%s)",
+ zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
__PRETTY_FUNCTION__,
- ((new_state == PIM_UPSTREAM_JOINED) ? "JOINED" : "NOTJOINED"),
- src_str, grp_str);
+ up->sg_str,
+ pim_upstream_state2str (up->join_state),
+ pim_upstream_state2str (new_state));
}
+ /*
+ * This code still needs work.
+ */
+ switch (up->join_state)
+ {
+ case PIM_UPSTREAM_PRUNE:
+ if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
+ {
+ up->join_state = new_state;
+ up->state_transition = pim_time_monotonic_sec ();
+ }
+ break;
+ case PIM_UPSTREAM_JOIN_PENDING:
+ break;
+ case PIM_UPSTREAM_NOTJOINED:
+ case PIM_UPSTREAM_JOINED:
+ up->join_state = new_state;
+ if (old_state != new_state)
+ up->state_transition = pim_time_monotonic_sec();
+
+ break;
+ }
+
pim_upstream_update_assert_tracking_desired(up);
if (new_state == PIM_UPSTREAM_JOINED) {
- forward_on(up);
- send_join(up);
- join_timer_start(up);
+ if (old_state != PIM_UPSTREAM_JOINED)
+ {
+ int old_fhr = PIM_UPSTREAM_FLAG_TEST_FHR(up->flags);
+ forward_on(up);
+ pim_msdp_up_join_state_changed(up);
+ 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);
+ pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
+ }
+ }
+ else
+ {
+ pim_upstream_send_join (up);
+ join_timer_start (up);
+ }
+ }
+ else
+ {
+ forward_on (up);
+ }
}
else {
forward_off(up);
+ if (old_state == PIM_UPSTREAM_JOINED)
+ pim_msdp_up_join_state_changed(up);
pim_joinprune_send(up->rpf.source_nexthop.interface,
- up->rpf.rpf_addr,
- up->source_addr,
- up->group_addr,
+ up->rpf.rpf_addr.u.prefix4,
+ up,
0 /* prune */);
- zassert(up->t_join_timer);
- THREAD_OFF(up->t_join_timer);
+ if (up->t_join_timer)
+ THREAD_OFF(up->t_join_timer);
}
-
}
+static int
+pim_upstream_compare (void *arg1, void *arg2)
+{
+ const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
+ const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
+
+ if (ntohl(up1->sg.grp.s_addr) < ntohl(up2->sg.grp.s_addr))
+ return -1;
+
+ if (ntohl(up1->sg.grp.s_addr) > ntohl(up2->sg.grp.s_addr))
+ return 1;
+
+ if (ntohl(up1->sg.src.s_addr) < ntohl(up2->sg.src.s_addr))
+ return -1;
+
+ if (ntohl(up1->sg.src.s_addr) > ntohl(up2->sg.src.s_addr))
+ return 1;
-static struct pim_upstream *pim_upstream_new(struct in_addr source_addr,
- struct in_addr group_addr,
- struct interface *incoming)
+ return 0;
+}
+
+static struct pim_upstream *
+pim_upstream_new (struct prefix_sg *sg,
+ struct interface *incoming,
+ int flags)
{
- struct pim_upstream *up;
enum pim_rpf_result rpf_result;
+ struct pim_interface *pim_ifp;
+ struct pim_upstream *up;
- up = XMALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
+ up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
if (!up) {
- zlog_err("%s: PIM XMALLOC(%zu) failure",
+ zlog_err("%s: PIM XCALLOC(%zu) failure",
__PRETTY_FUNCTION__, sizeof(*up));
return NULL;
}
- up->source_addr = source_addr;
- if (!pim_rp_set_upstream_addr (&up->upstream_addr, source_addr))
+ 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 (PIM_DEBUG_PIM_TRACE)
+ if (PIM_DEBUG_TRACE)
zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__);
+ hash_release (pim_upstream_hash, up);
XFREE (MTYPE_PIM_UPSTREAM, up);
return NULL;
}
- up->group_addr = group_addr;
- up->flags = 0;
+ up->parent = pim_upstream_find_parent (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);
+ up->flags = flags;
up->ref_count = 1;
up->t_join_timer = NULL;
up->t_ka_timer = NULL;
+ up->t_rs_timer = NULL;
+ up->t_msdp_reg_timer = NULL;
up->join_state = 0;
up->state_transition = pim_time_monotonic_sec();
up->channel_oil = NULL;
up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
- up->rpf.source_nexthop.interface = 0;
- up->rpf.source_nexthop.mrib_nexthop_addr.s_addr = PIM_NET_INADDR_ANY;
+ up->rpf.source_nexthop.interface = NULL;
+ up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET;
+ up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
up->rpf.source_nexthop.mrib_metric_preference = qpim_infinite_assert_metric.metric_preference;
up->rpf.source_nexthop.mrib_route_metric = qpim_infinite_assert_metric.route_metric;
- up->rpf.rpf_addr.s_addr = PIM_NET_INADDR_ANY;
+ up->rpf.rpf_addr.family = AF_INET;
+ up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
+
+ if (up->sg.src.s_addr != INADDR_ANY)
+ wheel_add_item (pim_upstream_sg_wheel, up);
- rpf_result = pim_rpf_update(up, 0, incoming);
+ rpf_result = pim_rpf_update(up, NULL);
if (rpf_result == PIM_RPF_FAILURE) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: Attempting to create upstream(%s), Unable to RPF for source", __PRETTY_FUNCTION__,
+ up->sg_str);
+
+ if (up->parent)
+ {
+ listnode_delete (up->parent->sources, up);
+ up->parent = NULL;
+ }
+
+ if (up->sg.src.s_addr != INADDR_ANY)
+ wheel_remove_item (pim_upstream_sg_wheel, up);
+
+ pim_upstream_remove_children (up);
+ if (up->sources)
+ list_delete (up->sources);
+
+ hash_release (pim_upstream_hash, up);
XFREE(MTYPE_PIM_UPSTREAM, up);
return NULL;
}
- listnode_add(qpim_upstream_list, up);
+ 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);
+
+ listnode_add_sort(pim_upstream_list, up);
+
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: Created Upstream %s", __PRETTY_FUNCTION__, up->sg_str);
return up;
}
-struct pim_upstream *pim_upstream_find(struct in_addr source_addr,
- struct in_addr group_addr)
+struct pim_upstream *pim_upstream_find(struct prefix_sg *sg)
{
- struct listnode *up_node;
- struct pim_upstream *up;
-
- for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, up_node, up)) {
- if (group_addr.s_addr == up->group_addr.s_addr) {
- if ((up->source_addr.s_addr == INADDR_ANY) ||
- (source_addr.s_addr == up->source_addr.s_addr)) {
- return up;
- }
- }
- }
+ struct pim_upstream lookup;
+ struct pim_upstream *up = NULL;
- return 0;
+ lookup.sg = *sg;
+ up = hash_lookup (pim_upstream_hash, &lookup);
+ return up;
}
-struct pim_upstream *pim_upstream_add(struct in_addr source_addr,
- struct in_addr group_addr,
- struct interface *incoming)
+static void pim_upstream_ref(struct pim_upstream *up, int flags)
{
- struct pim_upstream *up;
+ up->flags |= flags;
+ ++up->ref_count;
+}
- up = pim_upstream_find(source_addr, group_addr);
+struct pim_upstream *pim_upstream_add(struct prefix_sg *sg,
+ struct interface *incoming,
+ int flags, const char *name)
+{
+ struct pim_upstream *up = NULL;
+ int found = 0;
+ up = pim_upstream_find(sg);
if (up) {
- ++up->ref_count;
+ pim_upstream_ref(up, flags);
+ found = 1;
}
else {
- up = pim_upstream_new(source_addr, group_addr, incoming);
+ up = pim_upstream_new(sg, incoming, flags);
}
+ if (PIM_DEBUG_TRACE)
+ {
+ if (up)
+ zlog_debug("%s(%s): %s, found: %d: ref_count: %d",
+ __PRETTY_FUNCTION__, name,
+ up->sg_str, found,
+ up->ref_count);
+ else
+ zlog_debug("%s(%s): (%s) failure to create",
+ __PRETTY_FUNCTION__, name,
+ pim_str_sg_dump (sg));
+ }
+
return up;
}
-void pim_upstream_del(struct pim_upstream *up)
+static int
+pim_upstream_evaluate_join_desired_interface (struct pim_upstream *up,
+ struct pim_ifchannel *ch)
{
- --up->ref_count;
+ struct pim_upstream *parent = up->parent;
- if (up->ref_count < 1) {
- pim_upstream_delete(up);
- }
+ if (ch->upstream == up)
+ {
+ if (!pim_macro_ch_lost_assert(ch) && pim_macro_chisin_joins_or_include(ch))
+ return 1;
+
+ if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
+ return 0;
+ }
+
+ /*
+ * joins (*,G)
+ */
+ if (parent && ch->upstream == parent)
+ {
+ if (!pim_macro_ch_lost_assert (ch) && pim_macro_chisin_joins_or_include (ch))
+ return 1;
+ }
+
+ return 0;
}
/*
@@ -467,34 +714,23 @@ void pim_upstream_del(struct pim_upstream *up)
*/
int pim_upstream_evaluate_join_desired(struct pim_upstream *up)
{
- struct listnode *ifnode;
- struct listnode *ifnextnode;
struct listnode *chnode;
struct listnode *chnextnode;
- struct interface *ifp;
struct pim_interface *pim_ifp;
struct pim_ifchannel *ch;
+ int ret = 0;
- /* scan all interfaces */
- for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
- pim_ifp = ifp->info;
- if (!pim_ifp)
- continue;
-
- /* scan per-interface (S,G) state */
- for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
- if (ch->upstream != up)
+ /* scan per-interface (S,G) state */
+ for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch))
+ {
+ pim_ifp = ch->interface->info;
+ if (!pim_ifp)
continue;
- if (pim_macro_ch_lost_assert(ch))
- continue; /* keep searching */
-
- if (pim_macro_chisin_joins_or_include(ch))
- return 1; /* true */
+ ret += pim_upstream_evaluate_join_desired_interface (up, ch);
} /* scan iface channel list */
- } /* scan iflist */
- return 0; /* false */
+ return ret; /* false */
}
/*
@@ -515,14 +751,12 @@ void pim_upstream_update_join_desired(struct pim_upstream *up)
/* switched from false to true */
if (is_join_desired && !was_join_desired) {
- zassert(up->join_state == PIM_UPSTREAM_NOTJOINED);
pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
return;
}
/* switched from true to false */
if (!is_join_desired && was_join_desired) {
- zassert(up->join_state == PIM_UPSTREAM_JOINED);
pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED);
return;
}
@@ -544,22 +778,18 @@ void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr)
struct pim_upstream *up;
/*
- Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
- */
- for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) {
+ * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
+ */
+ for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
- if (PIM_DEBUG_PIM_TRACE) {
- char neigh_str[100];
- char src_str[100];
- char grp_str[100];
- char rpf_addr_str[100];
+ if (PIM_DEBUG_TRACE) {
+ char neigh_str[INET_ADDRSTRLEN];
+ char rpf_addr_str[PREFIX_STRLEN];
pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str));
- pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str));
- pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str));
- pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_addr_str, sizeof(rpf_addr_str));
- zlog_debug("%s: matching neigh=%s against upstream (S,G)=(%s,%s) joined=%d rpf_addr=%s",
+ pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_addr_str, sizeof(rpf_addr_str));
+ zlog_debug("%s: matching neigh=%s against upstream (S,G)=%s joined=%d rpf_addr=%s",
__PRETTY_FUNCTION__,
- neigh_str, src_str, grp_str,
+ neigh_str, up->sg_str,
up->join_state == PIM_UPSTREAM_JOINED,
rpf_addr_str);
}
@@ -569,7 +799,7 @@ void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr)
continue;
/* match RPF'(S,G)=neigh_addr */
- if (up->rpf.rpf_addr.s_addr != neigh_addr.s_addr)
+ if (up->rpf.rpf_addr.u.prefix4.s_addr != neigh_addr.s_addr)
continue;
pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change",
@@ -581,130 +811,141 @@ void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr)
void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
struct interface *old_rpf_ifp)
{
- struct listnode *ifnode;
- struct listnode *ifnextnode;
- struct interface *ifp;
+ struct listnode *chnode;
+ struct listnode *chnextnode;
+ struct pim_ifchannel *ch;
+ struct pim_interface *pim_ifp;
- /* scan all interfaces */
- for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
- struct listnode *chnode;
- struct listnode *chnextnode;
- struct pim_ifchannel *ch;
- struct pim_interface *pim_ifp;
+ /* search all ifchannels */
+ for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
- pim_ifp = ifp->info;
+ pim_ifp = ch->interface->info;
if (!pim_ifp)
continue;
- /* search all ifchannels */
- for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
- if (ch->upstream != up)
- continue;
+ if (ch->upstream != up)
+ continue;
- if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
- if (
- /* RPF_interface(S) was NOT I */
- (old_rpf_ifp == ch->interface)
- &&
- /* RPF_interface(S) stopped being I */
- (ch->upstream->rpf.source_nexthop.interface != ch->interface)
- ) {
- assert_action_a5(ch);
- }
- } /* PIM_IFASSERT_I_AM_LOSER */
+ if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
+ if (
+ /* RPF_interface(S) was NOT I */
+ (old_rpf_ifp == ch->interface)
+ &&
+ /* RPF_interface(S) stopped being I */
+ (ch->upstream->rpf.source_nexthop.interface != ch->interface)
+ ) {
+ assert_action_a5(ch);
+ }
+ } /* PIM_IFASSERT_I_AM_LOSER */
- pim_ifchannel_update_assert_tracking_desired(ch);
- }
+ pim_ifchannel_update_assert_tracking_desired(ch);
}
}
void pim_upstream_update_could_assert(struct pim_upstream *up)
{
- struct listnode *ifnode;
- struct listnode *ifnextnode;
struct listnode *chnode;
struct listnode *chnextnode;
- struct interface *ifp;
struct pim_interface *pim_ifp;
struct pim_ifchannel *ch;
- /* scan all interfaces */
- for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
- pim_ifp = ifp->info;
+ /* scan per-interface (S,G) state */
+ for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
+ pim_ifp = ch->interface->info;
if (!pim_ifp)
continue;
- /* scan per-interface (S,G) state */
- for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
-
- if (ch->upstream != up)
- continue;
-
- pim_ifchannel_update_could_assert(ch);
+ if (ch->upstream != up)
+ continue;
- } /* scan iface channel list */
- } /* scan iflist */
+ pim_ifchannel_update_could_assert(ch);
+ } /* scan iface channel list */
}
void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
{
- struct listnode *ifnode;
- struct listnode *ifnextnode;
struct listnode *chnode;
struct listnode *chnextnode;
- struct interface *ifp;
struct pim_interface *pim_ifp;
struct pim_ifchannel *ch;
- /* scan all interfaces */
- for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
- pim_ifp = ifp->info;
+ /* scan per-interface (S,G) state */
+ for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
+ pim_ifp = ch->interface->info;
if (!pim_ifp)
continue;
- /* scan per-interface (S,G) state */
- for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
-
- if (ch->upstream != up)
- continue;
+ if (ch->upstream != up)
+ continue;
- pim_ifchannel_update_my_assert_metric(ch);
+ pim_ifchannel_update_my_assert_metric(ch);
- } /* scan iface channel list */
- } /* scan iflist */
+ } /* scan iface channel list */
}
static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
{
- struct listnode *ifnode;
- struct listnode *ifnextnode;
struct listnode *chnode;
struct listnode *chnextnode;
- struct interface *ifp;
struct pim_interface *pim_ifp;
struct pim_ifchannel *ch;
- /* scan all interfaces */
- for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
- pim_ifp = ifp->info;
+ /* scan per-interface (S,G) state */
+ for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
+ pim_ifp = ch->interface->info;
if (!pim_ifp)
continue;
- /* scan per-interface (S,G) state */
- for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
+ if (ch->upstream != up)
+ continue;
- if (ch->upstream != up)
- continue;
+ pim_ifchannel_update_assert_tracking_desired(ch);
- pim_ifchannel_update_assert_tracking_desired(ch);
+ } /* scan iface channel list */
+}
- } /* scan iface channel list */
- } /* scan iflist */
+/* 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)
+{
+ if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
+ return;
+
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("kat expired on %s; clear fhr reg state", up->sg_str);
+
+ /* 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_OIF_FLAG_PROTO_PIM);
+ /* move to "not-joined" */
+ up->join_state = PIM_UPSTREAM_NOTJOINED;
+ PIM_UPSTREAM_FLAG_UNSET_FHR(up->flags);
+}
+
+/* When kat is started CouldRegister can go to true. And if it does we
+ * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
+ * to the OIL */
+static void pim_upstream_fhr_kat_start(struct pim_upstream *up)
+{
+ if (pim_upstream_could_register(up)) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("kat started on %s; set fhr reg state to joined", up->sg_str);
+
+ PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
+ if (up->join_state == PIM_UPSTREAM_NOTJOINED) {
+ pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
+ up->join_state = PIM_UPSTREAM_JOINED;
+ }
+ }
}
/*
* On an RP, the PMBR value must be cleared when the
* Keepalive Timer expires
+ * KAT expiry indicates that flow is inactive. If the flow was created or
+ * maintained by activity now is the time to deref it.
*/
static int
pim_upstream_keep_alive_timer (struct thread *t)
@@ -712,41 +953,73 @@ pim_upstream_keep_alive_timer (struct thread *t)
struct pim_upstream *up;
up = THREAD_ARG(t);
+ up->t_ka_timer = NULL;
+
+ if (I_am_RP (up->sg.grp))
+ {
+ pim_br_clear_pmbr (&up->sg);
+ /*
+ * We need to do more here :)
+ * But this is the start.
+ */
+ }
- if (I_am_RP (up->group_addr))
- {
- pim_br_clear_pmbr (up->source_addr, up->group_addr);
- /*
- * We need to do more here :)
- * But this is the start.
- */
- }
- else
- {
- pim_mroute_update_counters (up->channel_oil);
+ /* source is no longer active - pull the SA from MSDP's cache */
+ pim_msdp_sa_local_del(&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);
+ 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__);
+ }
- if (up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt)
- {
- pim_mroute_del (up->channel_oil);
- pim_upstream_delete (up);
- }
- else
- {
- up->t_ka_timer = NULL;
- pim_upstream_keep_alive_timer_start (up, PIM_KEEPALIVE_PERIOD);
- }
- }
- return 1;
+ return 0;
}
void
pim_upstream_keep_alive_timer_start (struct pim_upstream *up,
uint32_t time)
{
+ if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("kat start on %s with no stream reference", up->sg_str);
+ }
+ THREAD_OFF (up->t_ka_timer);
THREAD_TIMER_ON (master,
up->t_ka_timer,
pim_upstream_keep_alive_timer,
up, time);
+
+ /* any time keepalive is started against a SG we will have to
+ * re-evaluate our active source database */
+ pim_msdp_sa_local_update(up);
+}
+
+/* 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);
+ up->t_msdp_reg_timer = NULL;
+
+ /* source is no longer active - pull the SA from MSDP's cache */
+ pim_msdp_sa_local_del(&up->sg);
+ return 1;
+}
+void
+pim_upstream_msdp_reg_timer_start(struct pim_upstream *up)
+{
+ THREAD_OFF(up->t_msdp_reg_timer);
+ THREAD_TIMER_ON(master, up->t_msdp_reg_timer,
+ pim_upstream_msdp_reg_timer, up, PIM_MSDP_REG_RXED_PERIOD);
+
+ pim_msdp_sa_local_update(up);
}
/*
@@ -778,7 +1051,472 @@ pim_upstream_keep_alive_timer_start (struct pim_upstream *up,
* received for the source and group.
*/
int
-pim_upstream_switch_to_spt_desired (struct in_addr source, struct in_addr group)
+pim_upstream_switch_to_spt_desired (struct prefix_sg *sg)
+{
+ if (I_am_RP (sg->grp))
+ return 1;
+
+ return 0;
+}
+
+int
+pim_upstream_is_sg_rpt (struct pim_upstream *up)
+{
+ struct listnode *chnode;
+ struct pim_ifchannel *ch;
+
+ for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, chnode, ch))
+ {
+ if ((ch->upstream == up) &&
+ (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)))
+ return 1;
+ }
+
+ return 0;
+}
+/*
+ * After receiving a packet set SPTbit:
+ * void
+ * Update_SPTbit(S,G,iif) {
+ * if ( iif == RPF_interface(S)
+ * AND JoinDesired(S,G) == TRUE
+ * AND ( DirectlyConnected(S) == TRUE
+ * OR RPF_interface(S) != RPF_interface(RP(G))
+ * OR inherited_olist(S,G,rpt) == NULL
+ * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
+ * ( RPF'(S,G) != NULL ) )
+ * OR ( I_Am_Assert_Loser(S,G,iif) ) {
+ * Set SPTbit(S,G) to TRUE
+ * }
+ * }
+ */
+void
+pim_upstream_set_sptbit (struct pim_upstream *up, struct interface *incoming)
+{
+ struct pim_rpf *grpf = NULL;
+
+ // iif == RPF_interfvace(S)
+ if (up->rpf.source_nexthop.interface != incoming)
+ {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: Incoming Interface: %s is different than RPF_interface(S) %s",
+ __PRETTY_FUNCTION__, incoming->name, up->rpf.source_nexthop.interface->name);
+ return;
+ }
+
+ // AND JoinDesired(S,G) == TRUE
+ // FIXME
+
+ // DirectlyConnected(S) == TRUE
+ if (pim_if_connected_to_source (up->rpf.source_nexthop.interface, up->sg.src))
+ {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: %s is directly connected to the source", __PRETTY_FUNCTION__,
+ up->sg_str);
+ up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
+ return;
+ }
+
+ // OR RPF_interface(S) != RPF_interface(RP(G))
+ grpf = RP(up->sg.grp);
+ if (!grpf || up->rpf.source_nexthop.interface != grpf->source_nexthop.interface)
+ {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: %s RPF_interface(S) != RPF_interface(RP(G))",
+ __PRETTY_FUNCTION__, up->sg_str);
+ up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
+ return;
+ }
+
+ // OR inherited_olist(S,G,rpt) == NULL
+ if (pim_upstream_is_sg_rpt(up) && pim_upstream_empty_inherited_olist(up))
+ {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: %s OR inherited_olist(S,G,rpt) == NULL", __PRETTY_FUNCTION__,
+ up->sg_str);
+ up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
+ return;
+ }
+
+ // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
+ // ( RPF'(S,G) != NULL ) )
+ if (up->parent && pim_rpf_is_same (&up->rpf, &up->parent->rpf))
+ {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: %s RPF'(S,G) is the same as RPF'(*,G)", __PRETTY_FUNCTION__,
+ up->sg_str);
+ up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
+ return;
+ }
+
+ return;
+}
+
+const char *
+pim_upstream_state2str (enum pim_upstream_state join_state)
+{
+ switch (join_state)
+ {
+ case PIM_UPSTREAM_NOTJOINED:
+ return "NotJoined";
+ break;
+ case PIM_UPSTREAM_JOINED:
+ return "Joined";
+ break;
+ case PIM_UPSTREAM_JOIN_PENDING:
+ return "JoinPending";
+ break;
+ case PIM_UPSTREAM_PRUNE:
+ return "Prune";
+ break;
+ }
+ return "Unknown";
+}
+
+static int
+pim_upstream_register_stop_timer (struct thread *t)
+{
+ struct pim_interface *pim_ifp;
+ struct pim_upstream *up;
+ struct pim_rpf *rpg;
+ struct ip ip_hdr;
+ up = THREAD_ARG (t);
+
+ up->t_rs_timer = NULL;
+
+ if (PIM_DEBUG_TRACE)
+ {
+ zlog_debug ("%s: (S,G)=%s upstream register stop timer %s",
+ __PRETTY_FUNCTION__, up->sg_str,
+ pim_upstream_state2str(up->join_state));
+ }
+
+ switch (up->join_state)
+ {
+ case PIM_UPSTREAM_JOIN_PENDING:
+ up->join_state = PIM_UPSTREAM_JOINED;
+ pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
+ break;
+ case PIM_UPSTREAM_JOINED:
+ break;
+ case PIM_UPSTREAM_PRUNE:
+ pim_ifp = up->rpf.source_nexthop.interface->info;
+ if (!pim_ifp)
+ {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: Interface: %s is not configured for pim",
+ __PRETTY_FUNCTION__, up->rpf.source_nexthop.interface->name);
+ return 0;
+ }
+ up->join_state = PIM_UPSTREAM_JOIN_PENDING;
+ pim_upstream_start_register_stop_timer (up, 1);
+
+ if (((up->channel_oil->cc.lastused/100) > PIM_KEEPALIVE_PERIOD) &&
+ (I_am_RP (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);
+ memset (&ip_hdr, 0, sizeof (struct ip));
+ ip_hdr.ip_p = PIM_IP_PROTO_PIM;
+ ip_hdr.ip_hl = 5;
+ ip_hdr.ip_v = 4;
+ ip_hdr.ip_src = up->sg.src;
+ ip_hdr.ip_dst = up->sg.grp;
+ ip_hdr.ip_len = htons (20);
+ // checksum is broken
+ pim_register_send ((uint8_t *)&ip_hdr, sizeof (struct ip),
+ pim_ifp->primary_address, rpg, 1, up);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+void
+pim_upstream_start_register_stop_timer (struct pim_upstream *up, int null_register)
+{
+ uint32_t time;
+
+ if (up->t_rs_timer)
+ {
+ THREAD_TIMER_OFF (up->t_rs_timer);
+ up->t_rs_timer = NULL;
+ }
+
+ if (!null_register)
+ {
+ uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
+ uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
+ time = lower + (random () % (upper - lower + 1)) - PIM_REGISTER_PROBE_PERIOD;
+ }
+ else
+ time = PIM_REGISTER_PROBE_PERIOD;
+
+ if (PIM_DEBUG_TRACE)
+ {
+ zlog_debug ("%s: (S,G)=%s Starting upstream register stop timer %d",
+ __PRETTY_FUNCTION__, up->sg_str, time);
+ }
+ THREAD_TIMER_ON (master, up->t_rs_timer,
+ pim_upstream_register_stop_timer,
+ up, time);
+}
+
+int
+pim_upstream_inherited_olist_decide (struct pim_upstream *up)
+{
+ struct pim_interface *pim_ifp;
+ struct listnode *chnextnode;
+ struct pim_ifchannel *ch;
+ struct listnode *chnode;
+ int output_intf = 0;
+
+ pim_ifp = up->rpf.source_nexthop.interface->info;
+ if (pim_ifp && !up->channel_oil)
+ up->channel_oil = pim_channel_oil_add (&up->sg, pim_ifp->mroute_vif_index);
+
+ for (ALL_LIST_ELEMENTS (pim_ifchannel_list, chnode, chnextnode, ch))
+ {
+ pim_ifp = ch->interface->info;
+ if (!pim_ifp)
+ continue;
+
+ if (pim_upstream_evaluate_join_desired_interface (up, ch))
+ {
+ pim_channel_add_oif (up->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_PIM);
+ output_intf++;
+ }
+ }
+
+ return output_intf;
+}
+
+/*
+ * For a given upstream, determine the inherited_olist
+ * and apply it.
+ *
+ * inherited_olist(S,G,rpt) =
+ * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
+ * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
+ * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
+ *
+ * inherited_olist(S,G) =
+ * inherited_olist(S,G,rpt) (+)
+ * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
+ *
+ * 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 output_intf = pim_upstream_inherited_olist_decide (up);
+
+ /*
+ * If we have output_intf switch state to Join and work like normal
+ * If we don't have an output_intf that means we are probably a
+ * switch on a stick so turn on forwarding to just accept the
+ * incoming packets so we don't bother the other stuff!
+ */
+ if (output_intf)
+ pim_upstream_switch (up, PIM_UPSTREAM_JOINED);
+ else
+ forward_on (up);
+
+ return output_intf;
+}
+
+int
+pim_upstream_empty_inherited_olist (struct pim_upstream *up)
+{
+ return pim_channel_oil_empty (up->channel_oil);
+}
+
+/*
+ * When we have a new neighbor,
+ * find upstreams that don't have their rpf_addr
+ * set and see if the new neighbor allows
+ * the join to be sent
+ */
+void
+pim_upstream_find_new_rpf (void)
+{
+ struct listnode *up_node;
+ struct listnode *up_nextnode;
+ struct pim_upstream *up;
+
+ /*
+ * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
+ */
+ 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);
+ }
+ }
+}
+
+static 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)
{
+ 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;
+}
+
+static 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;
+
+ if ((up1->sg.grp.s_addr == up2->sg.grp.s_addr) &&
+ (up1->sg.src.s_addr == up2->sg.src.s_addr))
+ return 1;
+
return 0;
}
+
+/* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
+ * the cases where kat has to be restarted on rxing traffic -
+ *
+ * if( DirectlyConnected(S) == TRUE AND iif == RPF_interface(S) ) {
+ * set KeepaliveTimer(S,G) to Keepalive_Period
+ * # Note: a register state transition or UpstreamJPState(S,G)
+ * # transition may happen as a result of restarting
+ * # KeepaliveTimer, and must be dealt with here.
+ * }
+ * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
+ * inherited_olist(S,G) != NULL ) {
+ * set KeepaliveTimer(S,G) to Keepalive_Period
+ * }
+ */
+static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
+{
+ /* "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,
+ up->sg.src)) {
+ return true;
+ }
+
+ if ((up->join_state == PIM_UPSTREAM_JOINED) &&
+ !pim_upstream_empty_inherited_olist(up)) {
+ /* XXX: I have added this RP check just for 3.2 and it's a digression from
+ * what rfc-4601 says. Till now we were only running KAT on FHR and RP and
+ * there is some angst around making the change to run it all routers that
+ * maintain the (S, G) state. This is tracked via CM-13601 and MUST be
+ * removed to handle spt turn-arounds correctly in a 3-tier clos */
+ if (I_am_RP (up->sg.grp))
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Code to check and see if we've received packets on a S,G mroute
+ * and if so to set the SPT bit appropriately
+ */
+static void
+pim_upstream_sg_running (void *arg)
+{
+ struct pim_upstream *up = (struct pim_upstream *)arg;
+
+ // No packet can have arrived here if this is the case
+ if (!up->channel_oil || !up->channel_oil->installed)
+ {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: %s is not installed in mroute",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return;
+ }
+
+ /*
+ * This is a bit of a hack
+ * We've noted that we should rescan but
+ * we've missed the window for doing so in
+ * pim_zebra.c for some reason. I am
+ * only doing this at this point in time
+ * to get us up and working for the moment
+ */
+ if (up->channel_oil->oil_inherited_rescan)
+ {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: Handling unscanned inherited_olist for %s", __PRETTY_FUNCTION__, up->sg_str);
+ pim_upstream_inherited_olist_decide (up);
+ up->channel_oil->oil_inherited_rescan = 0;
+ }
+ pim_mroute_update_counters (up->channel_oil);
+
+ // Have we seen packets?
+ if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt) &&
+ (up->channel_oil->cc.lastused/100 > 30))
+ {
+ if (PIM_DEBUG_TRACE)
+ {
+ zlog_debug ("%s: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
+ __PRETTY_FUNCTION__, up->sg_str,
+ up->channel_oil->cc.oldpktcnt,
+ up->channel_oil->cc.pktcnt,
+ up->channel_oil->cc.lastused/100);
+ }
+ return;
+ }
+
+ if (pim_upstream_kat_start_ok(up)) {
+ /* Add a source reference to the stream if
+ * one doesn't already exist */
+ if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
+ {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("source reference created on kat restart %s", up->sg_str);
+
+ pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM);
+ 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);
+ }
+
+ if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE)
+ {
+ pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
+ }
+ return;
+}
+
+void
+pim_upstream_init (void)
+{
+ 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);
+
+ pim_upstream_list = list_new ();
+ pim_upstream_list->del = (void (*)(void *)) pim_upstream_free;
+ pim_upstream_list->cmp = pim_upstream_compare;
+
+}
diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h
index f10c8feb3b..1a50c0c6e3 100644
--- a/pimd/pim_upstream.h
+++ b/pimd/pim_upstream.h
@@ -22,52 +22,47 @@
#define PIM_UPSTREAM_H
#include <zebra.h>
+#include <prefix.h>
+
+#include <pimd/pim_rpf.h>
#define PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED (1 << 0)
-#define PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED (2 << 0)
+#define PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED (1 << 1)
+#define PIM_UPSTREAM_FLAG_MASK_FHR (1 << 2)
+#define PIM_UPSTREAM_FLAG_MASK_SRC_IGMP (1 << 3)
+#define PIM_UPSTREAM_FLAG_MASK_SRC_PIM (1 << 4)
+#define PIM_UPSTREAM_FLAG_MASK_SRC_STREAM (1 << 5)
+#define PIM_UPSTREAM_FLAG_MASK_SRC_MSDP (1 << 6)
#define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
#define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
+#define PIM_UPSTREAM_FLAG_TEST_FHR(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_FHR)
+#define PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
+#define PIM_UPSTREAM_FLAG_TEST_SRC_PIM(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
+#define PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
+#define PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
#define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
#define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
+#define PIM_UPSTREAM_FLAG_SET_FHR(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_FHR)
+#define PIM_UPSTREAM_FLAG_SET_SRC_IGMP(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
+#define PIM_UPSTREAM_FLAG_SET_SRC_PIM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
+#define PIM_UPSTREAM_FLAG_SET_SRC_STREAM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
+#define PIM_UPSTREAM_FLAG_SET_SRC_MSDP(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
#define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
#define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
-
-/*
- RFC 4601:
-
- Metric Preference
- Preference value assigned to the unicast routing protocol that
- provided the route to the multicast source or Rendezvous-Point.
-
- Metric
- The unicast routing table metric associated with the route used to
- reach the multicast source or Rendezvous-Point. The metric is in
- units applicable to the unicast routing protocol used.
-*/
-struct pim_nexthop {
- struct interface *interface; /* RPF_interface(S) */
- struct in_addr mrib_nexthop_addr; /* MRIB.next_hop(S) */
- uint32_t mrib_metric_preference; /* MRIB.pref(S) */
- uint32_t mrib_route_metric; /* MRIB.metric(S) */
-};
-
-struct pim_rpf {
- struct pim_nexthop source_nexthop;
- struct in_addr rpf_addr; /* RPF'(S,G) */
-};
-
-enum pim_rpf_result {
- PIM_RPF_OK = 0,
- PIM_RPF_CHANGED,
- PIM_RPF_FAILURE
-};
+#define PIM_UPSTREAM_FLAG_UNSET_FHR(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_FHR)
+#define PIM_UPSTREAM_FLAG_UNSET_SRC_IGMP(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
+#define PIM_UPSTREAM_FLAG_UNSET_SRC_PIM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
+#define PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
+#define PIM_UPSTREAM_FLAG_UNSET_SRC_MSDP(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
enum pim_upstream_state {
PIM_UPSTREAM_NOTJOINED,
- PIM_UPSTREAM_JOINED
+ PIM_UPSTREAM_JOINED,
+ PIM_UPSTREAM_JOIN_PENDING,
+ PIM_UPSTREAM_PRUNE,
};
enum pim_upstream_sptbit {
@@ -83,11 +78,14 @@ enum pim_upstream_sptbit {
See RFC 4601: 4.5.7. Sending (S,G) Join/Prune Message
*/
struct pim_upstream {
+ struct pim_upstream *parent;
struct in_addr upstream_addr;/* Who we are talking to */
- struct in_addr source_addr; /* (S,G) source key */
- struct in_addr group_addr; /* (S,G) group key */
+ struct in_addr upstream_register; /*Who we received a register from*/
+ struct prefix_sg sg; /* (S,G) group key */
+ char sg_str[PIM_SG_LEN];
uint32_t flags;
struct channel_oil *channel_oil;
+ struct list *sources;
enum pim_upstream_state join_state;
enum pim_upstream_sptbit sptbit;
@@ -99,23 +97,36 @@ struct pim_upstream {
struct thread *t_join_timer;
/*
+ * RST(S,G)
+ */
+ struct thread *t_rs_timer;
+#define PIM_REGISTER_SUPPRESSION_PERIOD (60)
+#define PIM_REGISTER_PROBE_PERIOD (15)
+
+ /*
* KAT(S,G)
*/
struct thread *t_ka_timer;
#define PIM_KEEPALIVE_PERIOD (210)
#define PIM_RP_KEEPALIVE_PERIOD ( 3 * qpim_register_suppress_time + qpim_register_probe_time )
+ /* on the RP we restart a timer to indicate if registers are being rxed for
+ * SG. This is needed by MSDP to determine its local SA cache */
+ struct thread *t_msdp_reg_timer;
+#define PIM_MSDP_REG_RXED_PERIOD (3 * (1.5 * qpim_register_suppress_time))
+
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);
-void pim_upstream_delete(struct pim_upstream *up);
-struct pim_upstream *pim_upstream_find(struct in_addr source_addr,
- struct in_addr group_addr);
-struct pim_upstream *pim_upstream_add(struct in_addr source_addr,
- struct in_addr group_addr,
- struct interface *ifp);
-void pim_upstream_del(struct pim_upstream *up);
+struct pim_upstream *pim_upstream_find (struct prefix_sg *sg);
+struct pim_upstream *pim_upstream_add (struct prefix_sg *sg,
+ struct interface *ifp, int flags,
+ const char *name);
+void pim_upstream_del(struct pim_upstream *up, const char *name);
int pim_upstream_evaluate_join_desired(struct pim_upstream *up);
void pim_upstream_update_join_desired(struct pim_upstream *up);
@@ -136,7 +147,27 @@ void pim_upstream_update_my_assert_metric(struct pim_upstream *up);
void pim_upstream_keep_alive_timer_start (struct pim_upstream *up, uint32_t time);
-int pim_upstream_switch_to_spt_desired (struct in_addr source, struct in_addr group);
-#define SwitchToSptDesired(S,G) pim_upstream_switch_to_spt_desired ((S), (G))
+int pim_upstream_switch_to_spt_desired (struct prefix_sg *sg);
+#define SwitchToSptDesired(sg) pim_upstream_switch_to_spt_desired (sg)
+int pim_upstream_is_sg_rpt (struct pim_upstream *up);
+
+void pim_upstream_set_sptbit (struct pim_upstream *up, struct interface *incoming);
+
+void pim_upstream_start_register_stop_timer (struct pim_upstream *up, int null_register);
+
+void pim_upstream_send_join (struct pim_upstream *up);
+
+void pim_upstream_switch (struct pim_upstream *up, enum pim_upstream_state new_state);
+
+const char *pim_upstream_state2str (enum pim_upstream_state join_state);
+
+int pim_upstream_inherited_olist_decide (struct pim_upstream *up);
+int pim_upstream_inherited_olist (struct pim_upstream *up);
+int pim_upstream_empty_inherited_olist (struct pim_upstream *up);
+
+void pim_upstream_find_new_rpf (void);
+void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up);
+void pim_upstream_init (void);
+void pim_upstream_terminate (void);
#endif /* PIM_UPSTREAM_H */
diff --git a/pimd/pim_util.c b/pimd/pim_util.c
index f5b6a8210a..1125db00a9 100644
--- a/pimd/pim_util.c
+++ b/pimd/pim_util.c
@@ -21,6 +21,7 @@
#include <zebra.h>
#include "log.h"
+#include "prefix.h"
#include "pim_util.h"
@@ -103,3 +104,43 @@ void pim_pkt_dump(const char *label, const uint8_t *buf, int size)
size);
zlog_hexdump(buf, size);
}
+
+int
+pim_is_group_224_0_0_0_24 (struct in_addr group_addr)
+{
+ static int first = 1;
+ static struct prefix group_224;
+ struct prefix group;
+
+ if (first)
+ {
+ str2prefix ("224.0.0.0/24", &group_224);
+ first = 0;
+ }
+
+ group.family = AF_INET;
+ group.u.prefix4 = group_addr;
+ group.prefixlen = 32;
+
+ return prefix_match (&group_224, &group);
+}
+
+int
+pim_is_group_224_4 (struct in_addr group_addr)
+{
+ static int first = 1;
+ static struct prefix group_all;
+ struct prefix group;
+
+ if (first)
+ {
+ str2prefix ("224.0.0.0/4", &group_all);
+ first = 0;
+ }
+
+ group.family = AF_INET;
+ group.u.prefix4 = group_addr;
+ group.prefixlen = 32;
+
+ return prefix_match (&group_all, &group);
+}
diff --git a/pimd/pim_util.h b/pimd/pim_util.h
index d780bfbc27..94635466d9 100644
--- a/pimd/pim_util.h
+++ b/pimd/pim_util.h
@@ -32,4 +32,6 @@ uint16_t igmp_msg_decode8to16(uint8_t code);
void pim_pkt_dump(const char *label, const uint8_t *buf, int size);
+int pim_is_group_224_0_0_0_24 (struct in_addr group_addr);
+int pim_is_group_224_4 (struct in_addr group_addr);
#endif /* PIM_UTIL_H */
diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c
index f9bc2319e7..03ee7e92ec 100644
--- a/pimd/pim_vty.c
+++ b/pimd/pim_vty.c
@@ -22,7 +22,10 @@
#include "if.h"
#include "linklist.h"
+#include "prefix.h"
+#include "vty.h"
#include "vrf.h"
+#include "plist.h"
#include "pimd.h"
#include "pim_vty.h"
@@ -33,11 +36,26 @@
#include "pim_pim.h"
#include "pim_oil.h"
#include "pim_static.h"
+#include "pim_rp.h"
+#include "pim_msdp.h"
-int pim_debug_config_write(struct vty *vty)
+int
+pim_debug_config_write (struct vty *vty)
{
int writes = 0;
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ vty_out(vty, "debug msdp events%s", VTY_NEWLINE);
+ ++writes;
+ }
+ if (PIM_DEBUG_MSDP_PACKETS) {
+ vty_out(vty, "debug msdp packets%s", VTY_NEWLINE);
+ ++writes;
+ }
+ if (PIM_DEBUG_MSDP_INTERNAL) {
+ vty_out(vty, "debug msdp internal%s", VTY_NEWLINE);
+ ++writes;
+ }
if (PIM_DEBUG_IGMP_EVENTS) {
vty_out(vty, "debug igmp events%s", VTY_NEWLINE);
++writes;
@@ -50,12 +68,21 @@ int pim_debug_config_write(struct vty *vty)
vty_out(vty, "debug igmp trace%s", VTY_NEWLINE);
++writes;
}
+ if (PIM_DEBUG_IGMP_TRACE_DETAIL) {
+ vty_out(vty, "debug igmp trace detail%s", VTY_NEWLINE);
+ ++writes;
+ }
if (PIM_DEBUG_MROUTE) {
vty_out(vty, "debug mroute%s", VTY_NEWLINE);
++writes;
}
+ if (PIM_DEBUG_MROUTE_DETAIL) {
+ vty_out (vty, "debug mroute detail%s", VTY_NEWLINE);
+ ++writes;
+ }
+
if (PIM_DEBUG_PIM_EVENTS) {
vty_out(vty, "debug pim events%s", VTY_NEWLINE);
++writes;
@@ -72,10 +99,15 @@ int pim_debug_config_write(struct vty *vty)
vty_out(vty, "debug pim packet-dump receive%s", VTY_NEWLINE);
++writes;
}
+
if (PIM_DEBUG_PIM_TRACE) {
vty_out(vty, "debug pim trace%s", VTY_NEWLINE);
++writes;
}
+ if (PIM_DEBUG_PIM_TRACE_DETAIL) {
+ vty_out(vty, "debug pim trace detail%s", VTY_NEWLINE);
+ ++writes;
+ }
if (PIM_DEBUG_ZEBRA) {
vty_out(vty, "debug pim zebra%s", VTY_NEWLINE);
@@ -87,22 +119,66 @@ int pim_debug_config_write(struct vty *vty)
++writes;
}
+ if (PIM_DEBUG_PIM_HELLO) {
+ vty_out (vty, "debug pim packets hello%s", VTY_NEWLINE);
+ ++writes;
+ }
+
+ if (PIM_DEBUG_PIM_J_P) {
+ vty_out (vty, "debug pim packets joins%s", VTY_NEWLINE);
+ ++writes;
+ }
+
+ if (PIM_DEBUG_PIM_REG) {
+ vty_out (vty, "debug pim packets register%s", VTY_NEWLINE);
+ ++writes;
+ }
+
+ if (PIM_DEBUG_STATIC) {
+ vty_out (vty, "debug pim static%s", VTY_NEWLINE);
+ ++writes;
+ }
+
return writes;
}
int pim_global_config_write(struct vty *vty)
{
int writes = 0;
- char buffer[32];
+
+ writes += pim_msdp_config_write (vty);
if (PIM_MROUTE_IS_ENABLED) {
vty_out(vty, "ip multicast-routing%s", VTY_NEWLINE);
++writes;
}
- if (qpim_rp.rpf_addr.s_addr != INADDR_NONE) {
- vty_out(vty, "ip pim rp %s%s", inet_ntop(AF_INET, &qpim_rp.rpf_addr, buffer, 32), VTY_NEWLINE);
- ++writes;
- }
+
+ writes += pim_rp_config_write (vty);
+
+ if (qpim_register_suppress_time != PIM_REGISTER_SUPPRESSION_TIME_DEFAULT)
+ {
+ vty_out (vty, "ip pim register-suppress-time %d%s",
+ qpim_register_suppress_time, VTY_NEWLINE);
+ ++writes;
+ }
+ if (qpim_t_periodic != PIM_DEFAULT_T_PERIODIC)
+ {
+ vty_out (vty, "ip pim join-prune-interval %d%s",
+ qpim_t_periodic, VTY_NEWLINE);
+ ++writes;
+ }
+ if (qpim_keep_alive_time != PIM_KEEPALIVE_PERIOD)
+ {
+ vty_out (vty, "ip pim keep-alive-timer %d%s",
+ qpim_keep_alive_time, VTY_NEWLINE);
+ ++writes;
+ }
+ if (qpim_packet_process != PIM_DEFAULT_PACKET_PROCESS)
+ {
+ vty_out (vty, "ip pim packets %d%s",
+ qpim_packet_process, VTY_NEWLINE);
+ ++writes;
+ }
if (qpim_ssmpingd_list) {
struct listnode *node;
@@ -110,7 +186,7 @@ int pim_global_config_write(struct vty *vty)
vty_out(vty, "!%s", VTY_NEWLINE);
++writes;
for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) {
- char source_str[100];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str));
vty_out(vty, "ip ssmpingd %s%s", source_str, VTY_NEWLINE);
++writes;
@@ -159,12 +235,30 @@ int pim_interface_config_write(struct vty *vty)
vty_out(vty, "%s", VTY_NEWLINE);
}
+ /* 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%s", src_str, VTY_NEWLINE);
+ ++writes;
+ }
+
/* IF ip igmp */
if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
vty_out(vty, " ip igmp%s", VTY_NEWLINE);
++writes;
}
+ /* ip igmp version */
+ if (pim_ifp->igmp_version != IGMP_DEFAULT_VERSION)
+ {
+ vty_out(vty, " ip igmp version %d%s",
+ pim_ifp->igmp_version,
+ VTY_NEWLINE);
+ ++writes;
+ }
+
/* IF ip igmp query-interval */
if (pim_ifp->igmp_default_query_interval != IGMP_GENERAL_QUERY_INTERVAL)
{
@@ -177,7 +271,7 @@ int pim_interface_config_write(struct vty *vty)
/* 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-dsec %d%s",
+ vty_out(vty, " ip igpm query-max-response-time %d%s",
pim_ifp->igmp_query_max_response_time_dsec,
VTY_NEWLINE);
++writes;
@@ -188,10 +282,10 @@ int pim_interface_config_write(struct vty *vty)
struct listnode *node;
struct igmp_join *ij;
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_join_list, node, ij)) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", ij->group_addr, group_str, sizeof(group_str));
- pim_inet4_dump("<src?>", ij->source_addr, source_str, sizeof(source_str));
+ inet_ntop(AF_INET, &ij->source_addr, source_str, sizeof(source_str));
vty_out(vty, " ip igmp join %s %s%s",
group_str, source_str,
VTY_NEWLINE);
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index f2195960c4..b21da624d6 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -28,6 +28,8 @@
#include "zclient.h"
#include "stream.h"
#include "network.h"
+#include "vty.h"
+#include "plist.h"
#include "pimd.h"
#include "pim_pim.h"
@@ -171,6 +173,7 @@ static int pim_zebra_if_state_down(int command, struct zclient *zclient,
}
if (!if_is_operative(ifp)) {
+ pim_ifchannel_delete_all(ifp);
/*
pim_if_addr_del_all() suffices for shutting down IGMP,
but not for shutting down PIM
@@ -186,6 +189,9 @@ static int pim_zebra_if_state_down(int command, struct zclient *zclient,
}
}
+ if (ifp->info)
+ pim_if_del_vif(ifp);
+
return 0;
}
@@ -220,7 +226,7 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
{
struct connected *c;
struct prefix *p;
- struct in_addr old = { .s_addr = 0 };
+ struct pim_interface *pim_ifp;
/*
zebra api notifies address adds/dels events by using the same call
@@ -234,10 +240,9 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
if (!c)
return 0;
+ pim_ifp = c->ifp->info;
p = c->address;
- if (p->family != AF_INET)
- return 0;
-
+
if (PIM_DEBUG_ZEBRA) {
char buf[BUFSIZ];
prefix2str(p, buf, BUFSIZ);
@@ -251,7 +256,25 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
#endif
}
- pim_rp_check_rp (old, p->u.prefix4);
+ if (p->family != AF_INET)
+ {
+ struct listnode *cnode;
+ struct connected *conn;
+ int v4addrs = 0;
+
+ for (ALL_LIST_ELEMENTS_RO (c->ifp->connected, cnode, conn))
+ {
+ if (conn->address->family == AF_INET)
+ v4addrs++;
+ }
+ if (!v4addrs && pim_ifp)
+ {
+ pim_ifp->primary_address = pim_find_primary_addr (c->ifp);
+ pim_if_addr_add_all (c->ifp);
+ pim_if_add_vif (c->ifp);
+ }
+ return 0;
+ }
if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) {
/* trying to add primary address */
@@ -262,20 +285,32 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
/* but we had a primary address already */
char buf[BUFSIZ];
- char old[100];
prefix2str(p, buf, BUFSIZ);
- pim_inet4_dump("<old?>", primary_addr, old, sizeof(old));
- zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s",
+ zlog_warn("%s: %s : forcing secondary flag on %s",
__PRETTY_FUNCTION__,
- c->ifp->name, old, buf);
+ c->ifp->name, buf);
}
SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
}
}
pim_if_addr_add(c);
+ if (pim_ifp)
+ pim_rp_check_on_if_add(pim_ifp);
+
+ if (if_is_loopback (c->ifp))
+ {
+ struct listnode *ifnode;
+ struct interface *ifp;
+
+ for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp))
+ {
+ if (!if_is_loopback (ifp) && if_is_operative (ifp))
+ pim_if_addr_add_all (ifp);
+ }
+ }
return 0;
}
@@ -285,7 +320,6 @@ static int pim_zebra_if_address_del(int command, struct zclient *client,
{
struct connected *c;
struct prefix *p;
- struct in_addr new = { .s_addr = 0 };
/*
zebra api notifies address adds/dels events by using the same call
@@ -316,8 +350,9 @@ static int pim_zebra_if_address_del(int command, struct zclient *client,
#endif
}
- pim_rp_check_rp (p->u.prefix4, new);
pim_if_addr_del(c, 0);
+ pim_rp_setup();
+ pim_i_am_rp_re_evaluate();
return 0;
}
@@ -328,18 +363,37 @@ static void scan_upstream_rpf_cache()
struct listnode *up_nextnode;
struct pim_upstream *up;
- for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) {
+ for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
struct in_addr old_rpf_addr;
+ struct interface *old_interface;
enum pim_rpf_result rpf_result;
- rpf_result = pim_rpf_update(up, &old_rpf_addr, NULL);
+ old_interface = up->rpf.source_nexthop.interface;
+ rpf_result = pim_rpf_update(up, &old_rpf_addr);
if (rpf_result == PIM_RPF_FAILURE)
continue;
if (rpf_result == PIM_RPF_CHANGED) {
-
+
+ /*
+ * 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 (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
@@ -356,17 +410,13 @@ static void scan_upstream_rpf_cache()
/* send Prune(S,G) to the old upstream neighbor */
- pim_joinprune_send(up->rpf.source_nexthop.interface,
- old_rpf_addr,
- up->source_addr,
- up->group_addr,
- 0 /* prune */);
+ pim_joinprune_send(old_interface, old_rpf_addr,
+ up, 0 /* prune */);
/* send Join(S,G) to the current upstream neighbor */
pim_joinprune_send(up->rpf.source_nexthop.interface,
- up->rpf.rpf_addr,
- up->source_addr,
- up->group_addr,
+ up->rpf.rpf_addr.u.prefix4,
+ up,
1 /* join */);
pim_upstream_join_timer_restart(up);
@@ -389,7 +439,7 @@ pim_scan_individual_oil (struct channel_oil *c_oil)
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 (&vif_source, c_oil->oil.mfcc_origin, c_oil->oil.mfcc_mcastgrp))
return;
input_iface_vif_index = fib_lookup_if_vif_index (vif_source);
@@ -397,20 +447,23 @@ pim_scan_individual_oil (struct channel_oil *c_oil)
{
if (PIM_DEBUG_ZEBRA)
{
- char source_str[100];
- char group_str[100];
+ char source_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
zlog_debug("%s %s: could not find input interface(%d) for (S,G)=(%s,%s)",
__FILE__, __PRETTY_FUNCTION__, c_oil->oil.mfcc_parent,
source_str, group_str);
}
- pim_mroute_del (c_oil);
+ pim_mroute_del (c_oil, __PRETTY_FUNCTION__);
return;
}
if (input_iface_vif_index == c_oil->oil.mfcc_parent)
{
+ if (!c_oil->installed)
+ pim_mroute_add (c_oil, __PRETTY_FUNCTION__);
+
/* RPF unchanged */
return;
}
@@ -419,15 +472,15 @@ pim_scan_individual_oil (struct channel_oil *c_oil)
{
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);
- char source_str[100];
- char group_str[100];
+ char source_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
__FILE__, __PRETTY_FUNCTION__,
source_str, group_str,
- old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
- new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
+ old_iif->name, c_oil->oil.mfcc_parent,
+ new_iif->name, input_iface_vif_index);
}
/* new iif loops to existing oif ? */
@@ -436,39 +489,41 @@ pim_scan_individual_oil (struct channel_oil *c_oil)
struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
if (PIM_DEBUG_ZEBRA) {
- char source_str[100];
- char group_str[100];
+ char source_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
__FILE__, __PRETTY_FUNCTION__,
source_str, group_str,
- new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
+ new_iif->name, input_iface_vif_index);
}
- del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY);
+ //del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY);
}
/* update iif vif_index */
old_vif_index = c_oil->oil.mfcc_parent;
c_oil->oil.mfcc_parent = input_iface_vif_index;
- zlog_debug ("FF");
/* update kernel multicast forwarding cache (MFC) */
- if (pim_mroute_add(c_oil))
+ if (pim_mroute_add(c_oil, __PRETTY_FUNCTION__))
{
- /* 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);
- char source_str[100];
- char group_str[100];
- pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
- pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
- zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
- __FILE__, __PRETTY_FUNCTION__,
- source_str, group_str,
- old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
- new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
+ 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);
+ char source_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
+ pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
+ zlog_debug("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
+ __FILE__, __PRETTY_FUNCTION__,
+ source_str, group_str,
+ old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
+ new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
+ }
}
}
@@ -481,13 +536,12 @@ void pim_scan_oil()
qpim_scan_oil_last = pim_time_monotonic_sec();
++qpim_scan_oil_events;
- for (ALL_LIST_ELEMENTS(qpim_channel_oil_list, node, nextnode, c_oil))
+ for (ALL_LIST_ELEMENTS(pim_channel_oil_list, node, nextnode, c_oil))
pim_scan_individual_oil (c_oil);
}
static int on_rpf_cache_refresh(struct thread *t)
{
- zassert(t);
zassert(qpim_rpf_cache_refresher);
qpim_rpf_cache_refresher = 0;
@@ -501,13 +555,16 @@ static int on_rpf_cache_refresh(struct thread *t)
qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
++qpim_rpf_cache_refresh_events;
+ pim_rp_setup ();
return 0;
}
-static void sched_rpf_cache_refresh()
+void sched_rpf_cache_refresh(void)
{
++qpim_rpf_cache_refresh_requests;
+ pim_rpf_set_refresh_time ();
+
if (qpim_rpf_cache_refresher) {
/* Refresh timer is already running */
return;
@@ -575,17 +632,6 @@ static int redist_read_ipv4_route(int command, struct zclient *zclient,
CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
}
- if (length < min_len) {
- zlog_warn("%s %s: short buffer: length=%d min_len=%d flags=%s%s%s%s",
- __FILE__, __PRETTY_FUNCTION__,
- length, min_len,
- CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
- CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
- CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
- CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
- return -1;
- }
-
/* IPv4 prefix. */
stream_get(&p.prefix, s, PSIZE(p.prefixlen));
@@ -654,6 +700,7 @@ static int redist_read_ipv4_route(int command, struct zclient *zclient,
sched_rpf_cache_refresh();
+ pim_rp_setup ();
return 0;
}
@@ -662,6 +709,7 @@ pim_zebra_connected (struct zclient *zclient)
{
zclient_send_reg_requests (zclient, VRF_DEFAULT);
}
+
void pim_zebra_init(char *zebra_sock_path)
{
int i;
@@ -719,9 +767,7 @@ void pim_zebra_init(char *zebra_sock_path)
__PRETTY_FUNCTION__);
}
- zassert(!qpim_zclient_lookup);
- qpim_zclient_lookup = zclient_lookup_new();
- zassert(qpim_zclient_lookup);
+ zclient_lookup_new();
}
void igmp_anysource_forward_start(struct igmp_group *group)
@@ -754,36 +800,42 @@ void igmp_anysource_forward_stop(struct igmp_group *group)
static int fib_lookup_if_vif_index(struct in_addr addr)
{
- struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE];
+ struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
int num_ifindex;
int vif_index;
ifindex_t first_ifindex;
- num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab,
- PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr,
+ num_ifindex = zclient_lookup_nexthop(nexthop_tab,
+ MULTIPATH_NUM, addr,
PIM_NEXTHOP_LOOKUP_MAX);
if (num_ifindex < 1) {
- char addr_str[100];
- 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);
+ if (PIM_DEBUG_ZEBRA)
+ {
+ 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);
+ }
return -1;
}
first_ifindex = nexthop_tab[0].ifindex;
if (num_ifindex > 1) {
- char addr_str[100];
- pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
- zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
- __FILE__, __PRETTY_FUNCTION__,
- num_ifindex, addr_str, first_ifindex);
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char addr_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
+ zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
+ __FILE__, __PRETTY_FUNCTION__,
+ num_ifindex, addr_str, first_ifindex);
+ }
/* debug warning only, do not return */
}
if (PIM_DEBUG_ZEBRA) {
- char addr_str[100];
+ 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__,
@@ -793,31 +845,17 @@ static int fib_lookup_if_vif_index(struct in_addr addr)
vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);
if (vif_index < 0) {
- char addr_str[100];
- pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
- zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
- __FILE__, __PRETTY_FUNCTION__,
- vif_index, addr_str);
+ if (PIM_DEBUG_ZEBRA)
+ {
+ 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, addr_str);
+ }
return -2;
}
- zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
-
- if (vif_index > qpim_mroute_oif_highest_vif_index) {
- char addr_str[100];
- pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
- zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
- __FILE__, __PRETTY_FUNCTION__,
- vif_index, qpim_mroute_oif_highest_vif_index, addr_str);
-
- zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
- __FILE__, __PRETTY_FUNCTION__,
- ifindex2ifname(vif_index),
- vif_index);
-
- return -3;
- }
-
return vif_index;
}
@@ -828,17 +866,11 @@ static int del_oif(struct channel_oil *channel_oil,
struct pim_interface *pim_ifp;
int old_ttl;
- zassert(channel_oil);
-
pim_ifp = oif->info;
- zassert(pim_ifp->mroute_vif_index >= 1);
- zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
- zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
-
if (PIM_DEBUG_MROUTE) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
@@ -850,15 +882,18 @@ static int del_oif(struct channel_oil *channel_oil,
/* Prevent single protocol from unsubscribing same interface from
channel (S,G) multiple times */
if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
- char group_str[100];
- char source_str[100];
- pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
- zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
- __FILE__, __PRETTY_FUNCTION__,
- proto_mask, oif->name, pim_ifp->mroute_vif_index,
- channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
- source_str, group_str);
+ if (PIM_DEBUG_MROUTE)
+ {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
+ pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
+ zlog_debug("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
+ __FILE__, __PRETTY_FUNCTION__,
+ proto_mask, oif->name, pim_ifp->mroute_vif_index,
+ channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
+ source_str, group_str);
+ }
return -2;
}
@@ -873,15 +908,18 @@ static int del_oif(struct channel_oil *channel_oil,
/* Check the OIF keeps existing before returning, and only log
warning otherwise */
if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
- char group_str[100];
- char source_str[100];
- pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
- zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
- __FILE__, __PRETTY_FUNCTION__,
- proto_mask, oif->name, pim_ifp->mroute_vif_index,
- channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
- source_str, group_str);
+ if (PIM_DEBUG_MROUTE)
+ {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
+ pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
+ zlog_debug("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
+ __FILE__, __PRETTY_FUNCTION__,
+ proto_mask, oif->name, pim_ifp->mroute_vif_index,
+ channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
+ source_str, group_str);
+ }
}
return 0;
@@ -890,22 +928,25 @@ static int del_oif(struct channel_oil *channel_oil,
old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
if (old_ttl < 1) {
- char group_str[100];
- char source_str[100];
- pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
- zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
- __FILE__, __PRETTY_FUNCTION__,
- oif->name, pim_ifp->mroute_vif_index,
- source_str, group_str);
+ if (PIM_DEBUG_MROUTE)
+ {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
+ pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
+ zlog_debug("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
+ __FILE__, __PRETTY_FUNCTION__,
+ oif->name, pim_ifp->mroute_vif_index,
+ source_str, group_str);
+ }
return -3;
}
channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
- if (pim_mroute_add(channel_oil)) {
- char group_str[100];
- char source_str[100];
+ if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
@@ -920,21 +961,24 @@ static int del_oif(struct channel_oil *channel_oil,
--channel_oil->oil_size;
if (channel_oil->oil_size < 1) {
- if (pim_mroute_del(channel_oil)) {
- /* just log a warning in case of failure */
- char group_str[100];
- char source_str[100];
- pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
- zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
- __FILE__, __PRETTY_FUNCTION__,
- source_str, group_str);
+ if (pim_mroute_del(channel_oil, __PRETTY_FUNCTION__)) {
+ if (PIM_DEBUG_MROUTE)
+ {
+ /* just log a warning in case of failure */
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
+ pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
+ zlog_debug("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
+ __FILE__, __PRETTY_FUNCTION__,
+ source_str, group_str);
+ }
}
}
if (PIM_DEBUG_MROUTE) {
- char group_str[100];
- char source_str[100];
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
@@ -949,16 +993,17 @@ static int del_oif(struct channel_oil *channel_oil,
void igmp_source_forward_start(struct igmp_source *source)
{
struct igmp_group *group;
+ struct prefix_sg sg;
int result;
+ memset (&sg, 0, sizeof (struct prefix_sg));
+ sg.src = source->source_addr;
+ sg.grp = source->source_group->group_addr;
+
if (PIM_DEBUG_IGMP_TRACE) {
- char source_str[100];
- char group_str[100];
- pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
- pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
- zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
+ zlog_debug("%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
__PRETTY_FUNCTION__,
- source_str, group_str,
+ pim_str_sg_dump (&sg),
source->source_group->group_igmp_sock->fd,
source->source_group->group_igmp_sock->interface->name,
IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
@@ -976,16 +1021,19 @@ void igmp_source_forward_start(struct igmp_source *source)
struct in_addr vif_source;
struct pim_interface *pim_oif;
- if (!pim_rp_set_upstream_addr (&vif_source, source->source_addr))
+ if (!pim_rp_set_upstream_addr (&vif_source, source->source_addr, sg.grp))
return;
int input_iface_vif_index = fib_lookup_if_vif_index(vif_source);
if (input_iface_vif_index < 1) {
- char source_str[100];
- pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
- zlog_warn("%s %s: could not find input interface for source %s",
- __FILE__, __PRETTY_FUNCTION__,
- source_str);
+ if (PIM_DEBUG_IGMP_TRACE)
+ {
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
+ zlog_debug("%s %s: could not find input interface for source %s",
+ __FILE__, __PRETTY_FUNCTION__,
+ source_str);
+ }
return;
}
@@ -996,28 +1044,21 @@ void igmp_source_forward_start(struct igmp_source *source)
*/
pim_oif = source->source_group->group_igmp_sock->interface->info;
if (!pim_oif) {
- zlog_warn("%s: multicast not enabled on oif=%s ?",
- __PRETTY_FUNCTION__,
- source->source_group->group_igmp_sock->interface->name);
- return;
- }
- if (pim_oif->mroute_vif_index < 1) {
- zlog_warn("%s %s: oif=%s vif_index=%d < 1",
- __FILE__, __PRETTY_FUNCTION__,
- source->source_group->group_igmp_sock->interface->name,
- pim_oif->mroute_vif_index);
+ if (PIM_DEBUG_IGMP_TRACE)
+ {
+ zlog_debug("%s: multicast not enabled on oif=%s ?",
+ __PRETTY_FUNCTION__,
+ source->source_group->group_igmp_sock->interface->name);
+ }
return;
}
+
if (input_iface_vif_index == pim_oif->mroute_vif_index) {
/* ignore request for looped MFC entry */
if (PIM_DEBUG_IGMP_TRACE) {
- char source_str[100];
- char group_str[100];
- pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
- pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
- zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d",
+ zlog_debug("%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d",
__PRETTY_FUNCTION__,
- source_str, group_str,
+ pim_str_sg_dump (&sg),
source->source_group->group_igmp_sock->fd,
source->source_group->group_igmp_sock->interface->name,
input_iface_vif_index);
@@ -1025,17 +1066,15 @@ void igmp_source_forward_start(struct igmp_source *source)
return;
}
- source->source_channel_oil = pim_channel_oil_add(group->group_addr,
- source->source_addr,
+ source->source_channel_oil = pim_channel_oil_add(&sg,
input_iface_vif_index);
if (!source->source_channel_oil) {
- char group_str[100];
- char source_str[100];
- pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
- zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
- __FILE__, __PRETTY_FUNCTION__,
- source_str, group_str);
+ if (PIM_DEBUG_IGMP_TRACE)
+ {
+ zlog_debug("%s %s: could not create OIL for channel (S,G)=%s",
+ __FILE__, __PRETTY_FUNCTION__,
+ pim_str_sg_dump (&sg));
+ }
return;
}
}
@@ -1044,8 +1083,11 @@ void igmp_source_forward_start(struct igmp_source *source)
group->group_igmp_sock->interface,
PIM_OIF_FLAG_PROTO_IGMP);
if (result) {
- zlog_warn("%s: add_oif() failed with return=%d",
- __func__, result);
+ if (PIM_DEBUG_MROUTE)
+ {
+ zlog_warn("%s: add_oif() failed with return=%d",
+ __func__, result);
+ }
return;
}
@@ -1053,8 +1095,7 @@ void igmp_source_forward_start(struct igmp_source *source)
Feed IGMPv3-gathered local membership information into PIM
per-interface (S,G) state.
*/
- pim_ifchannel_local_membership_add(group->group_igmp_sock->interface,
- source->source_addr, group->group_addr);
+ pim_ifchannel_local_membership_add(group->group_igmp_sock->interface, &sg);
IGMP_SOURCE_DO_FORWARDING(source->source_flags);
}
@@ -1066,16 +1107,17 @@ void igmp_source_forward_start(struct igmp_source *source)
void igmp_source_forward_stop(struct igmp_source *source)
{
struct igmp_group *group;
+ struct prefix_sg sg;
int result;
+ memset (&sg, 0, sizeof (struct prefix_sg));
+ sg.src = source->source_addr;
+ sg.grp = source->source_group->group_addr;
+
if (PIM_DEBUG_IGMP_TRACE) {
- char source_str[100];
- char group_str[100];
- pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
- pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
- zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
+ zlog_debug("%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
__PRETTY_FUNCTION__,
- source_str, group_str,
+ pim_str_sg_dump (&sg),
source->source_group->group_igmp_sock->fd,
source->source_group->group_igmp_sock->interface->name,
IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
@@ -1104,8 +1146,9 @@ void igmp_source_forward_stop(struct igmp_source *source)
group->group_igmp_sock->interface,
PIM_OIF_FLAG_PROTO_IGMP);
if (result) {
- zlog_warn("%s: del_oif() failed with return=%d",
- __func__, result);
+ if (PIM_DEBUG_IGMP_TRACE)
+ zlog_debug("%s: del_oif() failed with return=%d",
+ __func__, result);
return;
}
@@ -1114,7 +1157,7 @@ void igmp_source_forward_stop(struct igmp_source *source)
per-interface (S,G) state.
*/
pim_ifchannel_local_membership_del(group->group_igmp_sock->interface,
- source->source_addr, group->group_addr);
+ &sg);
IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
}
@@ -1124,12 +1167,12 @@ void pim_forward_start(struct pim_ifchannel *ch)
struct pim_upstream *up = ch->upstream;
if (PIM_DEBUG_PIM_TRACE) {
- char source_str[100];
- char group_str[100];
- char upstream_str[100];
+ char source_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
+ char upstream_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
- pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
+ pim_inet4_dump("<source?>", ch->sg.src, source_str, sizeof(source_str));
+ pim_inet4_dump("<group?>", ch->sg.grp, group_str, sizeof(group_str));
pim_inet4_dump("<upstream?>", up->upstream_addr, upstream_str, sizeof(upstream_str));
zlog_debug("%s: (S,G)=(%s,%s) oif=%s(%s)",
__PRETTY_FUNCTION__,
@@ -1139,24 +1182,24 @@ void pim_forward_start(struct pim_ifchannel *ch)
if (!up->channel_oil) {
int input_iface_vif_index = fib_lookup_if_vif_index(up->upstream_addr);
if (input_iface_vif_index < 1) {
- char source_str[100];
- pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
- zlog_warn("%s %s: could not find input interface for source %s",
- __FILE__, __PRETTY_FUNCTION__,
- source_str);
+ if (PIM_DEBUG_PIM_TRACE)
+ {
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<source?>", up->sg.src, source_str, sizeof(source_str));
+ zlog_debug("%s %s: could not find input interface for source %s",
+ __FILE__, __PRETTY_FUNCTION__,
+ source_str);
+ }
return;
}
- up->channel_oil = pim_channel_oil_add(up->group_addr, up->source_addr,
+ up->channel_oil = pim_channel_oil_add(&up->sg,
input_iface_vif_index);
if (!up->channel_oil) {
- char group_str[100];
- char source_str[100];
- pim_inet4_dump("<group?>", up->group_addr, group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
- zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
- __FILE__, __PRETTY_FUNCTION__,
- source_str, group_str);
+ if (PIM_DEBUG_PIM_TRACE)
+ zlog_debug("%s %s: could not create OIL for channel (S,G)=%s",
+ __FILE__, __PRETTY_FUNCTION__,
+ up->sg_str);
return;
}
}
@@ -1171,23 +1214,16 @@ void pim_forward_stop(struct pim_ifchannel *ch)
struct pim_upstream *up = ch->upstream;
if (PIM_DEBUG_PIM_TRACE) {
- char source_str[100];
- char group_str[100];
- pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
- pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
- zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
+ zlog_debug("%s: (S,G)=%s oif=%s",
__PRETTY_FUNCTION__,
- source_str, group_str, ch->interface->name);
+ ch->sg_str, ch->interface->name);
}
if (!up->channel_oil) {
- char source_str[100];
- char group_str[100];
- pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
- pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
- zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
- __PRETTY_FUNCTION__,
- source_str, group_str, ch->interface->name);
+ if (PIM_DEBUG_PIM_TRACE)
+ zlog_debug("%s: (S,G)=%s oif=%s missing channel OIL",
+ __PRETTY_FUNCTION__,
+ ch->sg_str, ch->interface->name);
return;
}
diff --git a/pimd/pim_zebra.h b/pimd/pim_zebra.h
index 257c9b896f..0c302efbd5 100644
--- a/pimd/pim_zebra.h
+++ b/pimd/pim_zebra.h
@@ -38,4 +38,5 @@ void igmp_source_forward_stop(struct igmp_source *source);
void pim_forward_start(struct pim_ifchannel *ch);
void pim_forward_stop(struct pim_ifchannel *ch);
+void sched_rpf_cache_refresh(void);
#endif /* PIM_ZEBRA_H */
diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c
index af561a0b62..61e3e27261 100644
--- a/pimd/pim_zlookup.c
+++ b/pimd/pim_zlookup.c
@@ -27,13 +27,17 @@
#include "stream.h"
#include "network.h"
#include "thread.h"
+#include "prefix.h"
+#include "vty.h"
#include "pimd.h"
+#include "pim_iface.h"
#include "pim_pim.h"
#include "pim_str.h"
+#include "pim_oil.h"
#include "pim_zlookup.h"
-extern int zclient_debug;
+static struct zclient *zlookup = NULL;
static void zclient_lookup_sched(struct zclient *zlookup, int delay);
@@ -116,15 +120,14 @@ static void zclient_lookup_failed(struct zclient *zlookup)
zclient_lookup_reconnect(zlookup);
}
-struct zclient *zclient_lookup_new()
+void
+zclient_lookup_new (void)
{
- struct zclient *zlookup;
-
zlookup = zclient_new (master);
if (!zlookup) {
zlog_err("%s: zclient_new() failure",
__PRETTY_FUNCTION__);
- return 0;
+ return;
}
zlookup->sock = -1;
@@ -137,7 +140,6 @@ struct zclient *zclient_lookup_new()
zlog_notice("%s: zclient lookup socket initialized",
__PRETTY_FUNCTION__);
- return zlookup;
}
static int zclient_read_nexthop(struct zclient *zlookup,
@@ -159,8 +161,8 @@ static int zclient_read_nexthop(struct zclient *zlookup,
int nexthop_num;
int i, err;
- if (PIM_DEBUG_ZEBRA) {
- char addr_str[100];
+ if (PIM_DEBUG_PIM_TRACE_DETAIL) {
+ char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s: addr=%s",
__PRETTY_FUNCTION__,
@@ -192,8 +194,8 @@ static int zclient_read_nexthop(struct zclient *zlookup,
raddr.s_addr = stream_get_ipv4(s);
if (raddr.s_addr != addr.s_addr) {
- char addr_str[100];
- char raddr_str[100];
+ char addr_str[INET_ADDRSTRLEN];
+ 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",
@@ -212,77 +214,52 @@ static int zclient_read_nexthop(struct zclient *zlookup,
return -6;
}
- length -= MIN_LEN;
-
for (i = 0; i < nexthop_num; ++i) {
enum nexthop_types_t nexthop_type;
+ struct pim_neighbor *nbr;
- if (length < 1) {
- zlog_err("%s: socket %d empty input expecting nexthop_type: len=%d",
- __func__, zlookup->sock, length);
- return -7;
- }
-
nexthop_type = stream_getc(s);
- --length;
-
+ if (num_ifindex >= tab_size) {
+ char addr_str[INET_ADDRSTRLEN];
+ 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);
+ return num_ifindex;
+ }
switch (nexthop_type) {
case NEXTHOP_TYPE_IFINDEX:
case NEXTHOP_TYPE_IPV4_IFINDEX:
- if (num_ifindex >= tab_size) {
- char addr_str[100];
- 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);
- return num_ifindex;
- }
- if (nexthop_type == NEXTHOP_TYPE_IPV4_IFINDEX) {
- if (length < 4) {
- zlog_err("%s: socket %d short input expecting nexthop IPv4-addr: len=%d",
- __func__, zlookup->sock, length);
- return -8;
- }
- nexthop_tab[num_ifindex].nexthop_addr.s_addr = stream_get_ipv4(s);
- length -= 4;
+ case NEXTHOP_TYPE_IPV4:
+ nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET;
+ if (nexthop_type == NEXTHOP_TYPE_IPV4_IFINDEX ||
+ nexthop_type == NEXTHOP_TYPE_IPV4) {
+ nexthop_tab[num_ifindex].nexthop_addr.u.prefix4.s_addr = stream_get_ipv4(s);
}
else {
- nexthop_tab[num_ifindex].nexthop_addr.s_addr = PIM_NET_INADDR_ANY;
+ nexthop_tab[num_ifindex].nexthop_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
}
nexthop_tab[num_ifindex].ifindex = stream_getl(s);
nexthop_tab[num_ifindex].protocol_distance = distance;
nexthop_tab[num_ifindex].route_metric = metric;
++num_ifindex;
break;
- case NEXTHOP_TYPE_IPV4:
- if (num_ifindex >= tab_size) {
- char addr_str[100];
- 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);
- return num_ifindex;
- }
- nexthop_tab[num_ifindex].nexthop_addr.s_addr = stream_get_ipv4(s);
- length -= 4;
- nexthop_tab[num_ifindex].ifindex = 0;
- nexthop_tab[num_ifindex].protocol_distance = distance;
- nexthop_tab[num_ifindex].route_metric = metric;
- if (PIM_DEBUG_ZEBRA) {
- char addr_str[100];
- char nexthop_str[100];
- pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
- pim_inet4_dump("<nexthop?>", nexthop_tab[num_ifindex].nexthop_addr, nexthop_str, sizeof(nexthop_str));
- zlog_debug("%s %s: zebra returned recursive nexthop %s for address %s",
- __FILE__, __PRETTY_FUNCTION__,
- nexthop_str, addr_str);
- }
- ++num_ifindex;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET6;
+ stream_get (&nexthop_tab[num_ifindex].nexthop_addr.u.prefix6, s, 16);
+ nexthop_tab[num_ifindex].ifindex = stream_getl (s);
+ nbr = pim_neighbor_find_if (if_lookup_by_index_vrf (nexthop_tab[num_ifindex].ifindex, VRF_DEFAULT));
+ if (nbr)
+ {
+ nexthop_tab[num_ifindex].nexthop_addr.family = AF_INET;
+ nexthop_tab[num_ifindex].nexthop_addr.u.prefix4 = nbr->source_addr;
+ }
+ ++num_ifindex;
break;
default:
/* do nothing */
{
- char addr_str[100];
+ char addr_str[INET_ADDRSTRLEN];
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__,
@@ -295,16 +272,16 @@ static int zclient_read_nexthop(struct zclient *zlookup,
return num_ifindex;
}
-static int zclient_lookup_nexthop_once(struct zclient *zlookup,
- struct pim_zlookup_nexthop nexthop_tab[],
- const int tab_size,
- struct in_addr addr)
+static int
+zclient_lookup_nexthop_once (struct pim_zlookup_nexthop nexthop_tab[],
+ const int tab_size,
+ struct in_addr addr)
{
struct stream *s;
int ret;
- if (PIM_DEBUG_ZEBRA) {
- char addr_str[100];
+ if (PIM_DEBUG_PIM_TRACE_DETAIL) {
+ char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
zlog_debug("%s: addr=%s",
__PRETTY_FUNCTION__,
@@ -327,8 +304,8 @@ static int zclient_lookup_nexthop_once(struct zclient *zlookup,
ret = writen(zlookup->sock, s->data, stream_get_endp(s));
if (ret < 0) {
- zlog_err("%s %s: writen() failure writing to zclient lookup socket",
- __FILE__, __PRETTY_FUNCTION__);
+ zlog_err("%s %s: writen() failure: %d writing to zclient lookup socket",
+ __FILE__, __PRETTY_FUNCTION__, errno);
zclient_lookup_failed(zlookup);
return -2;
}
@@ -343,26 +320,28 @@ static int zclient_lookup_nexthop_once(struct zclient *zlookup,
tab_size, addr);
}
-int zclient_lookup_nexthop(struct zclient *zlookup,
- struct pim_zlookup_nexthop nexthop_tab[],
- const int tab_size,
- struct in_addr addr,
- int max_lookup)
+int
+zclient_lookup_nexthop (struct pim_zlookup_nexthop nexthop_tab[],
+ const int tab_size,
+ struct in_addr addr,
+ int max_lookup)
{
int lookup;
uint32_t route_metric = 0xFFFFFFFF;
uint8_t protocol_distance = 0xFF;
+ qpim_nexthop_lookups++;
+
for (lookup = 0; lookup < max_lookup; ++lookup) {
int num_ifindex;
int first_ifindex;
- struct in_addr nexthop_addr;
+ struct prefix nexthop_addr;
- num_ifindex = zclient_lookup_nexthop_once(qpim_zclient_lookup, nexthop_tab,
- PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr);
+ num_ifindex = zclient_lookup_nexthop_once(nexthop_tab,
+ tab_size, addr);
if (num_ifindex < 1) {
if (PIM_DEBUG_ZEBRA) {
- char addr_str[100];
+ 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__,
@@ -378,9 +357,13 @@ int zclient_lookup_nexthop(struct zclient *zlookup,
}
/*
- FIXME: Non-recursive nexthop ensured only for first ifindex.
- However, recursive route lookup should really be fixed in zebra daemon.
- See also TODO T24.
+ * FIXME: Non-recursive nexthop ensured only for first ifindex.
+ * However, recursive route lookup should really be fixed in zebra daemon.
+ * See also TODO T24.
+ *
+ * So Zebra for NEXTHOP_TYPE_IPV4 returns the ifindex now since
+ * it was being stored. This Doesn't solve all cases of
+ * recursive lookup but for the most common types it does.
*/
first_ifindex = nexthop_tab[0].ifindex;
nexthop_addr = nexthop_tab[0].nexthop_addr;
@@ -390,7 +373,7 @@ int zclient_lookup_nexthop(struct zclient *zlookup,
if (lookup > 0) {
/* Report non-recursive success after first lookup */
if (PIM_DEBUG_ZEBRA) {
- char addr_str[100];
+ 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__,
@@ -400,7 +383,7 @@ int zclient_lookup_nexthop(struct zclient *zlookup,
}
/* use last address as nexthop address */
- nexthop_tab[0].nexthop_addr = addr;
+ nexthop_tab[0].nexthop_addr.u.prefix4 = addr;
/* report original route metric/distance */
nexthop_tab[0].route_metric = route_metric;
@@ -411,10 +394,10 @@ int zclient_lookup_nexthop(struct zclient *zlookup,
}
if (PIM_DEBUG_ZEBRA) {
- char addr_str[100];
- char nexthop_str[100];
+ char addr_str[INET_ADDRSTRLEN];
+ char nexthop_str[PREFIX_STRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
- pim_inet4_dump("<nexthop?>", nexthop_addr, nexthop_str, sizeof(nexthop_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,
@@ -422,12 +405,12 @@ int zclient_lookup_nexthop(struct zclient *zlookup,
nexthop_tab[0].route_metric);
}
- addr = nexthop_addr; /* use nexthop addr for recursive lookup */
+ addr = nexthop_addr.u.prefix4; /* use nexthop addr for recursive lookup */
} /* for (max_lookup) */
if (PIM_DEBUG_ZEBRA) {
- char addr_str[100];
+ 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__,
@@ -436,3 +419,100 @@ int zclient_lookup_nexthop(struct zclient *zlookup,
return -2;
}
+
+void
+pim_zlookup_show_ip_multicast (struct vty *vty)
+{
+ vty_out(vty, "Zclient lookup socket: ");
+ if (zlookup) {
+ vty_out(vty, "%d failures=%d%s", zlookup->sock,
+ zlookup->fail, VTY_NEWLINE);
+ }
+ else {
+ vty_out(vty, "<null zclient>%s", VTY_NEWLINE);
+ }
+}
+
+int
+pim_zlookup_sg_statistics (struct channel_oil *c_oil)
+{
+ struct stream *s = zlookup->obuf;
+ uint16_t command = 0;
+ unsigned long long lastused;
+ struct prefix_sg sg;
+ int count = 0;
+ int ret;
+ struct interface *ifp = pim_if_find_by_vif_index (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)", pim_str_sg_dump (&more));
+ }
+
+ if (!ifp)
+ return -1;
+
+ stream_reset (s);
+ zclient_create_header (s, ZEBRA_IPMR_ROUTE_STATS, VRF_DEFAULT);
+ 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);
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ count = stream_get_endp (s);
+ 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);
+ return -1;
+ }
+
+ s = zlookup->ibuf;
+
+ while (command != ZEBRA_IPMR_ROUTE_STATS)
+ {
+ int err;
+ uint16_t length = 0;
+ vrf_id_t vrf_id;
+ u_char marker;
+ u_char version;
+
+ stream_reset (s);
+ 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__);
+ zclient_lookup_failed(zlookup);
+ return -1;
+ }
+ }
+
+ sg.src.s_addr = stream_get_ipv4 (s);
+ 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));
+ 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);
+
+ c_oil->cc.lastused = lastused;
+
+ return 0;
+
+}
diff --git a/pimd/pim_zlookup.h b/pimd/pim_zlookup.h
index dbce92647b..d8e7ff9e0d 100644
--- a/pimd/pim_zlookup.h
+++ b/pimd/pim_zlookup.h
@@ -28,18 +28,20 @@
#define PIM_NEXTHOP_LOOKUP_MAX (3) /* max. recursive route lookup */
struct pim_zlookup_nexthop {
- struct in_addr nexthop_addr;
+ struct prefix nexthop_addr;
ifindex_t ifindex;
uint32_t route_metric;
uint8_t protocol_distance;
};
-struct zclient *zclient_lookup_new(void);
+void zclient_lookup_new (void);
-int zclient_lookup_nexthop(struct zclient *zlookup,
- struct pim_zlookup_nexthop nexthop_tab[],
+int zclient_lookup_nexthop(struct pim_zlookup_nexthop nexthop_tab[],
const int tab_size,
struct in_addr addr,
int max_lookup);
+void pim_zlookup_show_ip_multicast (struct vty *vty);
+
+int pim_zlookup_sg_statistics (struct channel_oil *c_oil);
#endif /* PIM_ZLOOKUP_H */
diff --git a/pimd/pimd.c b/pimd/pimd.c
index 15e52afc1d..1627c4048d 100644
--- a/pimd/pimd.c
+++ b/pimd/pimd.c
@@ -23,6 +23,9 @@
#include "log.h"
#include "memory.h"
#include "if.h"
+#include "prefix.h"
+#include "vty.h"
+#include "plist.h"
#include "pimd.h"
#include "pim_cmd.h"
@@ -35,6 +38,7 @@
#include "pim_rpf.h"
#include "pim_ssmpingd.h"
#include "pim_static.h"
+#include "pim_rp.h"
const char *const PIM_ALL_SYSTEMS = MCAST_ALL_SYSTEMS;
const char *const PIM_ALL_ROUTERS = MCAST_ALL_ROUTERS;
@@ -45,21 +49,17 @@ 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 */
-struct thread *qpim_mroute_socket_reader = 0;
int qpim_mroute_oif_highest_vif_index = -1;
-struct list *qpim_channel_oil_list = 0;
int qpim_t_periodic = PIM_DEFAULT_T_PERIODIC; /* Period between Join/Prune Messages */
-struct list *qpim_upstream_list = 0;
-struct zclient *qpim_zclient_update = 0;
-struct zclient *qpim_zclient_lookup = 0;
+struct zclient *qpim_zclient_update = NULL;
struct pim_assert_metric qpim_infinite_assert_metric;
-long qpim_rpf_cache_refresh_delay_msec = 10000;
-struct thread *qpim_rpf_cache_refresher = 0;
+long qpim_rpf_cache_refresh_delay_msec = 50;
+struct thread *qpim_rpf_cache_refresher = NULL;
int64_t qpim_rpf_cache_refresh_requests = 0;
int64_t qpim_rpf_cache_refresh_events = 0;
int64_t qpim_rpf_cache_refresh_last = 0;
struct in_addr qpim_inaddr_any;
-struct list *qpim_ssmpingd_list = 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;
@@ -67,8 +67,11 @@ 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 = 0;
-struct pim_rpf qpim_rp = { .rpf_addr.s_addr = INADDR_NONE };
+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;
int32_t qpim_register_suppress_time = PIM_REGISTER_SUPPRESSION_TIME_DEFAULT;
int32_t qpim_register_probe_time = PIM_REGISTER_PROBE_TIME_DEFAULT;
@@ -77,22 +80,28 @@ static void pim_free()
{
pim_ssmpingd_destroy();
- if (qpim_channel_oil_list)
- list_free(qpim_channel_oil_list);
+ pim_oil_terminate ();
- if (qpim_upstream_list)
- list_free(qpim_upstream_list);
+ pim_upstream_terminate ();
if (qpim_static_route_list)
list_free(qpim_static_route_list);
pim_route_map_terminate();
+
+ pim_if_terminate ();
+ pim_rp_free ();
+ pim_route_map_terminate();
}
void pim_init()
{
srandom(time(NULL));
+ 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",
__FILE__, __PRETTY_FUNCTION__,
@@ -101,22 +110,9 @@ void pim_init()
return;
}
- qpim_channel_oil_list = list_new();
- if (!qpim_channel_oil_list) {
- zlog_err("%s %s: failure: channel_oil_list=list_new()",
- __FILE__, __PRETTY_FUNCTION__);
- return;
- }
- qpim_channel_oil_list->del = (void (*)(void *)) pim_channel_oil_free;
+ pim_oil_init ();
- qpim_upstream_list = list_new();
- if (!qpim_upstream_list) {
- zlog_err("%s %s: failure: upstream_list=list_new()",
- __FILE__, __PRETTY_FUNCTION__);
- pim_free();
- return;
- }
- qpim_upstream_list->del = (void (*)(void *)) pim_upstream_free;
+ pim_upstream_init ();
qpim_static_route_list = list_new();
if (!qpim_static_route_list) {
@@ -129,9 +125,6 @@ void pim_init()
qpim_mroute_socket_fd = -1; /* mark mroute as disabled */
qpim_mroute_oif_highest_vif_index = -1;
- zassert(!qpim_debugs);
- zassert(!PIM_MROUTE_IS_ENABLED);
-
qpim_inaddr_any.s_addr = PIM_NET_INADDR_ANY;
/*
diff --git a/pimd/pimd.h b/pimd/pimd.h
index 2230a6ce91..20cf3c2dd2 100644
--- a/pimd/pimd.h
+++ b/pimd/pimd.h
@@ -23,13 +23,13 @@
#include <stdint.h>
+#include "pim_str.h"
#include "pim_memory.h"
#include "pim_assert.h"
#define PIMD_PROGNAME "pimd"
#define PIMD_DEFAULT_CONFIG "pimd.conf"
#define PIMD_VTY_PORT 2611
-#define PIMD_BUG_ADDRESS "https://github.com/udhos/qpimd"
#define PIM_IP_HEADER_MIN_LEN (20)
#define PIM_IP_HEADER_MAX_LEN (60)
@@ -51,6 +51,8 @@
#define PIM_INADDR_IS_ANY(addr) (addr).s_addr == PIM_NET_INADDR_ANY
#define PIM_INADDR_ISNOT_ANY(addr) ((addr).s_addr != PIM_NET_INADDR_ANY) /* struct in_addr addr */
+#define max(x,y) ((x) > (y) ? (x) : (y))
+
#define PIM_MASK_PIM_EVENTS (1 << 0)
#define PIM_MASK_PIM_EVENTS_DETAIL (1 << 1)
#define PIM_MASK_PIM_PACKETS (1 << 2)
@@ -65,9 +67,28 @@
#define PIM_MASK_ZEBRA (1 << 11)
#define PIM_MASK_SSMPINGD (1 << 12)
#define PIM_MASK_MROUTE (1 << 13)
-#define PIM_MASK_PIM_HELLO (1 << 14)
-#define PIM_MASK_PIM_J_P (1 << 15)
-#define PIM_MASK_STATIC (1 << 16)
+#define PIM_MASK_MROUTE_DETAIL (1 << 14)
+#define PIM_MASK_PIM_HELLO (1 << 15)
+#define PIM_MASK_PIM_J_P (1 << 16)
+#define PIM_MASK_STATIC (1 << 17)
+#define PIM_MASK_PIM_REG (1 << 18)
+#define PIM_MASK_MSDP_EVENTS (1 << 19)
+#define PIM_MASK_MSDP_PACKETS (1 << 20)
+#define PIM_MASK_MSDP_INTERNAL (1 << 21)
+
+
+/* PIM error codes */
+#define PIM_SUCCESS 0
+#define PIM_MALLOC_FAIL -1
+#define PIM_GROUP_BAD_ADDRESS -2
+#define PIM_GROUP_OVERLAP -3
+#define PIM_GROUP_PFXLIST_OVERLAP -4
+#define PIM_RP_BAD_ADDRESS -5
+#define PIM_RP_NO_PATH -6
+#define PIM_RP_NOT_FOUND -7
+#define PIM_RP_PFXLIST_IN_USE -8
+#define PIM_IFACE_NOT_FOUND -9
+#define PIM_UPDATE_SOURCE_DUP -10
const char *const PIM_ALL_SYSTEMS;
const char *const PIM_ALL_ROUTERS;
@@ -78,14 +99,10 @@ extern struct thread_master *master;
uint32_t qpim_debugs;
int qpim_mroute_socket_fd;
int64_t qpim_mroute_socket_creation; /* timestamp of creation */
-struct thread *qpim_mroute_socket_reader;
int qpim_mroute_oif_highest_vif_index;
-struct list *qpim_channel_oil_list; /* list of struct channel_oil */
struct in_addr qpim_all_pim_routers_addr;
int qpim_t_periodic; /* Period between Join/Prune Messages */
-struct list *qpim_upstream_list; /* list of struct pim_upstream */
struct zclient *qpim_zclient_update;
-struct zclient *qpim_zclient_lookup;
struct pim_assert_metric qpim_infinite_assert_metric;
long qpim_rpf_cache_refresh_delay_msec;
struct thread *qpim_rpf_cache_refresher;
@@ -101,8 +118,12 @@ 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 */
-struct pim_rpf qpim_rp;
+extern unsigned int qpim_keep_alive_time;
+extern signed int qpim_rp_keep_alive_time;
+extern int qpim_packet_process;
+#define PIM_DEFAULT_PACKET_PROCESS 3
#define PIM_JP_HOLDTIME (qpim_t_periodic * 7 / 2)
@@ -132,12 +153,17 @@ extern int32_t qpim_register_probe_time;
#define PIM_DEBUG_ZEBRA (qpim_debugs & PIM_MASK_ZEBRA)
#define PIM_DEBUG_SSMPINGD (qpim_debugs & PIM_MASK_SSMPINGD)
#define PIM_DEBUG_MROUTE (qpim_debugs & PIM_MASK_MROUTE)
+#define PIM_DEBUG_MROUTE_DETAIL (qpim_debugs & PIM_MASK_MROUTE_DETAIL)
#define PIM_DEBUG_PIM_HELLO (qpim_debugs & PIM_MASK_PIM_HELLO)
#define PIM_DEBUG_PIM_J_P (qpim_debugs & PIM_MASK_PIM_J_P)
+#define PIM_DEBUG_PIM_REG (qpim_debugs & PIM_MASK_PIM_REG)
#define PIM_DEBUG_STATIC (qpim_debugs & PIM_MASK_STATIC)
+#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_EVENTS (qpim_debugs & (PIM_MASK_PIM_EVENTS | PIM_MASK_IGMP_EVENTS))
-#define PIM_DEBUG_PACKETS (qpim_debugs & (PIM_MASK_PIM_PACKETS | PIM_MASK_IGMP_PACKETS))
+#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_DEBUG_TRACE (qpim_debugs & (PIM_MASK_PIM_TRACE | PIM_MASK_IGMP_TRACE))
#define PIM_DO_DEBUG_PIM_EVENTS (qpim_debugs |= PIM_MASK_PIM_EVENTS)
@@ -152,9 +178,14 @@ extern int32_t qpim_register_probe_time;
#define PIM_DO_DEBUG_ZEBRA (qpim_debugs |= PIM_MASK_ZEBRA)
#define PIM_DO_DEBUG_SSMPINGD (qpim_debugs |= PIM_MASK_SSMPINGD)
#define PIM_DO_DEBUG_MROUTE (qpim_debugs |= PIM_MASK_MROUTE)
+#define PIM_DO_DEBUG_MROUTE_DETAIL (qpim_debugs |= PIM_MASK_MROUTE_DETAIL)
#define PIM_DO_DEBUG_PIM_HELLO (qpim_debugs |= PIM_MASK_PIM_HELLO)
#define PIM_DO_DEBUG_PIM_J_P (qpim_debugs |= PIM_MASK_PIM_J_P)
+#define PIM_DO_DEBUG_PIM_REG (qpim_debugs |= PIM_MASK_PIM_REG)
#define PIM_DO_DEBUG_STATIC (qpim_debugs |= PIM_MASK_STATIC)
+#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_DONT_DEBUG_PIM_EVENTS (qpim_debugs &= ~PIM_MASK_PIM_EVENTS)
#define PIM_DONT_DEBUG_PIM_PACKETS (qpim_debugs &= ~PIM_MASK_PIM_PACKETS)
@@ -168,9 +199,14 @@ extern int32_t qpim_register_probe_time;
#define PIM_DONT_DEBUG_ZEBRA (qpim_debugs &= ~PIM_MASK_ZEBRA)
#define PIM_DONT_DEBUG_SSMPINGD (qpim_debugs &= ~PIM_MASK_SSMPINGD)
#define PIM_DONT_DEBUG_MROUTE (qpim_debugs &= ~PIM_MASK_MROUTE)
+#define PIM_DONT_DEBUG_MROUTE_DETAIL (qpim_debugs &= ~PIM_MASK_MROUTE_DETAIL)
#define PIM_DONT_DEBUG_PIM_HELLO (qpim_debugs &= ~PIM_MASK_PIM_HELLO)
#define PIM_DONT_DEBUG_PIM_J_P (qpim_debugs &= ~PIM_MASK_PIM_J_P)
+#define PIM_DONT_DEBUG_PIM_REG (qpim_debugs &= ~PIM_MASK_PIM_REG)
#define PIM_DONT_DEBUG_STATIC (qpim_debugs &= ~PIM_MASK_STATIC)
+#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)
void pim_init(void);
void pim_terminate(void);
diff --git a/tests/test-timer-performance.c b/tests/test-timer-performance.c
index ee45ede6ac..a7d09beecc 100644
--- a/tests/test-timer-performance.c
+++ b/tests/test-timer-performance.c
@@ -61,7 +61,7 @@ int main(int argc, char **argv)
for (i = 0; i < SCHEDULE_TIMERS; i++)
thread_cancel(timers[i]);
- quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv_start);
+ monotime(&tv_start);
for (i = 0; i < SCHEDULE_TIMERS; i++)
{
@@ -72,7 +72,7 @@ int main(int argc, char **argv)
NULL, interval_msec);
}
- quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv_lap);
+ monotime(&tv_lap);
for (i = 0; i < REMOVE_TIMERS; i++)
{
@@ -84,7 +84,7 @@ int main(int argc, char **argv)
timers[index] = NULL;
}
- quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv_stop);
+ monotime(&tv_stop);
t_schedule = 1000 * (tv_lap.tv_sec - tv_start.tv_sec);
t_schedule += (tv_lap.tv_usec - tv_start.tv_usec) / 1000;
diff --git a/tests/testcli.refout b/tests/testcli.refout
index 088cbdfec4..8b438baee2 100644
--- a/tests/testcli.refout
+++ b/tests/testcli.refout
@@ -188,15 +188,11 @@ test# pat c c x
% [NONE] Unknown command: pat c c x
test#
test# pat d
-cmd8 with 2 args.
-[00]: pat
-[01]: d
+% Command incomplete.
test# pat d
bar baz foo
test# pat d
-cmd8 with 2 args.
-[00]: pat
-[01]: d
+% Command incomplete.
test# pat d foo 1.2.3.4
cmd8 with 4 args.
[00]: pat
diff --git a/tools/permutations.c b/tools/permutations.c
index 8db51ee037..0ca980b259 100644
--- a/tools/permutations.c
+++ b/tools/permutations.c
@@ -70,7 +70,7 @@ permute (struct graph_node *start)
for (ALL_LIST_ELEMENTS_RO (position,ln,gnn))
{
struct cmd_token *tt = gnn->data;
- if (tt->type < SELECTOR_TKN)
+ if (tt->type < SPECIAL_TKN)
fprintf (stdout, "%s ", tt->text);
}
fprintf (stdout, "\n");
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 50677b5685..51b5091c57 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -312,6 +312,10 @@ vtysh_execute_func (const char *line, int pager)
{
vtysh_execute("exit-address-family");
}
+ else if (saved_node == BGP_VRF_POLICY_NODE && (tried == 1))
+ {
+ vtysh_execute("exit-vrf-policy");
+ }
else if ((saved_node == BGP_VNC_DEFAULTS_NODE
|| saved_node == BGP_VNC_NVE_GROUP_NODE
|| saved_node == BGP_VNC_L2_GROUP_NODE) && (tried == 1))
@@ -963,6 +967,11 @@ static struct cmd_node bgp_vnc_nve_group_node =
"%s(config-router-vnc-nve-group)# "
};
+static struct cmd_node bgp_vrf_policy_node = {
+ BGP_VRF_POLICY_NODE,
+ "%s(config-router-vrf-policy)# "
+};
+
static struct cmd_node bgp_vnc_l2_group_node =
{
BGP_VNC_L2_GROUP_NODE,
@@ -1210,6 +1219,17 @@ DEFUNSH (VTYSH_BGPD,
}
DEFUNSH (VTYSH_BGPD,
+ vnc_vrf_policy,
+ vnc_vrf_policy_cmd,
+ "vrf-policy NAME",
+ "Configure a VRF policy group\n"
+ "Group name\n")
+{
+ vty->node = BGP_VRF_POLICY_NODE;
+ return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_BGPD,
vnc_l2_group,
vnc_l2_group_cmd,
"vnc l2-group NAME",
@@ -1481,6 +1501,7 @@ vtysh_exit (struct vty *vty)
case BGP_IPV4M_NODE:
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
+ case BGP_VRF_POLICY_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
case BGP_VNC_L2_GROUP_NODE:
@@ -1560,6 +1581,17 @@ DEFUNSH (VTYSH_BGPD,
return CMD_SUCCESS;
}
+DEFUNSH (VTYSH_BGPD,
+ exit_vrf_policy,
+ exit_vrf_policy_cmd,
+ "exit-vrf-policy",
+ "Exit from VRF configuration mode\n")
+{
+ if (vty->node == BGP_VRF_POLICY_NODE)
+ vty->node = BGP_NODE;
+ return CMD_SUCCESS;
+}
+
DEFUNSH (VTYSH_RIPD,
vtysh_exit_ripd,
vtysh_exit_ripd_cmd,
@@ -3042,6 +3074,7 @@ vtysh_init_vty (void)
install_node (&bgp_ipv4m_node, NULL);
install_node (&bgp_ipv6_node, NULL);
install_node (&bgp_ipv6m_node, NULL);
+ install_node (&bgp_vrf_policy_node, NULL);
install_node (&bgp_vnc_defaults_node, NULL);
install_node (&bgp_vnc_nve_group_node, NULL);
install_node (&bgp_vnc_l2_group_node, NULL);
@@ -3079,6 +3112,7 @@ vtysh_init_vty (void)
vtysh_install_default (BGP_IPV6_NODE);
vtysh_install_default (BGP_IPV6M_NODE);
#if ENABLE_BGP_VNC
+ vtysh_install_default (BGP_VRF_POLICY_NODE);
vtysh_install_default (BGP_VNC_DEFAULTS_NODE);
vtysh_install_default (BGP_VNC_NVE_GROUP_NODE);
vtysh_install_default (BGP_VNC_L2_GROUP_NODE);
@@ -3150,6 +3184,8 @@ vtysh_init_vty (void)
install_element (BGP_IPV6M_NODE, &vtysh_exit_bgpd_cmd);
install_element (BGP_IPV6M_NODE, &vtysh_quit_bgpd_cmd);
#if defined (ENABLE_BGP_VNC)
+ install_element (BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd);
+ install_element (BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd);
install_element (BGP_VNC_DEFAULTS_NODE, &vtysh_exit_bgpd_cmd);
install_element (BGP_VNC_DEFAULTS_NODE, &vtysh_quit_bgpd_cmd);
install_element (BGP_VNC_NVE_GROUP_NODE, &vtysh_exit_bgpd_cmd);
@@ -3191,6 +3227,7 @@ vtysh_init_vty (void)
install_element (BGP_ENCAPV6_NODE, &vtysh_end_all_cmd);
install_element (BGP_IPV6_NODE, &vtysh_end_all_cmd);
install_element (BGP_IPV6M_NODE, &vtysh_end_all_cmd);
+ install_element (BGP_VRF_POLICY_NODE, &vtysh_end_all_cmd);
install_element (BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd);
install_element (BGP_VNC_NVE_GROUP_NODE, &vtysh_end_all_cmd);
install_element (BGP_VNC_L2_GROUP_NODE, &vtysh_end_all_cmd);
@@ -3239,6 +3276,7 @@ vtysh_init_vty (void)
install_element (BGP_NODE, &address_family_encapv4_cmd);
install_element (BGP_NODE, &address_family_encapv6_cmd);
#if defined(ENABLE_BGP_VNC)
+ install_element (BGP_NODE, &vnc_vrf_policy_cmd);
install_element (BGP_NODE, &vnc_defaults_cmd);
install_element (BGP_NODE, &vnc_nve_group_cmd);
install_element (BGP_NODE, &vnc_l2_group_cmd);
@@ -3256,6 +3294,7 @@ vtysh_init_vty (void)
install_element (BGP_IPV6_NODE, &exit_address_family_cmd);
install_element (BGP_IPV6M_NODE, &exit_address_family_cmd);
+ install_element (BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd);
install_element (BGP_VNC_DEFAULTS_NODE, &exit_vnc_config_cmd);
install_element (BGP_VNC_NVE_GROUP_NODE, &exit_vnc_config_cmd);
install_element (BGP_VNC_L2_GROUP_NODE, &exit_vnc_config_cmd);
diff --git a/zebra/Makefile.am b/zebra/Makefile.am
index 65927262f2..428090d488 100644
--- a/zebra/Makefile.am
+++ b/zebra/Makefile.am
@@ -44,7 +44,7 @@ zebra_SOURCES = \
irdp_main.c irdp_interface.c irdp_packet.c router-id.c zebra_fpm.c \
$(othersrc) 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 \
- $(protobuf_srcs) \
+ $(protobuf_srcs) zebra_mroute.c \
$(dev_srcs)
testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \
@@ -60,7 +60,7 @@ noinst_HEADERS = \
rt_netlink.h zebra_fpm.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
+ kernel_netlink.h if_netlink.h zebra_mroute.h
zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP) $(Q_FPM_PB_CLIENT_LDOPTS)
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index d553850546..660fad6530 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -173,6 +173,48 @@ netlink_to_zebra_link_type (unsigned int hwt)
}
}
+
+//Temporary Assignments to compile on older platforms.
+#ifndef IFLA_BR_MAX
+#define IFLA_BR_MAX 39
+#endif
+
+#ifndef IFLA_VXLAN_ID
+#define IFLA_VXLAN_ID 1
+#endif
+
+#ifndef IFLA_VXLAN_LOCAL
+#define IFLA_VXLAN_LOCAL 4
+#endif
+
+#ifndef IFLA_VXLAN_MAX
+#define IFLA_VXLAN_MAX 26
+#endif
+
+#ifndef IFLA_BRIDGE_MAX
+#define IFLA_BRIDGE_MAX 2
+#endif
+
+#ifndef IFLA_BRIDGE_VLAN_INFO
+#define IFLA_BRIDGE_VLAN_INFO 2
+#endif
+
+#ifndef BRIDGE_VLAN_INFO_PVID
+#define BRIDGE_VLAN_INFO_PVID (1<<1)
+#endif
+
+#ifndef RTEXT_FILTER_BRVLAN
+#define RTEXT_FILTER_BRVLAN (1<<1)
+#endif
+
+#ifndef NTF_SELF
+#define NTF_SELF 0x02
+#endif
+
+#ifndef IFLA_BR_VLAN_FILTERING
+#define IFLA_BR_VLAN_FILTERING 7
+#endif
+
#define parse_rtattr_nested(tb, max, rta) \
netlink_parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta))
diff --git a/zebra/kernel_null.c b/zebra/kernel_null.c
index a20597882c..896ca96b48 100644
--- a/zebra/kernel_null.c
+++ b/zebra/kernel_null.c
@@ -60,3 +60,5 @@ int kernel_neigh_update (int a, int b, uint32_t c, char *d, int e)
void kernel_init (struct zebra_ns *zns) { return; }
void kernel_terminate (struct zebra_ns *zns) { return; }
void route_read (struct zebra_ns *zns) { return; }
+
+int kernel_get_ipmr_sg_stats (void *m) { return 0; }
diff --git a/zebra/rt.h b/zebra/rt.h
index e56e3b8fe3..40beb6a45f 100644
--- a/zebra/rt.h
+++ b/zebra/rt.h
@@ -40,4 +40,5 @@ 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);
#endif /* _ZEBRA_RT_H */
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 913d1d5770..d2781f4c4e 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -55,6 +55,8 @@
#include "zebra/zebra_mpls.h"
#include "zebra/kernel_netlink.h"
#include "zebra/rt_netlink.h"
+#include "zebra/zebra_mroute.h"
+
/* TODO - Temporary definitions, need to refine. */
#ifndef AF_MPLS
@@ -88,6 +90,10 @@
#ifndef MPLS_IPTUNNEL_DST
#define MPLS_IPTUNNEL_DST 1
#endif
+
+#ifndef NDA_MASTER
+#define NDA_MASTER 9
+#endif
/* End of temporary definitions */
struct gw_family_t
@@ -520,15 +526,17 @@ netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
return 0;
}
+static struct mcast_route_data *mroute = NULL;
+
static int
netlink_route_change_read_multicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
ns_id_t ns_id)
{
int len;
- unsigned long long lastused = 0;
struct rtmsg *rtm;
struct rtattr *tb[RTA_MAX + 1];
- struct prefix_sg sg;
+ struct mcast_route_data *m;
+ struct mcast_route_data mr;
int iif = 0;
int count;
int oif[256];
@@ -536,10 +544,16 @@ netlink_route_change_read_multicast (struct sockaddr_nl *snl, struct nlmsghdr *h
char sbuf[40];
char gbuf[40];
char oif_list[256] = "\0";
- memset (&sg, 0, sizeof (sg));
- sg.family = IANA_AFI_IPMR;
vrf_id_t vrf = ns_id;
+ if (mroute)
+ m = mroute;
+ else
+ {
+ memset (&mr, 0, sizeof (mr));
+ m = &mr;
+ }
+
rtm = NLMSG_DATA (h);
len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
@@ -551,13 +565,13 @@ netlink_route_change_read_multicast (struct sockaddr_nl *snl, struct nlmsghdr *h
iif = *(int *)RTA_DATA (tb[RTA_IIF]);
if (tb[RTA_SRC])
- sg.src = *(struct in_addr *)RTA_DATA (tb[RTA_SRC]);
+ m->sg.src = *(struct in_addr *)RTA_DATA (tb[RTA_SRC]);
if (tb[RTA_DST])
- sg.grp = *(struct in_addr *)RTA_DATA (tb[RTA_DST]);
+ m->sg.grp = *(struct in_addr *)RTA_DATA (tb[RTA_DST]);
if ((RTA_EXPIRES <= RTA_MAX) && tb[RTA_EXPIRES])
- lastused = *(unsigned long long *)RTA_DATA (tb[RTA_EXPIRES]);
+ m->lastused = *(unsigned long long *)RTA_DATA (tb[RTA_EXPIRES]);
if (tb[RTA_MULTIPATH])
{
@@ -580,18 +594,20 @@ netlink_route_change_read_multicast (struct sockaddr_nl *snl, struct nlmsghdr *h
if (IS_ZEBRA_DEBUG_KERNEL)
{
- strcpy (sbuf, inet_ntoa (sg.src));
- strcpy (gbuf, inet_ntoa (sg.grp));
+ struct interface *ifp;
+ strcpy (sbuf, inet_ntoa (m->sg.src));
+ strcpy (gbuf, inet_ntoa (m->sg.grp));
for (count = 0; count < oif_count; count++)
{
- struct interface *ifp = if_lookup_by_index_vrf (oif[count], vrf);
+ ifp = if_lookup_by_index_vrf (oif[count], vrf);
char temp[256];
sprintf (temp, "%s ", ifp->name);
strcat (oif_list, temp);
}
- zlog_debug ("MCAST %s (%s,%s) IIF: %d OIF: %s jiffies: %lld",
- nl_msg_type_to_str (h->nlmsg_type), sbuf, gbuf, iif, oif_list, lastused);
+ ifp = if_lookup_by_index_vrf (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);
}
return 0;
}
@@ -1510,6 +1526,39 @@ skip:
}
int
+kernel_get_ipmr_sg_stats (void *in)
+{
+ int suc = 0;
+ struct mcast_route_data *mr = (struct mcast_route_data *)in;
+ struct {
+ struct nlmsghdr n;
+ struct ndmsg ndm;
+ char buf[256];
+ } req;
+
+ mroute = mr;
+ struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT);
+
+ memset(&req.n, 0, sizeof(req.n));
+ memset(&req.ndm, 0, sizeof(req.ndm));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.ndm.ndm_family = AF_INET;
+ 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);
+
+ suc = netlink_talk (netlink_route_change_read_multicast, &req.n, &zns->netlink_cmd, zns);
+
+ mroute = NULL;
+ return suc;
+}
+
+int
kernel_route_rib (struct prefix *p, struct rib *old, struct rib *new)
{
if (!old && new)
diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c
index b2c99d9813..f65ec887dd 100644
--- a/zebra/rt_socket.c
+++ b/zebra/rt_socket.c
@@ -416,3 +416,9 @@ kernel_neigh_update (int add, int ifindex, uint32_t addr, char *lla, int llalen)
/* TODO */
return 0;
}
+
+extern int
+kernel_get_ipmr_sg_stats (void *mroute)
+{
+ return 0;
+}
diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c
index d91cda9fb0..afa557096c 100644
--- a/zebra/zebra_fpm.c
+++ b/zebra/zebra_fpm.c
@@ -297,20 +297,6 @@ zfpm_state_to_str (zfpm_state_t state)
}
/*
- * zfpm_get_time
- */
-static time_t
-zfpm_get_time (void)
-{
- struct timeval tv;
-
- if (quagga_gettime (QUAGGA_CLK_MONOTONIC, &tv) < 0)
- zlog_warn ("FPM: quagga_gettime failed!!");
-
- return tv.tv_sec;
-}
-
-/*
* zfpm_get_elapsed_time
*
* Returns the time elapsed (in seconds) since the given time.
@@ -320,7 +306,7 @@ zfpm_get_elapsed_time (time_t reference)
{
time_t now;
- now = zfpm_get_time ();
+ now = monotime(NULL);
if (now < reference)
{
@@ -1179,7 +1165,7 @@ zfpm_connect_cb (struct thread *t)
*/
zfpm_g->connect_calls++;
zfpm_g->stats.connect_calls++;
- zfpm_g->last_connect_call_time = zfpm_get_time ();
+ zfpm_g->last_connect_call_time = monotime(NULL);
ret = connect (sock, (struct sockaddr *) &serv, sizeof (serv));
if (ret >= 0)
@@ -1533,7 +1519,7 @@ zfpm_clear_stats (struct vty *vty)
zfpm_stop_stats_timer ();
zfpm_start_stats_timer ();
- zfpm_g->last_stats_clear_time = zfpm_get_time();
+ zfpm_g->last_stats_clear_time = monotime(NULL);
vty_out (vty, "Cleared FPM stats%s", VTY_NEWLINE);
}
diff --git a/zebra/zebra_fpm_dt.c b/zebra/zebra_fpm_dt.c
index bd171c89b2..715e250a66 100644
--- a/zebra/zebra_fpm_dt.c
+++ b/zebra/zebra_fpm_dt.c
@@ -42,6 +42,8 @@
#include "vrf.h"
#include "zebra/rib.h"
+#include "zebra/zserv.h"
+#include "zebra/zebra_vrf.h"
#include "zebra_fpm_private.h"
diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c
index 2c781899f4..9fffc9e611 100644
--- a/zebra/zebra_fpm_netlink.c
+++ b/zebra/zebra_fpm_netlink.c
@@ -28,6 +28,7 @@
#include "log.h"
#include "rib.h"
#include "vty.h"
+#include "prefix.h"
#include "zebra/zserv.h"
#include "zebra/zebra_ns.h"
diff --git a/zebra/zebra_mroute.c b/zebra/zebra_mroute.c
new file mode 100644
index 0000000000..86356104bd
--- /dev/null
+++ b/zebra/zebra_mroute.c
@@ -0,0 +1,68 @@
+/* zebra_mroute code
+ * Copyright (C) 2016 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This file is part of Quagga
+ *
+ * Quagga 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.
+ *
+ * Quagga is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "stream.h"
+#include "prefix.h"
+#include "vrf.h"
+#include "rib.h"
+
+#include "zebra/zserv.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/zebra_mroute.h"
+#include "zebra/rt.h"
+
+int
+zebra_ipmr_route_stats (struct zserv *client, int fd, u_short length, struct zebra_vrf *zvrf)
+{
+ struct mcast_route_data mroute;
+ 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));
+
+ suc = kernel_get_ipmr_sg_stats (&mroute);
+
+ s = client->obuf;
+
+ stream_reset (s);
+
+ zserv_create_header (s, ZEBRA_IPMR_ROUTE_STATS, zvrf_id (zvrf));
+ stream_put_in_addr (s, &mroute.sg.src);
+ stream_put_in_addr (s, &mroute.sg.grp);
+ stream_put (s, &mroute.lastused, sizeof (mroute.lastused));
+ stream_putl (s, suc);
+
+ stream_putw_at (s, 0, stream_get_endp (s));
+ zebra_server_send_message (client);
+ return 0;
+}
diff --git a/zebra/zebra_mroute.h b/zebra/zebra_mroute.h
new file mode 100644
index 0000000000..c0bac43a81
--- /dev/null
+++ b/zebra/zebra_mroute.h
@@ -0,0 +1,35 @@
+/* zebra_mroute.h
+ * Copyright (C) 2016 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This file is part of Quagga.
+ *
+ * Quagga 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.
+ *
+ * Quagga is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __ZEBRA_MROUTE_H__
+#define __ZEBRA_MROUTE_H__
+
+struct mcast_route_data {
+ struct prefix_sg sg;
+ unsigned int ifindex;
+ unsigned long long lastused;
+};
+
+int zebra_ipmr_route_stats (struct zserv *client, int sock, u_short length, struct zebra_vrf *zvf);
+
+#endif
+
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index 315d4832dd..182cfe552d 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -922,7 +922,7 @@ send_client (struct rnh *rnh, struct zserv *client, rnh_type_t type, vrf_id_t vr
}
stream_putw_at (s, 0, stream_get_endp (s));
- client->nh_last_upd_time = quagga_monotime();
+ client->nh_last_upd_time = monotime(NULL);
client->last_write_cmd = cmd;
return zebra_server_send_message(client);
}
diff --git a/zebra/zserv.c b/zebra/zserv.c
index f53b2270f1..6f72ad1758 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -54,6 +54,7 @@
#include "zebra/rtadv.h"
#include "zebra/zebra_mpls.h"
#include "zebra/zebra_fpm.h"
+#include "zebra/zebra_mroute.h"
/* Event list of zebra. */
enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE };
@@ -100,7 +101,7 @@ zserv_flush_data(struct thread *thread)
break;
}
- client->last_write_time = quagga_monotime();
+ client->last_write_time = monotime(NULL);
return 0;
}
@@ -134,7 +135,7 @@ zebra_server_send_message(struct zserv *client)
break;
}
- client->last_write_time = quagga_monotime();
+ client->last_write_time = monotime(NULL);
return 0;
}
@@ -785,8 +786,6 @@ zsend_write_nexthop (struct stream *s, struct nexthop *nexthop)
switch (nexthop->type)
{
case NEXTHOP_TYPE_IPV4:
- stream_put_in_addr (s, &nexthop->gate.ipv4);
- break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
stream_put_in_addr (s, &nexthop->gate.ipv4);
stream_putl (s, nexthop->ifindex);
@@ -826,7 +825,7 @@ zserv_rnh_register (struct zserv *client, int sock, u_short length,
s = client->ibuf;
- client->nh_reg_time = quagga_monotime();
+ client->nh_reg_time = monotime(NULL);
while (l < length)
{
@@ -914,7 +913,7 @@ zserv_rnh_unregister (struct zserv *client, int sock, u_short length,
rnh = zebra_lookup_rnh(&p, zvrf_id (zvrf), type);
if (rnh)
{
- client->nh_dereg_time = quagga_monotime();
+ client->nh_dereg_time = monotime(NULL);
zebra_remove_rnh_client(rnh, client, type);
}
}
@@ -1826,7 +1825,7 @@ zebra_client_create (int sock)
/* Set table number. */
client->rtm_table = zebrad.rtm_table_default;
- client->connect_time = quagga_monotime();
+ client->connect_time = monotime(NULL);
/* Initialize flags */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
@@ -1952,7 +1951,7 @@ zebra_client_read (struct thread *thread)
zlog_debug ("zebra message received [%s] %d in VRF %u",
zserv_command_string (command), length, vrf_id);
- client->last_read_time = quagga_monotime();
+ client->last_read_time = monotime(NULL);
client->last_read_cmd = command;
zvrf = zebra_vrf_lookup_by_id (vrf_id);
@@ -2051,6 +2050,9 @@ zebra_client_read (struct thread *thread)
case ZEBRA_MPLS_LABELS_DELETE:
zread_mpls_labels (command, client, length, vrf_id);
break;
+ case ZEBRA_IPMR_ROUTE_STATS:
+ zebra_ipmr_route_stats (client, sock, length, zvrf);
+ break;
default:
zlog_info ("Zebra received unknown command %d", command);
break;
@@ -2263,7 +2265,7 @@ zserv_time_buf(time_t *time1, char *buf, int buflen)
return (buf);
}
- now = quagga_monotime();
+ now = monotime(NULL);
now -= *time1;
tm = gmtime(&now);