]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/redistribute.c
Merge branch 'cmaster' of ssh://stash.cumulusnetworks.com:7999/quag/quagga into cmaster
[mirror_frr.git] / zebra / redistribute.c
index 01b85700f2757693d9d249e8e30ad5cd07a3d88b..5bd0df92a755dee3f3d9d2f61715ab52a04db196 100644 (file)
@@ -63,7 +63,7 @@ is_zebra_import_table_enabled(afi_t afi, u_int32_t table_id)
   return 0;
 }
 
-static int
+int
 is_default (struct prefix *p)
 {
   if (p->family == AF_INET)
@@ -81,7 +81,7 @@ is_default (struct prefix *p)
 }
 
 static void
-zebra_redistribute_default (struct zserv *client)
+zebra_redistribute_default (struct zserv *client, vrf_id_t vrf_id)
 {
   struct prefix_ipv4 p;
   struct route_table *table;
@@ -97,7 +97,7 @@ zebra_redistribute_default (struct zserv *client)
   p.family = AF_INET;
 
   /* Lookup table.  */
-  table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT);
+  table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id);
   if (table)
     {
       rn = route_node_lookup (table, (struct prefix *)&p);
@@ -117,7 +117,7 @@ zebra_redistribute_default (struct zserv *client)
   p6.family = AF_INET6;
 
   /* Lookup table.  */
-  table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT);
+  table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id);
   if (table)
     {
       rn = route_node_lookup (table, (struct prefix *)&p6);
@@ -135,13 +135,13 @@ zebra_redistribute_default (struct zserv *client)
 
 /* Redistribute routes. */
 static void
-zebra_redistribute (struct zserv *client, int type, u_short instance)
+zebra_redistribute (struct zserv *client, int type, u_short instance, vrf_id_t vrf_id)
 {
   struct rib *newrib;
   struct route_table *table;
   struct route_node *rn;
 
-  table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT);
+  table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id);
   if (table)
     for (rn = route_top (table); rn; rn = route_next (rn))
       RNODE_FOREACH_RIB (rn, newrib)
@@ -156,7 +156,7 @@ zebra_redistribute (struct zserv *client, int type, u_short instance)
          }
   
 #ifdef HAVE_IPV6
-  table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, VRF_DEFAULT);
+  table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id);
   if (table)
     for (rn = route_top (table); rn; rn = route_next (rn))
       RNODE_FOREACH_RIB (rn, newrib)
@@ -181,6 +181,15 @@ redistribute_update (struct prefix *p, struct rib *rib, struct rib *prev_rib)
   struct zserv *client;
   int send_redistribute;
   int afi;
+  char buf[INET6_ADDRSTRLEN];
+
+  if (IS_ZEBRA_DEBUG_RIB)
+    {
+      inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN);
+      zlog_debug ("%u:%s/%d: Redist update rib %p (type %d), old %p (type %d)",
+                  rib->vrf_id, buf, p->prefixlen, rib, rib->type,
+                  prev_rib, prev_rib ? prev_rib->type : -1);
+    }
 
   afi = family2afi(p->family);
   if (!afi)
@@ -196,9 +205,14 @@ redistribute_update (struct prefix *p, struct rib *rib, struct rib *prev_rib)
       if (is_default(p) && client->redist_default)
          send_redistribute = 1;
 
-      if (redist_check_instance(&client->redist[afi][rib->type],
-                               rib->instance))
-       send_redistribute = 1;
+      if (rib->instance && redist_check_instance(&client->mi_redist[afi][rib->type],
+                                               rib->instance))
+        send_redistribute = 1;
+      else
+        if ((is_default (p) &&
+            vrf_bitmap_check (client->redist_default, rib->vrf_id))
+            || vrf_bitmap_check (client->redist[afi][rib->type], rib->vrf_id))
+         send_redistribute = 1;
 
       if (send_redistribute)
        {
@@ -220,8 +234,10 @@ redistribute_update (struct prefix *p, struct rib *rib, struct rib *prev_rib)
            }
        }
       else if (prev_rib &&
-              redist_check_instance(&client->redist[afi][prev_rib->type],
-                                    rib->instance))
+              ((rib->instance &&
+                redist_check_instance(&client->mi_redist[afi][prev_rib->type],
+                                      rib->instance)) ||
+                vrf_bitmap_check (client->redist[afi][prev_rib->type], rib->vrf_id))) 
        {
          switch (afi)
            {
@@ -247,6 +263,14 @@ redistribute_delete (struct prefix *p, struct rib *rib)
 {
   struct listnode *node, *nnode;
   struct zserv *client;
+  char buf[INET6_ADDRSTRLEN];
+
+  if (IS_ZEBRA_DEBUG_RIB)
+    {
+      inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN);
+      zlog_debug ("%u:%s/%d: Redist delete rib %p (type %d)",
+                  rib->vrf_id, buf, p->prefixlen, rib, rib->type);
+    }
 
   /* Add DISTANCE_INFINITY check. */
   if (rib->distance == DISTANCE_INFINITY)
@@ -257,16 +281,20 @@ redistribute_delete (struct prefix *p, struct rib *rib)
       if (is_default (p))
        {
          if ((p->family == AF_INET) &&
-              (client->redist_default ||
-               redist_check_instance(&client->redist[AFI_IP][rib->type],
-                                     rib->instance)))
+              (vrf_bitmap_check (client->redist_default, rib->vrf_id) ||
+               (rib->instance &&
+                redist_check_instance(&client->mi_redist[AFI_IP][rib->type],
+                                     rib->instance)) ||
+               vrf_bitmap_check (client->redist[AFI_IP][rib->type], rib->vrf_id)))
             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)))
+              (vrf_bitmap_check (client->redist_default, rib->vrf_id) ||
+               (rib->instance &&
+                redist_check_instance(&client->mi_redist[AFI_IP6][rib->type],
+                                     rib->instance)) ||
+               vrf_bitmap_check (client->redist[AFI_IP6][rib->type], rib->vrf_id)))
             zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_DEL, client, p,
                                      rib);
 #endif /* HAVE_IPV6 */
@@ -274,14 +302,18 @@ redistribute_delete (struct prefix *p, struct rib *rib)
       else
         {
           if ((p->family == AF_INET) &&
-               redist_check_instance(&client->redist[AFI_IP][rib->type],
-                                     rib->instance))
+              ((rib->instance &&
+               redist_check_instance(&client->mi_redist[AFI_IP][rib->type],
+                                     rib->instance)) ||
+              vrf_bitmap_check (client->redist[AFI_IP][rib->type], rib->vrf_id)))
             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))
+              ((rib->instance &&
+               redist_check_instance(&client->mi_redist[AFI_IP6][rib->type],
+                                     rib->instance)) ||
+               vrf_bitmap_check (client->redist[AFI_IP6][rib->type], rib->vrf_id)))
             zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_DEL, client, p,
                                      rib);
 #endif /* HAVE_IPV6 */
@@ -290,7 +322,8 @@ redistribute_delete (struct prefix *p, struct rib *rib)
 }
 
 void
-zebra_redistribute_add (int command, struct zserv *client, int length)
+zebra_redistribute_add (int command, struct zserv *client, int length,
+    vrf_id_t vrf_id)
 {
   afi_t afi;
   int type;
@@ -303,15 +336,22 @@ zebra_redistribute_add (int command, struct zserv *client, int length)
   if (type == 0 || type >= ZEBRA_ROUTE_MAX)
     return;
 
-  if (!redist_check_instance(&client->redist[afi][type], instance))
+  if (instance && !redist_check_instance(&client->mi_redist[afi][type], instance))
     {
-      redist_add_instance(&client->redist[afi][type], instance);
-      zebra_redistribute (client, type, instance);
+      redist_add_instance(&client->mi_redist[afi][type], instance);
+      zebra_redistribute (client, type, instance, vrf_id);
     }
+  else
+    if (! vrf_bitmap_check (client->redist[afi][type], vrf_id))
+      {
+        vrf_bitmap_set (client->redist[afi][type], vrf_id);
+        zebra_redistribute (client, type, 0, vrf_id);
+      }
 }
 
 void
-zebra_redistribute_delete (int command, struct zserv *client, int length)
+zebra_redistribute_delete (int command, struct zserv *client, int length,
+    vrf_id_t vrf_id)
 {
   afi_t afi;
   int type;
@@ -324,25 +364,27 @@ zebra_redistribute_delete (int command, struct zserv *client, int length)
   if (type == 0 || type >= ZEBRA_ROUTE_MAX)
     return;
 
-  if (redist_check_instance(&client->redist[afi][type], instance))
+  if (instance && redist_check_instance(&client->mi_redist[afi][type], instance))
     {
-      redist_del_instance(&client->redist[afi][type], instance);
+      redist_del_instance(&client->mi_redist[afi][type], instance);
       //Pending: why no reaction here?
     }
+  vrf_bitmap_unset (client->redist[afi][type], vrf_id);
 }
 
 void
-zebra_redistribute_default_add (int command, struct zserv *client, int length)
+zebra_redistribute_default_add (int command, struct zserv *client, int length,
+    vrf_id_t vrf_id)
 {
-  client->redist_default = 1;
-  zebra_redistribute_default (client);
+  vrf_bitmap_set (client->redist_default, vrf_id);
+  zebra_redistribute_default (client, vrf_id);
 }     
 
 void
 zebra_redistribute_default_delete (int command, struct zserv *client,
-                                  int length)
+    int length, vrf_id_t vrf_id)
 {
-  client->redist_default = 0;;
+  vrf_bitmap_unset (client->redist_default, vrf_id);
 }     
 
 /* Interface up information. */
@@ -414,6 +456,47 @@ zebra_interface_delete_update (struct interface *ifp)
       }
 }
 
+/* VRF information update. */
+void
+zebra_vrf_add_update (struct zebra_vrf *zvrf)
+{
+  struct listnode *node, *nnode;
+  struct zserv *client;
+
+  if (IS_ZEBRA_DEBUG_EVENT)
+    zlog_debug ("MESSAGE: ZEBRA_VRF_ADD %s", zvrf->name);
+    
+  for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
+    zsend_vrf_add (client, zvrf);
+}
+
+void
+zebra_vrf_delete_update (struct zebra_vrf *zvrf)
+{
+  struct listnode *node, *nnode;
+  struct zserv *client;
+
+  if (IS_ZEBRA_DEBUG_EVENT)
+    zlog_debug ("MESSAGE: ZEBRA_VRF_DELETE %s", zvrf->name);
+
+  for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
+    zsend_vrf_delete (client, zvrf);
+}
+
+void
+zebra_vrf_update_all (struct zserv *client)
+{
+  struct vrf *vrf;
+  vrf_iter_t iter;
+
+  for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
+    {
+      if ((vrf = vrf_iter2vrf (iter)) && vrf->vrf_id)
+        zsend_vrf_add (client, vrf_info_lookup (vrf->vrf_id));
+    }
+}
+
+
 /* Interface address addition. */
 void
 zebra_interface_address_add_update (struct interface *ifp,
@@ -475,6 +558,74 @@ zebra_interface_address_delete_update (struct interface *ifp,
       }
 }
 
+/* Interface VRF change. May need to delete from clients not interested in
+ * the new VRF. Note that this function is invoked *prior* to the VRF change.
+ */
+void
+zebra_interface_vrf_update_del (struct interface *ifp, vrf_id_t new_vrf_id)
+{
+  struct listnode *node, *nnode;
+  struct zserv *client;
+
+  if (IS_ZEBRA_DEBUG_EVENT)
+    zlog_debug ("MESSAGE: ZEBRA_INTERFACE_VRF_UPDATE/DEL %s VRF Id %u -> %u",
+                ifp->name, ifp->vrf_id, new_vrf_id);
+
+  for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
+    {
+      /* Skip clients not interested in both VRFs. */
+      if (!vrf_bitmap_check (client->ifinfo, ifp->vrf_id) &&
+          !vrf_bitmap_check (client->ifinfo, new_vrf_id))
+        continue;
+
+      if (!vrf_bitmap_check (client->ifinfo, new_vrf_id))
+        {
+          /* Need to delete if the client is not interested in the new VRF. */
+          zsend_interface_update (ZEBRA_INTERFACE_DOWN, client, ifp);
+          client->ifdel_cnt++;
+          zsend_interface_delete (client, ifp);
+        }
+      else if (vrf_bitmap_check (client->ifinfo, ifp->vrf_id))
+        {
+          /* Client is interested in both VRFs, inform about the change. */
+          zsend_interface_vrf_update (client, ifp, new_vrf_id);
+        }
+    }
+}
+
+/* Interface VRF change. This function is invoked *post* VRF change and sends an
+ * add to clients who are interested in the new VRF but not in the old VRF.
+ */
+void
+zebra_interface_vrf_update_add (struct interface *ifp, vrf_id_t old_vrf_id)
+{
+  struct listnode *node, *nnode;
+  struct zserv *client;
+
+  if (IS_ZEBRA_DEBUG_EVENT)
+    zlog_debug ("MESSAGE: ZEBRA_INTERFACE_VRF_UPDATE/ADD %s VRF Id %u -> %u",
+                ifp->name, old_vrf_id, ifp->vrf_id);
+
+  for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
+    {
+      /* Skip clients interested in both VRFs - they would've got an Update. */
+      if (vrf_bitmap_check (client->ifinfo, ifp->vrf_id) &&
+          vrf_bitmap_check (client->ifinfo, old_vrf_id))
+        continue;
+
+      /* Skip clients not interested in the new VRF - they would've
+       * got a Delete.
+       */
+      if (!vrf_bitmap_check (client->ifinfo, ifp->vrf_id))
+        continue;
+
+      /* Need to add if the client is interested in the new VRF. */
+      client->ifadd_cnt++;
+      zsend_interface_add (client, ifp);
+      zsend_interface_addresses (client, ifp);
+    }
+}
+
 int
 zebra_add_import_table_entry (struct route_node *rn, struct rib *rib)
 {
@@ -492,8 +643,7 @@ zebra_add_import_table_entry (struct route_node *rn, struct rib *rib)
       if (rib->nexthop_num == 1)
        {
          nhop = rib->nexthop;
-         if ((nhop->type == NEXTHOP_TYPE_IFINDEX) ||
-             (nhop->type == NEXTHOP_TYPE_IFNAME))
+         if (nhop->type == NEXTHOP_TYPE_IFINDEX)
            gate = NULL;
          else
            gate = &nhop->gate.ipv4;
@@ -519,7 +669,7 @@ zebra_add_import_table_entry (struct route_node *rn, struct rib *rib)
 
          /* Assuming these routes are never recursive */
          for (nhop = rib->nexthop; nhop; nhop = nhop->next)
-           copy_nexthops(newrib, nhop);
+           rib_copy_nexthops(newrib, nhop);
 
          rib_add_ipv4_multipath(&p4, newrib, SAFI_UNICAST);
        }