C18 MFC never recovers from removal of static route to source
diff --git a/pimd/CAVEATS b/pimd/CAVEATS
index c436d55..05a439b 100644
--- a/pimd/CAVEATS
+++ b/pimd/CAVEATS
@@ -134,4 +134,28 @@
 
 C17 SNMP / RFC 5060 (PIM MIB) is not supported.
 
+C18 MFC never recovers from removal of static route to source
+
+    # route add -host 1.2.3.4 gw 192.168.56.10
+    Before removal:
+    quagga-pimd-router# sh ip mroute
+    Source          Group           Proto Input iVifI Output oVifI TTL Uptime
+    1.2.3.4         232.1.2.3       I     eth1      3 eth0       2   1 00:00:36
+
+    # route del -host 1.2.3.4 gw 192.168.56.10
+    After removal: sh ip mroute --> empty output
+
+    # route add -host 1.2.3.4 gw 192.168.56.10
+    After the route is restored: sh ip mroute --> never recovers (empty output)
+
+    At this point, "no ip pim ssm" on the upstream interface (eth0) crashes pimd:
+
+    2014/02/14 16:30:14 PIM: ifmembership_set: (S,G)=(1.2.3.4,232.1.2.3) membership now is NOINFO on interface eth0
+    2014/02/14 16:30:14 PIM: pim_ifchannel_update_assert_tracking_desired: AssertTrackingDesired(1.2.3.4,232.1.2.3,eth0) changed from 1 to 0
+    2014/02/14 16:30:14 PIM: pim_zebra.c del_oif: nonexistent protocol mask 2 removed OIF eth0 (vif_index=2, min_ttl=0) from channel (S,G)=(1.2.3.4,232.1.2.3)
+    2014/02/14 16:30:14 PIM: pim_ifchannel_update_could_assert: CouldAssert(1.2.3.4,232.1.2.3,eth0) changed from 1 to 0
+    2014/02/14 16:30:14 PIM: pim_ifchannel_update_my_assert_metric: my_assert_metric(1.2.3.4,232.1.2.3,eth0) changed from 0,0,0,10.0.2.15 to 1,4294967295,4294967295,0.0.0.0
+    2014/02/14 16:30:14 PIM: pim_zebra.c del_oif: nonexistent protocol mask 1 removed OIF eth0 (vif_index=2, min_ttl=0) from channel (S,G)=(1.2.3.4,232.1.2.3)
+    2014/02/14 16:30:14 PIM: Assertion `!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)' failed in file pim_igmpv3.c, line 412, function igmp_source_delete
+
 -x-
diff --git a/pimd/COMMANDS b/pimd/COMMANDS
index fb09e6c..6210bb4 100644
--- a/pimd/COMMANDS
+++ b/pimd/COMMANDS
@@ -47,7 +47,9 @@
 debug commands:
        clear ip interfaces		Reset interfaces
        clear ip igmp interfaces		Reset IGMP interfaces
+       clear ip mroute                  Reset multicast routes
        clear ip pim interfaces		Reset PIM interfaces
+       clear ip pim oil			Rescan PIM OIL (output interface list)
        debug igmp			IGMP protocol activity
        debug mroute			PIM interaction with kernel MFC cache
        debug pim			PIM protocol activity
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index c89f2b5..25a567f 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -49,6 +49,7 @@
 #include "pim_rpf.h"
 #include "pim_macro.h"
 #include "pim_ssmpingd.h"
+#include "pim_zebra.h"
 
 static struct cmd_node pim_global_node = {
   PIM_NODE,
@@ -1097,6 +1098,25 @@
 	  refresh_uptime, VTY_NEWLINE);
 }
 
+static void show_scan_oil_stats(struct vty *vty, time_t now)
+{
+  char uptime_scan_oil[10];
+  char uptime_mroute_add[10];
+  char uptime_mroute_del[10];
+
+  pim_time_uptime_begin(uptime_scan_oil, sizeof(uptime_scan_oil), now, qpim_scan_oil_last);
+  pim_time_uptime_begin(uptime_mroute_add, sizeof(uptime_mroute_add), now, qpim_mroute_add_last);
+  pim_time_uptime_begin(uptime_mroute_del, sizeof(uptime_mroute_del), now, qpim_mroute_del_last);
+
+  vty_out(vty,
+          "Scan OIL - Last: %s  Events: %lld%s"
+          "MFC Add  - Last: %s  Events: %lld%s"
+          "MFC Del  - Last: %s  Events: %lld%s",
+          uptime_scan_oil,   (long long) qpim_scan_oil_events,   VTY_NEWLINE,
+          uptime_mroute_add, (long long) qpim_mroute_add_events, VTY_NEWLINE,
+          uptime_mroute_del, (long long) qpim_mroute_del_events, VTY_NEWLINE);
+}
+
 static void pim_show_rpf(struct vty *vty)
 {
   struct listnode     *up_node;
@@ -1576,6 +1596,57 @@
   return CMD_SUCCESS;
 }
 
+static void mroute_add_all()
+{
+  struct listnode    *node;
+  struct channel_oil *c_oil;
+
+  for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) {
+    if (pim_mroute_add(&c_oil->oil)) {
+      /* just log warning */
+      char source_str[100];
+      char group_str[100];
+      pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
+      pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
+      zlog_warn("%s %s: (S,G)=(%s,%s) failure writing MFC",
+                __FILE__, __PRETTY_FUNCTION__,
+                source_str, group_str);
+    }
+  }
+}
+
+static void mroute_del_all()
+{
+  struct listnode    *node;
+  struct channel_oil *c_oil;
+
+  for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) {
+    if (pim_mroute_del(&c_oil->oil)) {
+      /* just log warning */
+      char source_str[100];
+      char group_str[100];
+      pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
+      pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
+      zlog_warn("%s %s: (S,G)=(%s,%s) failure clearing MFC",
+                __FILE__, __PRETTY_FUNCTION__,
+                source_str, group_str);
+    }
+  }
+}
+
+DEFUN (clear_ip_mroute,
+       clear_ip_mroute_cmd,
+       "clear ip mroute",
+       CLEAR_STR
+       IP_STR
+       "Reset multicast routes\n")
+{
+  mroute_del_all();
+  mroute_add_all();
+
+  return CMD_SUCCESS;
+}
+
 DEFUN (clear_ip_pim_interfaces,
        clear_ip_pim_interfaces_cmd,
        "clear ip pim interfaces",
@@ -1589,6 +1660,19 @@
   return CMD_SUCCESS;
 }
 
+DEFUN (clear_ip_pim_oil,
+       clear_ip_pim_oil_cmd,
+       "clear ip pim oil",
+       CLEAR_STR
+       IP_STR
+       CLEAR_IP_PIM_STR
+       "Rescan PIM OIL (output interface list)\n")
+{
+  pim_scan_oil();
+
+  return CMD_SUCCESS;
+}
+
 DEFUN (show_ip_igmp_interface,
        show_ip_igmp_interface_cmd,
        "show ip igmp interface",
@@ -2026,6 +2110,10 @@
 
   show_rpf_refresh_stats(vty, now);
 
+  vty_out(vty, "%s", VTY_NEWLINE);
+
+  show_scan_oil_stats(vty, now);
+
   show_multicast_interfaces(vty);
   
   return CMD_SUCCESS;
@@ -2258,44 +2346,6 @@
   return CMD_SUCCESS;
 }
 
-static void mroute_add_all()
-{
-  struct listnode    *node;
-  struct channel_oil *c_oil;
-
-  for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) {
-    if (pim_mroute_add(&c_oil->oil)) {
-      /* just log warning */
-      char source_str[100];
-      char group_str[100]; 
-      pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
-      pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
-      zlog_warn("%s %s: (S,G)=(%s,%s) failure writing MFC",
-		__FILE__, __PRETTY_FUNCTION__,
-		source_str, group_str);
-    }
-  }
-}
-
-static void mroute_del_all()
-{
-  struct listnode    *node;
-  struct channel_oil *c_oil;
-
-  for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) {
-    if (pim_mroute_del(&c_oil->oil)) {
-      /* just log warning */
-      char source_str[100];
-      char group_str[100]; 
-      pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
-      pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
-      zlog_warn("%s %s: (S,G)=(%s,%s) failure clearing MFC",
-		__FILE__, __PRETTY_FUNCTION__,
-		source_str, group_str);
-    }
-  }
-}
-
 DEFUN (ip_multicast_routing,
        ip_multicast_routing_cmd,
        PIM_CMD_IP_MULTICAST_ROUTING,
@@ -4268,7 +4318,9 @@
 
   install_element (ENABLE_NODE, &clear_ip_interfaces_cmd);
   install_element (ENABLE_NODE, &clear_ip_igmp_interfaces_cmd);
+  install_element (ENABLE_NODE, &clear_ip_mroute_cmd);
   install_element (ENABLE_NODE, &clear_ip_pim_interfaces_cmd);
+  install_element (ENABLE_NODE, &clear_ip_pim_oil_cmd);
 
   install_element (ENABLE_NODE, &show_ip_igmp_interface_cmd);
   install_element (ENABLE_NODE, &show_ip_igmp_join_cmd);
diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c
index d883736..fa460e2 100644
--- a/pimd/pim_mroute.c
+++ b/pimd/pim_mroute.c
@@ -399,6 +399,9 @@
 {
   int err;
 
+  qpim_mroute_add_last = pim_time_monotonic_sec();
+  ++qpim_mroute_add_events;
+
   if (PIM_MROUTE_IS_DISABLED) {
     zlog_warn("%s: global multicast is disabled",
 	      __PRETTY_FUNCTION__);
@@ -424,6 +427,9 @@
 {
   int err;
 
+  qpim_mroute_del_last = pim_time_monotonic_sec();
+  ++qpim_mroute_del_events;
+
   if (PIM_MROUTE_IS_DISABLED) {
     zlog_warn("%s: global multicast is disabled",
 	      __PRETTY_FUNCTION__);
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index 74a60a5..820b0ef 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -353,12 +353,15 @@
   
 }
 
-static void scan_oil()
+void pim_scan_oil()
 {
   struct listnode    *node;
   struct listnode    *nextnode;
   struct channel_oil *c_oil;
 
+  qpim_scan_oil_last = pim_time_monotonic_sec();
+  ++qpim_scan_oil_events;
+
   for (ALL_LIST_ELEMENTS(qpim_channel_oil_list, node, nextnode, c_oil)) {
     int old_vif_index;
     int input_iface_vif_index = fib_lookup_if_vif_index(c_oil->oil.mfcc_origin);
@@ -445,7 +448,7 @@
   scan_upstream_rpf_cache();
 
   /* update kernel multicast forwarding cache (MFC) */
-  scan_oil();
+  pim_scan_oil();
 
   qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
   ++qpim_rpf_cache_refresh_events;
diff --git a/pimd/pim_zebra.h b/pimd/pim_zebra.h
index e0c9bdc..474e7a2 100644
--- a/pimd/pim_zebra.h
+++ b/pimd/pim_zebra.h
@@ -28,6 +28,8 @@
 
 void pim_zebra_init(void);
 
+void pim_scan_oil(void);
+
 void igmp_anysource_forward_start(struct igmp_group *group);
 void igmp_anysource_forward_stop(struct igmp_group *group);
 
diff --git a/pimd/pimd.c b/pimd/pimd.c
index 71b74e9..49ddc21 100644
--- a/pimd/pimd.c
+++ b/pimd/pimd.c
@@ -61,6 +61,12 @@
 struct in_addr            qpim_inaddr_any;
 struct list              *qpim_ssmpingd_list = 0;
 struct in_addr            qpim_ssmpingd_group_addr;
+int64_t                   qpim_scan_oil_events = 0;
+int64_t                   qpim_scan_oil_last = 0;
+int64_t                   qpim_mroute_add_events = 0;
+int64_t                   qpim_mroute_add_last = 0;
+int64_t                   qpim_mroute_del_events = 0;
+int64_t                   qpim_mroute_del_last = 0;
 
 static void pim_free()
 {
diff --git a/pimd/pimd.h b/pimd/pimd.h
index e11d5ba..0990088 100644
--- a/pimd/pimd.h
+++ b/pimd/pimd.h
@@ -90,6 +90,12 @@
 struct in_addr            qpim_inaddr_any;
 struct list              *qpim_ssmpingd_list; /* list of struct ssmpingd_sock */
 struct in_addr            qpim_ssmpingd_group_addr;
+int64_t                   qpim_scan_oil_events;
+int64_t                   qpim_scan_oil_last;
+int64_t                   qpim_mroute_add_events;
+int64_t                   qpim_mroute_add_last;
+int64_t                   qpim_mroute_del_events;
+int64_t                   qpim_mroute_del_last;
 
 #define PIM_JP_HOLDTIME (qpim_t_periodic * 7 / 2)