summaryrefslogtreecommitdiffstats
path: root/zebra/zebra_rib.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zebra_rib.c')
-rw-r--r--zebra/zebra_rib.c669
1 files changed, 470 insertions, 199 deletions
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 1650dabf..53691c76 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -35,13 +35,16 @@
#include "prefix.h"
#include "routemap.h"
#include "vrf.h"
+#include "nexthop.h"
+#include "zebra/connected.h"
#include "zebra/rib.h"
#include "zebra/rt.h"
#include "zebra/zserv.h"
#include "zebra/redistribute.h"
#include "zebra/debug.h"
#include "zebra/zebra_fpm.h"
+#include "zebra/zebra_rnh.h"
/* Default rtm_table for all clients */
extern struct zebra_t zebrad;
@@ -110,57 +113,38 @@ _rnode_zlog(const char *_func, struct route_node *rn, int priority,
#define rnode_info(node, ...) \
_rnode_zlog(__func__, node, LOG_INFO, __VA_ARGS__)
-/*
- * nexthop_type_to_str
- */
-const char *
-nexthop_type_to_str (enum nexthop_types_t nh_type)
-{
- static const char *desc[] = {
- "none",
- "Directly connected",
- "Interface route",
- "IPv4 nexthop",
- "IPv4 nexthop with ifindex",
- "IPv4 nexthop with ifname",
- "IPv6 nexthop",
- "IPv6 nexthop with ifindex",
- "IPv6 nexthop with ifname",
- "Null0 nexthop",
- };
-
- if (nh_type >= ZEBRA_NUM_OF (desc))
- return "<Invalid nh type>";
-
- return desc[nh_type];
-}
-
-/* Add nexthop to the end of a nexthop list. */
-static void
-_nexthop_add (struct nexthop **target, struct nexthop *nexthop)
+/* Add nexthop to the end of a rib node's nexthop list */
+void
+rib_nexthop_add (struct rib *rib, struct nexthop *nexthop)
{
- struct nexthop *last;
-
- for (last = *target; last && last->next; last = last->next)
- ;
- if (last)
- last->next = nexthop;
- else
- *target = nexthop;
- nexthop->prev = last;
+ nexthop_add(&rib->nexthop, nexthop);
+ rib->nexthop_num++;
}
-/* Add nexthop to the end of a rib node's nexthop list */
-static void
-nexthop_add (struct rib *rib, struct nexthop *nexthop)
+/**
+ * copy_nexthop - copy a nexthop to the rib structure.
+ */
+void
+rib_copy_nexthops (struct rib *rib, struct nexthop *nh)
{
- _nexthop_add(&rib->nexthop, nexthop);
- rib->nexthop_num++;
+ struct nexthop *nexthop;
+
+ nexthop = nexthop_new();
+ nexthop->flags = nh->flags;
+ nexthop->type = nh->type;
+ nexthop->ifindex = nh->ifindex;
+ if (nh->ifname)
+ nexthop->ifname = XSTRDUP(0, nh->ifname);
+ memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr));
+ memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr));
+ rib_nexthop_add(rib, nexthop);
+ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE))
+ copy_nexthops(&nexthop->resolved, nh->resolved);
}
/* Delete specified nexthop from the list. */
static void
-nexthop_delete (struct rib *rib, struct nexthop *nexthop)
+rib_nexthop_delete (struct rib *rib, struct nexthop *nexthop)
{
if (nexthop->next)
nexthop->next->prev = nexthop->prev;
@@ -171,150 +155,130 @@ nexthop_delete (struct rib *rib, struct nexthop *nexthop)
rib->nexthop_num--;
}
-static void nexthops_free(struct nexthop *nexthop);
-
-/* Free nexthop. */
-static void
-nexthop_free (struct nexthop *nexthop)
-{
- if (nexthop->ifname)
- XFREE (0, nexthop->ifname);
- if (nexthop->resolved)
- nexthops_free(nexthop->resolved);
- XFREE (MTYPE_NEXTHOP, nexthop);
-}
-
-/* Frees a list of nexthops */
-static void
-nexthops_free (struct nexthop *nexthop)
-{
- struct nexthop *nh, *next;
-
- for (nh = nexthop; nh; nh = next)
- {
- next = nh->next;
- nexthop_free (nh);
- }
-}
-
struct nexthop *
-nexthop_ifindex_add (struct rib *rib, ifindex_t ifindex)
+rib_nexthop_ifindex_add (struct rib *rib, ifindex_t ifindex)
{
struct nexthop *nexthop;
- nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ nexthop = nexthop_new ();
nexthop->type = NEXTHOP_TYPE_IFINDEX;
nexthop->ifindex = ifindex;
- nexthop_add (rib, nexthop);
+ rib_nexthop_add (rib, nexthop);
return nexthop;
}
struct nexthop *
-nexthop_ifname_add (struct rib *rib, char *ifname)
+rib_nexthop_ifname_add (struct rib *rib, char *ifname)
{
struct nexthop *nexthop;
- nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ nexthop = nexthop_new ();
nexthop->type = NEXTHOP_TYPE_IFNAME;
nexthop->ifname = XSTRDUP (0, ifname);
- nexthop_add (rib, nexthop);
+ rib_nexthop_add (rib, nexthop);
return nexthop;
}
struct nexthop *
-nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src)
+rib_nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src)
{
struct nexthop *nexthop;
- nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ nexthop = nexthop_new ();
nexthop->type = NEXTHOP_TYPE_IPV4;
nexthop->gate.ipv4 = *ipv4;
if (src)
nexthop->src.ipv4 = *src;
- nexthop_add (rib, nexthop);
+ rib_nexthop_add (rib, nexthop);
return nexthop;
}
struct nexthop *
-nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4,
- struct in_addr *src, ifindex_t ifindex)
+rib_nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4,
+ struct in_addr *src, ifindex_t ifindex)
{
struct nexthop *nexthop;
- nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ nexthop = nexthop_new ();
nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
nexthop->gate.ipv4 = *ipv4;
if (src)
nexthop->src.ipv4 = *src;
nexthop->ifindex = ifindex;
- nexthop_add (rib, nexthop);
+ rib_nexthop_add (rib, nexthop);
return nexthop;
}
struct nexthop *
-nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6)
+rib_nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6)
{
struct nexthop *nexthop;
- nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ nexthop = nexthop_new ();
nexthop->type = NEXTHOP_TYPE_IPV6;
nexthop->gate.ipv6 = *ipv6;
- nexthop_add (rib, nexthop);
+ rib_nexthop_add (rib, nexthop);
return nexthop;
}
static struct nexthop *
-nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6,
- char *ifname)
+rib_nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6,
+ char *ifname)
{
struct nexthop *nexthop;
- nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ nexthop = nexthop_new ();
nexthop->type = NEXTHOP_TYPE_IPV6_IFNAME;
nexthop->gate.ipv6 = *ipv6;
nexthop->ifname = XSTRDUP (0, ifname);
- nexthop_add (rib, nexthop);
+ rib_nexthop_add (rib, nexthop);
return nexthop;
}
-static struct nexthop *
-nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6,
- ifindex_t ifindex)
+struct nexthop *
+rib_nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6,
+ ifindex_t ifindex)
{
struct nexthop *nexthop;
+ struct interface *ifp;
- nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ nexthop = nexthop_new ();
nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
nexthop->gate.ipv6 = *ipv6;
nexthop->ifindex = ifindex;
+ ifp = if_lookup_by_index (nexthop->ifindex);
+ if (connected_is_unnumbered(ifp))
+ {
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
+ }
- nexthop_add (rib, nexthop);
+ rib_nexthop_add (rib, nexthop);
return nexthop;
}
struct nexthop *
-nexthop_blackhole_add (struct rib *rib)
+rib_nexthop_blackhole_add (struct rib *rib)
{
struct nexthop *nexthop;
- nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop));
+ nexthop = nexthop_new ();
nexthop->type = NEXTHOP_TYPE_BLACKHOLE;
SET_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE);
- nexthop_add (rib, nexthop);
+ rib_nexthop_add (rib, nexthop);
return nexthop;
}
@@ -348,8 +312,9 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
struct route_node *rn;
struct rib *match;
int resolved;
- struct nexthop *newhop;
+ struct nexthop *newhop, *tnewhop;
struct nexthop *resolved_hop;
+ int recursing = 0;
if (nexthop->type == NEXTHOP_TYPE_IPV4)
nexthop->ifindex = 0;
@@ -357,11 +322,18 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
if (set)
{
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+ zebra_deregister_rnh_static_nexthops (nexthop->resolved, top);
nexthops_free(nexthop->resolved);
nexthop->resolved = NULL;
rib->nexthop_mtu = 0;
}
+ /* Skip nexthops that have been filtered out due to route-map */
+ /* The nexthops are specific to this route and so the same */
+ /* nexthop for a different route may not have this flag set */
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED))
+ return 0;
+
/* Make lookup prefix. */
memset (&p, 0, sizeof (struct prefix_ipv4));
p.family = AF_INET;
@@ -393,8 +365,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
/* If there is no selected route or matched route is EGP, go up
tree. */
- if (! match
- || match->type == ZEBRA_ROUTE_BGP)
+ if (! match)
{
do {
rn = rn->parent;
@@ -429,6 +400,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
if (set)
{
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+ SET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop));
SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
@@ -455,7 +427,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
resolved_hop->ifindex = newhop->ifindex;
}
- _nexthop_add(&nexthop->resolved, resolved_hop);
+ nexthop_add(&nexthop->resolved, resolved_hop);
}
resolved = 1;
}
@@ -463,6 +435,57 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
rib->nexthop_mtu = match->mtu;
return resolved;
}
+ else if (rib->type == ZEBRA_ROUTE_STATIC)
+ {
+ resolved = 0;
+ for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing))
+ if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
+ {
+ if (set)
+ {
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+
+ resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop));
+ SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
+ /* If the resolving route specifies a gateway, use it */
+ if (newhop->type == NEXTHOP_TYPE_IPV4
+ || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX
+ || newhop->type == NEXTHOP_TYPE_IPV4_IFNAME)
+ {
+ resolved_hop->type = newhop->type;
+ resolved_hop->gate.ipv4 = newhop->gate.ipv4;
+
+ if (newhop->ifindex)
+ {
+ resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ resolved_hop->ifindex = newhop->ifindex;
+ }
+ }
+
+ /* If the resolving route is an interface route,
+ * it means the gateway we are looking up is connected
+ * to that interface. (The actual network is _not_ onlink).
+ * Therefore, the resolved route should have the original
+ * gateway as nexthop as it is directly connected.
+ *
+ * On Linux, we have to set the onlink netlink flag because
+ * otherwise, the kernel won't accept the route.
+ */
+ if (newhop->type == NEXTHOP_TYPE_IFINDEX
+ || newhop->type == NEXTHOP_TYPE_IFNAME)
+ {
+ resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
+ resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ resolved_hop->gate.ipv4 = nexthop->gate.ipv4;
+ resolved_hop->ifindex = newhop->ifindex;
+ }
+
+ nexthop_add(&nexthop->resolved, resolved_hop);
+ }
+ resolved = 1;
+ }
+ return resolved;
+ }
else
{
return 0;
@@ -483,8 +506,10 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
struct route_node *rn;
struct rib *match;
int resolved;
- struct nexthop *newhop;
+ struct nexthop *newhop, *tnewhop;
+ int recursing = 0;
struct nexthop *resolved_hop;
+ struct interface *ifp;
if (nexthop->type == NEXTHOP_TYPE_IPV6)
nexthop->ifindex = 0;
@@ -492,10 +517,36 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
if (set)
{
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+ zebra_deregister_rnh_static_nexthops (nexthop->resolved, top);
nexthops_free(nexthop->resolved);
nexthop->resolved = NULL;
}
+ /* Skip nexthops that have been filtered out due to route-map */
+ /* The nexthops are specific to this route and so the same */
+ /* nexthop for a different route may not have this flag set */
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FILTERED))
+ return 0;
+
+ /*
+ * Check to see if we should trust the passed in information
+ * for UNNUMBERED interfaces as that we won't find the GW
+ * address in the routing table.
+ */
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
+ {
+ ifp = if_lookup_by_index (nexthop->ifindex);
+ if (ifp && connected_is_unnumbered(ifp))
+ {
+ if (if_is_operative(ifp))
+ return 1;
+ else
+ return 0;
+ }
+ else
+ return 0;
+ }
+
/* Make lookup prefix. */
memset (&p, 0, sizeof (struct prefix_ipv6));
p.family = AF_INET6;
@@ -527,8 +578,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
/* If there is no selected route or matched route is EGP, go up
tree. */
- if (! match
- || match->type == ZEBRA_ROUTE_BGP)
+ if (! match)
{
do {
rn = rn->parent;
@@ -564,6 +614,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
if (set)
{
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+ SET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop));
SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
@@ -592,7 +643,50 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
resolved_hop->ifindex = newhop->ifindex;
}
- _nexthop_add(&nexthop->resolved, resolved_hop);
+ nexthop_add(&nexthop->resolved, resolved_hop);
+ }
+ resolved = 1;
+ }
+ return resolved;
+ }
+ else if (rib->type == ZEBRA_ROUTE_STATIC)
+ {
+ resolved = 0;
+ for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing))
+ if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
+ {
+ if (set)
+ {
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+
+ resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop));
+ SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
+ /* See nexthop_active_ipv4 for a description how the
+ * resolved nexthop is constructed. */
+ if (newhop->type == NEXTHOP_TYPE_IPV6
+ || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
+ || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME)
+ {
+ resolved_hop->type = newhop->type;
+ resolved_hop->gate.ipv6 = newhop->gate.ipv6;
+
+ if (newhop->ifindex)
+ {
+ resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ resolved_hop->ifindex = newhop->ifindex;
+ }
+ }
+
+ if (newhop->type == NEXTHOP_TYPE_IFINDEX
+ || newhop->type == NEXTHOP_TYPE_IFNAME)
+ {
+ resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
+ resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ resolved_hop->gate.ipv6 = nexthop->gate.ipv6;
+ resolved_hop->ifindex = newhop->ifindex;
+ }
+
+ nexthop_add(&nexthop->resolved, resolved_hop);
}
resolved = 1;
}
@@ -608,7 +702,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
}
struct rib *
-rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp,
+rib_match_ipv4_safi (struct in_addr addr, safi_t safi,
struct route_node **rn_out, vrf_id_t vrf_id)
{
struct route_table *table;
@@ -639,7 +733,7 @@ rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp,
/* If there is no selected route or matched route is EGP, go up
tree. */
- if (!match || (skip_bgp && (match->type == ZEBRA_ROUTE_BGP)))
+ if (! match)
{
do {
rn = rn->parent;
@@ -676,29 +770,22 @@ rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out,
{
struct rib *rib = NULL, *mrib = NULL, *urib = NULL;
struct route_node *m_rn = NULL, *u_rn = NULL;
- int skip_bgp = 0; /* bool */
switch (ipv4_multicast_mode)
{
case MCAST_MRIB_ONLY:
- return rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, rn_out,
- vrf_id);
+ return rib_match_ipv4_safi (addr, SAFI_MULTICAST, rn_out, vrf_id);
case MCAST_URIB_ONLY:
- return rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, rn_out,
- vrf_id);
+ return rib_match_ipv4_safi (addr, SAFI_UNICAST, rn_out, vrf_id);
case MCAST_NO_CONFIG:
case MCAST_MIX_MRIB_FIRST:
- rib = mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn,
- vrf_id);
+ rib = mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, &m_rn, vrf_id);
if (!mrib)
- rib = urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn,
- vrf_id);
+ rib = urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, &u_rn, vrf_id);
break;
case MCAST_MIX_DISTANCE:
- mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn,
- vrf_id);
- urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn,
- vrf_id);
+ mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, &m_rn, vrf_id);
+ urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, &u_rn, vrf_id);
if (mrib && urib)
rib = urib->distance < mrib->distance ? urib : mrib;
else if (mrib)
@@ -707,10 +794,8 @@ rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out,
rib = urib;
break;
case MCAST_MIX_PFXLEN:
- mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, skip_bgp, &m_rn,
- vrf_id);
- urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &u_rn,
- vrf_id);
+ mrib = rib_match_ipv4_safi (addr, SAFI_MULTICAST, &m_rn, vrf_id);
+ urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, &u_rn, vrf_id);
if (mrib && urib)
rib = u_rn->p.prefixlen > m_rn->p.prefixlen ? urib : mrib;
else if (mrib)
@@ -782,7 +867,7 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p, vrf_id_t vrf_id)
break;
}
- if (! match || match->type == ZEBRA_ROUTE_BGP)
+ if (! match)
return NULL;
if (match->type == ZEBRA_ROUTE_CONNECT)
@@ -910,8 +995,7 @@ rib_match_ipv6 (struct in6_addr *addr, vrf_id_t vrf_id)
/* If there is no selected route or matched route is EGP, go up
tree. */
- if (! match
- || match->type == ZEBRA_ROUTE_BGP)
+ if (! match)
{
do {
rn = rn->parent;
@@ -956,9 +1040,8 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
rib_table_info_t *info = rn->table->info;
struct interface *ifp;
route_map_result_t ret = RMAP_MATCH;
- extern char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1];
- struct route_map *rmap;
int family;
+ char buf[INET6_ADDRSTRLEN+1];
family = 0;
switch (nexthop->type)
@@ -1045,19 +1128,21 @@ nexthop_active_check (struct route_node *rn, struct rib *rib,
if (!family)
family = info->afi;
- rmap = 0;
- if (rib->type >= 0 && rib->type < ZEBRA_ROUTE_MAX &&
- proto_rm[family][rib->type])
- rmap = route_map_lookup_by_name (proto_rm[family][rib->type]);
- if (!rmap && proto_rm[family][ZEBRA_ROUTE_MAX])
- rmap = route_map_lookup_by_name (proto_rm[family][ZEBRA_ROUTE_MAX]);
- if (rmap) {
- struct nexthop_vrfid nh_vrf = {nexthop, rib->vrf_id};
- ret = route_map_apply(rmap, &rn->p, RMAP_ZEBRA, &nh_vrf);
- }
+ memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
+ /* It'll get set if required inside */
+ ret = zebra_route_map_check(family, rib->type, &rn->p, nexthop, rib->vrf_id);
if (ret == RMAP_DENYMATCH)
- UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ {
+ if (IS_ZEBRA_DEBUG_RIB)
+ {
+ inet_ntop (rn->p.family, &rn->p.u.prefix, buf, sizeof (buf));
+ zlog_debug("%s: Filtering out %s with NH out %s due to route map",
+ __FUNCTION__, buf, nexthop->ifname);
+ }
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+ }
+
return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
}
@@ -1074,22 +1159,35 @@ static int
nexthop_active_update (struct route_node *rn, struct rib *rib, int set)
{
struct nexthop *nexthop;
- unsigned int prev_active, new_active;
+ union g_addr prev_src;
+ unsigned int prev_active, new_active, old_num_nh;
ifindex_t prev_index;
-
+
+ old_num_nh = rib->nexthop_active_num;
+
rib->nexthop_active_num = 0;
- UNSET_FLAG (rib->status, RIB_ENTRY_CHANGED);
+ UNSET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
{
+ /* No protocol daemon provides src and so we're skipping tracking it */
+ prev_src = nexthop->rmap_src;
prev_active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE);
prev_index = nexthop->ifindex;
if ((new_active = nexthop_active_check (rn, rib, nexthop, set)))
rib->nexthop_active_num++;
+ /* Don't allow src setting on IPv6 addr for now */
if (prev_active != new_active ||
- prev_index != nexthop->ifindex)
- SET_FLAG (rib->status, RIB_ENTRY_CHANGED);
+ prev_index != nexthop->ifindex ||
+ ((nexthop->type >= NEXTHOP_TYPE_IFINDEX &&
+ nexthop->type < NEXTHOP_TYPE_IPV6) &&
+ prev_src.ipv4.s_addr != nexthop->rmap_src.ipv4.s_addr))
+ SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
}
+
+ if (old_num_nh != rib->nexthop_active_num)
+ SET_FLAG (rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
+
return rib->nexthop_active_num;
}
@@ -1275,6 +1373,8 @@ rib_process (struct route_node *rn)
RNODE_FOREACH_RIB (rn, rib)
{
+ UNSET_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED);
+
/* Currently installed rib. */
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
{
@@ -1292,7 +1392,18 @@ rib_process (struct route_node *rn)
continue;
/* Skip unreachable nexthop. */
- if (! nexthop_active_update (rn, rib, 0))
+ /* This first call to nexthop_active_update is merely to determine if
+ * there's any change to nexthops associated with this RIB entry. Now,
+ * rib_process() can be invoked due to an external event such as link
+ * down or due to next-hop-tracking evaluation. In the latter case,
+ * a decision has already been made that the NHs have changed. So, no
+ * need to invoke a potentially expensive call again. Further, since
+ * the change might be in a recursive NH which is not caught in
+ * the nexthop_active_update() code. Thus, we might miss changes to
+ * recursive NHs.
+ */
+ if (!CHECK_FLAG(rib->status, RIB_ENTRY_NEXTHOPS_CHANGED) &&
+ ! nexthop_active_update (rn, rib, 0))
continue;
/* Infinit distance. */
@@ -1327,7 +1438,7 @@ rib_process (struct route_node *rn)
/* Update kernel if FIB entry has changed */
if (old_fib != new_fib
- || (new_fib && CHECK_FLAG (new_fib->status, RIB_ENTRY_CHANGED)))
+ || (new_fib && CHECK_FLAG (new_fib->status, RIB_ENTRY_NEXTHOPS_CHANGED)))
{
if (old_fib && old_fib != new_fib)
{
@@ -1365,7 +1476,7 @@ rib_process (struct route_node *rn)
/* Redistribute SELECTED entry */
if (old_selected != new_selected
- || (new_selected && CHECK_FLAG (new_selected->status, RIB_ENTRY_CHANGED)))
+ || (new_selected && CHECK_FLAG (new_selected->status, RIB_ENTRY_NEXTHOPS_CHANGED)))
{
if (old_selected)
{
@@ -1436,6 +1547,18 @@ process_subq (struct list * subq, u_char qindex)
return 1;
}
+/*
+ * All meta queues have been processed. Trigger next-hop evaluation.
+ */
+static void
+meta_queue_process_complete (struct work_queue *dummy)
+{
+ zebra_evaluate_rnh_table(0, AF_INET, 0);
+#ifdef HAVE_IPV6
+ zebra_evaluate_rnh_table(0, AF_INET6, 0);
+#endif /* HAVE_IPV6 */
+}
+
/* Dispatch the meta queue by picking, processing and unlocking the next RN from
* a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and data
* is pointed to the meta queue structure.
@@ -1507,7 +1630,7 @@ rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn)
}
/* Add route_node to work queue and schedule processing */
-static void
+void
rib_queue_add (struct zebra_t *zebra, struct route_node *rn)
{
assert (zebra && rn);
@@ -1588,6 +1711,7 @@ rib_queue_init (struct zebra_t *zebra)
/* fill in the work queue spec */
zebra->ribq->spec.workfunc = &meta_queue_process;
zebra->ribq->spec.errorfunc = NULL;
+ zebra->ribq->spec.completion_func = &meta_queue_process_complete;
/* XXX: TODO: These should be runtime configurable via vty */
zebra->ribq->spec.max_retries = 3;
zebra->ribq->spec.hold = rib_process_hold_time;
@@ -1720,7 +1844,8 @@ rib_unlink (struct route_node *rn, struct rib *rib)
}
/* free RIB and nexthops */
- nexthops_free(rib->nexthop);
+ zebra_deregister_rnh_static_nexthops (rib->nexthop, rn);
+ nexthops_free (rib->nexthop);
XFREE (MTYPE_RIB, rib);
}
@@ -1811,12 +1936,12 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
if (gate)
{
if (ifindex)
- nexthop_ipv4_ifindex_add (rib, gate, src, ifindex);
+ rib_nexthop_ipv4_ifindex_add (rib, gate, src, ifindex);
else
- nexthop_ipv4_add (rib, gate, src);
+ rib_nexthop_ipv4_add (rib, gate, src);
}
else
- nexthop_ifindex_add (rib, ifindex);
+ rib_nexthop_ifindex_add (rib, ifindex);
/* If this route is kernel route, set FIB flag to the route. */
if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT)
@@ -2009,6 +2134,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi)
struct route_node *rn;
struct rib *same;
struct nexthop *nexthop;
+ int ret = 0;
/* Lookup table. */
table = zebra_vrf_table (AFI_IP, safi, rib->vrf_id);
@@ -2051,6 +2177,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi)
/* Link new rib to node.*/
rib_addnode (rn, rib);
+ ret = 1;
if (IS_ZEBRA_DEBUG_RIB)
{
zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry",
@@ -2068,10 +2195,11 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi)
rib_dump (p, same);
}
rib_delnode (rn, same);
+ ret = -1;
}
route_unlock_node (rn);
- return 0;
+ return ret;
}
/* XXX factor with rib_delete_ipv6 */
@@ -2178,14 +2306,19 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
kernel. */
if (! same)
{
- if (fib && type == ZEBRA_ROUTE_KERNEL)
- {
- /* Unset flags. */
- for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
- UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
-
- UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB);
- }
+ if (fib && type == ZEBRA_ROUTE_KERNEL &&
+ CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE))
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ {
+ zlog_debug ("Zebra route %s/%d was deleted by others from kernel",
+ inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN),
+ p->prefixlen);
+ }
+ /* This means someone else, other than Zebra, has deleted
+ * a Zebra router from the kernel. We will add it back */
+ rib_update_kernel(rn, NULL, fib);
+ }
else
{
if (IS_ZEBRA_DEBUG_KERNEL)
@@ -2222,6 +2355,7 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro
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);
@@ -2241,28 +2375,40 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro
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:
- nexthop_ipv4_add (rib, &si->addr.ipv4, NULL);
+ 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(&nh_p, rn);
break;
case STATIC_IPV4_IFNAME:
- nexthop_ifname_add (rib, si->ifname);
+ rib_nexthop_ifname_add (rib, si->ifname);
break;
case STATIC_IPV4_BLACKHOLE:
- nexthop_blackhole_add (rib);
+ rib_nexthop_blackhole_add (rib);
break;
case STATIC_IPV6_GATEWAY:
- nexthop_ipv6_add (rib, &si->addr.ipv6);
+ 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(&nh_p, rn);
break;
case STATIC_IPV6_IFNAME:
- nexthop_ifname_add (rib, si->ifname);
+ rib_nexthop_ifname_add (rib, si->ifname);
break;
case STATIC_IPV6_GATEWAY_IFNAME:
- nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname);
+ rib_nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname);
break;
}
rib_queue_add (&zebrad, rn);
@@ -2278,26 +2424,35 @@ static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_ro
rib->vrf_id = si->vrf_id;
rib->table = zebrad.rtm_table_default;
rib->nexthop_num = 0;
+ rib->tag = si->tag;
switch (si->type)
{
case STATIC_IPV4_GATEWAY:
- nexthop_ipv4_add (rib, &si->addr.ipv4, NULL);
+ 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(&nh_p, rn);
break;
case STATIC_IPV4_IFNAME:
- nexthop_ifname_add (rib, si->ifname);
+ rib_nexthop_ifname_add (rib, si->ifname);
break;
case STATIC_IPV4_BLACKHOLE:
- nexthop_blackhole_add (rib);
+ rib_nexthop_blackhole_add (rib);
break;
case STATIC_IPV6_GATEWAY:
- nexthop_ipv6_add (rib, &si->addr.ipv6);
+ 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(&nh_p, rn);
break;
case STATIC_IPV6_IFNAME:
- nexthop_ifname_add (rib, si->ifname);
+ rib_nexthop_ifname_add (rib, si->ifname);
break;
case STATIC_IPV6_GATEWAY_IFNAME:
- nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname);
+ rib_nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname);
break;
}
@@ -2347,6 +2502,7 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_
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);
@@ -2363,7 +2519,8 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
continue;
- if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance)
+ if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance &&
+ rib->tag == si->tag)
break;
}
@@ -2392,7 +2549,21 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_
{
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
rib_uninstall (rn, rib);
- nexthop_delete (rib, nexthop);
+
+ if (afi == AF_INET)
+ {
+ 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(&nh_p, rn);
nexthop_free (nexthop);
rib_queue_add (&zebrad, rn);
}
@@ -2402,7 +2573,7 @@ static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_
int
static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate,
- const char *ifname, u_char flags, u_char distance,
+ const char *ifname, u_char flags, u_short tag, u_char distance,
vrf_id_t vrf_id)
{
u_char type = 0;
@@ -2435,7 +2606,8 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate,
&& (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4))
&& (! ifname || strcmp (ifname, si->ifname) == 0))
{
- if (distance == si->distance)
+ if (distance == si->distance &&
+ tag == si->tag)
{
route_unlock_node (rn);
return 0;
@@ -2445,15 +2617,16 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate,
}
}
- /* Distance changed. */
+ /* Distance or tag changed. */
if (update)
- static_delete_ipv4_safi (safi, p, gate, ifname, update->distance, vrf_id);
+ static_delete_ipv4_safi (safi, p, gate, ifname, update->tag, update->distance, vrf_id);
/* Make new static route structure. */
si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route));
si->type = type;
si->distance = distance;
+ si->tag = tag;
si->flags = flags;
si->vrf_id = vrf_id;
@@ -2497,7 +2670,7 @@ static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate,
int
static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate,
- const char *ifname, u_char distance, vrf_id_t vrf_id)
+ const char *ifname, u_short tag, u_char distance, vrf_id_t vrf_id)
{
u_char type = 0;
struct route_node *rn;
@@ -2526,7 +2699,8 @@ static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate,
for (si = rn->info; si; si = si->next)
if (type == si->type
&& (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4))
- && (! ifname || strcmp (ifname, si->ifname) == 0))
+ && (! ifname || strcmp (ifname, si->ifname) == 0)
+ && (! tag || (tag == si->tag)))
break;
/* Can't find static route. */
@@ -2628,12 +2802,12 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
if (gate)
{
if (ifindex)
- nexthop_ipv6_ifindex_add (rib, gate, ifindex);
+ rib_nexthop_ipv6_ifindex_add (rib, gate, ifindex);
else
- nexthop_ipv6_add (rib, gate);
+ rib_nexthop_ipv6_add (rib, gate);
}
else
- nexthop_ifindex_add (rib, ifindex);
+ rib_nexthop_ifindex_add (rib, ifindex);
/* If this route is kernel route, set FIB flag to the route. */
if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT)
@@ -2665,6 +2839,86 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p,
return 0;
}
+int
+rib_add_ipv6_multipath (struct prefix_ipv6 *p, struct rib *rib, safi_t safi)
+{
+ struct route_table *table;
+ struct route_node *rn;
+ struct rib *same = NULL;
+ struct nexthop *nexthop;
+ int ret = 0;
+
+ if (!rib)
+ return 0; /* why are we getting called with NULL rib */
+
+ /* Lookup table. */
+ table = zebra_vrf_table (AFI_IP6, safi, rib->vrf_id);
+
+ if (! table)
+ return 0;
+
+ /* Make sure mask is applied. */
+ apply_mask_ipv6 (p);
+
+ /* Set default distance by route type. */
+ if (rib->distance == 0)
+ {
+ rib->distance = route_info[rib->type].distance;
+
+ /* iBGP distance is 200. */
+ if (rib->type == ZEBRA_ROUTE_BGP
+ && CHECK_FLAG (rib->flags, ZEBRA_FLAG_IBGP))
+ rib->distance = 200;
+ }
+
+ /* Lookup route node.*/
+ rn = route_node_get (table, (struct prefix *) p);
+
+ /* If same type of route are installed, treat it as a implicit
+ withdraw. */
+ RNODE_FOREACH_RIB (rn, same) {
+ if (CHECK_FLAG (same->status, RIB_ENTRY_REMOVED)) {
+ continue;
+ }
+ if (same->type != rib->type) {
+ continue;
+ }
+
+ if (same->table != rib->table) {
+ continue;
+ }
+ if (same->type != ZEBRA_ROUTE_CONNECT) {
+ break;
+ }
+ }
+
+ /* If this route is kernel route, set FIB flag to the route. */
+ if (rib->type == ZEBRA_ROUTE_KERNEL || rib->type == ZEBRA_ROUTE_CONNECT) {
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) {
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+ }
+ }
+
+ /* Link new rib to node.*/
+ rib_addnode (rn, rib);
+ ret = 1;
+ /* Free implicit route.*/
+ if (same)
+ {
+ if (IS_ZEBRA_DEBUG_RIB)
+ {
+ zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry",
+ __func__, rn, same);
+ rib_dump ((struct prefix *)p, same);
+ }
+ rib_delnode (rn, same);
+ ret = -1;
+ }
+
+ route_unlock_node (rn);
+ return ret;
+}
+
/* XXX factor with rib_delete_ipv6 */
int
rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
@@ -2757,14 +3011,19 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
kernel. */
if (! same)
{
- if (fib && type == ZEBRA_ROUTE_KERNEL)
- {
- /* Unset flags. */
- for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next)
- UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
-
- UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB);
- }
+ if (fib && type == ZEBRA_ROUTE_KERNEL &&
+ CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE))
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ {
+ zlog_debug ("Zebra route %s/%d was deleted by others from kernel",
+ inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN),
+ p->prefixlen);
+ }
+ /* This means someone else, other than Zebra, has deleted a Zebra
+ * route from the kernel. We will add it back */
+ rib_update_kernel(rn, NULL, fib);
+ }
else
{
if (IS_ZEBRA_DEBUG_KERNEL)
@@ -2794,12 +3053,11 @@ rib_delete_ipv6 (int type, 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,
- const char *ifname, u_char flags, u_char distance,
- vrf_id_t vrf_id)
+ const char *ifname, u_char flags, u_short tag,
+ u_char distance, vrf_id_t vrf_id)
{
struct route_node *rn;
struct static_route *si;
@@ -2827,6 +3085,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
for (si = rn->info; si; si = si->next)
{
if (type == si->type
+ && tag == si->tag
&& (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6))
&& (! ifname || strcmp (ifname, si->ifname) == 0))
{
@@ -2841,13 +3100,14 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
}
if (update)
- static_delete_ipv6(p, type, gate, ifname, si->distance, vrf_id);
+ static_delete_ipv6(p, type, gate, ifname, tag, si->distance, vrf_id);
/* Make new static route structure. */
si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route));
si->type = type;
si->distance = distance;
+ si->tag = tag;
si->flags = flags;
si->vrf_id = vrf_id;
@@ -2894,7 +3154,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
/* Delete static route from static route configuration. */
int
static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
- const char *ifname, u_char distance, vrf_id_t vrf_id)
+ const char *ifname, u_short tag, u_char distance, vrf_id_t vrf_id)
{
struct route_node *rn;
struct static_route *si;
@@ -2915,7 +3175,8 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate,
if (distance == si->distance
&& type == si->type
&& (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6))
- && (! ifname || strcmp (ifname, si->ifname) == 0))
+ && (! ifname || strcmp (ifname, si->ifname) == 0)
+ && (! tag || (tag == si->tag)))
break;
/* Can't find static route. */
@@ -3237,6 +3498,13 @@ rib_tables_iter_next (rib_tables_iter_t *iter)
return table;
}
+/* Lookup VRF by identifier. */
+struct zebra_vrf *
+zebra_vrf_lookup (vrf_id_t vrf_id)
+{
+ return vrf_info_lookup (vrf_id);
+}
+
/*
* Create a routing table for the specific AFI/SAFI in the given VRF.
*/
@@ -3279,6 +3547,9 @@ zebra_vrf_alloc (vrf_id_t vrf_id)
zvrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init ();
zvrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init ();
+ zvrf->rnh_table[AFI_IP] = route_table_init();
+ zvrf->rnh_table[AFI_IP6] = route_table_init();
+
/* Set VRF ID */
zvrf->vrf_id = vrf_id;