]> git.puffer.fish Git - matthieu/frr.git/commitdiff
Zebra: Make redistribute do replace instead of del/add for better convergence
authorvivek <vivek@cumulusnetworks.com>
Wed, 21 Oct 2015 04:38:38 +0000 (21:38 -0700)
committervivek <vivek@cumulusnetworks.com>
Wed, 21 Oct 2015 04:38:38 +0000 (21:38 -0700)
Ticket: CM-6768
Reviewed By: CCR-3207
Testing Done: bgpsmoke, smoke, topo to create failure

Redistributing routes goes through a del/add cycle whenever a redistributed
is updated. This del/add cycle causes disruption by causing traffic loss
for brief/long periods of time(6-8 s in case of OSPF). The modifications in
this patch remove the del/add cycle to ensure that this disruption doesn't
happen.

Also fixed sending no forwarding address when announcing IPv4 routes with IPv6
nexthops, and sending nexthop only when there is a single path.

Signed-off-by: Dinesh G Dutt <ddutt@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
13 files changed:
bgpd/bgp_zebra.c
isisd/isis_zebra.c
lib/zclient.c
lib/zclient.h
lib/zebra.h
ospf6d/ospf6_zebra.c
ospfd/ospf_asbr.c
ospfd/ospf_zebra.c
ripd/rip_zebra.c
zebra/redistribute.c
zebra/zebra_rib.c
zebra/zserv.c
zebra/zserv.h

index ee6b32244f2d57ed284503e4cfa291bfecf8559b..c7b0b4364e6184382c9bfdae7ecef05b6f871477 100644 (file)
@@ -484,7 +484,7 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)
   else
     api.tag = 0;
 
-  if (command == ZEBRA_IPV4_ROUTE_ADD)
+  if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD)
     {
       if (bgp_debug_zebra((struct prefix *)&p))
        {
@@ -500,7 +500,7 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)
       bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL, ifindex,
                           api.metric, api.type, api.instance, api.tag);
     }
-  else
+  else if (command == ZEBRA_REDISTRIBUTE_IPV4_DEL)
     {
       if (bgp_debug_zebra((struct prefix *)&p))
        {
@@ -582,7 +582,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length)
   if (IN6_IS_ADDR_LINKLOCAL (&p.prefix))
     return 0;
 
-  if (command == ZEBRA_IPV6_ROUTE_ADD)
+  if (command == ZEBRA_REDISTRIBUTE_IPV6_ADD)
     {
       if (bgp_debug_zebra((struct prefix *)&p))
        {
@@ -598,7 +598,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length)
       bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop, ifindex,
                            api.metric, api.type, api.instance, api.tag);
     }
-  else
+  else if (command == ZEBRA_REDISTRIBUTE_IPV6_DEL)
     {
       if (bgp_debug_zebra((struct prefix *)&p))
        {
@@ -1696,11 +1696,15 @@ bgp_zebra_init (struct thread_master *master)
   zclient->interface_nbr_address_delete = bgp_interface_nbr_address_delete;
   zclient->ipv4_route_add = zebra_read_ipv4;
   zclient->ipv4_route_delete = zebra_read_ipv4;
+  zclient->redistribute_route_ipv4_add = zebra_read_ipv4;
+  zclient->redistribute_route_ipv4_del = zebra_read_ipv4;
   zclient->interface_up = bgp_interface_up;
   zclient->interface_down = bgp_interface_down;
 #ifdef HAVE_IPV6
   zclient->ipv6_route_add = zebra_read_ipv6;
   zclient->ipv6_route_delete = zebra_read_ipv6;
+  zclient->redistribute_route_ipv6_add = zebra_read_ipv6;
+  zclient->redistribute_route_ipv6_del = zebra_read_ipv6;
 #endif /* HAVE_IPV6 */
   zclient->nexthop_update = bgp_read_nexthop_update;
   zclient->import_check_update = bgp_read_import_check_update;
index f4179e50e040d0815c97fd36ddac3b3c443880b2..a29ad681721904e0d96d49ac38be126492b3708a 100644 (file)
@@ -555,7 +555,7 @@ isis_zebra_read_ipv4 (int command, struct zclient *zclient,
   else
     api.metric = 0;
 
-  if (command == ZEBRA_IPV4_ROUTE_ADD)
+  if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD)
     {
       if (isis->debugs & DEBUG_ZEBRA)
        zlog_debug ("IPv4 Route add from Z");
@@ -606,9 +606,13 @@ isis_zebra_init (struct thread_master *master)
   zclient->interface_address_delete = isis_zebra_if_address_del;
   zclient->ipv4_route_add = isis_zebra_read_ipv4;
   zclient->ipv4_route_delete = isis_zebra_read_ipv4;
+  zclient->redistribute_route_ipv4_add = isis_zebra_read_ipv4;
+  zclient->redistribute_route_ipv4_del = isis_zebra_read_ipv4;
 #ifdef HAVE_IPV6
   zclient->ipv6_route_add = isis_zebra_read_ipv6;
   zclient->ipv6_route_delete = isis_zebra_read_ipv6;
+  zclient->redistribute_route_ipv6_add = isis_zebra_read_ipv6;
+  zclient->redistribute_route_ipv6_del = isis_zebra_read_ipv6;
 #endif /* HAVE_IPV6 */
 
   return;
index e071228cc3f3e101ab16776dc94e779dc527e34d..623ca1583fcc0ca4ee59f9bedc7ec7f1e1fbaafb 100644 (file)
@@ -1259,6 +1259,22 @@ zclient_read (struct thread *thread)
       if (zclient->bfd_dest_replay)
        (*zclient->bfd_dest_replay) (command, zclient, length);
       break;
+    case ZEBRA_REDISTRIBUTE_IPV4_ADD:
+      if (zclient->redistribute_route_ipv4_add)
+       (*zclient->redistribute_route_ipv4_add) (command, zclient, length);
+      break;
+    case ZEBRA_REDISTRIBUTE_IPV4_DEL:
+      if (zclient->redistribute_route_ipv4_del)
+       (*zclient->redistribute_route_ipv4_del) (command, zclient, length);
+      break;
+    case ZEBRA_REDISTRIBUTE_IPV6_ADD:
+      if (zclient->redistribute_route_ipv6_add)
+       (*zclient->redistribute_route_ipv6_add) (command, zclient, length);
+      break;
+    case ZEBRA_REDISTRIBUTE_IPV6_DEL:
+      if (zclient->redistribute_route_ipv6_del)
+       (*zclient->redistribute_route_ipv6_del) (command, zclient, length);
+      break;
     default:
       break;
     }
index 1fbb80da90fb51fb19d3b4043dab7568ec5e4459..8caf682d81bd325b41a876c44f11019d860cc2ca 100644 (file)
@@ -98,6 +98,10 @@ struct zclient
   int (*nexthop_update) (int, struct zclient *, uint16_t);
   int (*import_check_update) (int, struct zclient *, uint16_t);
   int (*bfd_dest_replay) (int, struct zclient *, uint16_t);
+  int (*redistribute_route_ipv4_add) (int, struct zclient *, uint16_t);
+  int (*redistribute_route_ipv4_del) (int, struct zclient *, uint16_t);
+  int (*redistribute_route_ipv6_add) (int, struct zclient *, uint16_t);
+  int (*redistribute_route_ipv6_del) (int, struct zclient *, uint16_t);
 };
 
 /* Zebra API message flag. */
index 41de01ec25219a1720aa68356c76f838a717aa96..0a1dd7f46c7351770b78d8dd07df835103b35150 100644 (file)
@@ -438,7 +438,11 @@ struct in_pktinfo
 #define ZEBRA_BFD_DEST_DEREGISTER         35
 #define ZEBRA_BFD_DEST_UPDATE             36
 #define ZEBRA_BFD_DEST_REPLAY             37
-#define ZEBRA_MESSAGE_MAX                 38
+#define ZEBRA_REDISTRIBUTE_IPV4_ADD       38
+#define ZEBRA_REDISTRIBUTE_IPV4_DEL       39
+#define ZEBRA_REDISTRIBUTE_IPV6_ADD       40
+#define ZEBRA_REDISTRIBUTE_IPV6_DEL       41
+#define ZEBRA_MESSAGE_MAX                 42
 
 /* Marker value used in new Zserv, in the byte location corresponding
  * the command value in the old zserv header. To allow old and new
index a285714937e4afd9962c6c7fbb85ad7950e0447a..f97a9db723ac1f1fb9d5422b7f8cc48daef0bdad 100644 (file)
@@ -261,7 +261,7 @@ ospf6_zebra_read_ipv6 (int command, struct zclient *zclient,
                  zebra_route_string(api.type), prefixstr, nexthopstr, ifindex);
     }
  
-  if (command == ZEBRA_IPV6_ROUTE_ADD)
+  if (command == ZEBRA_REDISTRIBUTE_IPV6_ADD)
     ospf6_asbr_redistribute_add (api.type, ifindex, (struct prefix *) &p,
                                  api.nexthop_num, nexthop);
   else
@@ -649,8 +649,12 @@ ospf6_zebra_init (struct thread_master *master)
   zclient->interface_address_delete = ospf6_zebra_if_address_update_delete;
   zclient->ipv4_route_add = NULL;
   zclient->ipv4_route_delete = NULL;
+  zclient->redistribute_route_ipv4_add = NULL;
+  zclient->redistribute_route_ipv4_del = NULL;
   zclient->ipv6_route_add = ospf6_zebra_read_ipv6;
   zclient->ipv6_route_delete = ospf6_zebra_read_ipv6;
+  zclient->redistribute_route_ipv6_add = ospf6_zebra_read_ipv6;
+  zclient->redistribute_route_ipv6_del = ospf6_zebra_read_ipv6;
 
   /* redistribute connected route by default */
   /* ospf6_zebra_redistribute (ZEBRA_ROUTE_CONNECT); */
index 5eb97d8f6648ea14d22cd6e85ba03d9d76e3eebd..397ab6037444a8303048b41c1d50a516ba06acd2 100644 (file)
@@ -142,6 +142,7 @@ ospf_external_info_add (u_char type, u_short instance, struct prefix_ipv4 p,
   struct external_info *new;
   struct route_node *rn;
   struct ospf_external *ext;
+  char inetbuf[INET6_BUFSIZ];
 
   ext = ospf_external_lookup(type, instance);
   if (!ext)
@@ -152,12 +153,20 @@ ospf_external_info_add (u_char type, u_short instance, struct prefix_ipv4 p,
   if (rn)
     if (rn->info)
       {
-       route_unlock_node (rn);
-       zlog_warn ("Redistribute[%s][%d]: %s/%d already exists, discard.",
+       new = rn->info;
+       if ((new->ifindex == ifindex) &&
+           (new->nexthop.s_addr == nexthop.s_addr) && (new->tag == tag))
+         {
+           route_unlock_node(rn);
+           return NULL;        /* NULL => no LSA to refresh */
+         }
+
+       inet_ntop(AF_INET, (void *)&nexthop.s_addr, inetbuf, INET6_BUFSIZ);
+       zlog_warn ("Redistribute[%s][%d]: %s/%d discarding old info with NH %s.",
                   ospf_redist_string(type), instance,
-                  inet_ntoa (p.prefix), p.prefixlen);
-       /* XFREE (MTYPE_OSPF_TMP, rn->info); */
-       return rn->info;
+                  inet_ntoa (p.prefix), p.prefixlen, inetbuf);
+       XFREE (MTYPE_OSPF_EXTERNAL_INFO, rn->info);
+       rn->info = NULL;
       }
 
   /* Create new External info instance. */
@@ -167,13 +176,17 @@ ospf_external_info_add (u_char type, u_short instance, struct prefix_ipv4 p,
   new->nexthop = nexthop;
   new->tag = tag;
 
+  /* we don't unlock rn from the get() because we're attaching the info */
   if (rn)
     rn->info = new;
 
   if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
-    zlog_debug ("Redistribute[%s]: %s/%d external info created.",
-              ospf_redist_string(type),
-              inet_ntoa (p.prefix), p.prefixlen);
+    {
+      inet_ntop(AF_INET, (void *)&nexthop.s_addr, inetbuf, INET6_BUFSIZ);
+      zlog_debug ("Redistribute[%s]: %s/%d external info created, with NH %s",
+                 ospf_redist_string(type),
+                 inet_ntoa (p.prefix), p.prefixlen, inetbuf);
+    }
   return new;
 }
 
index 8c152cdf72f8fa7559b75d7b5223fc07bca41e66..a95b2e1b676525c74cc819044774f807a2dd1d0e 100644 (file)
@@ -1070,7 +1070,7 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient,
   if (ospf == NULL)
     return 0;
 
-  if (command == ZEBRA_IPV4_ROUTE_ADD)
+  if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD)
     {
       /* XXX|HACK|TODO|FIXME:
        * Maybe we should ignore reject/blackhole routes? Testing shows that
@@ -1098,7 +1098,11 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient,
 
       ei = ospf_external_info_add (api.type, api.instance, p, ifindex,
                                    nexthop, api.tag);
-
+      if (ei == NULL)
+       {
+         /* Nothing has changed, so nothing to do; return */
+         return 0;
+       }
       if (ospf->router_id.s_addr == 0)
         /* Set flags to generate AS-external-LSA originate event
            for each redistributed protocols later. */
@@ -1116,17 +1120,19 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient,
                   current = ospf_external_info_find_lsa (ospf, &ei->p);
                   if (!current)
                     ospf_external_lsa_originate (ospf, ei);
-                  else if (IS_LSA_MAXAGE (current))
-                    ospf_external_lsa_refresh (ospf, current,
-                                               ei, LSA_REFRESH_FORCE);
                   else
-                    zlog_warn ("ospf_zebra_read_ipv4() : %s already exists",
-                               inet_ntoa (p.prefix));
+                   {
+                     if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE))
+                       zlog_debug ("ospf_zebra_read_ipv4() : %s refreshing LSA",
+                                   inet_ntoa (p.prefix));
+                     ospf_external_lsa_refresh (ospf, current,
+                                                ei, LSA_REFRESH_FORCE);
+                   }
                 }
             }
         }
     }
-  else                          /* if (command == ZEBRA_IPV4_ROUTE_DELETE) */
+  else                          /* if (command == ZEBRA_REDISTRIBUTE_IPV4_DEL) */
     {
       ospf_external_info_delete (api.type, api.instance, p);
       if (is_prefix_default (&p))
@@ -1554,6 +1560,8 @@ ospf_zebra_init (struct thread_master *master, u_short instance)
   zclient->interface_address_delete = ospf_interface_address_delete;
   zclient->ipv4_route_add = ospf_zebra_read_ipv4;
   zclient->ipv4_route_delete = ospf_zebra_read_ipv4;
+  zclient->redistribute_route_ipv4_add = ospf_zebra_read_ipv4;
+  zclient->redistribute_route_ipv4_del = ospf_zebra_read_ipv4;
 
   access_list_add_hook (ospf_filter_update);
   access_list_delete_hook (ospf_filter_update);
index e0092f5422aa9847180c50af0b2a933e614a382c..a5cc8260dbb886072e8307763a8cfcf348994be8 100644 (file)
@@ -140,10 +140,10 @@ rip_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)
     api.metric = 0;
 
   /* Then fetch IPv4 prefixes. */
-  if (command == ZEBRA_IPV4_ROUTE_ADD)
+  if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD)
     rip_redistribute_add (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex, 
                           &nexthop, api.metric, api.distance);
-  else 
+  else if (command == ZEBRA_REDISTRIBUTE_IPV4_DEL)
     rip_redistribute_delete (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex);
 
   return 0;
@@ -683,6 +683,8 @@ rip_zclient_init (struct thread_master *master)
   zclient->ipv4_route_delete = rip_zebra_read_ipv4;
   zclient->interface_up = rip_interface_up;
   zclient->interface_down = rip_interface_down;
+  zclient->redistribute_route_ipv4_add = rip_zebra_read_ipv4;
+  zclient->redistribute_route_ipv4_del = rip_zebra_read_ipv4;
   
   /* Install zebra node. */
   install_node (&zebra_node, config_write_zebra);
index 0f4cf9521712e6eab1857a7c62e90224bcf5d742..f55b04ee0db88b6ae26738d98f78875a8cd7197d 100644 (file)
@@ -105,7 +105,7 @@ zebra_redistribute_default (struct zserv *client)
          RNODE_FOREACH_RIB (rn, newrib)
            if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
                && newrib->distance != DISTANCE_INFINITY)
-             zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib);
+             zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_ADD, client, &rn->p, newrib);
          route_unlock_node (rn);
        }
     }
@@ -125,7 +125,7 @@ zebra_redistribute_default (struct zserv *client)
          RNODE_FOREACH_RIB (rn, newrib)
            if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
                && newrib->distance != DISTANCE_INFINITY)
-             zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib);
+             zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_ADD, client, &rn->p, newrib);
          route_unlock_node (rn);
        }
     }
@@ -151,7 +151,7 @@ zebra_redistribute (struct zserv *client, int type, u_short instance)
            && zebra_check_addr (&rn->p))
          {
            client->redist_v4_add_cnt++;
-           zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib);
+           zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_ADD, client, &rn->p, newrib);
          }
   
 #ifdef HAVE_IPV6
@@ -166,7 +166,7 @@ zebra_redistribute (struct zserv *client, int type, u_short instance)
            && zebra_check_addr (&rn->p))
          {
            client->redist_v6_add_cnt++;
-           zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib);
+           zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_ADD, client, &rn->p, newrib);
          }
 #endif /* HAVE_IPV6 */
 }
@@ -187,7 +187,8 @@ redistribute_add (struct prefix *p, struct rib *rib)
                                     rib->instance)))
            {
              client->redist_v4_add_cnt++;
-              zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib);
+              zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_ADD, client,
+                                       p, rib);
             }
 #ifdef HAVE_IPV6
           if ((p->family == AF_INET6) &&
@@ -196,7 +197,8 @@ redistribute_add (struct prefix *p, struct rib *rib)
                                     rib->instance)))
             {
               client->redist_v6_add_cnt++;
-              zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib);
+              zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_ADD, client,
+                                    p, rib);
             }
 #endif /* HAVE_IPV6 */   
         }
@@ -207,7 +209,8 @@ redistribute_add (struct prefix *p, struct rib *rib)
                                     rib->instance))
            {
              client->redist_v4_add_cnt++;
-              zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib);
+              zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_ADD, client,
+                                       p, rib);
             }
 #ifdef HAVE_IPV6
           if ((p->family == AF_INET6) &&
@@ -215,7 +218,8 @@ redistribute_add (struct prefix *p, struct rib *rib)
                                     rib->instance))
             {
               client->redist_v6_add_cnt++;
-              zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib);
+              zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_ADD, client,
+                                       p, rib);
             }
 #endif /* HAVE_IPV6 */   
         }
@@ -240,15 +244,15 @@ redistribute_delete (struct prefix *p, struct rib *rib)
               (client->redist_default ||
                redist_check_instance(&client->redist[AFI_IP][rib->type],
                                      rib->instance)))
-            zsend_route_multipath (ZEBRA_IPV4_ROUTE_DELETE, client, p,
+            zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_DEL, client, p,
                                       rib);
 #ifdef HAVE_IPV6
          if ((p->family == AF_INET6) &&
               (client->redist_default ||
                redist_check_instance(&client->redist[AFI_IP6][rib->type],
                                      rib->instance)))
-            zsend_route_multipath (ZEBRA_IPV6_ROUTE_DELETE, client, p,
-                                      rib);
+            zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_DEL, client, p,
+                                     rib);
 #endif /* HAVE_IPV6 */
        }
       else
@@ -256,14 +260,14 @@ redistribute_delete (struct prefix *p, struct rib *rib)
           if ((p->family == AF_INET) &&
                redist_check_instance(&client->redist[AFI_IP][rib->type],
                                      rib->instance))
-            zsend_route_multipath (ZEBRA_IPV4_ROUTE_DELETE, client, p,
-                                      rib);
+            zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_DEL, client, p,
+                                     rib);
 #ifdef HAVE_IPV6
          if ((p->family == AF_INET6) &&
                redist_check_instance(&client->redist[AFI_IP6][rib->type],
                                      rib->instance))
-            zsend_route_multipath (ZEBRA_IPV6_ROUTE_DELETE, client, p,
-                                      rib);
+            zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_DEL, client, p,
+                                     rib);
 #endif /* HAVE_IPV6 */
        }
     }
index 8e873211a0ddea5629246dc8c6e881881ce49ef7..4e4306b9fb8f03c1c991408e34d051cdf52e2a69 100644 (file)
@@ -1683,13 +1683,11 @@ rib_process (struct route_node *rn)
         {
          zfpm_trigger_update (rn, "updating existing route");
 
-          redistribute_delete (&rn->p, select);
-
           if (! RIB_SYSTEM_ROUTE (select))
             {
               /* For v4, use the replace semantics of netlink. */
               if (PREFIX_FAMILY (&rn->p) == AF_INET)
-                update_ok = 1;
+                 update_ok = 1;
               else
                 rib_uninstall_kernel (rn, select);
             }
@@ -1709,10 +1707,15 @@ rib_process (struct route_node *rn)
                 }
              if (! RIB_SYSTEM_ROUTE (select))
                rib_install_kernel (rn, select, update_ok);
+
+             /* assuming that the receiver knows how to dedup */
              redistribute_add (&rn->p, select);
            }
          else
            {
+             /* Withdraw unreachable redistribute route */
+             redistribute_delete(&rn->p, select);
+
               /* For IPv4, do the uninstall here. */
               if (update_ok)
                 rib_uninstall_kernel (rn, select);
@@ -1753,7 +1756,9 @@ rib_process (struct route_node *rn)
 
       zfpm_trigger_update (rn, "removing existing route");
 
-      redistribute_delete (&rn->p, fib);
+      /* If there's no route to replace this with, withdraw redistribute */
+      if (!select)
+       redistribute_delete(&rn->p, fib);
 
       if (! RIB_SYSTEM_ROUTE (fib))
         {
@@ -1762,7 +1767,7 @@ rib_process (struct route_node *rn)
            */
           if (PREFIX_FAMILY (&rn->p) == AF_INET)
             {
-              if (!select || RIB_SYSTEM_ROUTE(select))
+              if (!select)
                 rib_uninstall_kernel (rn, fib);
               else
                 update_ok = 1;
@@ -1802,6 +1807,7 @@ rib_process (struct route_node *rn)
          if (! RIB_SYSTEM_ROUTE (select))
            rib_install_kernel (rn, select, update_ok);
          SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED);
+         /* Unconditionally announce, this part is exercised by new routes */
          redistribute_add (&rn->p, select);
        }
       else
@@ -1812,6 +1818,8 @@ rib_process (struct route_node *rn)
               assert (fib);
               rib_uninstall_kernel (rn, fib);
             }
+         /* if "select", the earlier redist delete wouldn't have happened */
+         redistribute_delete(&rn->p, select);
        }
       UNSET_FLAG(select->flags, ZEBRA_FLAG_CHANGED);
     }
@@ -2941,7 +2949,6 @@ static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si)
       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
       if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
         {
-          redistribute_delete (&rn->p, rib);
           /* If there are other active nexthops, do an update. */
           if (rib->nexthop_active_num > 1)
             {
@@ -2949,7 +2956,10 @@ static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si)
               redistribute_add (&rn->p, rib);
             }
           else
-            rib_uninstall_kernel (rn, rib);
+           {
+             redistribute_delete (&rn->p, rib);
+             rib_uninstall_kernel (rn, rib);
+           }
         }
 
       /* Delete the nexthop and dereg from NHT */
index 1bd5b98825ba0feb0c3ce6677d7855e010ffe3c4..ba3c59aafb5a6d0235bdebcb1f9cef641edafe28 100644 (file)
@@ -480,31 +480,18 @@ zsend_interface_update (int cmd, struct zserv *client, struct interface *ifp)
 }
 
 /*
- * The zebra server sends the clients  a ZEBRA_IPV4_ROUTE_ADD or a
- * ZEBRA_IPV6_ROUTE_ADD via zsend_route_multipath in the following
- * situations:
- * - when the client starts up, and requests default information
- *   by sending a ZEBRA_REDISTRIBUTE_DEFAULT_ADD to the zebra server, in the
- * - case of rip, ripngd, ospfd and ospf6d, when the client sends a
- *   ZEBRA_REDISTRIBUTE_ADD as a result of the "redistribute" vty cmd,
- * - when the zebra server redistributes routes after it updates its rib
+ * This is the new function to announce and withdraw redistributed routes, used
+ * by Zebra. This is the old zsend_route_multipath() function. That function
+ * was duplicating code to send a lot of information that was essentially thrown
+ * away or ignored by the receiver. This is the leaner function that is not a
+ * duplicate of the zapi_ipv4_route_add/del.
  *
- * The zebra server sends clients a ZEBRA_IPV4_ROUTE_DELETE or a
- * ZEBRA_IPV6_ROUTE_DELETE via zsend_route_multipath when:
- * - a "ip route"  or "ipv6 route" vty command is issued, a prefix is
- * - deleted from zebra's rib, and this info
- *   has to be redistributed to the clients 
- * 
- * XXX The ZEBRA_IPV*_ROUTE_ADD message is also sent by the client to the
- * zebra server when the client wants to tell the zebra server to add a
- * route to the kernel (zapi_ipv4_add etc. ).  Since it's essentially the
- * same message being sent back and forth, this function and
- * zapi_ipv{4,6}_{add, delete} should be re-written to avoid code
- * duplication.
+ * The primary difference is that this function merely sends a single NH instead of
+ * all the nexthops.
  */
 int
-zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p,
-                       struct rib *rib)
+zsend_redistribute_route (int cmd, struct zserv *client, struct prefix *p,
+                         struct rib *rib)
 {
   int psize;
   struct stream *s;
@@ -512,17 +499,19 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p,
   unsigned long nhnummark = 0, messmark = 0;
   int nhnum = 0;
   u_char zapi_flags = 0;
-  
+  struct nexthop dummy_nh;
+
   s = client->obuf;
   stream_reset (s);
-  
+  memset(&dummy_nh, 0, sizeof(struct nexthop));
+
   zserv_create_header (s, cmd);
-  
+
   /* Put type and nexthop. */
   stream_putc (s, rib->type);
   stream_putw (s, rib->instance);
   stream_putc (s, rib->flags);
-  
+
   /* marker for message flags field */
   messmark = stream_get_endp (s);
   stream_putc (s, 0);
@@ -532,30 +521,45 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p,
   stream_putc (s, p->prefixlen);
   stream_write (s, (u_char *) & p->u.prefix, psize);
 
-  /* 
-   * XXX The message format sent by zebra below does not match the format
-   * of the corresponding message expected by the zebra server
-   * itself (e.g., see zread_ipv4_add). The nexthop_num is not set correctly,
-   * (is there a bug on the client side if more than one segment is sent?)
-   * nexthop ZEBRA_NEXTHOP_IPV4 is never set, ZEBRA_NEXTHOP_IFINDEX 
-   * is hard-coded.
-   */
-  /* Nexthop */
-  
   for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
     {
+      /* We don't send any nexthops when there's a multipath */
+      if (rib->nexthop_active_num > 1)
+       {
+          SET_FLAG (zapi_flags, ZAPI_MESSAGE_NEXTHOP);
+          SET_FLAG (zapi_flags, ZAPI_MESSAGE_IFINDEX);
+
+         stream_putc(s, 1);
+         if (p->family == AF_INET)
+           {
+             stream_put_in_addr (s, &dummy_nh.gate.ipv4);
+           }
+         else if (p->family == AF_INET6)
+           {
+                stream_write (s, (u_char *) &dummy_nh.gate.ipv6, 16);
+           }
+         else
+           {
+             /* We don't handle anything else now, abort */
+             zlog_err("%s: Unable to redistribute route of unknown family, %d\n",
+                      __func__, p->family);
+             return -1;
+           }
+          stream_putc (s, 1);
+          stream_putl (s, 0);  /* dummy ifindex */
+         break;
+       }
+
       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)
           || nexthop_has_fib_child(nexthop))
         {
           SET_FLAG (zapi_flags, ZAPI_MESSAGE_NEXTHOP);
           SET_FLAG (zapi_flags, ZAPI_MESSAGE_IFINDEX);
-          
           if (nhnummark == 0)
             {
               nhnummark = stream_get_endp (s);
               stream_putc (s, 1); /* placeholder */
             }
-          
           nhnum++;
 
           switch(nexthop->type) 
@@ -568,12 +572,16 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p,
               case NEXTHOP_TYPE_IPV6:
               case NEXTHOP_TYPE_IPV6_IFINDEX:
               case NEXTHOP_TYPE_IPV6_IFNAME:
-                stream_write (s, (u_char *) &nexthop->gate.ipv6, 16);
+               /* Only BGP supports IPv4 prefix with IPv6 NH, so kill this */
+               if (p->family == AF_INET)
+                 stream_put_in_addr(s, &dummy_nh.gate.ipv4);
+               else
+                 stream_write (s, (u_char *) &nexthop->gate.ipv6, 16);
                 break;
 #endif
               default:
-                if (cmd == ZEBRA_IPV4_ROUTE_ADD 
-                    || cmd == ZEBRA_IPV4_ROUTE_DELETE)
+                if (cmd == ZEBRA_REDISTRIBUTE_IPV4_ADD
+                    || cmd == ZEBRA_REDISTRIBUTE_IPV4_DEL)
                   {
                     struct in_addr empty;
                     memset (&empty, 0, sizeof (struct in_addr));
@@ -596,7 +604,7 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p,
     }
 
   /* Metric */
-  if (cmd == ZEBRA_IPV4_ROUTE_ADD || cmd == ZEBRA_IPV6_ROUTE_ADD)
+  if (cmd == ZEBRA_REDISTRIBUTE_IPV4_ADD || cmd == ZEBRA_REDISTRIBUTE_IPV6_ADD)
     {
       SET_FLAG (zapi_flags, ZAPI_MESSAGE_DISTANCE);
       stream_putc (s, rib->distance);
@@ -610,14 +618,14 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p,
           stream_putw(s, rib->tag);
         }
     }
-  
+
   /* write real message flags value */
   stream_putc_at (s, messmark, zapi_flags);
-  
+
   /* Write next-hop number */
   if (nhnummark)
     stream_putc_at (s, nhnummark, nhnum);
-  
+
   /* Write packet size. */
   stream_putw_at (s, 0, stream_get_endp (s));
 
index 41aaecef1477f944258bc5eceae686f30d694b63..41a4b9ea9f5acce3d3e831e5b38640e6fdecd921 100644 (file)
@@ -149,8 +149,8 @@ extern void nbr_connected_replacement_add_ipv6 (struct interface *,
                                                 struct in6_addr *, u_char);
 extern void nbr_connected_delete_ipv6 (struct interface *, struct in6_addr *, u_char);
 extern int zsend_interface_update (int, struct zserv *, struct interface *);
-extern int zsend_route_multipath (int, struct zserv *, struct prefix *, 
-                                  struct rib *);
+extern int zsend_redistribute_route (int, struct zserv *, struct prefix *,
+                                    struct rib *);
 extern int zsend_router_id_update(struct zserv *, struct prefix *);
 extern pid_t pid;