summaryrefslogtreecommitdiff
path: root/pimd/pim_mroute.c
diff options
context:
space:
mode:
Diffstat (limited to 'pimd/pim_mroute.c')
-rw-r--r--pimd/pim_mroute.c657
1 files changed, 450 insertions, 207 deletions
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;
}