ospf: suppress delete using replacement

After a SPF run, OSPF deletes routes that have changed in terms of any
metric, type, and/or next-hops and re-adds them. Given that the Zebra-RIB
already support replacement semantics, we suppress deletes for routes
that will be added back again.

This has the following advantages. It reduces the number of IPC messages
between OSPF/Zebra. Also, in the current flow, a batch of route deletes
were followed by a batch of adds even for say a metric change.

With the change, routes are sent as "add" when they are modified. Zebra
already implicitly deletes older routes.

Signed-off-by: Ayan Banerjee <ayan@cumulusnetworks.com>
Reviewed-by: Scott Feldman <sfeldma@cumulusnetworks.com>
Reviewed-by: Dinesh Dutt <ddutt@cumulusnetworks.com>
Signed-off-by: Scott Feldman <sfeldma@cumulusnetworks.com>
diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c
index c3acba3..eb7829a 100644
--- a/ospfd/ospf_route.c
+++ b/ospfd/ospf_route.c
@@ -126,6 +126,31 @@
    route_table_finish (rt);
 }
 
+/* If a prefix exists in the new routing table, then return 1,
+   otherwise return 0. Since the ZEBRA-RIB does an implicit
+   withdraw, it is not necessary to send a delete, an add later
+   will act like an implicit delete. */
+static int
+ospf_route_exist_new_table (struct route_table *rt, struct prefix_ipv4 *prefix)
+{
+  struct route_node *rn;
+
+  assert (rt);
+  assert (prefix);
+
+  rn = route_node_lookup (rt, (struct prefix *) prefix);
+  if (!rn) {
+    return 0;
+  }
+  route_unlock_node (rn);
+
+  if (!rn->info) {
+    return 0;
+  }
+
+  return 1;
+}
+
 /* If a prefix and a nexthop match any route in the routing table,
    then return 1, otherwise return 0. */
 int
@@ -223,13 +248,13 @@
 	{
 	  if (or->type == OSPF_DESTINATION_NETWORK)
 	    {
-	      if (! ospf_route_match_same (cmprt, 
-					   (struct prefix_ipv4 *) &rn->p, or))
+	      if (! ospf_route_exist_new_table (cmprt,
+					   (struct prefix_ipv4 *) &rn->p))
 		ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or);
 	    }
 	  else if (or->type == OSPF_DESTINATION_DISCARD)
-	    if (! ospf_route_match_same (cmprt,
-					 (struct prefix_ipv4 *) &rn->p, or))
+	    if (! ospf_route_exist_new_table (cmprt,
+					 (struct prefix_ipv4 *) &rn->p))
 	      ospf_zebra_delete_discard ((struct prefix_ipv4 *) &rn->p);
 	}
 }