[pim] Packet dump debugging
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index eed7492..d42f3bf 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -3086,6 +3086,10 @@
   PIM_DONT_DEBUG_PIM_EVENTS;
   PIM_DONT_DEBUG_PIM_PACKETS;
   PIM_DONT_DEBUG_PIM_TRACE;
+
+  PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND;
+  PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV;
+
   return CMD_SUCCESS;
 }
 
@@ -3155,6 +3159,72 @@
        DEBUG_PIM_STR
        DEBUG_PIM_PACKETS_STR)
 
+DEFUN (debug_pim_packetdump_send,
+       debug_pim_packetdump_send_cmd,
+       "debug pim packet-dump send",
+       DEBUG_STR
+       DEBUG_PIM_STR
+       DEBUG_PIM_PACKETDUMP_STR
+       DEBUG_PIM_PACKETDUMP_SEND_STR)
+{
+  PIM_DO_DEBUG_PIM_PACKETDUMP_SEND;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_pim_packetdump_send,
+       no_debug_pim_packetdump_send_cmd,
+       "no debug pim packet-dump send",
+       NO_STR
+       DEBUG_STR
+       DEBUG_PIM_STR
+       DEBUG_PIM_PACKETDUMP_STR
+       DEBUG_PIM_PACKETDUMP_SEND_STR)
+{
+  PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND;
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_pim_packetdump_send,
+       undebug_pim_packetdump_send_cmd,
+       "undebug pim packet-dump send",
+       UNDEBUG_STR
+       DEBUG_PIM_STR
+       DEBUG_PIM_PACKETDUMP_STR
+       DEBUG_PIM_PACKETDUMP_SEND_STR)
+
+DEFUN (debug_pim_packetdump_recv,
+       debug_pim_packetdump_recv_cmd,
+       "debug pim packet-dump receive",
+       DEBUG_STR
+       DEBUG_PIM_STR
+       DEBUG_PIM_PACKETDUMP_STR
+       DEBUG_PIM_PACKETDUMP_RECV_STR)
+{
+  PIM_DO_DEBUG_PIM_PACKETDUMP_RECV;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_pim_packetdump_recv,
+       no_debug_pim_packetdump_recv_cmd,
+       "no debug pim packet-dump receive",
+       NO_STR
+       DEBUG_STR
+       DEBUG_PIM_STR
+       DEBUG_PIM_PACKETDUMP_STR
+       DEBUG_PIM_PACKETDUMP_RECV_STR)
+{
+  PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV;
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_pim_packetdump_recv,
+       undebug_pim_packetdump_recv_cmd,
+       "undebug pim packet-dump receive",
+       UNDEBUG_STR
+       DEBUG_PIM_STR
+       DEBUG_PIM_PACKETDUMP_STR
+       DEBUG_PIM_PACKETDUMP_RECV_STR)
+
 DEFUN (debug_pim_trace,
        debug_pim_trace_cmd,
        "debug pim trace",
@@ -4047,6 +4117,12 @@
   install_element (ENABLE_NODE, &debug_pim_packets_cmd);
   install_element (ENABLE_NODE, &no_debug_pim_packets_cmd);
   install_element (ENABLE_NODE, &undebug_pim_packets_cmd);
+  install_element (ENABLE_NODE, &debug_pim_packetdump_send_cmd);
+  install_element (ENABLE_NODE, &no_debug_pim_packetdump_send_cmd);
+  install_element (ENABLE_NODE, &undebug_pim_packetdump_send_cmd);
+  install_element (ENABLE_NODE, &debug_pim_packetdump_recv_cmd);
+  install_element (ENABLE_NODE, &no_debug_pim_packetdump_recv_cmd);
+  install_element (ENABLE_NODE, &undebug_pim_packetdump_recv_cmd);
   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);
diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h
index 800bfcb..fd1a62f 100644
--- a/pimd/pim_cmd.h
+++ b/pimd/pim_cmd.h
@@ -41,6 +41,9 @@
 #define DEBUG_PIM_STR                               "PIM protocol activity\n"
 #define DEBUG_PIM_EVENTS_STR                        "PIM protocol events\n"
 #define DEBUG_PIM_PACKETS_STR                       "PIM 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"
 #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"
diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c
index 9b6dc35..9595d2d 100644
--- a/pimd/pim_pim.c
+++ b/pimd/pim_pim.c
@@ -169,6 +169,10 @@
   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);
@@ -289,6 +293,10 @@
 	       len, from_str, to_str, fd, ifindex, ifp->ifindex);
   }
 
+  if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
+    pim_pkt_dump(__PRETTY_FUNCTION__, buf, len);
+  }
+
 #ifdef PIM_CHECK_RECV_IFINDEX_SANITY
   /* ifindex sanity check */
   if (ifindex != (int) ifp->ifindex) {
@@ -456,6 +464,10 @@
 #endif
   tolen = sizeof(to);
 
+  if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
+    pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size);
+  }
+
   sent = sendto(fd, pim_msg, pim_msg_size, MSG_DONTWAIT, &to, tolen);
   if (sent != (ssize_t) pim_msg_size) {
     int e = errno;
diff --git a/pimd/pim_util.c b/pimd/pim_util.c
index 5bc8d07..13230c0 100644
--- a/pimd/pim_util.c
+++ b/pimd/pim_util.c
@@ -20,6 +20,10 @@
   $QuaggaId: $Format:%an, %ai, %h$ $
 */
 
+#include <zebra.h>
+
+#include "log.h"
+
 #include "pim_util.h"
 
 /*
@@ -130,3 +134,26 @@
   return checksum;
 }
 #endif /* PIM_USE_QUAGGA_INET_CHECKSUM */
+
+void pim_pkt_dump(const char *label, const char *buf, int size)
+{
+  char dump_buf[1000];
+  int i = 0;
+  int j = 0;
+
+  for (; i < size; ++i, j += 3) {
+    int left = sizeof(dump_buf) - j;
+    if (left < 4) {
+      if (left > 1) {
+	strcat(dump_buf + j, "!"); /* mark as truncated */
+      }
+      break;
+    }
+    snprintf(dump_buf + j, left, " %02x", buf[i]);
+  }
+
+  zlog_debug("%s: pkt dump size=%d:%s",
+	     label,
+	     size,
+	     dump_buf);
+}
diff --git a/pimd/pim_util.h b/pimd/pim_util.h
index 0fcdce0..5863d5f 100644
--- a/pimd/pim_util.h
+++ b/pimd/pim_util.h
@@ -38,4 +38,6 @@
 uint16_t pim_inet_checksum(const char *buf, int size);
 #endif /* PIM_USE_QUAGGA_INET_CHECKSUM */
 
+void pim_pkt_dump(const char *label, const char *buf, int size);
+
 #endif /* PIM_UTIL_H */
diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c
index 0b06d0e..3a1abf1 100644
--- a/pimd/pim_vty.c
+++ b/pimd/pim_vty.c
@@ -57,6 +57,14 @@
     vty_out(vty, "debug pim packets%s", VTY_NEWLINE);
     ++writes;
   }
+  if (PIM_DEBUG_PIM_PACKETDUMP_SEND) {
+    vty_out(vty, "debug pim packet-dump send%s", VTY_NEWLINE);
+    ++writes;
+  }
+  if (PIM_DEBUG_PIM_PACKETDUMP_RECV) {
+    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;
diff --git a/pimd/pimd.h b/pimd/pimd.h
index b42c54c..1dcd865 100644
--- a/pimd/pimd.h
+++ b/pimd/pimd.h
@@ -53,14 +53,16 @@
 #define PIM_INADDR_IS_ANY(addr) ((addr).s_addr == PIM_NET_INADDR_ANY) /* struct in_addr addr */
 #define PIM_INADDR_ISNOT_ANY(addr) ((addr).s_addr != PIM_NET_INADDR_ANY) /* struct in_addr addr */
 
-#define PIM_MASK_PIM_EVENTS   (1 << 0)
-#define PIM_MASK_PIM_PACKETS  (1 << 1)
-#define PIM_MASK_PIM_TRACE    (1 << 2)
-#define PIM_MASK_IGMP_EVENTS  (1 << 3)
-#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)
+#define PIM_MASK_PIM_EVENTS          (1 << 0)
+#define PIM_MASK_PIM_PACKETS         (1 << 1)
+#define PIM_MASK_PIM_PACKETDUMP_SEND (1 << 2)
+#define PIM_MASK_PIM_PACKETDUMP_RECV (1 << 3)
+#define PIM_MASK_PIM_TRACE           (1 << 4)
+#define PIM_MASK_IGMP_EVENTS         (1 << 5)
+#define PIM_MASK_IGMP_PACKETS        (1 << 6)
+#define PIM_MASK_IGMP_TRACE          (1 << 7)
+#define PIM_MASK_ZEBRA               (1 << 8)
+#define PIM_MASK_SSMPINGD            (1 << 9)
 
 const char *const PIM_ALL_SYSTEMS;
 const char *const PIM_ALL_ROUTERS;
@@ -93,36 +95,42 @@
 #define PIM_MROUTE_IS_ENABLED  (qpim_mroute_socket_fd >= 0)
 #define PIM_MROUTE_IS_DISABLED (qpim_mroute_socket_fd < 0)
 
-#define PIM_DEBUG_PIM_EVENTS   (qpim_debugs & PIM_MASK_PIM_EVENTS)
-#define PIM_DEBUG_PIM_PACKETS  (qpim_debugs & PIM_MASK_PIM_PACKETS)
-#define PIM_DEBUG_PIM_TRACE    (qpim_debugs & PIM_MASK_PIM_TRACE)
-#define PIM_DEBUG_IGMP_EVENTS  (qpim_debugs & PIM_MASK_IGMP_EVENTS)
-#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_PIM_EVENTS          (qpim_debugs & PIM_MASK_PIM_EVENTS)
+#define PIM_DEBUG_PIM_PACKETS         (qpim_debugs & PIM_MASK_PIM_PACKETS)
+#define PIM_DEBUG_PIM_PACKETDUMP_SEND (qpim_debugs & PIM_MASK_PIM_PACKETDUMP_SEND)
+#define PIM_DEBUG_PIM_PACKETDUMP_RECV (qpim_debugs & PIM_MASK_PIM_PACKETDUMP_RECV)
+#define PIM_DEBUG_PIM_TRACE           (qpim_debugs & PIM_MASK_PIM_TRACE)
+#define PIM_DEBUG_IGMP_EVENTS         (qpim_debugs & PIM_MASK_IGMP_EVENTS)
+#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))
 #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)
-#define PIM_DO_DEBUG_PIM_PACKETS  (qpim_debugs |= PIM_MASK_PIM_PACKETS)
-#define PIM_DO_DEBUG_PIM_TRACE    (qpim_debugs |= PIM_MASK_PIM_TRACE)
-#define PIM_DO_DEBUG_IGMP_EVENTS  (qpim_debugs |= PIM_MASK_IGMP_EVENTS)
-#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_DO_DEBUG_PIM_EVENTS          (qpim_debugs |= PIM_MASK_PIM_EVENTS)
+#define PIM_DO_DEBUG_PIM_PACKETS         (qpim_debugs |= PIM_MASK_PIM_PACKETS)
+#define PIM_DO_DEBUG_PIM_PACKETDUMP_SEND (qpim_debugs |= PIM_MASK_PIM_PACKETDUMP_SEND)
+#define PIM_DO_DEBUG_PIM_PACKETDUMP_RECV (qpim_debugs |= PIM_MASK_PIM_PACKETDUMP_RECV)
+#define PIM_DO_DEBUG_PIM_TRACE           (qpim_debugs |= PIM_MASK_PIM_TRACE)
+#define PIM_DO_DEBUG_IGMP_EVENTS         (qpim_debugs |= PIM_MASK_IGMP_EVENTS)
+#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)
-#define PIM_DONT_DEBUG_PIM_TRACE    (qpim_debugs &= ~PIM_MASK_PIM_TRACE)
-#define PIM_DONT_DEBUG_IGMP_EVENTS  (qpim_debugs &= ~PIM_MASK_IGMP_EVENTS)
-#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)
+#define PIM_DONT_DEBUG_PIM_EVENTS          (qpim_debugs &= ~PIM_MASK_PIM_EVENTS)
+#define PIM_DONT_DEBUG_PIM_PACKETS         (qpim_debugs &= ~PIM_MASK_PIM_PACKETS)
+#define PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND (qpim_debugs &= ~PIM_MASK_PIM_PACKETDUMP_SEND)
+#define PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV (qpim_debugs &= ~PIM_MASK_PIM_PACKETDUMP_RECV)
+#define PIM_DONT_DEBUG_PIM_TRACE           (qpim_debugs &= ~PIM_MASK_PIM_TRACE)
+#define PIM_DONT_DEBUG_IGMP_EVENTS         (qpim_debugs &= ~PIM_MASK_IGMP_EVENTS)
+#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);