zebra: Dissallow outside programs to delete Quagga routes

Do not allow a program outside Quagga to delete a Quagga route from the kernel.
To delete a Quagga route, do it inside Quagga.

Signed-off-by: James Li <jli@cumulusnetworks.com>
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 105e559..1a91426 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -908,6 +908,7 @@
   int len;
   struct rtmsg *rtm;
   struct rtattr *tb[RTA_MAX + 1];
+  u_char zebra_flags = 0;
 
   char anyaddr[16] = { 0 };
 
@@ -965,6 +966,8 @@
 
   if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
     return 0;
+  if (rtm->rtm_protocol == RTPROT_ZEBRA)
+    SET_FLAG(zebra_flags, ZEBRA_FLAG_SELFROUTE);
 
   if (rtm->rtm_src_len != 0)
     {
@@ -1084,8 +1087,8 @@
             }
         }
       else
-        rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id,
-                         SAFI_UNICAST);
+        rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, gate,
+			 index, vrf_id, SAFI_UNICAST);
     }
 
 #ifdef HAVE_IPV6
@@ -1109,7 +1112,7 @@
         rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, table,
                       0, mtu, 0, SAFI_UNICAST);
       else
-        rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id,
+        rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, gate, index, vrf_id,
                          SAFI_UNICAST);
     }
 #endif /* HAVE_IPV6 */
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 0aa516c..a55d358 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -2079,14 +2079,19 @@
      kernel. */
   if (! same)
     {
-      if (fib && type == ZEBRA_ROUTE_KERNEL)
-	{
-	  /* Unset flags. */
-	  for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
-	    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
-
-	  UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB);
-	}
+      if (fib && type == ZEBRA_ROUTE_KERNEL &&
+          CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE))
+        {
+          if (IS_ZEBRA_DEBUG_KERNEL)
+            {
+              zlog_debug ("Zebra route %s/%d was deleted by others from kernel",
+                         inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN),
+                         p->prefixlen);
+            }
+          /* This means someone else, other than Zebra, has deleted
+           * a Zebra router from the kernel. We will add it back */
+           rib_update_kernel(rn, NULL, fib);
+        }
       else
 	{
 	  if (IS_ZEBRA_DEBUG_KERNEL)
@@ -2738,14 +2743,19 @@
      kernel. */
   if (! same)
     {
-      if (fib && type == ZEBRA_ROUTE_KERNEL)
-	{
-	  /* Unset flags. */
-	  for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
-	    UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
-
-	  UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB);
-	}
+      if (fib && type == ZEBRA_ROUTE_KERNEL &&
+          CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE))
+        {
+          if (IS_ZEBRA_DEBUG_KERNEL)
+            {
+              zlog_debug ("Zebra route %s/%d was deleted by others from kernel",
+                         inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN),
+                         p->prefixlen);
+            }
+          /* This means someone else, other than Zebra, has deleted a Zebra
+           * route from the kernel. We will add it back */
+          rib_update_kernel(rn, NULL, fib);
+        }
       else
 	{
 	  if (IS_ZEBRA_DEBUG_KERNEL)