[pim] Hooks for ssmpingd support
diff --git a/lib/memtypes.c b/lib/memtypes.c
index 26e27e7..4ed1e89 100644
--- a/lib/memtypes.c
+++ b/lib/memtypes.c
@@ -268,6 +268,7 @@
{ 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 692c2fc..a4073f5 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -2137,6 +2137,47 @@
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 @@
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 @@
"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 @@
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 @@
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 @@
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 @@
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 f3b2f96..800bfcb 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 e4b16aa..4eb5c8d 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 32563ae..4bef20b 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 7d69b5b..0b06d0e 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 @@
++writes;
}
+ if (PIM_DEBUG_SSMPINGD) {
+ vty_out(vty, "debug ssmpingd%s", VTY_NEWLINE);
+ ++writes;
+ }
+
return writes;
}
@@ -78,6 +84,19 @@
++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 @@
/* 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 @@
/* 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 @@
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 @@
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 bdf83b4..a2dc643 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 @@
#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 @@
#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 @@
#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);