summaryrefslogtreecommitdiffstats
path: root/zebra
diff options
context:
space:
mode:
authorDonald Sharp <sharpd@cumulusnetworks.com>2016-09-01 13:20:02 +0200
committerDonald Sharp <sharpd@cumulusnetworks.com>2016-09-01 13:20:02 +0200
commit28f6dde859dad5785aa40067a9ce611684e28fb4 (patch)
tree0eec75011e5aa89f109bce8c126f10d8d889d663 /zebra
parentquagga-reload.py should be importable (diff)
downloadfrr-28f6dde859dad5785aa40067a9ce611684e28fb4.tar.xz
frr-28f6dde859dad5785aa40067a9ce611684e28fb4.zip
zebra: Create zebra_static.[ch] to isolate code
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>
Diffstat (limited to 'zebra')
-rw-r--r--zebra/Makefile.am6
-rw-r--r--zebra/rib.h75
-rw-r--r--zebra/zebra_rib.c593
-rw-r--r--zebra/zebra_static.c617
-rw-r--r--zebra/zebra_static.h95
-rw-r--r--zebra/zebra_vrf.c1
-rw-r--r--zebra/zebra_vty.c3
7 files changed, 729 insertions, 661 deletions
diff --git a/zebra/Makefile.am b/zebra/Makefile.am
index 4492f9e6d..0218af81b 100644
--- a/zebra/Makefile.am
+++ b/zebra/Makefile.am
@@ -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)
diff --git a/zebra/rib.h b/zebra/rib.h
index 095b9c6f8..32f370f9e 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -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,
@@ -436,19 +383,9 @@ 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);
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 195d3633e..0db1b0a68 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -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
index 000000000..9d16f1267
--- /dev/null
+++ b/zebra/zebra_static.c
@@ -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
index 000000000..a3096725f
--- /dev/null
+++ b/zebra/zebra_static.h
@@ -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
diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c
index 46dc29d10..d9bd919bf 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -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;
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 3c2626670..716e74c0b 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -29,13 +29,14 @@
#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;