diff options
Diffstat (limited to 'pimd/pim_mroute.c')
| -rw-r--r-- | pimd/pim_mroute.c | 657 |
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; } |
