diff options
-rw-r--r-- | lib/memtypes.c | 1 | ||||
-rw-r--r-- | pimd/pim_cmd.c | 82 | ||||
-rw-r--r-- | pimd/pim_cmd.h | 4 | ||||
-rw-r--r-- | pimd/pim_ssmpingd.c | 304 | ||||
-rw-r--r-- | pimd/pim_ssmpingd.h | 2 | ||||
-rw-r--r-- | pimd/pim_vty.c | 32 | ||||
-rw-r--r-- | pimd/pimd.h | 4 |
7 files changed, 418 insertions, 11 deletions
diff --git a/lib/memtypes.c b/lib/memtypes.c index 26e27e72..4ed1e895 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -268,6 +268,7 @@ struct memory_list memory_list_pim[] = { MTYPE_PIM_NEIGHBOR, "PIM interface neighbor" }, { MTYPE_PIM_IFCHANNEL, "PIM interface (S,G) state" }, { MTYPE_PIM_UPSTREAM, "PIM upstream (S,G) state" }, + { MTYPE_PIM_SSMPINGD, "PIM sspimgd socket" }, { -1, NULL }, }; diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 692c2fcc..a4073f50 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -2137,6 +2137,47 @@ DEFUN (show_ip_route, return CMD_SUCCESS; } +static void show_ssmpingd(struct vty *vty) +{ + struct listnode *node; + struct ssmpingd_sock *ss; + time_t now; + + vty_out(vty, "Source Socket Uptime Requests%s", + VTY_NEWLINE); + + if (!qpim_ssmpingd_list) + return; + + now = pim_time_monotonic_sec(); + + for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) { + char source_str[100]; + char ss_uptime[10]; + + pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str)); + pim_time_uptime(ss_uptime, sizeof(ss_uptime), now - ss->creation); + + vty_out(vty, "%-15s %6d %8s %8lld%s", + source_str, + ss->sock_fd, + ss_uptime, + ss->requests, + VTY_NEWLINE); + } +} + +DEFUN (show_ip_ssmpingd, + show_ip_ssmpingd_cmd, + "show ip ssmpingd", + SHOW_STR + IP_STR + SHOW_SSMPINGD_STR) +{ + show_ssmpingd(vty); + return CMD_SUCCESS; +} + static void mroute_add_all() { struct listnode *node; @@ -2205,7 +2246,7 @@ DEFUN (ip_ssmpingd, ip_ssmpingd_cmd, "ip ssmpingd [A.B.C.D]", IP_STR - SSMPINGD_STR + CONF_SSMPINGD_STR "Source address\n") { int result; @@ -2234,7 +2275,7 @@ DEFUN (no_ip_ssmpingd, "no ip ssmpingd [A.B.C.D]", NO_STR IP_STR - SSMPINGD_STR + CONF_SSMPINGD_STR "Source address\n") { int result; @@ -3132,6 +3173,36 @@ ALIAS (no_debug_pim_trace, DEBUG_PIM_STR DEBUG_PIM_TRACE_STR) +DEFUN (debug_ssmpingd, + debug_ssmpingd_cmd, + "debug ssmpingd", + DEBUG_STR + DEBUG_PIM_STR + DEBUG_SSMPINGD_STR) +{ + PIM_DO_DEBUG_SSMPINGD; + return CMD_SUCCESS; +} + +DEFUN (no_debug_ssmpingd, + no_debug_ssmpingd_cmd, + "no debug ssmpingd", + NO_STR + DEBUG_STR + DEBUG_PIM_STR + DEBUG_SSMPINGD_STR) +{ + PIM_DONT_DEBUG_SSMPINGD; + return CMD_SUCCESS; +} + +ALIAS (no_debug_ssmpingd, + undebug_ssmpingd_cmd, + "undebug ssmpingd", + UNDEBUG_STR + DEBUG_PIM_STR + DEBUG_SSMPINGD_STR) + DEFUN (debug_pim_zebra, debug_pim_zebra_cmd, "debug pim zebra", @@ -3897,6 +3968,7 @@ void pim_cmd_init() install_element (VIEW_NODE, &show_ip_mroute_cmd); install_element (VIEW_NODE, &show_ip_mroute_count_cmd); install_element (VIEW_NODE, &show_ip_route_cmd); + install_element (VIEW_NODE, &show_ip_ssmpingd_cmd); install_element (VIEW_NODE, &show_debugging_cmd); install_element (ENABLE_NODE, &clear_ip_interfaces_cmd); @@ -3965,6 +4037,9 @@ void pim_cmd_init() install_element (ENABLE_NODE, &debug_pim_trace_cmd); install_element (ENABLE_NODE, &no_debug_pim_trace_cmd); install_element (ENABLE_NODE, &undebug_pim_trace_cmd); + install_element (ENABLE_NODE, &debug_ssmpingd_cmd); + install_element (ENABLE_NODE, &no_debug_ssmpingd_cmd); + install_element (ENABLE_NODE, &undebug_ssmpingd_cmd); install_element (ENABLE_NODE, &debug_pim_zebra_cmd); install_element (ENABLE_NODE, &no_debug_pim_zebra_cmd); install_element (ENABLE_NODE, &undebug_pim_zebra_cmd); @@ -3993,6 +4068,9 @@ void pim_cmd_init() install_element (CONFIG_NODE, &debug_pim_trace_cmd); install_element (CONFIG_NODE, &no_debug_pim_trace_cmd); install_element (CONFIG_NODE, &undebug_pim_trace_cmd); + install_element (CONFIG_NODE, &debug_ssmpingd_cmd); + install_element (CONFIG_NODE, &no_debug_ssmpingd_cmd); + install_element (CONFIG_NODE, &undebug_ssmpingd_cmd); install_element (CONFIG_NODE, &debug_pim_zebra_cmd); install_element (CONFIG_NODE, &no_debug_pim_zebra_cmd); install_element (CONFIG_NODE, &undebug_pim_zebra_cmd); diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h index f3b2f96c..800bfcb4 100644 --- a/pimd/pim_cmd.h +++ b/pimd/pim_cmd.h @@ -27,7 +27,8 @@ #define IGMP_STR "IGMP information\n" #define IGMP_GROUP_STR "IGMP groups information\n" #define IGMP_SOURCE_STR "IGMP sources information\n" -#define SSMPINGD_STR "Enable ssmpingd operation\n" +#define CONF_SSMPINGD_STR "Enable ssmpingd operation\n" +#define SHOW_SSMPINGD_STR "ssmpingd operation\n" #define IFACE_PIM_STR "Enable PIM SSM operation\n" #define IFACE_IGMP_STR "Enable IGMP operation\n" #define IFACE_IGMP_QUERY_INTERVAL_STR "IGMP host query interval\n" @@ -42,6 +43,7 @@ #define DEBUG_PIM_PACKETS_STR "PIM protocol packets\n" #define DEBUG_PIM_TRACE_STR "PIM internal daemon activity\n" #define DEBUG_PIM_ZEBRA_STR "ZEBRA protocol activity\n" +#define DEBUG_SSMPINGD_STR "ssmpingd activity\n" #define CLEAR_IP_IGMP_STR "IGMP clear commands\n" #define CLEAR_IP_PIM_STR "PIM clear commands\n" #define MROUTE_STR "IP multicast routing table\n" diff --git a/pimd/pim_ssmpingd.c b/pimd/pim_ssmpingd.c index e4b16aa3..4eb5c8dc 100644 --- a/pimd/pim_ssmpingd.c +++ b/pimd/pim_ssmpingd.c @@ -20,26 +20,328 @@ $QuaggaId: $Format:%an, %ai, %h$ $ */ +#include <zebra.h> + +#include "if.h" +#include "log.h" +#include "memory.h" + #include "pim_ssmpingd.h" #include "pim_time.h" +#include "pim_sock.h" +#include "pim_str.h" #include "pimd.h" +static void ssmpingd_read_on(struct ssmpingd_sock *ss); + void pim_ssmpingd_init() { + zassert(!qpim_ssmpingd_list); } void pim_ssmpingd_destroy() { - if (qpim_ssmpingd_list) + if (qpim_ssmpingd_list) { list_free(qpim_ssmpingd_list); + qpim_ssmpingd_list = 0; + } +} + +static struct ssmpingd_sock *ssmpingd_find(struct in_addr source_addr) +{ + struct listnode *node; + struct ssmpingd_sock *ss; + + if (!qpim_ssmpingd_list) + return 0; + + for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) + if (source_addr.s_addr == ss->source_addr.s_addr) + return ss; + + return 0; +} + +static void ssmpingd_free(struct ssmpingd_sock *ss) +{ + XFREE(MTYPE_PIM_SSMPINGD, ss); +} + +static int ssmpingd_socket(struct in_addr addr, int mttl) +{ + int fd; + + fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (fd < 0) { + zlog_err("%s: could not create socket: errno=%d: %s", + __PRETTY_FUNCTION__, errno, safe_strerror(errno)); + return -1; + } + + /* Needed to obtain destination address from recvmsg() */ + { +#if defined(HAVE_IP_PKTINFO) + /* Linux IP_PKTINFO */ + int opt = 1; + if (setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt))) { + zlog_warn("Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s", + fd, errno, safe_strerror(errno)); + } +#elif defined(HAVE_IP_RECVDSTADDR) + /* BSD IP_RECVDSTADDR */ + int opt = 1; + if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt))) { + zlog_warn("Could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s", + fd, errno, safe_strerror(errno)); + } +#else + zlog_err("%s %s: missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()", + __FILE__, __PRETTY_FUNCTION__); + close(fd); + return -1; +#endif + } + + { + int reuse = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + (void *) &reuse, sizeof(reuse))) { + zlog_warn("%s: could not set Reuse Address Option on socket fd=%d: errno=%d: %s", + __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); + close(fd); + return -1; + } + } + + if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, + (void *) &mttl, sizeof(mttl))) { + zlog_warn("%s: could not set multicast TTL=%d on socket fd=%d: errno=%d: %s", + __PRETTY_FUNCTION__, mttl, fd, errno, safe_strerror(errno)); + close(fd); + return -1; + } + + if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, + (void *) &addr, sizeof(addr))) { + zlog_warn("%s: could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s", + __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); + close(fd); + return -1; + } + + { + long flags; + + flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) { + zlog_warn("%s: could not get fcntl(F_GETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s", + __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); + close(fd); + return -1; + } + + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { + zlog_warn("%s: could not set fcntl(F_SETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s", + __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); + close(fd); + return -1; + } + } + + return fd; +} + +static void ssmpingd_delete(struct ssmpingd_sock *ss) +{ + zassert(ss); + zassert(qpim_ssmpingd_list); + + THREAD_OFF(ss->t_sock_read); + + if (close(ss->sock_fd)) { + int e = errno; + char source_str[100]; + 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)); + /* warning only */ + } + + listnode_delete(qpim_ssmpingd_list, ss); + ssmpingd_free(ss); +} + +static int ssmpingd_read_msg(struct ssmpingd_sock *ss) +{ + struct interface *ifp; + struct sockaddr_in from; + struct sockaddr_in to; + socklen_t fromlen = sizeof(from); + socklen_t tolen = sizeof(to); + int ifindex = -1; + char buf[1000]; + int len; + + len = pim_socket_recvfromto(ss->sock_fd, buf, sizeof(buf), + &from, &fromlen, + &to, &tolen, + &ifindex); + if (len < 0) { + char source_str[100]; + 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)); + return -1; + } + + ifp = if_lookup_by_index(ifindex); + + if (PIM_DEBUG_SSMPINGD) { + char source_str[100]; + char from_str[100]; + char to_str[100]; + 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)); + zlog_debug("%s: ssmpingd on source %s: interface %s ifindex=%d received ssmping from %s to %s on fd=%d", + __PRETTY_FUNCTION__, + source_str, + ifp ? ifp->name : "<iface?>", + ifindex, from_str, to_str, ss->sock_fd); + } + + return 0; +} + +static int ssmpingd_sock_read(struct thread *t) +{ + struct ssmpingd_sock *ss; + int sock_fd; + int result; + + zassert(t); + + ss = THREAD_ARG(t); + zassert(ss); + + sock_fd = THREAD_FD(t); + zassert(sock_fd == ss->sock_fd); + + result = ssmpingd_read_msg(ss); + + /* Keep reading */ + ss->t_sock_read = 0; + ssmpingd_read_on(ss); + + return result; +} + +static void ssmpingd_read_on(struct ssmpingd_sock *ss) +{ + zassert(!ss->t_sock_read); + THREAD_READ_ON(master, ss->t_sock_read, + ssmpingd_sock_read, ss, ss->sock_fd); +} + +static struct ssmpingd_sock *ssmpingd_new(struct in_addr source_addr) +{ + struct ssmpingd_sock *ss; + int sock_fd; + + if (!qpim_ssmpingd_list) { + qpim_ssmpingd_list = list_new(); + if (!qpim_ssmpingd_list) { + zlog_err("%s %s: failure: qpim_ssmpingd_list=list_new()", + __FILE__, __PRETTY_FUNCTION__); + return 0; + } + qpim_ssmpingd_list->del = (void (*)(void *)) ssmpingd_free; + } + + sock_fd = ssmpingd_socket(source_addr, 64 /* ttl */); + if (sock_fd < 0) { + char source_str[100]; + 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)); + if (!ss) { + char source_str[100]; + pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); + zlog_err("%s: XMALLOC(%d) failure for ssmpingd source %s", + __PRETTY_FUNCTION__, + sizeof(*ss), source_str); + close(sock_fd); + return 0; + } + + ss->sock_fd = sock_fd; + ss->t_sock_read = 0; + ss->source_addr = source_addr; + ss->creation = pim_time_monotonic_sec(); + ss->requests = 0; + + listnode_add(qpim_ssmpingd_list, ss); + + ssmpingd_read_on(ss); + + return ss; } int pim_ssmpingd_start(struct in_addr source_addr) { + struct ssmpingd_sock *ss; + + ss = ssmpingd_find(source_addr); + if (ss) { + /* silently ignore request to recreate entry */ + return 0; + } + + { + char source_str[100]; + pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); + zlog_info("%s: starting ssmpingd for source %s", + __PRETTY_FUNCTION__, source_str); + } + + ss = ssmpingd_new(source_addr); + if (!ss) { + char source_str[100]; + pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); + zlog_warn("%s: ssmpingd_new() failure for source %s", + __PRETTY_FUNCTION__, source_str); + return -1; + } + return 0; } int pim_ssmpingd_stop(struct in_addr source_addr) { + struct ssmpingd_sock *ss; + + ss = ssmpingd_find(source_addr); + if (!ss) { + char source_str[100]; + 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); + return -1; + } + + { + char source_str[100]; + pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str)); + zlog_info("%s: stopping ssmpingd for source %s", + __PRETTY_FUNCTION__, source_str); + } + + ssmpingd_delete(ss); + return 0; } diff --git a/pimd/pim_ssmpingd.h b/pimd/pim_ssmpingd.h index 32563aeb..4bef20b2 100644 --- a/pimd/pim_ssmpingd.h +++ b/pimd/pim_ssmpingd.h @@ -32,7 +32,7 @@ struct ssmpingd_sock { int sock_fd; /* socket */ struct thread *t_sock_read; /* thread for reading socket */ - struct in_addr source; /* source address */ + struct in_addr source_addr; /* source address */ int64_t creation; /* timestamp of socket creation */ int64_t requests; /* counter */ }; diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 7d69b5b1..0b06d0ec 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -30,6 +30,7 @@ #include "pim_iface.h" #include "pim_cmd.h" #include "pim_str.h" +#include "pim_ssmpingd.h" int pim_debug_config_write(struct vty *vty) { @@ -66,6 +67,11 @@ int pim_debug_config_write(struct vty *vty) ++writes; } + if (PIM_DEBUG_SSMPINGD) { + vty_out(vty, "debug ssmpingd%s", VTY_NEWLINE); + ++writes; + } + return writes; } @@ -78,6 +84,19 @@ int pim_global_config_write(struct vty *vty) ++writes; } + if (qpim_ssmpingd_list) { + struct listnode *node; + struct ssmpingd_sock *ss; + vty_out(vty, "!%s", VTY_NEWLINE); + ++writes; + for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) { + char source_str[100]; + pim_inet4_dump("<src?>", ss->source_addr, source_str, sizeof(source_str)); + vty_out(vty, "ip ssmpingd %s%s", source_str, VTY_NEWLINE); + ++writes; + } + } + return writes; } @@ -91,7 +110,7 @@ int pim_interface_config_write(struct vty *vty) /* IF name */ vty_out(vty, "interface %s%s", ifp->name, VTY_NEWLINE); - writes++; + ++writes; if (ifp->info) { struct pim_interface *pim_ifp = ifp->info; @@ -99,13 +118,13 @@ int pim_interface_config_write(struct vty *vty) /* IF ip pim ssm */ if (PIM_IF_TEST_PIM(pim_ifp->options)) { vty_out(vty, " ip pim ssm%s", VTY_NEWLINE); - writes++; + ++writes; } /* IF ip igmp */ if (PIM_IF_TEST_IGMP(pim_ifp->options)) { vty_out(vty, " ip igmp%s", VTY_NEWLINE); - writes++; + ++writes; } /* IF ip igmp query-interval */ @@ -113,14 +132,14 @@ int pim_interface_config_write(struct vty *vty) PIM_CMD_IP_IGMP_QUERY_INTERVAL, pim_ifp->igmp_default_query_interval, VTY_NEWLINE); - writes++; + ++writes; /* IF ip igmp query-max-response-time */ vty_out(vty, " %s %d%s", PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC, pim_ifp->igmp_query_max_response_time_dsec, VTY_NEWLINE); - writes++; + ++writes; /* IF ip igmp join */ if (pim_ifp->igmp_join_list) { @@ -134,11 +153,12 @@ int pim_interface_config_write(struct vty *vty) vty_out(vty, " ip igmp join %s %s%s", group_str, source_str, VTY_NEWLINE); - writes++; + ++writes; } } } vty_out(vty, "!%s", VTY_NEWLINE); + ++writes; } return writes; diff --git a/pimd/pimd.h b/pimd/pimd.h index bdf83b43..a2dc6430 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -60,6 +60,7 @@ #define PIM_MASK_IGMP_PACKETS (1 << 4) #define PIM_MASK_IGMP_TRACE (1 << 5) #define PIM_MASK_ZEBRA (1 << 6) +#define PIM_MASK_SSMPINGD (1 << 7) const char *const PIM_ALL_SYSTEMS; const char *const PIM_ALL_ROUTERS; @@ -98,6 +99,7 @@ struct list *qpim_ssmpingd_list; /* list of struct ssmpingd_sock */ #define PIM_DEBUG_IGMP_PACKETS (qpim_debugs & PIM_MASK_IGMP_PACKETS) #define PIM_DEBUG_IGMP_TRACE (qpim_debugs & PIM_MASK_IGMP_TRACE) #define PIM_DEBUG_ZEBRA (qpim_debugs & PIM_MASK_ZEBRA) +#define PIM_DEBUG_SSMPINGD (qpim_debugs & PIM_MASK_SSMPINGD) #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)) @@ -110,6 +112,7 @@ struct list *qpim_ssmpingd_list; /* list of struct ssmpingd_sock */ #define PIM_DO_DEBUG_IGMP_PACKETS (qpim_debugs |= PIM_MASK_IGMP_PACKETS) #define PIM_DO_DEBUG_IGMP_TRACE (qpim_debugs |= PIM_MASK_IGMP_TRACE) #define PIM_DO_DEBUG_ZEBRA (qpim_debugs |= PIM_MASK_ZEBRA) +#define PIM_DO_DEBUG_SSMPINGD (qpim_debugs |= PIM_MASK_SSMPINGD) #define PIM_DONT_DEBUG_PIM_EVENTS (qpim_debugs &= ~PIM_MASK_PIM_EVENTS) #define PIM_DONT_DEBUG_PIM_PACKETS (qpim_debugs &= ~PIM_MASK_PIM_PACKETS) @@ -118,6 +121,7 @@ struct list *qpim_ssmpingd_list; /* list of struct ssmpingd_sock */ #define PIM_DONT_DEBUG_IGMP_PACKETS (qpim_debugs &= ~PIM_MASK_IGMP_PACKETS) #define PIM_DONT_DEBUG_IGMP_TRACE (qpim_debugs &= ~PIM_MASK_IGMP_TRACE) #define PIM_DONT_DEBUG_ZEBRA (qpim_debugs &= ~PIM_MASK_ZEBRA) +#define PIM_DONT_DEBUG_SSMPINGD (qpim_debugs &= ~PIM_MASK_SSMPINGD) void pim_init(void); void pim_terminate(void); |