]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra: Create zebra_static.[ch] to isolate code
authorDonald Sharp <sharpd@cumulusnetworks.com>
Thu, 1 Sep 2016 11:20:02 +0000 (07:20 -0400)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Thu, 1 Sep 2016 11:20:02 +0000 (07:20 -0400)
Isolate the zebra static_XXX functions from zebra_rib.c
This is the first in a series of changes to clean up
the zebra code a bit more.

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
zebra/Makefile.am
zebra/rib.h
zebra/zebra_rib.c
zebra/zebra_static.c [new file with mode: 0644]
zebra/zebra_static.h [new file with mode: 0644]
zebra/zebra_vrf.c
zebra/zebra_vty.c

index 4492f9e6d4e1053bf3f49d56131baae6f9ca3616..0218af81b7ec4780e307e2c8ae4ffc7d2112b63c 100644 (file)
@@ -31,19 +31,19 @@ zebra_SOURCES = \
        redistribute.c debug.c rtadv.c zebra_snmp.c zebra_vty.c \
        irdp_main.c irdp_interface.c irdp_packet.c router-id.c zebra_fpm.c \
        $(othersrc) zebra_ptm.c zebra_rnh.c zebra_ptm_redistribute.c \
-       zebra_ns.c zebra_vrf.c
+       zebra_ns.c zebra_vrf.c zebra_static.c
 
 testzebra_SOURCES = test_main.c zebra_rib.c interface.c connected.c debug.c \
        zebra_vty.c zebra_ptm.c zebra_routemap.c zebra_ns.c zebra_vrf.c \
        kernel_null.c  redistribute_null.c ioctl_null.c misc_null.c zebra_rnh_null.c \
-       zebra_ptm_null.c rtadv_null.c if_null.c zserv_null.c
+       zebra_ptm_null.c rtadv_null.c if_null.c zserv_null.c zebra_static.c
 
 noinst_HEADERS = \
        connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \
        interface.h ipforward.h irdp.h router-id.h kernel_socket.h \
        rt_netlink.h zebra_fpm.h zebra_fpm_private.h zebra_rnh.h \
        zebra_ptm_redistribute.h zebra_ptm.h zebra_routemap.h \
-       zebra_ns.h zebra_vrf.h ioctl_solaris.h
+       zebra_ns.h zebra_vrf.h ioctl_solaris.h zebra_static.h
 
 zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP)
 
index 095b9c6f8f9b089fec2c2b512c371c8ee88a923f..32f370f9ef12c26d8afc5d58ab9616a58e577c2d 100644 (file)
@@ -175,51 +175,6 @@ typedef struct rib_dest_t_
 #define RNODE_FOREACH_RIB_SAFE(rn, rib, next)                          \
   RIB_DEST_FOREACH_ROUTE_SAFE (rib_dest_from_rnode (rn), rib, next)
 
-/* Static route information. */
-struct static_route
-{
-  /* For linked list. */
-  struct static_route *prev;
-  struct static_route *next;
-
-  /* VRF identifier. */
-  vrf_id_t vrf_id;
-
-  /* Administrative distance. */
-  u_char distance;
-
-  /* Tag */
-  u_short tag;
-
-  /* Flag for this static route's type. */
-  u_char type;
-#define STATIC_IFINDEX               1
-#define STATIC_IPV4_GATEWAY          2
-#define STATIC_IPV4_BLACKHOLE        3
-#define STATIC_IPV6_GATEWAY          4
-#define STATIC_IPV6_GATEWAY_IFINDEX  5
-
-  /*
-   * Nexthop value.
-   *
-   * Under IPv4 addr and ifindex are
-   * used independentyly.
-   * STATIC_IPV4_GATEWAY uses addr
-   * STATIC_IFINDEX uses ifindex
-   */
-  union g_addr addr;
-  ifindex_t ifindex;
-
-  char ifname[INTERFACE_NAMSIZ + 1];
-
-  /* bit flags */
-  u_char flags;
-/*
- see ZEBRA_FLAG_REJECT
-     ZEBRA_FLAG_BLACKHOLE
- */
-};
-
 /* The following for loop allows to iterate over the nexthop
  * structure of routes.
  *
@@ -365,6 +320,7 @@ extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *,
 #define ZEBRA_RIB_FOUND_CONNECTED 2
 #define ZEBRA_RIB_NOTFOUND 3
 
+extern void rib_nexthop_delete (struct rib *rib, struct nexthop *nexthop);
 extern struct nexthop *rib_nexthop_ipv6_add (struct rib *, struct in6_addr *);
 extern struct nexthop *rib_nexthop_ipv6_ifindex_add (struct rib *rib,
                                                     struct in6_addr *ipv6,
@@ -374,6 +330,11 @@ extern int is_zebra_valid_kernel_table(u_int32_t table_id);
 extern int is_zebra_main_routing_table(u_int32_t table_id);
 extern int zebra_check_addr (struct prefix *p);
 
+extern void rib_addnode (struct route_node *rn, struct rib *rib, int process);
+extern void rib_delnode (struct route_node *rn, struct rib *rib);
+extern int rib_install_kernel (struct route_node *rn, struct rib *rib, int update);
+extern int rib_uninstall_kernel (struct route_node *rn, struct rib *rib);
+
 /* NOTE:
  * All rib_add_ipv[46]* functions will not just add prefix into RIB, but
  * also implicitly withdraw equal prefix of same type. */
@@ -404,20 +365,6 @@ extern void rib_init (void);
 extern unsigned long rib_score_proto (u_char proto, u_short instance);
 extern void rib_queue_add (struct route_node *rn);
 
-extern void
-static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si);
-extern void
-static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si);
-
-extern int
-static_add_ipv4 (safi_t safi, struct prefix *p, struct in_addr *gate, ifindex_t ifindex,
-                 const char *ifname, u_char flags, u_short tag,
-                u_char distance, struct zebra_vrf *zvrf);
-
-extern int
-static_delete_ipv4 (safi_t safi, struct prefix *p, struct in_addr *gate, ifindex_t ifindex,
-                   u_short tag, u_char distance, struct zebra_vrf *zvrf);
-
 extern int
 rib_add_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p,
              struct in6_addr *gate, ifindex_t ifindex, vrf_id_t vrf_id,
@@ -435,20 +382,10 @@ extern struct rib *rib_match_ipv6 (struct in6_addr *, vrf_id_t);
 
 extern struct route_table *rib_table_ipv6;
 
-extern int
-static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
-                ifindex_t ifindex, const char *ifname, u_char flags,
-                u_short tag, u_char distance, struct zebra_vrf *zvrf);
-
 extern int
 rib_add_ipv6_multipath (struct prefix *, struct rib *, safi_t,
                         ifindex_t);
 
-extern int
-static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
-                   ifindex_t ifindex, u_short tag, u_char distance,
-                    struct zebra_vrf *zvrf);
-
 extern int rib_gc_dest (struct route_node *rn);
 extern struct route_table *rib_tables_iter_next (rib_tables_iter_t *iter);
 
index 195d3633e1b8bcbd993bc0eb343a6b3647909d05..0db1b0a689431d2f16c64c191f1004e4df67d71a 100644 (file)
@@ -195,7 +195,7 @@ rib_copy_nexthops (struct rib *rib, struct nexthop *nh)
 }
 
 /* Delete specified nexthop from the list. */
-static void
+void
 rib_nexthop_delete (struct rib *rib, struct nexthop *nexthop)
 {
   if (nexthop->next)
@@ -1248,7 +1248,7 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set)
 /* Update flag indicates whether this is a "replace" or not. Currently, this
  * is only used for IPv4.
  */
-static int
+int
 rib_install_kernel (struct route_node *rn, struct rib *rib, int update)
 {
   int ret = 0;
@@ -1303,7 +1303,7 @@ rib_install_kernel (struct route_node *rn, struct rib *rib, int update)
 }
 
 /* Uninstall the route from kernel. */
-static int
+int
 rib_uninstall_kernel (struct route_node *rn, struct rib *rib)
 {
   int ret = 0;
@@ -1555,7 +1555,6 @@ rib_process_update_route (struct zebra_vrf *zvrf, struct route_node *rn,
                   for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
                     UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
                 }
-
             }
 
           /* Update for redistribution. */
@@ -2324,7 +2323,7 @@ rib_link (struct route_node *rn, struct rib *rib, int process)
       rib_queue_add (rn);
 }
 
-static void
+void
 rib_addnode (struct route_node *rn, struct rib *rib, int process)
 {
   /* RIB node has been un-removed before route-node is processed. 
@@ -2379,7 +2378,7 @@ rib_unlink (struct route_node *rn, struct rib *rib)
 
 }
 
-static void
+void
 rib_delnode (struct route_node *rn, struct rib *rib)
 {
   afi_t afi;
@@ -2910,440 +2909,7 @@ rib_delete_ipv4 (int type, u_short instance, int flags, struct prefix_ipv4 *p,
   return 0;
 }
 
-/* Install static route into rib. */
-void
-static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si)
-{
-  struct rib *rib;
-  struct route_node *rn;
-  struct route_table *table;
-  struct prefix nh_p;
-
-  /* Lookup table.  */
-  table = zebra_vrf_table (afi, safi, si->vrf_id);
-  if (! table)
-    return;
-
-  /* Lookup existing route */
-  rn = route_node_get (table, p);
-  RNODE_FOREACH_RIB (rn, rib)
-    {
-       if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
-         continue;
-        
-       if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
-         break;
-    }
-
-  if (rib)
-    {
-      /* if tag value changed , update old value in RIB */
-      if (rib->tag != si->tag)
-        rib->tag = si->tag;
-
-      /* Same distance static route is there.  Update it with new
-         nexthop. */
-      route_unlock_node (rn);
-      switch (si->type)
-        {
-       case STATIC_IPV4_GATEWAY:
-         rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL);
-         nh_p.family = AF_INET;
-         nh_p.prefixlen = IPV4_MAX_BITLEN;
-         nh_p.u.prefix4 = si->addr.ipv4;
-         zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
-         break;
-       case STATIC_IFINDEX:
-         rib_nexthop_ifindex_add (rib, si->ifindex);
-         break;
-       case STATIC_IPV4_BLACKHOLE:
-         rib_nexthop_blackhole_add (rib);
-         break;
-       case STATIC_IPV6_GATEWAY:
-         rib_nexthop_ipv6_add (rib, &si->addr.ipv6);
-         nh_p.family = AF_INET6;
-         nh_p.prefixlen = IPV6_MAX_BITLEN;
-         nh_p.u.prefix6 = si->addr.ipv6;
-         zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
-         break;
-       case STATIC_IPV6_GATEWAY_IFINDEX:
-         rib_nexthop_ipv6_ifindex_add (rib, &si->addr.ipv6, si->ifindex);
-         break;
-        }
-
-      if (IS_ZEBRA_DEBUG_RIB)
-        {
-          char buf[INET6_ADDRSTRLEN];
-          if (IS_ZEBRA_DEBUG_RIB)
-            {
-              inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN);
-              zlog_debug ("%u:%s/%d: Modifying route rn %p, rib %p (type %d)",
-                          si->vrf_id, buf, p->prefixlen, rn, rib, rib->type);
-            }
-        }
-      /* Schedule route for processing or invoke NHT, as appropriate. */
-      if (si->type == STATIC_IPV4_GATEWAY ||
-          si->type == STATIC_IPV6_GATEWAY)
-        zebra_evaluate_rnh(si->vrf_id, nh_p.family, 1, RNH_NEXTHOP_TYPE, &nh_p);
-      else
-        rib_queue_add (rn);
-    }
-  else
-    {
-      /* This is new static route. */
-      rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
-      
-      rib->type = ZEBRA_ROUTE_STATIC;
-      rib->instance = 0;
-      rib->distance = si->distance;
-      rib->metric = 0;
-      rib->mtu = 0;
-      rib->vrf_id = si->vrf_id;
-      rib->table =  si->vrf_id ? (zebra_vrf_lookup(si->vrf_id))->table_id : zebrad.rtm_table_default;
-      rib->nexthop_num = 0;
-      rib->tag = si->tag;
-
-      switch (si->type)
-        {
-       case STATIC_IPV4_GATEWAY:
-         rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL);
-         nh_p.family = AF_INET;
-         nh_p.prefixlen = IPV4_MAX_BITLEN;
-         nh_p.u.prefix4 = si->addr.ipv4;
-         zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
-         break;
-       case STATIC_IFINDEX:
-         rib_nexthop_ifindex_add (rib, si->ifindex);
-         break;
-       case STATIC_IPV4_BLACKHOLE:
-         rib_nexthop_blackhole_add (rib);
-         break;
-       case STATIC_IPV6_GATEWAY:
-         rib_nexthop_ipv6_add (rib, &si->addr.ipv6);
-         nh_p.family = AF_INET6;
-         nh_p.prefixlen = IPV6_MAX_BITLEN;
-         nh_p.u.prefix6 = si->addr.ipv6;
-         zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
-         break;
-       case STATIC_IPV6_GATEWAY_IFINDEX:
-         rib_nexthop_ipv6_ifindex_add (rib, &si->addr.ipv6, si->ifindex);
-         break;
-        }
-
-      /* Save the flags of this static routes (reject, blackhole) */
-      rib->flags = si->flags;
-
-      if (IS_ZEBRA_DEBUG_RIB)
-        {
-          char buf[INET6_ADDRSTRLEN];
-          if (IS_ZEBRA_DEBUG_RIB)
-            {
-              inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN);
-              zlog_debug ("%u:%s/%d: Inserting route rn %p, rib %p (type %d)",
-                          si->vrf_id, buf, p->prefixlen, rn, rib, rib->type);
-            }
-        }
-      /* Link this rib to the tree. Schedule for processing or invoke NHT,
-       * as appropriate.
-       */
-      if (si->type == STATIC_IPV4_GATEWAY ||
-          si->type == STATIC_IPV6_GATEWAY)
-        {
-          rib_addnode (rn, rib, 0);
-          zebra_evaluate_rnh(si->vrf_id, nh_p.family, 1, RNH_NEXTHOP_TYPE, &nh_p);
-        }
-      else
-        rib_addnode (rn, rib, 1);
-    }
-}
-
-static int
-static_nexthop_same (struct nexthop *nexthop, struct static_route *si)
-{
-  if (nexthop->type == NEXTHOP_TYPE_IPV4
-      && si->type == STATIC_IPV4_GATEWAY
-      && IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->addr.ipv4))
-    return 1;
-  if (nexthop->type == NEXTHOP_TYPE_IFINDEX
-      && si->type == STATIC_IFINDEX
-      && nexthop->ifindex == si->ifindex)
-    return 1;
-  if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE
-      && si->type == STATIC_IPV4_BLACKHOLE)
-    return 1;
-  if (nexthop->type == NEXTHOP_TYPE_IPV6
-      && si->type == STATIC_IPV6_GATEWAY
-      && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6))
-    return 1;
-  if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
-      && si->type == STATIC_IPV6_GATEWAY_IFINDEX
-      && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6)
-      && nexthop->ifindex == si->ifindex)
-    return 1;
-  return 0;
-}
-
-/* Uninstall static route from RIB. */
-void
-static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si)
-{
-  struct route_node *rn;
-  struct rib *rib;
-  struct nexthop *nexthop;
-  struct route_table *table;
-  struct prefix nh_p;
-
-  /* Lookup table.  */
-  table = zebra_vrf_table (afi, safi, si->vrf_id);
-  if (! table)
-    return;
-  
-  /* Lookup existing route with type and distance. */
-  rn = route_node_lookup (table, p);
-  if (! rn)
-    return;
-
-  RNODE_FOREACH_RIB (rn, rib)
-    {
-      if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
-        continue;
-
-      if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance &&
-          rib->tag == si->tag)
-        break;
-    }
-
-  if (! rib)
-    {
-      route_unlock_node (rn);
-      return;
-    }
-
-  /* Lookup nexthop. */
-  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
-    if (static_nexthop_same (nexthop, si))
-      break;
-
-  /* Can't find nexthop. */
-  if (! nexthop)
-    {
-      route_unlock_node (rn);
-      return;
-    }
-  
-  /* Check nexthop. */
-  if (rib->nexthop_num == 1)
-    rib_delnode (rn, rib);
-  else
-    {
-      /* Mark this nexthop as inactive and reinstall the route. Then, delete
-       * the nexthop. There is no need to re-evaluate the route for this
-       * scenario.
-       */
-      if (IS_ZEBRA_DEBUG_RIB)
-        {
-          char buf[INET6_ADDRSTRLEN];
-          if (IS_ZEBRA_DEBUG_RIB)
-            {
-              inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN);
-              zlog_debug ("%u:%s/%d: Modifying route rn %p, rib %p (type %d)",
-                          si->vrf_id, buf, p->prefixlen, rn, rib, rib->type);
-            }
-        }
-      UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
-        {
-          /* If there are other active nexthops, do an update. */
-          if (rib->nexthop_active_num > 1)
-            {
-              rib_install_kernel (rn, rib, 1);
-              redistribute_update (&rn->p, rib, NULL);
-            }
-          else
-            {
-              redistribute_delete (&rn->p, rib);
-              rib_uninstall_kernel (rn, rib);
-            }
-        }
-
-      if (afi == AFI_IP)
-       {
-         /* Delete the nexthop and dereg from NHT */
-         nh_p.family = AF_INET;
-         nh_p.prefixlen = IPV4_MAX_BITLEN;
-         nh_p.u.prefix4 = nexthop->gate.ipv4;
-       }
-      else
-       {
-         nh_p.family = AF_INET6;
-         nh_p.prefixlen = IPV6_MAX_BITLEN;
-         nh_p.u.prefix6 = nexthop->gate.ipv6;
-       }
-      rib_nexthop_delete (rib, nexthop);
-      zebra_deregister_rnh_static_nh(si->vrf_id, &nh_p, rn);
-      nexthop_free (nexthop);
-    }
-  /* Unlock node. */
-  route_unlock_node (rn);
-}
-
-int
-static_add_ipv4 (safi_t safi, struct prefix *p, struct in_addr *gate, ifindex_t ifindex,
-                const char *ifname, u_char flags, u_short tag,
-                u_char distance, struct zebra_vrf *zvrf)
-{
-  u_char type = 0;
-  struct route_node *rn;
-  struct static_route *si;
-  struct static_route *pp;
-  struct static_route *cp;
-  struct static_route *update = NULL;
-  struct route_table *stable = zvrf->stable[AFI_IP][safi];
-
-  if (! stable)
-    return -1;
-  
-  /* Lookup static route prefix. */
-  rn = route_node_get (stable, p);
-
-  /* Make flags. */
-  if (gate)
-    type = STATIC_IPV4_GATEWAY;
-  else if (ifindex)
-    type = STATIC_IFINDEX;
-  else
-    type = STATIC_IPV4_BLACKHOLE;
-
-  /* Do nothing if there is a same static route.  */
-  for (si = rn->info; si; si = si->next)
-    {
-      if (type == si->type
-         && (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4))
-         && (! ifindex || ifindex == si->ifindex))
-       {
-         if ((distance == si->distance) && (tag == si->tag))
-           {
-             route_unlock_node (rn);
-             return 0;
-           }
-         else
-           update = si;
-       }
-    }
-
-  /* Distance or tag changed. */
-  if (update)
-    static_delete_ipv4 (safi, p, gate, ifindex, update->tag, update->distance, zvrf);
-
-  /* Make new static route structure. */
-  si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route));
 
-  si->type = type;
-  si->distance = distance;
-  si->flags = flags;
-  si->tag = tag;
-  si->vrf_id = zvrf->vrf_id;
-  si->ifindex = ifindex;
-  if (si->ifindex)
-    strcpy(si->ifname, ifname);
-
-  if (gate)
-    si->addr.ipv4 = *gate;
-
-  /* Add new static route information to the tree with sort by
-     distance value and gateway address. */
-  for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next)
-    {
-      if (si->distance < cp->distance)
-       break;
-      if (si->distance > cp->distance)
-       continue;
-      if (si->type == STATIC_IPV4_GATEWAY && cp->type == STATIC_IPV4_GATEWAY)
-       {
-         if (ntohl (si->addr.ipv4.s_addr) < ntohl (cp->addr.ipv4.s_addr))
-           break;
-         if (ntohl (si->addr.ipv4.s_addr) > ntohl (cp->addr.ipv4.s_addr))
-           continue;
-       }
-    }
-
-  /* Make linked list. */
-  if (pp)
-    pp->next = si;
-  else
-    rn->info = si;
-  if (cp)
-    cp->prev = si;
-  si->prev = pp;
-  si->next = cp;
-
-  /* Install into rib. */
-  static_install_route (AFI_IP, safi, p, si);
-
-  return 1;
-}
-
-int
-static_delete_ipv4 (safi_t safi, struct prefix *p, struct in_addr *gate, ifindex_t ifindex,
-                   u_short tag, u_char distance, struct zebra_vrf *zvrf)
-{
-  u_char type = 0;
-  struct route_node *rn;
-  struct static_route *si;
-  struct route_table *stable;
-
-  /* Lookup table.  */
-  stable = zebra_vrf_static_table (AFI_IP, safi, zvrf);
-  if (! stable)
-    return -1;
-
-  /* Lookup static route prefix. */
-  rn = route_node_lookup (stable, p);
-  if (! rn)
-    return 0;
-
-  /* Make flags. */
-  if (gate)
-    type = STATIC_IPV4_GATEWAY;
-  else if (ifindex)
-    type = STATIC_IFINDEX;
-  else
-    type = STATIC_IPV4_BLACKHOLE;
-
-  /* Find same static route is the tree */
-  for (si = rn->info; si; si = si->next)
-    if (type == si->type
-       && (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4))
-       && (! ifindex || ifindex == si->ifindex)
-       && (! tag || (tag == si->tag)))
-      break;
-
-  /* Can't find static route. */
-  if (! si)
-    {
-      route_unlock_node (rn);
-      return 0;
-    }
-
-  /* Install into rib. */
-  static_uninstall_route (AFI_IP, safi, p, si);
-
-  /* Unlink static route from linked list. */
-  if (si->prev)
-    si->prev->next = si->next;
-  else
-    rn->info = si->next;
-  if (si->next)
-    si->next->prev = si->prev;
-  route_unlock_node (rn);
-  
-  /* Free static route configuration. */
-  XFREE (MTYPE_STATIC_ROUTE, si);
-
-  route_unlock_node (rn);
-
-  return 1;
-}
 
 int
 rib_add_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p,
@@ -3707,155 +3273,6 @@ rib_delete_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p,
   return 0;
 }
 
-/* Add static route into static route configuration. */
-int
-static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
-                ifindex_t ifindex, const char *ifname, u_char flags,
-                u_short tag, u_char distance, struct zebra_vrf *zvrf)
-{
-  struct route_node *rn;
-  struct static_route *si;
-  struct static_route *pp;
-  struct static_route *cp;
-  struct static_route *update = NULL;
-  struct route_table *stable = zvrf->stable[AFI_IP6][SAFI_UNICAST];
-
-  if (! stable)
-    return -1;
-    
-  if (!gate &&
-      (type == STATIC_IPV6_GATEWAY || type == STATIC_IPV6_GATEWAY_IFINDEX))
-    return -1;
-  
-  if (!ifindex &&
-      (type == STATIC_IPV6_GATEWAY_IFINDEX || type == STATIC_IFINDEX))
-    return -1;
-
-  /* Lookup static route prefix. */
-  rn = route_node_get (stable, p);
-
-  /* Do nothing if there is a same static route.  */
-  for (si = rn->info; si; si = si->next)
-    {
-      if (type == si->type
-         && (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6))
-         && (! ifindex || ifindex ==  si->ifindex))
-       {
-         if ((distance == si->distance) && (tag == si->tag))
-           {
-             route_unlock_node (rn);
-             return 0;
-           }
-         else
-           update = si;
-       }
-    }
-
-  /* Distance or tag changed. */
-  if (update)
-    static_delete_ipv6 (p, type, gate, ifindex, update->tag, update->distance, zvrf);
-
-  /* Make new static route structure. */
-  si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route));
-
-  si->type = type;
-  si->distance = distance;
-  si->flags = flags;
-  si->tag = tag;
-  si->vrf_id = zvrf->vrf_id;
-  si->ifindex = ifindex;
-  if (si->ifindex)
-    strcpy (si->ifname, ifname);
-
-  switch (type)
-    {
-    case STATIC_IPV6_GATEWAY:
-      si->addr.ipv6 = *gate;
-      break;
-    case STATIC_IPV6_GATEWAY_IFINDEX:
-      si->addr.ipv6 = *gate;
-      break;
-    }
-
-  /* Add new static route information to the tree with sort by
-     distance value and gateway address. */
-  for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next)
-    {
-      if (si->distance < cp->distance)
-       break;
-      if (si->distance > cp->distance)
-       continue;
-    }
-
-  /* Make linked list. */
-  if (pp)
-    pp->next = si;
-  else
-    rn->info = si;
-  if (cp)
-    cp->prev = si;
-  si->prev = pp;
-  si->next = cp;
-
-  /* Install into rib. */
-  static_install_route (AFI_IP6, SAFI_UNICAST, p, si);
-
-  return 1;
-}
-
-/* Delete static route from static route configuration. */
-int
-static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
-                   ifindex_t ifindex, u_short tag, u_char distance,
-                    struct zebra_vrf *zvrf)
-{
-  struct route_node *rn;
-  struct static_route *si;
-  struct route_table *stable;
-
-  /* Lookup table.  */
-  stable = zebra_vrf_static_table (AFI_IP6, SAFI_UNICAST, zvrf);
-  if (! stable)
-    return -1;
-
-  /* Lookup static route prefix. */
-  rn = route_node_lookup (stable, p);
-  if (! rn)
-    return 0;
-
-  /* Find same static route is the tree */
-  for (si = rn->info; si; si = si->next)
-    if (distance == si->distance 
-       && type == si->type
-       && (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6))
-       && (! ifindex || ifindex == si->ifindex)
-       && (! tag || (tag == si->tag)))
-      break;
-
-  /* Can't find static route. */
-  if (! si)
-    {
-      route_unlock_node (rn);
-      return 0;
-    }
-
-  /* Install into rib. */
-  static_uninstall_route (AFI_IP6, SAFI_UNICAST, p, si);
-
-  /* Unlink static route from linked list. */
-  if (si->prev)
-    si->prev->next = si->next;
-  else
-    rn->info = si->next;
-  if (si->next)
-    si->next->prev = si->prev;
-  
-  /* Free static route configuration. */
-  XFREE (MTYPE_STATIC_ROUTE, si);
-
-  return 1;
-}
-
 /* Schedule routes of a particular table (address-family) based on event. */
 static void
 rib_update_table (struct route_table *table, rib_update_event_t event)
diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c
new file mode 100644 (file)
index 0000000..9d16f12
--- /dev/null
@@ -0,0 +1,617 @@
+/*
+ * Static Routing Information code
+ * Copyright (C) 2016 Cumulus Networks
+ *               Donald Sharp
+ *
+ * This file is part of Quagga.
+ *
+ * Quagga is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * Quagga is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Quagga; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <zebra.h>
+
+#include <lib/nexthop.h>
+#include <lib/memory.h>
+
+#include "zebra/debug.h"
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/zebra_static.h"
+#include "zebra/zebra_rnh.h"
+#include "zebra/redistribute.h"
+
+/* Install static route into rib. */
+void
+static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si)
+{
+  struct rib *rib;
+  struct route_node *rn;
+  struct route_table *table;
+  struct prefix nh_p;
+
+  /* Lookup table.  */
+  table = zebra_vrf_table (afi, safi, si->vrf_id);
+  if (! table)
+    return;
+
+  /* Lookup existing route */
+  rn = route_node_get (table, p);
+  RNODE_FOREACH_RIB (rn, rib)
+    {
+       if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
+         continue;
+
+       if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
+         break;
+    }
+
+  if (rib)
+    {
+      /* if tag value changed , update old value in RIB */
+      if (rib->tag != si->tag)
+        rib->tag = si->tag;
+
+      /* Same distance static route is there.  Update it with new
+         nexthop. */
+      route_unlock_node (rn);
+      switch (si->type)
+        {
+       case STATIC_IPV4_GATEWAY:
+         rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL);
+         nh_p.family = AF_INET;
+         nh_p.prefixlen = IPV4_MAX_BITLEN;
+         nh_p.u.prefix4 = si->addr.ipv4;
+         zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
+         break;
+       case STATIC_IFINDEX:
+         rib_nexthop_ifindex_add (rib, si->ifindex);
+         break;
+       case STATIC_IPV4_BLACKHOLE:
+         rib_nexthop_blackhole_add (rib);
+         break;
+       case STATIC_IPV6_GATEWAY:
+         rib_nexthop_ipv6_add (rib, &si->addr.ipv6);
+         nh_p.family = AF_INET6;
+         nh_p.prefixlen = IPV6_MAX_BITLEN;
+         nh_p.u.prefix6 = si->addr.ipv6;
+         zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
+         break;
+       case STATIC_IPV6_GATEWAY_IFINDEX:
+         rib_nexthop_ipv6_ifindex_add (rib, &si->addr.ipv6, si->ifindex);
+         break;
+        }
+
+      if (IS_ZEBRA_DEBUG_RIB)
+        {
+          char buf[INET6_ADDRSTRLEN];
+          if (IS_ZEBRA_DEBUG_RIB)
+            {
+              inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN);
+              zlog_debug ("%u:%s/%d: Modifying route rn %p, rib %p (type %d)",
+                          si->vrf_id, buf, p->prefixlen, rn, rib, rib->type);
+            }
+        }
+      /* Schedule route for processing or invoke NHT, as appropriate. */
+      if (si->type == STATIC_IPV4_GATEWAY ||
+          si->type == STATIC_IPV6_GATEWAY)
+        zebra_evaluate_rnh(si->vrf_id, nh_p.family, 1, RNH_NEXTHOP_TYPE, &nh_p);
+      else
+        rib_queue_add (rn);
+    }
+  else
+    {
+      /* This is new static route. */
+      rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
+
+      rib->type = ZEBRA_ROUTE_STATIC;
+      rib->instance = 0;
+      rib->distance = si->distance;
+      rib->metric = 0;
+      rib->mtu = 0;
+      rib->vrf_id = si->vrf_id;
+      rib->table =  si->vrf_id ? (zebra_vrf_lookup(si->vrf_id))->table_id : zebrad.rtm_table_default;
+      rib->nexthop_num = 0;
+      rib->tag = si->tag;
+
+      switch (si->type)
+        {
+       case STATIC_IPV4_GATEWAY:
+         rib_nexthop_ipv4_add (rib, &si->addr.ipv4, NULL);
+         nh_p.family = AF_INET;
+         nh_p.prefixlen = IPV4_MAX_BITLEN;
+         nh_p.u.prefix4 = si->addr.ipv4;
+         zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
+         break;
+       case STATIC_IFINDEX:
+         rib_nexthop_ifindex_add (rib, si->ifindex);
+         break;
+       case STATIC_IPV4_BLACKHOLE:
+         rib_nexthop_blackhole_add (rib);
+         break;
+       case STATIC_IPV6_GATEWAY:
+         rib_nexthop_ipv6_add (rib, &si->addr.ipv6);
+         nh_p.family = AF_INET6;
+         nh_p.prefixlen = IPV6_MAX_BITLEN;
+         nh_p.u.prefix6 = si->addr.ipv6;
+         zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
+         break;
+       case STATIC_IPV6_GATEWAY_IFINDEX:
+         rib_nexthop_ipv6_ifindex_add (rib, &si->addr.ipv6, si->ifindex);
+         break;
+        }
+
+      /* Save the flags of this static routes (reject, blackhole) */
+      rib->flags = si->flags;
+
+      if (IS_ZEBRA_DEBUG_RIB)
+        {
+          char buf[INET6_ADDRSTRLEN];
+          if (IS_ZEBRA_DEBUG_RIB)
+            {
+              inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN);
+              zlog_debug ("%u:%s/%d: Inserting route rn %p, rib %p (type %d)",
+                          si->vrf_id, buf, p->prefixlen, rn, rib, rib->type);
+            }
+        }
+      /* Link this rib to the tree. Schedule for processing or invoke NHT,
+       * as appropriate.
+       */
+      if (si->type == STATIC_IPV4_GATEWAY ||
+          si->type == STATIC_IPV6_GATEWAY)
+        {
+          rib_addnode (rn, rib, 0);
+          zebra_evaluate_rnh(si->vrf_id, nh_p.family, 1, RNH_NEXTHOP_TYPE, &nh_p);
+        }
+      else
+        rib_addnode (rn, rib, 1);
+    }
+}
+static int
+static_nexthop_same (struct nexthop *nexthop, struct static_route *si)
+{
+  if (nexthop->type == NEXTHOP_TYPE_IPV4
+      && si->type == STATIC_IPV4_GATEWAY
+      && IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->addr.ipv4))
+    return 1;
+  if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+      && si->type == STATIC_IFINDEX
+      && nexthop->ifindex == si->ifindex)
+    return 1;
+  if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE
+      && si->type == STATIC_IPV4_BLACKHOLE)
+    return 1;
+  if (nexthop->type == NEXTHOP_TYPE_IPV6
+      && si->type == STATIC_IPV6_GATEWAY
+      && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6))
+    return 1;
+  if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
+      && si->type == STATIC_IPV6_GATEWAY_IFINDEX
+      && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6)
+      && nexthop->ifindex == si->ifindex)
+    return 1;
+  return 0;
+}
+
+/* Uninstall static route from RIB. */
+void
+static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si)
+{
+  struct route_node *rn;
+  struct rib *rib;
+  struct nexthop *nexthop;
+  struct route_table *table;
+  struct prefix nh_p;
+
+  /* Lookup table.  */
+  table = zebra_vrf_table (afi, safi, si->vrf_id);
+  if (! table)
+    return;
+
+  /* Lookup existing route with type and distance. */
+  rn = route_node_lookup (table, p);
+  if (! rn)
+    return;
+
+  RNODE_FOREACH_RIB (rn, rib)
+    {
+      if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
+        continue;
+
+      if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance &&
+          rib->tag == si->tag)
+        break;
+    }
+
+  if (! rib)
+    {
+      route_unlock_node (rn);
+      return;
+    }
+
+  /* Lookup nexthop. */
+  for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+    if (static_nexthop_same (nexthop, si))
+      break;
+
+  /* Can't find nexthop. */
+  if (! nexthop)
+    {
+      route_unlock_node (rn);
+      return;
+    }
+
+  /* Check nexthop. */
+  if (rib->nexthop_num == 1)
+    rib_delnode (rn, rib);
+  else
+    {
+      /* Mark this nexthop as inactive and reinstall the route. Then, delete
+       * the nexthop. There is no need to re-evaluate the route for this
+       * scenario.
+       */
+      if (IS_ZEBRA_DEBUG_RIB)
+        {
+          char buf[INET6_ADDRSTRLEN];
+          if (IS_ZEBRA_DEBUG_RIB)
+            {
+              inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN);
+              zlog_debug ("%u:%s/%d: Modifying route rn %p, rib %p (type %d)",
+                          si->vrf_id, buf, p->prefixlen, rn, rib, rib->type);
+            }
+        }
+      UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+      if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
+        {
+          /* If there are other active nexthops, do an update. */
+          if (rib->nexthop_active_num > 1)
+            {
+              rib_install_kernel (rn, rib, 1);
+              redistribute_update (&rn->p, rib, NULL);
+            }
+          else
+            {
+              redistribute_delete (&rn->p, rib);
+              rib_uninstall_kernel (rn, rib);
+            }
+        }
+
+      if (afi == AFI_IP)
+       {
+         /* Delete the nexthop and dereg from NHT */
+         nh_p.family = AF_INET;
+         nh_p.prefixlen = IPV4_MAX_BITLEN;
+         nh_p.u.prefix4 = nexthop->gate.ipv4;
+       }
+      else
+       {
+         nh_p.family = AF_INET6;
+         nh_p.prefixlen = IPV6_MAX_BITLEN;
+         nh_p.u.prefix6 = nexthop->gate.ipv6;
+       }
+      rib_nexthop_delete (rib, nexthop);
+      zebra_deregister_rnh_static_nh(si->vrf_id, &nh_p, rn);
+      nexthop_free (nexthop);
+    }
+  /* Unlock node. */
+  route_unlock_node (rn);
+}
+
+int
+static_add_ipv4 (safi_t safi, struct prefix *p, struct in_addr *gate, ifindex_t ifindex,
+                const char *ifname, u_char flags, u_short tag,
+                u_char distance, struct zebra_vrf *zvrf)
+{
+  u_char type = 0;
+  struct route_node *rn;
+  struct static_route *si;
+  struct static_route *pp;
+  struct static_route *cp;
+  struct static_route *update = NULL;
+  struct route_table *stable = zvrf->stable[AFI_IP][safi];
+
+  if (! stable)
+    return -1;
+
+  /* Lookup static route prefix. */
+  rn = route_node_get (stable, p);
+
+  /* Make flags. */
+  if (gate)
+    type = STATIC_IPV4_GATEWAY;
+  else if (ifindex)
+    type = STATIC_IFINDEX;
+  else
+    type = STATIC_IPV4_BLACKHOLE;
+
+  /* Do nothing if there is a same static route.  */
+  for (si = rn->info; si; si = si->next)
+    {
+      if (type == si->type
+         && (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4))
+         && (! ifindex || ifindex == si->ifindex))
+       {
+         if ((distance == si->distance) && (tag == si->tag))
+           {
+             route_unlock_node (rn);
+             return 0;
+           }
+         else
+           update = si;
+       }
+    }
+
+  /* Distance or tag changed. */
+  if (update)
+    static_delete_ipv4 (safi, p, gate, ifindex, update->tag, update->distance, zvrf);
+
+  /* Make new static route structure. */
+  si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route));
+
+  si->type = type;
+  si->distance = distance;
+  si->flags = flags;
+  si->tag = tag;
+  si->vrf_id = zvrf->vrf_id;
+  si->ifindex = ifindex;
+  if (si->ifindex)
+    strcpy(si->ifname, ifname);
+
+  if (gate)
+    si->addr.ipv4 = *gate;
+
+  /* Add new static route information to the tree with sort by
+     distance value and gateway address. */
+  for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next)
+    {
+      if (si->distance < cp->distance)
+       break;
+      if (si->distance > cp->distance)
+       continue;
+      if (si->type == STATIC_IPV4_GATEWAY && cp->type == STATIC_IPV4_GATEWAY)
+       {
+         if (ntohl (si->addr.ipv4.s_addr) < ntohl (cp->addr.ipv4.s_addr))
+           break;
+         if (ntohl (si->addr.ipv4.s_addr) > ntohl (cp->addr.ipv4.s_addr))
+           continue;
+       }
+    }
+
+  /* Make linked list. */
+  if (pp)
+    pp->next = si;
+  else
+    rn->info = si;
+  if (cp)
+    cp->prev = si;
+  si->prev = pp;
+  si->next = cp;
+
+  /* Install into rib. */
+  static_install_route (AFI_IP, safi, p, si);
+
+  return 1;
+}
+
+int
+static_delete_ipv4 (safi_t safi, struct prefix *p, struct in_addr *gate, ifindex_t ifindex,
+                   u_short tag, u_char distance, struct zebra_vrf *zvrf)
+{
+  u_char type = 0;
+  struct route_node *rn;
+  struct static_route *si;
+  struct route_table *stable;
+
+  /* Lookup table.  */
+  stable = zebra_vrf_static_table (AFI_IP, safi, zvrf);
+  if (! stable)
+    return -1;
+
+  /* Lookup static route prefix. */
+  rn = route_node_lookup (stable, p);
+  if (! rn)
+    return 0;
+
+  /* Make flags. */
+  if (gate)
+    type = STATIC_IPV4_GATEWAY;
+  else if (ifindex)
+    type = STATIC_IFINDEX;
+  else
+    type = STATIC_IPV4_BLACKHOLE;
+
+  /* Find same static route is the tree */
+  for (si = rn->info; si; si = si->next)
+    if (type == si->type
+       && (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4))
+       && (! ifindex || ifindex == si->ifindex)
+       && (! tag || (tag == si->tag)))
+      break;
+
+  /* Can't find static route. */
+  if (! si)
+    {
+      route_unlock_node (rn);
+      return 0;
+    }
+
+  /* Install into rib. */
+  static_uninstall_route (AFI_IP, safi, p, si);
+
+  /* Unlink static route from linked list. */
+  if (si->prev)
+    si->prev->next = si->next;
+  else
+    rn->info = si->next;
+  if (si->next)
+    si->next->prev = si->prev;
+  route_unlock_node (rn);
+
+  /* Free static route configuration. */
+  XFREE (MTYPE_STATIC_ROUTE, si);
+
+  route_unlock_node (rn);
+
+  return 1;
+}
+
+/* Add static route into static route configuration. */
+int
+static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
+                ifindex_t ifindex, const char *ifname, u_char flags,
+                u_short tag, u_char distance, struct zebra_vrf *zvrf)
+{
+  struct route_node *rn;
+  struct static_route *si;
+  struct static_route *pp;
+  struct static_route *cp;
+  struct static_route *update = NULL;
+  struct route_table *stable = zvrf->stable[AFI_IP6][SAFI_UNICAST];
+
+  if (! stable)
+    return -1;
+
+  if (!gate &&
+      (type == STATIC_IPV6_GATEWAY || type == STATIC_IPV6_GATEWAY_IFINDEX))
+    return -1;
+
+  if (!ifindex &&
+      (type == STATIC_IPV6_GATEWAY_IFINDEX || type == STATIC_IFINDEX))
+    return -1;
+
+  /* Lookup static route prefix. */
+  rn = route_node_get (stable, p);
+
+  /* Do nothing if there is a same static route.  */
+  for (si = rn->info; si; si = si->next)
+    {
+      if (type == si->type
+         && (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6))
+         && (! ifindex || ifindex ==  si->ifindex))
+       {
+         if ((distance == si->distance) && (tag == si->tag))
+           {
+             route_unlock_node (rn);
+             return 0;
+           }
+         else
+           update = si;
+       }
+    }
+
+  /* Distance or tag changed. */
+  if (update)
+    static_delete_ipv6 (p, type, gate, ifindex, update->tag, update->distance, zvrf);
+
+  /* Make new static route structure. */
+  si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route));
+
+  si->type = type;
+  si->distance = distance;
+  si->flags = flags;
+  si->tag = tag;
+  si->vrf_id = zvrf->vrf_id;
+  si->ifindex = ifindex;
+  if (si->ifindex)
+    strcpy (si->ifname, ifname);
+
+  switch (type)
+    {
+    case STATIC_IPV6_GATEWAY:
+      si->addr.ipv6 = *gate;
+      break;
+    case STATIC_IPV6_GATEWAY_IFINDEX:
+      si->addr.ipv6 = *gate;
+      break;
+    }
+
+  /* Add new static route information to the tree with sort by
+     distance value and gateway address. */
+  for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next)
+    {
+      if (si->distance < cp->distance)
+       break;
+      if (si->distance > cp->distance)
+       continue;
+    }
+
+  /* Make linked list. */
+  if (pp)
+    pp->next = si;
+  else
+    rn->info = si;
+  if (cp)
+    cp->prev = si;
+  si->prev = pp;
+  si->next = cp;
+
+  /* Install into rib. */
+  static_install_route (AFI_IP6, SAFI_UNICAST, p, si);
+
+  return 1;
+}
+
+/* Delete static route from static route configuration. */
+int
+static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
+                   ifindex_t ifindex, u_short tag, u_char distance,
+                    struct zebra_vrf *zvrf)
+{
+  struct route_node *rn;
+  struct static_route *si;
+  struct route_table *stable;
+
+  /* Lookup table.  */
+  stable = zebra_vrf_static_table (AFI_IP6, SAFI_UNICAST, zvrf);
+  if (! stable)
+    return -1;
+
+  /* Lookup static route prefix. */
+  rn = route_node_lookup (stable, p);
+  if (! rn)
+    return 0;
+
+  /* Find same static route is the tree */
+  for (si = rn->info; si; si = si->next)
+    if (distance == si->distance
+       && type == si->type
+       && (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6))
+       && (! ifindex || ifindex == si->ifindex)
+       && (! tag || (tag == si->tag)))
+      break;
+
+  /* Can't find static route. */
+  if (! si)
+    {
+      route_unlock_node (rn);
+      return 0;
+    }
+
+  /* Install into rib. */
+  static_uninstall_route (AFI_IP6, SAFI_UNICAST, p, si);
+
+  /* Unlink static route from linked list. */
+  if (si->prev)
+    si->prev->next = si->next;
+  else
+    rn->info = si->next;
+  if (si->next)
+    si->next->prev = si->prev;
+
+  /* Free static route configuration. */
+  XFREE (MTYPE_STATIC_ROUTE, si);
+
+  return 1;
+}
diff --git a/zebra/zebra_static.h b/zebra/zebra_static.h
new file mode 100644 (file)
index 0000000..a309672
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Static Routing Information header
+ * Copyright (C) 2016 Cumulus Networks
+ *               Donald Sharp
+ *
+ * This file is part of Quagga.
+ *
+ * Quagga is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * Quagga is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Quagga; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#ifndef __ZEBRA_STATIC_H__
+#define __ZEBRA_STATIC_H__
+
+/* Static route information. */
+struct static_route
+{
+  /* For linked list. */
+  struct static_route *prev;
+  struct static_route *next;
+
+  /* VRF identifier. */
+  vrf_id_t vrf_id;
+
+  /* Administrative distance. */
+  u_char distance;
+
+  /* Tag */
+  u_short tag;
+
+  /* Flag for this static route's type. */
+  u_char type;
+#define STATIC_IFINDEX               1
+#define STATIC_IPV4_GATEWAY          2
+#define STATIC_IPV4_BLACKHOLE        3
+#define STATIC_IPV6_GATEWAY          4
+#define STATIC_IPV6_GATEWAY_IFINDEX  5
+
+  /*
+   * Nexthop value.
+   *
+   * Under IPv4 addr and ifindex are
+   * used independentyly.
+   * STATIC_IPV4_GATEWAY uses addr
+   * STATIC_IFINDEX uses ifindex
+   */
+  union g_addr addr;
+  ifindex_t ifindex;
+
+  char ifname[INTERFACE_NAMSIZ + 1];
+
+  /* bit flags */
+  u_char flags;
+/*
+ see ZEBRA_FLAG_REJECT
+     ZEBRA_FLAG_BLACKHOLE
+ */
+};
+
+extern void
+static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si);
+extern void
+static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si);
+
+extern int
+static_add_ipv4 (safi_t safi, struct prefix *p, struct in_addr *gate, ifindex_t ifindex,
+                 const char *ifname, u_char flags, u_short tag,
+                u_char distance, struct zebra_vrf *zvrf);
+
+extern int
+static_delete_ipv4 (safi_t safi, struct prefix *p, struct in_addr *gate, ifindex_t ifindex,
+                   u_short tag, u_char distance, struct zebra_vrf *zvrf);
+
+extern int
+static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
+                ifindex_t ifindex, const char *ifname, u_char flags,
+                u_short tag, u_char distance, struct zebra_vrf *zvrf);
+
+extern int
+static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
+                   ifindex_t ifindex, u_short tag, u_char distance,
+                    struct zebra_vrf *zvrf);
+
+#endif
index 46dc29d102fffd9d134916c93c8a7485f61952e7..d9bd919bfebb8bda2c7bfab2e8c2cd56d87b21e5 100644 (file)
@@ -29,6 +29,7 @@
 #include "zebra/rib.h"
 #include "zebra/zebra_vrf.h"
 #include "zebra/router-id.h"
+#include "zebra/zebra_static.h"
 
 extern struct zebra_t zebrad;
 struct list *zvrf_list;
index 3c2626670b78195983f71b1e34c57f70bad27c7b..716e74c0b066fff6cfc51ba753955345de264871 100644 (file)
 #include "rib.h"
 #include "nexthop.h"
 #include "vrf.h"
+#include "lib/json.h"
 
 #include "zebra/zserv.h"
 #include "zebra/zebra_vrf.h"
 #include "zebra/zebra_rnh.h"
 #include "zebra/redistribute.h"
 #include "zebra/zebra_routemap.h"
-#include "lib/json.h"
+#include "zebra/zebra_static.h"
 
 extern int allow_delete;