version 1.1.1.2, 2012/10/09 09:22:29
|
version 1.1.1.4, 2016/11/02 10:09:10
|
Line 34
|
Line 34
|
#include "workqueue.h" |
#include "workqueue.h" |
#include "prefix.h" |
#include "prefix.h" |
#include "routemap.h" |
#include "routemap.h" |
|
#include "vrf.h" |
|
|
#include "zebra/rib.h" |
#include "zebra/rib.h" |
#include "zebra/rt.h" |
#include "zebra/rt.h" |
#include "zebra/zserv.h" |
#include "zebra/zserv.h" |
#include "zebra/redistribute.h" |
#include "zebra/redistribute.h" |
#include "zebra/debug.h" |
#include "zebra/debug.h" |
|
#include "zebra/zebra_fpm.h" |
|
|
/* Default rtm_table for all clients */ |
/* Default rtm_table for all clients */ |
extern struct zebra_t zebrad; |
extern struct zebra_t zebrad; |
Line 70 static const struct
|
Line 72 static const struct
|
[ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 95}, |
[ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 95}, |
/* no entry/default: 150 */ |
/* no entry/default: 150 */ |
}; |
}; |
|
|
/* Vector for routing table. */ |
|
static vector vrf_vector; |
|
|
|
/* Allocate new VRF. */ | /* RPF lookup behaviour */ |
static struct vrf * | static enum multicast_mode ipv4_multicast_mode = MCAST_NO_CONFIG; |
vrf_alloc (const char *name) | |
{ | |
struct vrf *vrf; | |
|
|
vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf)); | static void __attribute__((format (printf, 4, 5))) |
| _rnode_zlog(const char *_func, struct route_node *rn, int priority, |
/* Put name. */ | const char *msgfmt, ...) |
if (name) | |
vrf->name = XSTRDUP (MTYPE_VRF_NAME, name); | |
| |
/* Allocate routing table and static table. */ | |
vrf->table[AFI_IP][SAFI_UNICAST] = route_table_init (); | |
vrf->table[AFI_IP6][SAFI_UNICAST] = route_table_init (); | |
vrf->stable[AFI_IP][SAFI_UNICAST] = route_table_init (); | |
vrf->stable[AFI_IP6][SAFI_UNICAST] = route_table_init (); | |
vrf->table[AFI_IP][SAFI_MULTICAST] = route_table_init (); | |
vrf->table[AFI_IP6][SAFI_MULTICAST] = route_table_init (); | |
vrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init (); | |
vrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init (); | |
| |
| |
return vrf; | |
} | |
| |
/* Lookup VRF by identifier. */ | |
struct vrf * | |
vrf_lookup (u_int32_t id) | |
{ |
{ |
return vector_lookup (vrf_vector, id); | char prefix[PREFIX_STRLEN], buf[256]; |
} | char msgbuf[512]; |
| va_list ap; |
|
|
/* Initialize VRF. */ | va_start(ap, msgfmt); |
static void | vsnprintf(msgbuf, sizeof(msgbuf), msgfmt, ap); |
vrf_init (void) | va_end(ap); |
{ | |
struct vrf *default_table; | |
|
|
/* Allocate VRF vector. */ | if (rn) |
vrf_vector = vector_init (1); | { |
| rib_table_info_t *info = rn->table->info; |
|
|
/* Allocate default main table. */ | snprintf(buf, sizeof(buf), "%s%s vrf %u", |
default_table = vrf_alloc ("Default-IP-Routing-Table"); | prefix2str(&rn->p, prefix, sizeof(prefix)), |
| info->safi == SAFI_MULTICAST ? " (MRIB)" : "", |
| info->zvrf->vrf_id); |
| } |
| else |
| { |
| snprintf(buf, sizeof(buf), "{(route_node *) NULL}"); |
| } |
|
|
/* Default table index must be 0. */ | zlog (NULL, priority, "%s: %s: %s", _func, buf, msgbuf); |
vector_set_index (vrf_vector, 0, default_table); | |
} |
} |
|
|
/* Lookup route table. */ | #define rnode_debug(node, ...) \ |
struct route_table * | _rnode_zlog(__func__, node, LOG_DEBUG, __VA_ARGS__) |
vrf_table (afi_t afi, safi_t safi, u_int32_t id) | #define rnode_info(node, ...) \ |
{ | _rnode_zlog(__func__, node, LOG_INFO, __VA_ARGS__) |
struct vrf *vrf; | |
|
|
vrf = vrf_lookup (id); | /* |
if (! vrf) | * nexthop_type_to_str |
return NULL; | */ |
| const char * |
return vrf->table[afi][safi]; | nexthop_type_to_str (enum nexthop_types_t nh_type) |
} | |
| |
/* Lookup static route table. */ | |
struct route_table * | |
vrf_static_table (afi_t afi, safi_t safi, u_int32_t id) | |
{ |
{ |
struct vrf *vrf; | 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", |
| }; |
|
|
vrf = vrf_lookup (id); | if (nh_type >= ZEBRA_NUM_OF (desc)) |
if (! vrf) | return "<Invalid nh type>"; |
return NULL; | |
|
|
return vrf->stable[afi][safi]; | return desc[nh_type]; |
} |
} |
| |
/* Add nexthop to the end of the list. */ | /* Add nexthop to the end of a nexthop list. */ |
static void |
static void |
nexthop_add (struct rib *rib, struct nexthop *nexthop) | _nexthop_add (struct nexthop **target, struct nexthop *nexthop) |
{ |
{ |
struct nexthop *last; |
struct nexthop *last; |
|
|
for (last = rib->nexthop; last && last->next; last = last->next) | for (last = *target; last && last->next; last = last->next) |
; |
; |
if (last) |
if (last) |
last->next = nexthop; |
last->next = nexthop; |
else |
else |
rib->nexthop = nexthop; | *target = nexthop; |
nexthop->prev = last; |
nexthop->prev = last; |
|
} |
|
|
|
/* Add nexthop to the end of a rib node's nexthop list */ |
|
static void |
|
nexthop_add (struct rib *rib, struct nexthop *nexthop) |
|
{ |
|
_nexthop_add(&rib->nexthop, nexthop); |
rib->nexthop_num++; |
rib->nexthop_num++; |
} |
} |
|
|
Line 179 nexthop_delete (struct rib *rib, struct nexthop *nexth
|
Line 171 nexthop_delete (struct rib *rib, struct nexthop *nexth
|
rib->nexthop_num--; |
rib->nexthop_num--; |
} |
} |
|
|
|
static void nexthops_free(struct nexthop *nexthop); |
|
|
/* Free nexthop. */ |
/* Free nexthop. */ |
static void |
static void |
nexthop_free (struct nexthop *nexthop) |
nexthop_free (struct nexthop *nexthop) |
{ |
{ |
if (nexthop->ifname) |
if (nexthop->ifname) |
XFREE (0, nexthop->ifname); |
XFREE (0, nexthop->ifname); |
|
if (nexthop->resolved) |
|
nexthops_free(nexthop->resolved); |
XFREE (MTYPE_NEXTHOP, nexthop); |
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 * |
struct nexthop * |
nexthop_ifindex_add (struct rib *rib, unsigned int ifindex) | nexthop_ifindex_add (struct rib *rib, ifindex_t ifindex) |
{ |
{ |
struct nexthop *nexthop; |
struct nexthop *nexthop; |
|
|
Line 234 nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv
|
Line 243 nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv
|
|
|
struct nexthop * |
struct nexthop * |
nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, |
nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, |
struct in_addr *src, unsigned int ifindex) | struct in_addr *src, ifindex_t ifindex) |
{ |
{ |
struct nexthop *nexthop; |
struct nexthop *nexthop; |
|
|
Line 250 nexthop_ipv4_ifindex_add (struct rib *rib, struct in_a
|
Line 259 nexthop_ipv4_ifindex_add (struct rib *rib, struct in_a
|
return nexthop; |
return nexthop; |
} |
} |
|
|
#ifdef HAVE_IPV6 |
|
struct nexthop * |
struct nexthop * |
nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6) |
nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6) |
{ |
{ |
Line 283 nexthop_ipv6_ifname_add (struct rib *rib, struct in6_a
|
Line 291 nexthop_ipv6_ifname_add (struct rib *rib, struct in6_a
|
|
|
static struct nexthop * |
static struct nexthop * |
nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6, |
nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6, |
unsigned int ifindex) | ifindex_t ifindex) |
{ |
{ |
struct nexthop *nexthop; |
struct nexthop *nexthop; |
|
|
Line 296 nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_
|
Line 304 nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_
|
|
|
return nexthop; |
return nexthop; |
} |
} |
#endif /* HAVE_IPV6 */ |
|
|
|
struct nexthop * |
struct nexthop * |
nexthop_blackhole_add (struct rib *rib) |
nexthop_blackhole_add (struct rib *rib) |
Line 312 nexthop_blackhole_add (struct rib *rib)
|
Line 319 nexthop_blackhole_add (struct rib *rib)
|
return nexthop; |
return nexthop; |
} |
} |
|
|
|
/* This method checks whether a recursive nexthop has at |
|
* least one resolved nexthop in the fib. |
|
*/ |
|
int |
|
nexthop_has_fib_child(struct nexthop *nexthop) |
|
{ |
|
struct nexthop *nh; |
|
|
|
if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) |
|
return 0; |
|
|
|
for (nh = nexthop->resolved; nh; nh = nh->next) |
|
if (CHECK_FLAG (nh->flags, NEXTHOP_FLAG_FIB)) |
|
return 1; |
|
|
|
return 0; |
|
} |
|
|
/* If force flag is not set, do not modify falgs at all for uninstall |
/* If force flag is not set, do not modify falgs at all for uninstall |
the route from FIB. */ |
the route from FIB. */ |
static int |
static int |
Line 322 nexthop_active_ipv4 (struct rib *rib, struct nexthop *
|
Line 347 nexthop_active_ipv4 (struct rib *rib, struct nexthop *
|
struct route_table *table; |
struct route_table *table; |
struct route_node *rn; |
struct route_node *rn; |
struct rib *match; |
struct rib *match; |
|
int resolved; |
struct nexthop *newhop; |
struct nexthop *newhop; |
|
struct nexthop *resolved_hop; |
|
|
if (nexthop->type == NEXTHOP_TYPE_IPV4) |
if (nexthop->type == NEXTHOP_TYPE_IPV4) |
nexthop->ifindex = 0; |
nexthop->ifindex = 0; |
|
|
if (set) |
if (set) |
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); | { |
| UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); |
| nexthops_free(nexthop->resolved); |
| nexthop->resolved = NULL; |
| rib->nexthop_mtu = 0; |
| } |
|
|
/* Make lookup prefix. */ |
/* Make lookup prefix. */ |
memset (&p, 0, sizeof (struct prefix_ipv4)); |
memset (&p, 0, sizeof (struct prefix_ipv4)); |
Line 337 nexthop_active_ipv4 (struct rib *rib, struct nexthop *
|
Line 369 nexthop_active_ipv4 (struct rib *rib, struct nexthop *
|
p.prefix = nexthop->gate.ipv4; |
p.prefix = nexthop->gate.ipv4; |
|
|
/* Lookup table. */ |
/* Lookup table. */ |
table = vrf_table (AFI_IP, SAFI_UNICAST, 0); | table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, rib->vrf_id); |
if (! table) |
if (! table) |
return 0; |
return 0; |
|
|
Line 351 nexthop_active_ipv4 (struct rib *rib, struct nexthop *
|
Line 383 nexthop_active_ipv4 (struct rib *rib, struct nexthop *
|
return 0; |
return 0; |
|
|
/* Pick up selected route. */ |
/* Pick up selected route. */ |
for (match = rn->info; match; match = match->next) | RNODE_FOREACH_RIB (rn, match) |
{ |
{ |
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) |
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) |
continue; |
continue; |
if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) | if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) |
break; |
break; |
} |
} |
|
|
Line 372 nexthop_active_ipv4 (struct rib *rib, struct nexthop *
|
Line 404 nexthop_active_ipv4 (struct rib *rib, struct nexthop *
|
} |
} |
else |
else |
{ |
{ |
|
/* If the longest prefix match for the nexthop yields |
|
* a blackhole, mark it as inactive. */ |
|
if (CHECK_FLAG (match->flags, ZEBRA_FLAG_BLACKHOLE) |
|
|| CHECK_FLAG (match->flags, ZEBRA_FLAG_REJECT)) |
|
return 0; |
|
|
if (match->type == ZEBRA_ROUTE_CONNECT) |
if (match->type == ZEBRA_ROUTE_CONNECT) |
{ |
{ |
/* Directly point connected route. */ |
/* Directly point connected route. */ |
Line 383 nexthop_active_ipv4 (struct rib *rib, struct nexthop *
|
Line 421 nexthop_active_ipv4 (struct rib *rib, struct nexthop *
|
} |
} |
else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) |
else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) |
{ |
{ |
|
resolved = 0; |
for (newhop = match->nexthop; newhop; newhop = newhop->next) |
for (newhop = match->nexthop; newhop; newhop = newhop->next) |
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB) |
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB) |
&& ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE)) |
&& ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE)) |
Line 390 nexthop_active_ipv4 (struct rib *rib, struct nexthop *
|
Line 429 nexthop_active_ipv4 (struct rib *rib, struct nexthop *
|
if (set) |
if (set) |
{ |
{ |
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); |
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); |
nexthop->rtype = newhop->type; | |
if (newhop->type == NEXTHOP_TYPE_IPV4 || | resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop)); |
newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) | SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE); |
nexthop->rgate.ipv4 = newhop->gate.ipv4; | /* 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; |
| 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. Therefore, the resolved route |
| * should have the original gateway as nexthop as it |
| * is directly connected. */ |
if (newhop->type == NEXTHOP_TYPE_IFINDEX |
if (newhop->type == NEXTHOP_TYPE_IFINDEX |
|| newhop->type == NEXTHOP_TYPE_IFNAME | || newhop->type == NEXTHOP_TYPE_IFNAME) |
|| newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) | { |
nexthop->rifindex = newhop->ifindex; | 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); |
} |
} |
return 1; | resolved = 1; |
} |
} |
return 0; | if (resolved && set) |
| rib->nexthop_mtu = match->mtu; |
| return resolved; |
} |
} |
else |
else |
{ |
{ |
Line 412 nexthop_active_ipv4 (struct rib *rib, struct nexthop *
|
Line 472 nexthop_active_ipv4 (struct rib *rib, struct nexthop *
|
return 0; |
return 0; |
} |
} |
|
|
#ifdef HAVE_IPV6 |
|
/* If force flag is not set, do not modify falgs at all for uninstall |
/* If force flag is not set, do not modify falgs at all for uninstall |
the route from FIB. */ |
the route from FIB. */ |
static int |
static int |
Line 423 nexthop_active_ipv6 (struct rib *rib, struct nexthop *
|
Line 482 nexthop_active_ipv6 (struct rib *rib, struct nexthop *
|
struct route_table *table; |
struct route_table *table; |
struct route_node *rn; |
struct route_node *rn; |
struct rib *match; |
struct rib *match; |
|
int resolved; |
struct nexthop *newhop; |
struct nexthop *newhop; |
|
struct nexthop *resolved_hop; |
|
|
if (nexthop->type == NEXTHOP_TYPE_IPV6) |
if (nexthop->type == NEXTHOP_TYPE_IPV6) |
nexthop->ifindex = 0; |
nexthop->ifindex = 0; |
|
|
if (set) |
if (set) |
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); | { |
| UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); |
| nexthops_free(nexthop->resolved); |
| nexthop->resolved = NULL; |
| } |
|
|
/* Make lookup prefix. */ |
/* Make lookup prefix. */ |
memset (&p, 0, sizeof (struct prefix_ipv6)); |
memset (&p, 0, sizeof (struct prefix_ipv6)); |
Line 438 nexthop_active_ipv6 (struct rib *rib, struct nexthop *
|
Line 503 nexthop_active_ipv6 (struct rib *rib, struct nexthop *
|
p.prefix = nexthop->gate.ipv6; |
p.prefix = nexthop->gate.ipv6; |
|
|
/* Lookup table. */ |
/* Lookup table. */ |
table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); | table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, rib->vrf_id); |
if (! table) |
if (! table) |
return 0; |
return 0; |
|
|
Line 452 nexthop_active_ipv6 (struct rib *rib, struct nexthop *
|
Line 517 nexthop_active_ipv6 (struct rib *rib, struct nexthop *
|
return 0; |
return 0; |
|
|
/* Pick up selected route. */ |
/* Pick up selected route. */ |
for (match = rn->info; match; match = match->next) | RNODE_FOREACH_RIB (rn, match) |
{ |
{ |
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) |
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) |
continue; |
continue; |
if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) | if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) |
break; |
break; |
} |
} |
|
|
Line 473 nexthop_active_ipv6 (struct rib *rib, struct nexthop *
|
Line 538 nexthop_active_ipv6 (struct rib *rib, struct nexthop *
|
} |
} |
else |
else |
{ |
{ |
|
/* If the longest prefix match for the nexthop yields |
|
* a blackhole, mark it as inactive. */ |
|
if (CHECK_FLAG (match->flags, ZEBRA_FLAG_BLACKHOLE) |
|
|| CHECK_FLAG (match->flags, ZEBRA_FLAG_REJECT)) |
|
return 0; |
|
|
if (match->type == ZEBRA_ROUTE_CONNECT) |
if (match->type == ZEBRA_ROUTE_CONNECT) |
{ |
{ |
/* Directly point connected route. */ |
/* Directly point connected route. */ |
Line 485 nexthop_active_ipv6 (struct rib *rib, struct nexthop *
|
Line 556 nexthop_active_ipv6 (struct rib *rib, struct nexthop *
|
} |
} |
else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) |
else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) |
{ |
{ |
|
resolved = 0; |
for (newhop = match->nexthop; newhop; newhop = newhop->next) |
for (newhop = match->nexthop; newhop; newhop = newhop->next) |
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB) |
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB) |
&& ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE)) |
&& ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE)) |
Line 492 nexthop_active_ipv6 (struct rib *rib, struct nexthop *
|
Line 564 nexthop_active_ipv6 (struct rib *rib, struct nexthop *
|
if (set) |
if (set) |
{ |
{ |
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); |
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); |
nexthop->rtype = newhop->type; | |
| 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 |
if (newhop->type == NEXTHOP_TYPE_IPV6 |
|| newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX |
|| newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX |
|| newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) |
|| newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) |
nexthop->rgate.ipv6 = newhop->gate.ipv6; | { |
| 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 |
if (newhop->type == NEXTHOP_TYPE_IFINDEX |
|| newhop->type == NEXTHOP_TYPE_IFNAME | || newhop->type == NEXTHOP_TYPE_IFNAME) |
|| newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX | { |
|| newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) | resolved_hop->flags |= NEXTHOP_FLAG_ONLINK; |
nexthop->rifindex = newhop->ifindex; | 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); |
} |
} |
return 1; | resolved = 1; |
} |
} |
return 0; | return resolved; |
} |
} |
else |
else |
{ |
{ |
Line 515 nexthop_active_ipv6 (struct rib *rib, struct nexthop *
|
Line 606 nexthop_active_ipv6 (struct rib *rib, struct nexthop *
|
} |
} |
return 0; |
return 0; |
} |
} |
#endif /* HAVE_IPV6 */ |
|
|
|
struct rib * |
struct rib * |
rib_match_ipv4 (struct in_addr addr) | rib_match_ipv4_safi (struct in_addr addr, safi_t safi, int skip_bgp, |
| struct route_node **rn_out, vrf_id_t vrf_id) |
{ |
{ |
struct prefix_ipv4 p; |
|
struct route_table *table; |
struct route_table *table; |
struct route_node *rn; |
struct route_node *rn; |
struct rib *match; |
struct rib *match; |
struct nexthop *newhop; | struct nexthop *newhop, *tnewhop; |
| int recursing; |
|
|
/* Lookup table. */ |
/* Lookup table. */ |
table = vrf_table (AFI_IP, SAFI_UNICAST, 0); | table = zebra_vrf_table (AFI_IP, safi, vrf_id); |
if (! table) |
if (! table) |
return 0; |
return 0; |
|
|
memset (&p, 0, sizeof (struct prefix_ipv4)); | rn = route_node_match_ipv4 (table, &addr); |
p.family = AF_INET; | |
p.prefixlen = IPV4_MAX_PREFIXLEN; | |
p.prefix = addr; | |
|
|
rn = route_node_match (table, (struct prefix *) &p); |
|
|
|
while (rn) |
while (rn) |
{ |
{ |
route_unlock_node (rn); |
route_unlock_node (rn); |
| |
/* Pick up selected route. */ |
/* Pick up selected route. */ |
for (match = rn->info; match; match = match->next) | RNODE_FOREACH_RIB (rn, match) |
{ |
{ |
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) |
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) |
continue; |
continue; |
if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) | if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) |
break; |
break; |
} |
} |
|
|
/* If there is no selected route or matched route is EGP, go up |
/* If there is no selected route or matched route is EGP, go up |
tree. */ |
tree. */ |
if (! match | if (!match || (skip_bgp && (match->type == ZEBRA_ROUTE_BGP))) |
|| match->type == ZEBRA_ROUTE_BGP) | |
{ |
{ |
do { |
do { |
rn = rn->parent; |
rn = rn->parent; |
Line 564 rib_match_ipv4 (struct in_addr addr)
|
Line 649 rib_match_ipv4 (struct in_addr addr)
|
} |
} |
else |
else |
{ |
{ |
if (match->type == ZEBRA_ROUTE_CONNECT) | if (match->type != ZEBRA_ROUTE_CONNECT) |
/* Directly point connected route. */ | |
return match; | |
else | |
{ |
{ |
for (newhop = match->nexthop; newhop; newhop = newhop->next) | int found = 0; |
| for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing)) |
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) |
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) |
return match; | { |
return NULL; | found = 1; |
| break; |
| } |
| if (!found) |
| return NULL; |
} |
} |
|
|
|
if (rn_out) |
|
*rn_out = rn; |
|
return match; |
} |
} |
} |
} |
return NULL; |
return NULL; |
} |
} |
|
|
struct rib * |
struct rib * |
rib_lookup_ipv4 (struct prefix_ipv4 *p) | rib_match_ipv4_multicast (struct in_addr addr, struct route_node **rn_out, |
| vrf_id_t vrf_id) |
{ |
{ |
|
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); |
|
case MCAST_URIB_ONLY: |
|
return rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, 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); |
|
if (!mrib) |
|
rib = urib = rib_match_ipv4_safi (addr, SAFI_UNICAST, skip_bgp, &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); |
|
if (mrib && urib) |
|
rib = urib->distance < mrib->distance ? urib : mrib; |
|
else if (mrib) |
|
rib = mrib; |
|
else if (urib) |
|
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); |
|
if (mrib && urib) |
|
rib = u_rn->p.prefixlen > m_rn->p.prefixlen ? urib : mrib; |
|
else if (mrib) |
|
rib = mrib; |
|
else if (urib) |
|
rib = urib; |
|
break; |
|
} |
|
|
|
if (rn_out) |
|
*rn_out = (rib == mrib) ? m_rn : u_rn; |
|
|
|
if (IS_ZEBRA_DEBUG_RIB) |
|
{ |
|
char buf[BUFSIZ]; |
|
inet_ntop (AF_INET, &addr, buf, BUFSIZ); |
|
|
|
zlog_debug("%s: %s vrf %u: found %s, using %s", |
|
__func__, buf, vrf_id, |
|
mrib ? (urib ? "MRIB+URIB" : "MRIB") : |
|
urib ? "URIB" : "nothing", |
|
rib == urib ? "URIB" : rib == mrib ? "MRIB" : "none"); |
|
} |
|
return rib; |
|
} |
|
|
|
void |
|
multicast_mode_ipv4_set (enum multicast_mode mode) |
|
{ |
|
if (IS_ZEBRA_DEBUG_RIB) |
|
zlog_debug("%s: multicast lookup mode set (%d)", __func__, mode); |
|
ipv4_multicast_mode = mode; |
|
} |
|
|
|
enum multicast_mode |
|
multicast_mode_ipv4_get (void) |
|
{ |
|
return ipv4_multicast_mode; |
|
} |
|
|
|
struct rib * |
|
rib_lookup_ipv4 (struct prefix_ipv4 *p, vrf_id_t vrf_id) |
|
{ |
struct route_table *table; |
struct route_table *table; |
struct route_node *rn; |
struct route_node *rn; |
struct rib *match; |
struct rib *match; |
struct nexthop *nexthop; | struct nexthop *nexthop, *tnexthop; |
| int recursing; |
|
|
/* Lookup table. */ |
/* Lookup table. */ |
table = vrf_table (AFI_IP, SAFI_UNICAST, 0); | table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); |
if (! table) |
if (! table) |
return 0; |
return 0; |
|
|
Line 601 rib_lookup_ipv4 (struct prefix_ipv4 *p)
|
Line 774 rib_lookup_ipv4 (struct prefix_ipv4 *p)
|
/* Unlock node. */ |
/* Unlock node. */ |
route_unlock_node (rn); |
route_unlock_node (rn); |
|
|
for (match = rn->info; match; match = match->next) | RNODE_FOREACH_RIB (rn, match) |
{ |
{ |
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) |
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) |
continue; |
continue; |
if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) | if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) |
break; |
break; |
} |
} |
|
|
Line 615 rib_lookup_ipv4 (struct prefix_ipv4 *p)
|
Line 788 rib_lookup_ipv4 (struct prefix_ipv4 *p)
|
if (match->type == ZEBRA_ROUTE_CONNECT) |
if (match->type == ZEBRA_ROUTE_CONNECT) |
return match; |
return match; |
|
|
for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next) | for (ALL_NEXTHOPS_RO(match->nexthop, nexthop, tnexthop, recursing)) |
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) |
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) |
return match; |
return match; |
|
|
Line 635 rib_lookup_ipv4 (struct prefix_ipv4 *p)
|
Line 808 rib_lookup_ipv4 (struct prefix_ipv4 *p)
|
* 3: no matches found |
* 3: no matches found |
*/ |
*/ |
int |
int |
rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate) | rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate, |
| vrf_id_t vrf_id) |
{ |
{ |
struct route_table *table; |
struct route_table *table; |
struct route_node *rn; |
struct route_node *rn; |
struct rib *match; |
struct rib *match; |
struct nexthop *nexthop; | struct nexthop *nexthop, *tnexthop; |
| int recursing; |
| int nexthops_active; |
|
|
/* Lookup table. */ |
/* Lookup table. */ |
table = vrf_table (AFI_IP, SAFI_UNICAST, 0); | table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); |
if (! table) |
if (! table) |
return ZEBRA_RIB_LOOKUP_ERROR; |
return ZEBRA_RIB_LOOKUP_ERROR; |
|
|
Line 658 rib_lookup_ipv4_route (struct prefix_ipv4 *p, union so
|
Line 834 rib_lookup_ipv4_route (struct prefix_ipv4 *p, union so
|
route_unlock_node (rn); |
route_unlock_node (rn); |
|
|
/* Find out if a "selected" RR for the discovered RIB entry exists ever. */ |
/* Find out if a "selected" RR for the discovered RIB entry exists ever. */ |
for (match = rn->info; match; match = match->next) | RNODE_FOREACH_RIB (rn, match) |
{ |
{ |
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) |
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) |
continue; |
continue; |
if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) | if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) |
break; |
break; |
} |
} |
|
|
Line 674 rib_lookup_ipv4_route (struct prefix_ipv4 *p, union so
|
Line 850 rib_lookup_ipv4_route (struct prefix_ipv4 *p, union so
|
return ZEBRA_RIB_FOUND_CONNECTED; |
return ZEBRA_RIB_FOUND_CONNECTED; |
|
|
/* Ok, we have a cood candidate, let's check it's nexthop list... */ |
/* Ok, we have a cood candidate, let's check it's nexthop list... */ |
for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next) | nexthops_active = 0; |
| for (ALL_NEXTHOPS_RO(match->nexthop, nexthop, tnexthop, recursing)) |
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) |
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) |
{ |
|
/* We are happy with either direct or recursive hexthop */ |
|
if (nexthop->gate.ipv4.s_addr == qgate->sin.sin_addr.s_addr || |
|
nexthop->rgate.ipv4.s_addr == qgate->sin.sin_addr.s_addr) |
|
return ZEBRA_RIB_FOUND_EXACT; |
|
else |
|
{ |
{ |
|
nexthops_active = 1; |
|
if (nexthop->gate.ipv4.s_addr == sockunion2ip (qgate)) |
|
return ZEBRA_RIB_FOUND_EXACT; |
if (IS_ZEBRA_DEBUG_RIB) |
if (IS_ZEBRA_DEBUG_RIB) |
{ | { |
char gate_buf[INET_ADDRSTRLEN], rgate_buf[INET_ADDRSTRLEN], qgate_buf[INET_ADDRSTRLEN]; | char gate_buf[INET_ADDRSTRLEN], qgate_buf[INET_ADDRSTRLEN]; |
inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, gate_buf, INET_ADDRSTRLEN); | inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, gate_buf, INET_ADDRSTRLEN); |
inet_ntop (AF_INET, &nexthop->rgate.ipv4.s_addr, rgate_buf, INET_ADDRSTRLEN); | inet_ntop (AF_INET, &sockunion2ip(qgate), qgate_buf, INET_ADDRSTRLEN); |
inet_ntop (AF_INET, &qgate->sin.sin_addr.s_addr, qgate_buf, INET_ADDRSTRLEN); | zlog_debug ("%s: qgate == %s, %s == %s", __func__, |
zlog_debug ("%s: qgate == %s, gate == %s, rgate == %s", __func__, qgate_buf, gate_buf, rgate_buf); | qgate_buf, recursing ? "rgate" : "gate", gate_buf); |
} | } |
return ZEBRA_RIB_FOUND_NOGATE; | |
} |
} |
} |
|
|
|
|
if (nexthops_active) |
|
return ZEBRA_RIB_FOUND_NOGATE; |
|
|
return ZEBRA_RIB_NOTFOUND; |
return ZEBRA_RIB_NOTFOUND; |
} |
} |
|
|
#ifdef HAVE_IPV6 |
|
struct rib * |
struct rib * |
rib_match_ipv6 (struct in6_addr *addr) | rib_match_ipv6 (struct in6_addr *addr, vrf_id_t vrf_id) |
{ |
{ |
struct prefix_ipv6 p; |
struct prefix_ipv6 p; |
struct route_table *table; |
struct route_table *table; |
struct route_node *rn; |
struct route_node *rn; |
struct rib *match; |
struct rib *match; |
struct nexthop *newhop; | struct nexthop *newhop, *tnewhop; |
| int recursing; |
|
|
/* Lookup table. */ |
/* Lookup table. */ |
table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); | table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); |
if (! table) |
if (! table) |
return 0; |
return 0; |
|
|
Line 725 rib_match_ipv6 (struct in6_addr *addr)
|
Line 900 rib_match_ipv6 (struct in6_addr *addr)
|
route_unlock_node (rn); |
route_unlock_node (rn); |
|
|
/* Pick up selected route. */ |
/* Pick up selected route. */ |
for (match = rn->info; match; match = match->next) | RNODE_FOREACH_RIB (rn, match) |
{ |
{ |
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) |
if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) |
continue; |
continue; |
if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) | if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) |
break; |
break; |
} |
} |
|
|
Line 751 rib_match_ipv6 (struct in6_addr *addr)
|
Line 926 rib_match_ipv6 (struct in6_addr *addr)
|
return match; |
return match; |
else |
else |
{ |
{ |
for (newhop = match->nexthop; newhop; newhop = newhop->next) | for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing)) |
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) |
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) |
return match; |
return match; |
return NULL; |
return NULL; |
Line 760 rib_match_ipv6 (struct in6_addr *addr)
|
Line 935 rib_match_ipv6 (struct in6_addr *addr)
|
} |
} |
return NULL; |
return NULL; |
} |
} |
#endif /* HAVE_IPV6 */ |
|
|
|
#define RIB_SYSTEM_ROUTE(R) \ |
#define RIB_SYSTEM_ROUTE(R) \ |
((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT) |
((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT) |
Line 779 static unsigned
|
Line 953 static unsigned
|
nexthop_active_check (struct route_node *rn, struct rib *rib, |
nexthop_active_check (struct route_node *rn, struct rib *rib, |
struct nexthop *nexthop, int set) |
struct nexthop *nexthop, int set) |
{ |
{ |
|
rib_table_info_t *info = rn->table->info; |
struct interface *ifp; |
struct interface *ifp; |
route_map_result_t ret = RMAP_MATCH; |
route_map_result_t ret = RMAP_MATCH; |
extern char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; |
extern char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; |
Line 789 nexthop_active_check (struct route_node *rn, struct ri
|
Line 964 nexthop_active_check (struct route_node *rn, struct ri
|
switch (nexthop->type) |
switch (nexthop->type) |
{ |
{ |
case NEXTHOP_TYPE_IFINDEX: |
case NEXTHOP_TYPE_IFINDEX: |
ifp = if_lookup_by_index (nexthop->ifindex); | ifp = if_lookup_by_index_vrf (nexthop->ifindex, rib->vrf_id); |
if (ifp && if_is_operative(ifp)) |
if (ifp && if_is_operative(ifp)) |
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); |
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); |
else |
else |
Line 798 nexthop_active_check (struct route_node *rn, struct ri
|
Line 973 nexthop_active_check (struct route_node *rn, struct ri
|
case NEXTHOP_TYPE_IPV6_IFNAME: |
case NEXTHOP_TYPE_IPV6_IFNAME: |
family = AFI_IP6; |
family = AFI_IP6; |
case NEXTHOP_TYPE_IFNAME: |
case NEXTHOP_TYPE_IFNAME: |
ifp = if_lookup_by_name (nexthop->ifname); | ifp = if_lookup_by_name_vrf (nexthop->ifname, rib->vrf_id); |
if (ifp && if_is_operative(ifp)) |
if (ifp && if_is_operative(ifp)) |
{ |
{ |
if (set) |
if (set) |
Line 820 nexthop_active_check (struct route_node *rn, struct ri
|
Line 995 nexthop_active_check (struct route_node *rn, struct ri
|
else |
else |
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); |
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); |
break; |
break; |
#ifdef HAVE_IPV6 |
|
case NEXTHOP_TYPE_IPV6: |
case NEXTHOP_TYPE_IPV6: |
family = AFI_IP6; |
family = AFI_IP6; |
if (nexthop_active_ipv6 (rib, nexthop, set, rn)) |
if (nexthop_active_ipv6 (rib, nexthop, set, rn)) |
Line 832 nexthop_active_check (struct route_node *rn, struct ri
|
Line 1006 nexthop_active_check (struct route_node *rn, struct ri
|
family = AFI_IP6; |
family = AFI_IP6; |
if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6)) |
if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6)) |
{ |
{ |
ifp = if_lookup_by_index (nexthop->ifindex); | ifp = if_lookup_by_index_vrf (nexthop->ifindex, rib->vrf_id); |
if (ifp && if_is_operative(ifp)) |
if (ifp && if_is_operative(ifp)) |
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); |
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); |
else |
else |
Line 846 nexthop_active_check (struct route_node *rn, struct ri
|
Line 1020 nexthop_active_check (struct route_node *rn, struct ri
|
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); |
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); |
} |
} |
break; |
break; |
#endif /* HAVE_IPV6 */ |
|
case NEXTHOP_TYPE_BLACKHOLE: |
case NEXTHOP_TYPE_BLACKHOLE: |
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); |
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); |
break; |
break; |
Line 856 nexthop_active_check (struct route_node *rn, struct ri
|
Line 1029 nexthop_active_check (struct route_node *rn, struct ri
|
if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) |
if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) |
return 0; |
return 0; |
|
|
|
/* XXX: What exactly do those checks do? Do we support |
|
* e.g. IPv4 routes with IPv6 nexthops or vice versa? */ |
if (RIB_SYSTEM_ROUTE(rib) || |
if (RIB_SYSTEM_ROUTE(rib) || |
(family == AFI_IP && rn->p.family != AF_INET) || |
(family == AFI_IP && rn->p.family != AF_INET) || |
(family == AFI_IP6 && rn->p.family != AF_INET6)) |
(family == AFI_IP6 && rn->p.family != AF_INET6)) |
return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); |
return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); |
|
|
|
/* The original code didn't determine the family correctly |
|
* e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi |
|
* from the rib_table_info in those cases. |
|
* Possibly it may be better to use only the rib_table_info |
|
* in every case. |
|
*/ |
|
if (!family) |
|
family = info->afi; |
|
|
rmap = 0; |
rmap = 0; |
if (rib->type >= 0 && rib->type < ZEBRA_ROUTE_MAX && |
if (rib->type >= 0 && rib->type < ZEBRA_ROUTE_MAX && |
proto_rm[family][rib->type]) |
proto_rm[family][rib->type]) |
Line 868 nexthop_active_check (struct route_node *rn, struct ri
|
Line 1052 nexthop_active_check (struct route_node *rn, struct ri
|
if (!rmap && proto_rm[family][ZEBRA_ROUTE_MAX]) |
if (!rmap && proto_rm[family][ZEBRA_ROUTE_MAX]) |
rmap = route_map_lookup_by_name (proto_rm[family][ZEBRA_ROUTE_MAX]); |
rmap = route_map_lookup_by_name (proto_rm[family][ZEBRA_ROUTE_MAX]); |
if (rmap) { |
if (rmap) { |
ret = route_map_apply(rmap, &rn->p, RMAP_ZEBRA, nexthop); | struct nexthop_vrfid nh_vrf = {nexthop, rib->vrf_id}; |
| ret = route_map_apply(rmap, &rn->p, RMAP_ZEBRA, &nh_vrf); |
} |
} |
|
|
if (ret == RMAP_DENYMATCH) |
if (ret == RMAP_DENYMATCH) |
Line 879 nexthop_active_check (struct route_node *rn, struct ri
|
Line 1064 nexthop_active_check (struct route_node *rn, struct ri
|
/* Iterate over all nexthops of the given RIB entry and refresh their |
/* Iterate over all nexthops of the given RIB entry and refresh their |
* ACTIVE flag. rib->nexthop_active_num is updated accordingly. If any |
* ACTIVE flag. rib->nexthop_active_num is updated accordingly. If any |
* nexthop is found to toggle the ACTIVE flag, the whole rib structure |
* nexthop is found to toggle the ACTIVE flag, the whole rib structure |
* is flagged with ZEBRA_FLAG_CHANGED. The 4th 'set' argument is | * is flagged with RIB_ENTRY_CHANGED. The 4th 'set' argument is |
* transparently passed to nexthop_active_check(). |
* transparently passed to nexthop_active_check(). |
* |
* |
* Return value is the new number of active nexthops. |
* Return value is the new number of active nexthops. |
Line 889 static int
|
Line 1074 static int
|
nexthop_active_update (struct route_node *rn, struct rib *rib, int set) |
nexthop_active_update (struct route_node *rn, struct rib *rib, int set) |
{ |
{ |
struct nexthop *nexthop; |
struct nexthop *nexthop; |
unsigned int prev_active, prev_index, new_active; | unsigned int prev_active, new_active; |
| ifindex_t prev_index; |
| |
rib->nexthop_active_num = 0; |
rib->nexthop_active_num = 0; |
UNSET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); | UNSET_FLAG (rib->status, RIB_ENTRY_CHANGED); |
|
|
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) |
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) |
{ |
{ |
Line 902 nexthop_active_update (struct route_node *rn, struct r
|
Line 1088 nexthop_active_update (struct route_node *rn, struct r
|
rib->nexthop_active_num++; |
rib->nexthop_active_num++; |
if (prev_active != new_active || |
if (prev_active != new_active || |
prev_index != nexthop->ifindex) |
prev_index != nexthop->ifindex) |
SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); | SET_FLAG (rib->status, RIB_ENTRY_CHANGED); |
} |
} |
return rib->nexthop_active_num; |
return rib->nexthop_active_num; |
} |
} |
|
|
|
|
|
|
static void | |
rib_install_kernel (struct route_node *rn, struct rib *rib) | static int |
| rib_update_kernel (struct route_node *rn, struct rib *old, struct rib *new) |
{ |
{ |
int ret = 0; |
int ret = 0; |
struct nexthop *nexthop; | struct nexthop *nexthop, *tnexthop; |
| rib_table_info_t *info = rn->table->info; |
| int recursing; |
|
|
switch (PREFIX_FAMILY (&rn->p)) | if (info->safi != SAFI_UNICAST) |
{ |
{ |
case AF_INET: | if (new) |
ret = kernel_add_ipv4 (&rn->p, rib); | for (ALL_NEXTHOPS_RO(new->nexthop, nexthop, tnexthop, recursing)) |
break; | SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); |
#ifdef HAVE_IPV6 | if (old) |
case AF_INET6: | for (ALL_NEXTHOPS_RO(old->nexthop, nexthop, tnexthop, recursing)) |
ret = kernel_add_ipv6 (&rn->p, rib); | UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); |
break; | return 0; |
#endif /* HAVE_IPV6 */ | |
} |
} |
|
|
/* This condition is never met, if we are using rt_socket.c */ | /* |
if (ret < 0) | * Make sure we update the FPM any time we send new information to |
{ | * the kernel. |
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) | */ |
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); | zfpm_trigger_update (rn, "updating in kernel"); |
} | |
} | |
|
|
/* Uninstall the route from kernel. */ | ret = kernel_route_rib (&rn->p, old, new); |
static int | |
rib_uninstall_kernel (struct route_node *rn, struct rib *rib) | |
{ | |
int ret = 0; | |
struct nexthop *nexthop; | |
|
|
switch (PREFIX_FAMILY (&rn->p)) | /* This condition is never met, if we are using rt_socket.c */ |
{ | if (ret < 0 && new) |
case AF_INET: | for (ALL_NEXTHOPS_RO(new->nexthop, nexthop, tnexthop, recursing)) |
ret = kernel_delete_ipv4 (&rn->p, rib); | UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); |
break; | |
#ifdef HAVE_IPV6 | |
case AF_INET6: | |
ret = kernel_delete_ipv6 (&rn->p, rib); | |
break; | |
#endif /* HAVE_IPV6 */ | |
} | |
|
|
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) | if (old) |
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); | for (ALL_NEXTHOPS_RO(old->nexthop, nexthop, tnexthop, recursing)) |
| UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); |
|
|
return ret; |
return ret; |
} |
} |
Line 964 rib_uninstall_kernel (struct route_node *rn, struct ri
|
Line 1138 rib_uninstall_kernel (struct route_node *rn, struct ri
|
static void |
static void |
rib_uninstall (struct route_node *rn, struct rib *rib) |
rib_uninstall (struct route_node *rn, struct rib *rib) |
{ |
{ |
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) | rib_table_info_t *info = rn->table->info; |
| |
| if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) |
{ |
{ |
|
if (info->safi == SAFI_UNICAST) |
|
zfpm_trigger_update (rn, "rib_uninstall"); |
|
|
redistribute_delete (&rn->p, rib); |
redistribute_delete (&rn->p, rib); |
if (! RIB_SYSTEM_ROUTE (rib)) |
if (! RIB_SYSTEM_ROUTE (rib)) |
rib_uninstall_kernel (rn, rib); | rib_update_kernel (rn, rib, NULL); |
UNSET_FLAG (rib->flags, ZEBRA_FLAG_SELECTED); |
UNSET_FLAG (rib->flags, ZEBRA_FLAG_SELECTED); |
} |
} |
} |
} |
|
|
static void rib_unlink (struct route_node *, struct rib *); |
static void rib_unlink (struct route_node *, struct rib *); |
|
|
|
/* |
|
* rib_can_delete_dest |
|
* |
|
* Returns TRUE if the given dest can be deleted from the table. |
|
*/ |
|
static int |
|
rib_can_delete_dest (rib_dest_t *dest) |
|
{ |
|
if (dest->routes) |
|
{ |
|
return 0; |
|
} |
|
|
|
/* |
|
* Don't delete the dest if we have to update the FPM about this |
|
* prefix. |
|
*/ |
|
if (CHECK_FLAG (dest->flags, RIB_DEST_UPDATE_FPM) || |
|
CHECK_FLAG (dest->flags, RIB_DEST_SENT_TO_FPM)) |
|
return 0; |
|
|
|
return 1; |
|
} |
|
|
|
/* |
|
* rib_gc_dest |
|
* |
|
* Garbage collect the rib dest corresponding to the given route node |
|
* if appropriate. |
|
* |
|
* Returns TRUE if the dest was deleted, FALSE otherwise. |
|
*/ |
|
int |
|
rib_gc_dest (struct route_node *rn) |
|
{ |
|
rib_dest_t *dest; |
|
|
|
dest = rib_dest_from_rnode (rn); |
|
if (!dest) |
|
return 0; |
|
|
|
if (!rib_can_delete_dest (dest)) |
|
return 0; |
|
|
|
if (IS_ZEBRA_DEBUG_RIB) |
|
rnode_debug (rn, "removing dest from table"); |
|
|
|
dest->rnode = NULL; |
|
XFREE (MTYPE_RIB_DEST, dest); |
|
rn->info = NULL; |
|
|
|
/* |
|
* Release the one reference that we keep on the route node. |
|
*/ |
|
route_unlock_node (rn); |
|
return 1; |
|
} |
|
|
|
/* Check if 'alternate' RIB entry is better than 'current'. */ |
|
static struct rib * |
|
rib_choose_best (struct rib *current, struct rib *alternate) |
|
{ |
|
if (current == NULL) |
|
return alternate; |
|
|
|
/* filter route selection in following order: |
|
* - connected beats other types |
|
* - lower distance beats higher |
|
* - lower metric beats higher for equal distance |
|
* - last, hence oldest, route wins tie break. |
|
*/ |
|
|
|
/* Connected routes. Pick the last connected |
|
* route of the set of lowest metric connected routes. |
|
*/ |
|
if (alternate->type == ZEBRA_ROUTE_CONNECT) |
|
{ |
|
if (current->type != ZEBRA_ROUTE_CONNECT |
|
|| alternate->metric <= current->metric) |
|
return alternate; |
|
|
|
return current; |
|
} |
|
|
|
if (current->type == ZEBRA_ROUTE_CONNECT) |
|
return current; |
|
|
|
/* higher distance loses */ |
|
if (alternate->distance < current->distance) |
|
return alternate; |
|
if (current->distance < alternate->distance) |
|
return current; |
|
|
|
/* metric tie-breaks equal distance */ |
|
if (alternate->metric <= current->metric) |
|
return alternate; |
|
|
|
return current; |
|
} |
|
|
/* Core function for processing routing information base. */ |
/* Core function for processing routing information base. */ |
static void |
static void |
rib_process (struct route_node *rn) |
rib_process (struct route_node *rn) |
{ |
{ |
struct rib *rib; |
struct rib *rib; |
struct rib *next; |
struct rib *next; |
struct rib *fib = NULL; | struct rib *old_selected = NULL; |
struct rib *select = NULL; | struct rib *new_selected = NULL; |
struct rib *del = NULL; | struct rib *old_fib = NULL; |
| struct rib *new_fib = NULL; |
int installed = 0; |
int installed = 0; |
struct nexthop *nexthop = NULL; | struct nexthop *nexthop = NULL, *tnexthop; |
char buf[INET6_ADDRSTRLEN]; | int recursing; |
| rib_table_info_t *info; |
| |
assert (rn); |
assert (rn); |
|
|
if (IS_ZEBRA_DEBUG_RIB || IS_ZEBRA_DEBUG_RIB_Q) |
|
inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); |
|
|
|
for (rib = rn->info; rib; rib = next) | info = rn->table->info; |
| |
| RNODE_FOREACH_RIB (rn, rib) |
{ |
{ |
/* The next pointer is saved, because current pointer |
|
* may be passed to rib_unlink() in the middle of iteration. |
|
*/ |
|
next = rib->next; |
|
|
|
/* Currently installed rib. */ |
/* Currently installed rib. */ |
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) |
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) |
{ |
{ |
assert (fib == NULL); | assert (old_selected == NULL); |
fib = rib; | old_selected = rib; |
} |
} |
| if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) |
/* Unlock removed routes, so they'll be freed, bar the FIB entry, | |
* which we need to do do further work with below. | |
*/ | |
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) | |
{ |
{ |
if (rib != fib) | assert (old_fib == NULL); |
{ | old_fib = rib; |
if (IS_ZEBRA_DEBUG_RIB) | |
zlog_debug ("%s: %s/%d: rn %p, removing rib %p", __func__, | |
buf, rn->p.prefixlen, rn, rib); | |
rib_unlink (rn, rib); | |
} | |
else | |
del = rib; | |
| |
continue; | |
} |
} |
|
|
|
/* Skip deleted entries from selection */ |
|
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
|
continue; |
|
|
/* Skip unreachable nexthop. */ |
/* Skip unreachable nexthop. */ |
if (! nexthop_active_update (rn, rib, 0)) |
if (! nexthop_active_update (rn, rib, 0)) |
Line 1033 rib_process (struct route_node *rn)
|
Line 1299 rib_process (struct route_node *rn)
|
if (rib->distance == DISTANCE_INFINITY) |
if (rib->distance == DISTANCE_INFINITY) |
continue; |
continue; |
|
|
/* Newly selected rib, the common case. */ | if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_FIB_OVERRIDE)) |
if (!select) | new_fib = rib_choose_best(new_fib, rib); |
{ | else |
select = rib; | new_selected = rib_choose_best(new_selected, rib); |
continue; | } /* RNODE_FOREACH_RIB_SAFE */ |
} | |
| |
/* filter route selection in following order: | |
* - connected beats other types | |
* - lower distance beats higher | |
* - lower metric beats higher for equal distance | |
* - last, hence oldest, route wins tie break. | |
*/ | |
| |
/* Connected routes. Pick the last connected | |
* route of the set of lowest metric connected routes. | |
*/ | |
if (rib->type == ZEBRA_ROUTE_CONNECT) | |
{ | |
if (select->type != ZEBRA_ROUTE_CONNECT | |
|| rib->metric <= select->metric) | |
select = rib; | |
continue; | |
} | |
else if (select->type == ZEBRA_ROUTE_CONNECT) | |
continue; | |
| |
/* higher distance loses */ | |
if (rib->distance > select->distance) | |
continue; | |
| |
/* lower wins */ | |
if (rib->distance < select->distance) | |
{ | |
select = rib; | |
continue; | |
} | |
| |
/* metric tie-breaks equal distance */ | |
if (rib->metric <= select->metric) | |
select = rib; | |
} /* for (rib = rn->info; rib; rib = next) */ | |
|
|
|
/* If no FIB override route, use the selected route also for FIB */ |
|
if (new_fib == NULL) |
|
new_fib = new_selected; |
|
|
/* After the cycle is finished, the following pointers will be set: |
/* After the cycle is finished, the following pointers will be set: |
* select --- the winner RIB entry, if any was found, otherwise NULL | * old_selected --- RIB entry currently having SELECTED |
* fib --- the SELECTED RIB entry, if any, otherwise NULL | * new_selected --- RIB entry that is newly SELECTED |
* del --- equal to fib, if fib is queued for deletion, NULL otherwise | * old_fib --- RIB entry currently in kernel FIB |
* rib --- NULL | * new_fib --- RIB entry that is newly to be in kernel FIB |
| * |
| * new_selected will get SELECTED flag, and is going to be redistributed |
| * the zclients. new_fib (which can be new_selected) will be installed in kernel. |
*/ |
*/ |
|
|
/* Same RIB entry is selected. Update FIB and finish. */ | /* Set real nexthops. */ |
if (select && select == fib) | if (new_fib) |
| nexthop_active_update (rn, new_fib, 1); |
| if (new_selected && new_selected != new_fib) |
| nexthop_active_update (rn, new_selected, 1); |
| |
| /* Update kernel if FIB entry has changed */ |
| if (old_fib != new_fib |
| || (new_fib && CHECK_FLAG (new_fib->status, RIB_ENTRY_CHANGED))) |
{ |
{ |
if (IS_ZEBRA_DEBUG_RIB) | if (old_fib && old_fib != new_fib) |
zlog_debug ("%s: %s/%d: Updating existing route, select %p, fib %p", | { |
__func__, buf, rn->p.prefixlen, select, fib); | if (! RIB_SYSTEM_ROUTE (old_fib) && (! new_fib || RIB_SYSTEM_ROUTE (new_fib))) |
if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED)) | rib_update_kernel (rn, old_fib, NULL); |
{ | UNSET_FLAG (old_fib->status, RIB_ENTRY_SELECTED_FIB); |
redistribute_delete (&rn->p, select); | } |
if (! RIB_SYSTEM_ROUTE (select)) | |
rib_uninstall_kernel (rn, select); | |
|
|
/* Set real nexthop. */ | if (new_fib) |
nexthop_active_update (rn, select, 1); | { |
| /* Install new or replace existing FIB entry */ |
if (! RIB_SYSTEM_ROUTE (select)) | SET_FLAG (new_fib->status, RIB_ENTRY_SELECTED_FIB); |
rib_install_kernel (rn, select); | if (! RIB_SYSTEM_ROUTE (new_fib)) |
redistribute_add (&rn->p, select); | rib_update_kernel (rn, old_fib, new_fib); |
} | } |
else if (! RIB_SYSTEM_ROUTE (select)) | |
{ | |
/* Housekeeping code to deal with | |
race conditions in kernel with linux | |
netlink reporting interface up before IPv4 or IPv6 protocol | |
is ready to add routes. | |
This makes sure the routes are IN the kernel. | |
*/ | |
|
|
for (nexthop = select->nexthop; nexthop; nexthop = nexthop->next) | if (info->safi == SAFI_UNICAST) |
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) | zfpm_trigger_update (rn, "updating existing route"); |
{ | |
installed = 1; | |
break; | |
} | |
if (! installed) | |
rib_install_kernel (rn, select); | |
} | |
goto end; | |
} |
} |
| else if (old_fib == new_fib && new_fib && ! RIB_SYSTEM_ROUTE (new_fib)) |
/* At this point we either haven't found the best RIB entry or it is | |
* different from what we currently intend to flag with SELECTED. In both | |
* cases, if a RIB block is present in FIB, it should be withdrawn. | |
*/ | |
if (fib) | |
{ |
{ |
if (IS_ZEBRA_DEBUG_RIB) | /* Housekeeping code to deal with race conditions in kernel with |
zlog_debug ("%s: %s/%d: Removing existing route, fib %p", __func__, | * linux netlink reporting interface up before IPv4 or IPv6 protocol |
buf, rn->p.prefixlen, fib); | * is ready to add routes. This makes sure routes are IN the kernel. |
redistribute_delete (&rn->p, fib); | */ |
if (! RIB_SYSTEM_ROUTE (fib)) | for (ALL_NEXTHOPS_RO(new_fib->nexthop, nexthop, tnexthop, recursing)) |
rib_uninstall_kernel (rn, fib); | if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) |
UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); | { |
| installed = 1; |
/* Set real nexthop. */ | break; |
nexthop_active_update (rn, fib, 1); | } |
| if (! installed) |
| rib_update_kernel (rn, NULL, new_fib); |
} |
} |
|
|
/* Regardless of some RIB entry being SELECTED or not before, now we can | /* Redistribute SELECTED entry */ |
* tell, that if a new winner exists, FIB is still not updated with this | if (old_selected != new_selected |
* data, but ready to be. | || (new_selected && CHECK_FLAG (new_selected->status, RIB_ENTRY_CHANGED))) |
*/ | |
if (select) | |
{ |
{ |
if (IS_ZEBRA_DEBUG_RIB) | if (old_selected) |
zlog_debug ("%s: %s/%d: Adding route, select %p", __func__, buf, | { |
rn->p.prefixlen, select); | if (! new_selected) |
/* Set real nexthop. */ | redistribute_delete (&rn->p, old_selected); |
nexthop_active_update (rn, select, 1); | if (old_selected != new_selected) |
| UNSET_FLAG (old_selected->flags, ZEBRA_FLAG_SELECTED); |
| } |
|
|
if (! RIB_SYSTEM_ROUTE (select)) | if (new_selected) |
rib_install_kernel (rn, select); | { |
SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED); | /* Install new or replace existing redistributed entry */ |
redistribute_add (&rn->p, select); | SET_FLAG (new_selected->flags, ZEBRA_FLAG_SELECTED); |
} | redistribute_add (&rn->p, new_selected); |
| } |
| } |
|
|
/* FIB route was removed, should be deleted */ | /* Remove all RIB entries queued for removal */ |
if (del) | RNODE_FOREACH_RIB_SAFE (rn, rib, next) |
{ |
{ |
if (IS_ZEBRA_DEBUG_RIB) | if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
zlog_debug ("%s: %s/%d: Deleting fib %p, rn %p", __func__, buf, | { |
rn->p.prefixlen, del, rn); | if (IS_ZEBRA_DEBUG_RIB) |
rib_unlink (rn, del); | rnode_debug (rn, "rn %p, removing rib %p", |
| (void *)rn, (void *)rib); |
| rib_unlink (rn, rib); |
| } |
} |
} |
|
|
end: |
|
if (IS_ZEBRA_DEBUG_RIB_Q) |
if (IS_ZEBRA_DEBUG_RIB_Q) |
zlog_debug ("%s: %s/%d: rn %p dequeued", __func__, buf, rn->p.prefixlen, rn); | rnode_debug (rn, "rn %p dequeued", (void *)rn); |
| |
| /* |
| * Check if the dest can be deleted now. |
| */ |
| rib_gc_dest (rn); |
} |
} |
|
|
/* Take a list of route_node structs and return 1, if there was a record |
/* Take a list of route_node structs and return 1, if there was a record |
Line 1189 process_subq (struct list * subq, u_char qindex)
|
Line 1420 process_subq (struct list * subq, u_char qindex)
|
rnode = listgetdata (lnode); |
rnode = listgetdata (lnode); |
rib_process (rnode); |
rib_process (rnode); |
|
|
if (rnode->info) /* The first RIB record is holding the flags bitmask. */ | if (rnode->info) |
UNSET_FLAG (((struct rib *)rnode->info)->rn_status, RIB_ROUTE_QUEUED(qindex)); | UNSET_FLAG (rib_dest_from_rnode (rnode)->flags, RIB_ROUTE_QUEUED (qindex)); |
| |
#if 0 |
#if 0 |
else |
else |
{ |
{ |
Line 1223 meta_queue_process (struct work_queue *dummy, void *da
|
Line 1455 meta_queue_process (struct work_queue *dummy, void *da
|
return mq->size ? WQ_REQUEUE : WQ_SUCCESS; |
return mq->size ? WQ_REQUEUE : WQ_SUCCESS; |
} |
} |
|
|
/* Map from rib types to queue type (priority) in meta queue */ | /* |
| * Map from rib types to queue type (priority) in meta queue |
| */ |
static const u_char meta_queue_map[ZEBRA_ROUTE_MAX] = { |
static const u_char meta_queue_map[ZEBRA_ROUTE_MAX] = { |
[ZEBRA_ROUTE_SYSTEM] = 4, |
[ZEBRA_ROUTE_SYSTEM] = 4, |
[ZEBRA_ROUTE_KERNEL] = 0, |
[ZEBRA_ROUTE_KERNEL] = 0, |
Line 1246 static void
|
Line 1480 static void
|
rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) |
rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) |
{ |
{ |
struct rib *rib; |
struct rib *rib; |
char buf[INET6_ADDRSTRLEN]; |
|
|
|
if (IS_ZEBRA_DEBUG_RIB_Q) | RNODE_FOREACH_RIB (rn, rib) |
inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); | |
| |
for (rib = rn->info; rib; rib = rib->next) | |
{ |
{ |
u_char qindex = meta_queue_map[rib->type]; |
u_char qindex = meta_queue_map[rib->type]; |
|
|
/* Invariant: at this point we always have rn->info set. */ |
/* Invariant: at this point we always have rn->info set. */ |
if (CHECK_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED(qindex))) | if (CHECK_FLAG (rib_dest_from_rnode (rn)->flags, |
| RIB_ROUTE_QUEUED (qindex))) |
{ |
{ |
if (IS_ZEBRA_DEBUG_RIB_Q) |
if (IS_ZEBRA_DEBUG_RIB_Q) |
zlog_debug ("%s: %s/%d: rn %p is already queued in sub-queue %u", | rnode_debug (rn, "rn %p is already queued in sub-queue %u", |
__func__, buf, rn->p.prefixlen, rn, qindex); | (void *)rn, qindex); |
continue; |
continue; |
} |
} |
|
|
SET_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED(qindex)); | SET_FLAG (rib_dest_from_rnode (rn)->flags, RIB_ROUTE_QUEUED (qindex)); |
listnode_add (mq->subq[qindex], rn); |
listnode_add (mq->subq[qindex], rn); |
route_lock_node (rn); |
route_lock_node (rn); |
mq->size++; |
mq->size++; |
|
|
if (IS_ZEBRA_DEBUG_RIB_Q) |
if (IS_ZEBRA_DEBUG_RIB_Q) |
zlog_debug ("%s: %s/%d: queued rn %p into sub-queue %u", | rnode_debug (rn, "queued rn %p into sub-queue %u", |
__func__, buf, rn->p.prefixlen, rn, qindex); | (void *)rn, qindex); |
} |
} |
} |
} |
|
|
Line 1279 rib_meta_queue_add (struct meta_queue *mq, struct rout
|
Line 1510 rib_meta_queue_add (struct meta_queue *mq, struct rout
|
static void |
static void |
rib_queue_add (struct zebra_t *zebra, struct route_node *rn) |
rib_queue_add (struct zebra_t *zebra, struct route_node *rn) |
{ |
{ |
char buf[INET_ADDRSTRLEN]; |
|
assert (zebra && rn); |
assert (zebra && rn); |
|
|
if (IS_ZEBRA_DEBUG_RIB_Q) |
|
inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN); |
|
|
|
/* Pointless to queue a route_node with no RIB entries to add or remove */ |
/* Pointless to queue a route_node with no RIB entries to add or remove */ |
if (!rn->info) | if (!rnode_to_ribs (rn)) |
{ |
{ |
zlog_debug ("%s: called for route_node (%p, %d) with no ribs", |
zlog_debug ("%s: called for route_node (%p, %d) with no ribs", |
__func__, rn, rn->lock); | __func__, (void *)rn, rn->lock); |
zlog_backtrace(LOG_DEBUG); |
zlog_backtrace(LOG_DEBUG); |
return; |
return; |
} |
} |
|
|
if (IS_ZEBRA_DEBUG_RIB_Q) |
if (IS_ZEBRA_DEBUG_RIB_Q) |
zlog_info ("%s: %s/%d: work queue added", __func__, buf, rn->p.prefixlen); | rnode_info (rn, "work queue added"); |
|
|
assert (zebra); |
assert (zebra); |
|
|
Line 1319 rib_queue_add (struct zebra_t *zebra, struct route_nod
|
Line 1546 rib_queue_add (struct zebra_t *zebra, struct route_nod
|
rib_meta_queue_add (zebra->mq, rn); |
rib_meta_queue_add (zebra->mq, rn); |
|
|
if (IS_ZEBRA_DEBUG_RIB_Q) |
if (IS_ZEBRA_DEBUG_RIB_Q) |
zlog_debug ("%s: %s/%d: rn %p queued", __func__, buf, rn->p.prefixlen, rn); | rnode_debug (rn, "rn %p queued", (void *)rn); |
|
|
return; |
return; |
} |
} |
Line 1379 rib_queue_init (struct zebra_t *zebra)
|
Line 1606 rib_queue_init (struct zebra_t *zebra)
|
* as a route_node will not be requeued, if already queued. |
* as a route_node will not be requeued, if already queued. |
* |
* |
* RIBs are submitted via rib_addnode or rib_delnode which set minimal |
* RIBs are submitted via rib_addnode or rib_delnode which set minimal |
* state, or static_install_ipv{4,6} (when an existing RIB is updated) | * state, or static_install_route (when an existing RIB is updated) |
* and then submit route_node to queue for best-path selection later. |
* and then submit route_node to queue for best-path selection later. |
* Order of add/delete state changes are preserved for any given RIB. |
* Order of add/delete state changes are preserved for any given RIB. |
* |
* |
Line 1395 rib_queue_init (struct zebra_t *zebra)
|
Line 1622 rib_queue_init (struct zebra_t *zebra)
|
* |-> set RIB_ENTRY_REMOVE | |
* |-> set RIB_ENTRY_REMOVE | |
* rib_delnode (RIB freed) |
* rib_delnode (RIB freed) |
* |
* |
* | * The 'info' pointer of a route_node points to a rib_dest_t |
* Queueing state for a route_node is kept in the head RIB entry, this | * ('dest'). Queueing state for a route_node is kept on the dest. The |
* state must be preserved as and when the head RIB entry of a | * dest is created on-demand by rib_link() and is kept around at least |
* route_node is changed by rib_unlink / rib_link. A small complication, | * as long as there are ribs hanging off it (@see rib_gc_dest()). |
* but saves having to allocate a dedicated object for this. | |
* |
* |
* Refcounting (aka "locking" throughout the GNU Zebra and Quagga code): |
* Refcounting (aka "locking" throughout the GNU Zebra and Quagga code): |
* |
* |
* - route_nodes: refcounted by: |
* - route_nodes: refcounted by: |
* - RIBs attached to route_node: | * - dest attached to route_node: |
* - managed by: rib_link/unlink | * - managed by: rib_link/rib_gc_dest |
* - route_node processing queue |
* - route_node processing queue |
* - managed by: rib_addqueue, rib_process. |
* - managed by: rib_addqueue, rib_process. |
* |
* |
Line 1416 static void
|
Line 1642 static void
|
rib_link (struct route_node *rn, struct rib *rib) |
rib_link (struct route_node *rn, struct rib *rib) |
{ |
{ |
struct rib *head; |
struct rib *head; |
char buf[INET6_ADDRSTRLEN]; | rib_dest_t *dest; |
| |
assert (rib && rn); |
assert (rib && rn); |
|
|
route_lock_node (rn); /* rn route table reference */ |
|
|
|
if (IS_ZEBRA_DEBUG_RIB) |
if (IS_ZEBRA_DEBUG_RIB) |
{ | rnode_debug (rn, "rn %p, rib %p", (void *)rn, (void *)rib); |
inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); | |
zlog_debug ("%s: %s/%d: rn %p, rib %p", __func__, | |
buf, rn->p.prefixlen, rn, rib); | |
} | |
|
|
head = rn->info; | dest = rib_dest_from_rnode (rn); |
if (head) | if (!dest) |
{ |
{ |
if (IS_ZEBRA_DEBUG_RIB) |
if (IS_ZEBRA_DEBUG_RIB) |
zlog_debug ("%s: %s/%d: new head, rn_status copied over", __func__, | rnode_debug (rn, "adding dest to table"); |
buf, rn->p.prefixlen); | |
| dest = XCALLOC (MTYPE_RIB_DEST, sizeof (rib_dest_t)); |
| route_lock_node (rn); /* rn route table reference */ |
| rn->info = dest; |
| dest->rnode = rn; |
| } |
| |
| head = dest->routes; |
| if (head) |
| { |
head->prev = rib; |
head->prev = rib; |
/* Transfer the rn status flags to the new head RIB */ |
|
rib->rn_status = head->rn_status; |
|
} |
} |
rib->next = head; |
rib->next = head; |
rn->info = rib; | dest->routes = rib; |
rib_queue_add (&zebrad, rn); |
rib_queue_add (&zebrad, rn); |
} |
} |
|
|
Line 1453 rib_addnode (struct route_node *rn, struct rib *rib)
|
Line 1680 rib_addnode (struct route_node *rn, struct rib *rib)
|
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
{ |
{ |
if (IS_ZEBRA_DEBUG_RIB) |
if (IS_ZEBRA_DEBUG_RIB) |
{ | rnode_debug (rn, "rn %p, un-removed rib %p", (void *)rn, (void *)rib); |
char buf[INET6_ADDRSTRLEN]; | |
inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); | |
zlog_debug ("%s: %s/%d: rn %p, un-removed rib %p", | |
__func__, buf, rn->p.prefixlen, rn, rib); | |
} | |
UNSET_FLAG (rib->status, RIB_ENTRY_REMOVED); |
UNSET_FLAG (rib->status, RIB_ENTRY_REMOVED); |
return; |
return; |
} |
} |
rib_link (rn, rib); |
rib_link (rn, rib); |
} |
} |
|
|
|
/* |
|
* rib_unlink |
|
* |
|
* Detach a rib structure from a route_node. |
|
* |
|
* Note that a call to rib_unlink() should be followed by a call to |
|
* rib_gc_dest() at some point. This allows a rib_dest_t that is no |
|
* longer required to be deleted. |
|
*/ |
static void |
static void |
rib_unlink (struct route_node *rn, struct rib *rib) |
rib_unlink (struct route_node *rn, struct rib *rib) |
{ |
{ |
struct nexthop *nexthop, *next; | rib_dest_t *dest; |
char buf[INET6_ADDRSTRLEN]; | |
|
|
assert (rn && rib); |
assert (rn && rib); |
|
|
if (IS_ZEBRA_DEBUG_RIB) |
if (IS_ZEBRA_DEBUG_RIB) |
{ | rnode_debug (rn, "rn %p, rib %p", (void *)rn, (void *)rib); |
inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); | |
zlog_debug ("%s: %s/%d: rn %p, rib %p", | |
__func__, buf, rn->p.prefixlen, rn, rib); | |
} | |
|
|
|
dest = rib_dest_from_rnode (rn); |
|
|
if (rib->next) |
if (rib->next) |
rib->next->prev = rib->prev; |
rib->next->prev = rib->prev; |
|
|
Line 1487 rib_unlink (struct route_node *rn, struct rib *rib)
|
Line 1716 rib_unlink (struct route_node *rn, struct rib *rib)
|
rib->prev->next = rib->next; |
rib->prev->next = rib->next; |
else |
else |
{ |
{ |
rn->info = rib->next; | dest->routes = rib->next; |
| |
if (rn->info) | |
{ | |
if (IS_ZEBRA_DEBUG_RIB) | |
zlog_debug ("%s: %s/%d: rn %p, rib %p, new head copy", | |
__func__, buf, rn->p.prefixlen, rn, rib); | |
rib->next->rn_status = rib->rn_status; | |
} | |
} |
} |
|
|
/* free RIB and nexthops */ |
/* free RIB and nexthops */ |
for (nexthop = rib->nexthop; nexthop; nexthop = next) | nexthops_free(rib->nexthop); |
{ | |
next = nexthop->next; | |
nexthop_free (nexthop); | |
} | |
XFREE (MTYPE_RIB, rib); |
XFREE (MTYPE_RIB, rib); |
|
|
route_unlock_node (rn); /* rn route table reference */ |
|
} |
} |
|
|
static void |
static void |
rib_delnode (struct route_node *rn, struct rib *rib) |
rib_delnode (struct route_node *rn, struct rib *rib) |
{ |
{ |
if (IS_ZEBRA_DEBUG_RIB) |
if (IS_ZEBRA_DEBUG_RIB) |
{ | rnode_debug (rn, "rn %p, rib %p, removing", (void *)rn, (void *)rib); |
char buf[INET6_ADDRSTRLEN]; | |
inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); | |
zlog_debug ("%s: %s/%d: rn %p, rib %p, removing", __func__, | |
buf, rn->p.prefixlen, rn, rib); | |
} | |
SET_FLAG (rib->status, RIB_ENTRY_REMOVED); |
SET_FLAG (rib->status, RIB_ENTRY_REMOVED); |
rib_queue_add (&zebrad, rn); |
rib_queue_add (&zebrad, rn); |
} |
} |
Line 1526 rib_delnode (struct route_node *rn, struct rib *rib)
|
Line 1737 rib_delnode (struct route_node *rn, struct rib *rib)
|
int |
int |
rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, |
rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, |
struct in_addr *gate, struct in_addr *src, |
struct in_addr *gate, struct in_addr *src, |
unsigned int ifindex, u_int32_t vrf_id, | ifindex_t ifindex, vrf_id_t vrf_id, int table_id, |
u_int32_t metric, u_char distance, safi_t safi) | u_int32_t metric, u_int32_t mtu, u_char distance, safi_t safi) |
{ |
{ |
struct rib *rib; |
struct rib *rib; |
struct rib *same = NULL; |
struct rib *same = NULL; |
Line 1536 rib_add_ipv4 (int type, int flags, struct prefix_ipv4
|
Line 1747 rib_add_ipv4 (int type, int flags, struct prefix_ipv4
|
struct nexthop *nexthop; |
struct nexthop *nexthop; |
|
|
/* Lookup table. */ |
/* Lookup table. */ |
table = vrf_table (AFI_IP, safi, 0); | table = zebra_vrf_table (AFI_IP, safi, vrf_id); |
if (! table) |
if (! table) |
return 0; |
return 0; |
|
|
Line 1546 rib_add_ipv4 (int type, int flags, struct prefix_ipv4
|
Line 1757 rib_add_ipv4 (int type, int flags, struct prefix_ipv4
|
/* Set default distance by route type. */ |
/* Set default distance by route type. */ |
if (distance == 0) |
if (distance == 0) |
{ |
{ |
if ((unsigned)type >= sizeof(route_info) / sizeof(route_info[0])) | if ((unsigned)type >= array_size(route_info)) |
distance = 150; |
distance = 150; |
else |
else |
distance = route_info[type].distance; |
distance = route_info[type].distance; |
Line 1561 rib_add_ipv4 (int type, int flags, struct prefix_ipv4
|
Line 1772 rib_add_ipv4 (int type, int flags, struct prefix_ipv4
|
|
|
/* If same type of route are installed, treat it as a implicit |
/* If same type of route are installed, treat it as a implicit |
withdraw. */ |
withdraw. */ |
for (rib = rn->info; rib; rib = rib->next) | RNODE_FOREACH_RIB (rn, rib) |
{ |
{ |
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
continue; |
continue; |
Line 1590 rib_add_ipv4 (int type, int flags, struct prefix_ipv4
|
Line 1801 rib_add_ipv4 (int type, int flags, struct prefix_ipv4
|
rib->distance = distance; |
rib->distance = distance; |
rib->flags = flags; |
rib->flags = flags; |
rib->metric = metric; |
rib->metric = metric; |
rib->table = vrf_id; | rib->mtu = mtu; |
| rib->vrf_id = vrf_id; |
| rib->table = table_id; |
rib->nexthop_num = 0; |
rib->nexthop_num = 0; |
rib->uptime = time (NULL); |
rib->uptime = time (NULL); |
|
|
Line 1612 rib_add_ipv4 (int type, int flags, struct prefix_ipv4
|
Line 1825 rib_add_ipv4 (int type, int flags, struct prefix_ipv4
|
|
|
/* Link new rib to node.*/ |
/* Link new rib to node.*/ |
if (IS_ZEBRA_DEBUG_RIB) |
if (IS_ZEBRA_DEBUG_RIB) |
zlog_debug ("%s: calling rib_addnode (%p, %p)", __func__, rn, rib); | zlog_debug ("%s: calling rib_addnode (%p, %p)", |
| __func__, (void *)rn, (void *)rib); |
rib_addnode (rn, rib); |
rib_addnode (rn, rib); |
|
|
/* Free implicit route.*/ |
/* Free implicit route.*/ |
if (same) |
if (same) |
{ |
{ |
if (IS_ZEBRA_DEBUG_RIB) |
if (IS_ZEBRA_DEBUG_RIB) |
zlog_debug ("%s: calling rib_delnode (%p, %p)", __func__, rn, rib); | zlog_debug ("%s: calling rib_delnode (%p, %p)", |
| __func__, (void *)rn, (void *)rib); |
rib_delnode (rn, same); |
rib_delnode (rn, same); |
} |
} |
|
|
Line 1632 rib_add_ipv4 (int type, int flags, struct prefix_ipv4
|
Line 1847 rib_add_ipv4 (int type, int flags, struct prefix_ipv4
|
* question are passed as 1st and 2nd arguments. |
* question are passed as 1st and 2nd arguments. |
*/ |
*/ |
|
|
void rib_dump (const char * func, const struct prefix_ipv4 * p, const struct rib * rib) | void _rib_dump (const char * func, |
| union prefix46constptr pp, const struct rib * rib) |
{ |
{ |
char straddr1[INET_ADDRSTRLEN], straddr2[INET_ADDRSTRLEN]; | const struct prefix *p = pp.p; |
struct nexthop *nexthop; | char straddr[PREFIX_STRLEN]; |
| struct nexthop *nexthop, *tnexthop; |
| int recursing; |
|
|
inet_ntop (AF_INET, &p->prefix, straddr1, INET_ADDRSTRLEN); | zlog_debug ("%s: dumping RIB entry %p for %s vrf %u", func, (void *)rib, |
zlog_debug ("%s: dumping RIB entry %p for %s/%d", func, rib, straddr1, p->prefixlen); | prefix2str(p, straddr, sizeof(straddr)), rib->vrf_id); |
zlog_debug |
zlog_debug |
( |
( |
"%s: refcnt == %lu, uptime == %lu, type == %u, table == %d", |
"%s: refcnt == %lu, uptime == %lu, type == %u, table == %d", |
Line 1665 void rib_dump (const char * func, const struct prefix_
|
Line 1883 void rib_dump (const char * func, const struct prefix_
|
rib->nexthop_active_num, |
rib->nexthop_active_num, |
rib->nexthop_fib_num |
rib->nexthop_fib_num |
); |
); |
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) | |
{ | for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) |
inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, straddr1, INET_ADDRSTRLEN); | { |
inet_ntop (AF_INET, &nexthop->rgate.ipv4.s_addr, straddr2, INET_ADDRSTRLEN); | inet_ntop (p->family, &nexthop->gate, straddr, INET6_ADDRSTRLEN); |
zlog_debug | zlog_debug |
( | ( |
"%s: NH %s (%s) with flags %s%s%s", | "%s: %s %s with flags %s%s%s", |
func, | func, |
straddr1, | (recursing ? " NH" : "NH"), |
straddr2, | straddr, |
(CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE " : ""), | (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE " : ""), |
(CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? "FIB " : ""), | (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? "FIB " : ""), |
(CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) ? "RECURSIVE" : "") | (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) ? "RECURSIVE" : "") |
); | ); |
} | } |
zlog_debug ("%s: dump complete", func); |
zlog_debug ("%s: dump complete", func); |
} |
} |
|
|
Line 1695 void rib_lookup_and_dump (struct prefix_ipv4 * p)
|
Line 1913 void rib_lookup_and_dump (struct prefix_ipv4 * p)
|
char prefix_buf[INET_ADDRSTRLEN]; |
char prefix_buf[INET_ADDRSTRLEN]; |
|
|
/* Lookup table. */ |
/* Lookup table. */ |
table = vrf_table (AFI_IP, SAFI_UNICAST, 0); | table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); |
if (! table) |
if (! table) |
{ |
{ |
zlog_err ("%s: vrf_table() returned NULL", __func__); | zlog_err ("%s: zebra_vrf_table() returned NULL", __func__); |
return; |
return; |
} |
} |
|
|
inet_ntop (AF_INET, &p->prefix.s_addr, prefix_buf, INET_ADDRSTRLEN); |
|
/* Scan the RIB table for exactly matching RIB entry. */ |
/* Scan the RIB table for exactly matching RIB entry. */ |
rn = route_node_lookup (table, (struct prefix *) p); |
rn = route_node_lookup (table, (struct prefix *) p); |
|
|
/* No route for this prefix. */ |
/* No route for this prefix. */ |
if (! rn) |
if (! rn) |
{ |
{ |
zlog_debug ("%s: lookup failed for %s/%d", __func__, prefix_buf, p->prefixlen); | zlog_debug ("%s: lookup failed for %s", __func__, |
| prefix2str((struct prefix*) p, prefix_buf, sizeof(prefix_buf))); |
return; |
return; |
} |
} |
|
|
Line 1717 void rib_lookup_and_dump (struct prefix_ipv4 * p)
|
Line 1935 void rib_lookup_and_dump (struct prefix_ipv4 * p)
|
route_unlock_node (rn); |
route_unlock_node (rn); |
|
|
/* let's go */ |
/* let's go */ |
for (rib = rn->info; rib; rib = rib->next) | RNODE_FOREACH_RIB (rn, rib) |
{ |
{ |
zlog_debug |
zlog_debug |
( |
( |
"%s: rn %p, rib %p: %s, %s", |
"%s: rn %p, rib %p: %s, %s", |
__func__, |
__func__, |
rn, | (void *)rn, |
rib, | (void *)rib, |
(CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED) ? "removed" : "NOT removed"), |
(CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED) ? "removed" : "NOT removed"), |
(CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) ? "selected" : "NOT selected") |
(CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) ? "selected" : "NOT selected") |
); |
); |
rib_dump (__func__, p, rib); | rib_dump (p, rib); |
} |
} |
} |
} |
|
|
Line 1744 void rib_lookup_and_pushup (struct prefix_ipv4 * p)
|
Line 1962 void rib_lookup_and_pushup (struct prefix_ipv4 * p)
|
struct rib *rib; |
struct rib *rib; |
unsigned changed = 0; |
unsigned changed = 0; |
|
|
if (NULL == (table = vrf_table (AFI_IP, SAFI_UNICAST, 0))) | if (NULL == (table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT))) |
{ |
{ |
zlog_err ("%s: vrf_table() returned NULL", __func__); | zlog_err ("%s: zebra_vrf_table() returned NULL", __func__); |
return; |
return; |
} |
} |
|
|
Line 1764 void rib_lookup_and_pushup (struct prefix_ipv4 * p)
|
Line 1982 void rib_lookup_and_pushup (struct prefix_ipv4 * p)
|
* RIBQ record already on head. This is necessary for proper revalidation |
* RIBQ record already on head. This is necessary for proper revalidation |
* of the rest of the RIB. |
* of the rest of the RIB. |
*/ |
*/ |
for (rib = rn->info; rib; rib = rib->next) | RNODE_FOREACH_RIB (rn, rib) |
{ |
{ |
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) && | if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB) && |
! RIB_SYSTEM_ROUTE (rib)) |
! RIB_SYSTEM_ROUTE (rib)) |
{ |
{ |
changed = 1; |
changed = 1; |
if (IS_ZEBRA_DEBUG_RIB) |
if (IS_ZEBRA_DEBUG_RIB) |
{ |
{ |
char buf[INET_ADDRSTRLEN]; | char buf[PREFIX_STRLEN]; |
inet_ntop (rn->p.family, &p->prefix, buf, INET_ADDRSTRLEN); | zlog_debug ("%s: freeing way for connected prefix %s", __func__, |
zlog_debug ("%s: freeing way for connected prefix %s/%d", __func__, buf, p->prefixlen); | prefix2str(&rn->p, buf, sizeof(buf))); |
rib_dump (__func__, (struct prefix_ipv4 *)&rn->p, rib); | rib_dump (&rn->p, rib); |
} |
} |
rib_uninstall (rn, rib); |
rib_uninstall (rn, rib); |
} |
} |
Line 1793 rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct
|
Line 2011 rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct
|
struct nexthop *nexthop; |
struct nexthop *nexthop; |
|
|
/* Lookup table. */ |
/* Lookup table. */ |
table = vrf_table (AFI_IP, safi, 0); | table = zebra_vrf_table (AFI_IP, safi, rib->vrf_id); |
if (! table) |
if (! table) |
return 0; |
return 0; |
|
|
Line 1816 rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct
|
Line 2034 rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct
|
|
|
/* If same type of route are installed, treat it as a implicit |
/* If same type of route are installed, treat it as a implicit |
withdraw. */ |
withdraw. */ |
for (same = rn->info; same; same = same->next) | RNODE_FOREACH_RIB (rn, same) |
{ |
{ |
if (CHECK_FLAG (same->status, RIB_ENTRY_REMOVED)) |
if (CHECK_FLAG (same->status, RIB_ENTRY_REMOVED)) |
continue; |
continue; |
Line 1836 rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct
|
Line 2054 rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct
|
if (IS_ZEBRA_DEBUG_RIB) |
if (IS_ZEBRA_DEBUG_RIB) |
{ |
{ |
zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry", |
zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry", |
__func__, rn, rib); | __func__, (void *)rn, (void *)rib); |
rib_dump (__func__, p, rib); | rib_dump (p, rib); |
} |
} |
|
|
/* Free implicit route.*/ |
/* Free implicit route.*/ |
Line 1846 rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct
|
Line 2064 rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct
|
if (IS_ZEBRA_DEBUG_RIB) |
if (IS_ZEBRA_DEBUG_RIB) |
{ |
{ |
zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry", |
zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry", |
__func__, rn, same); | __func__, (void *)rn, (void *)same); |
rib_dump (__func__, p, same); | rib_dump (p, same); |
} |
} |
rib_delnode (rn, same); |
rib_delnode (rn, same); |
} |
} |
Line 1859 rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct
|
Line 2077 rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct
|
/* XXX factor with rib_delete_ipv6 */ |
/* XXX factor with rib_delete_ipv6 */ |
int |
int |
rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, |
rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, |
struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id, safi_t safi) | struct in_addr *gate, ifindex_t ifindex, |
| vrf_id_t vrf_id, safi_t safi) |
{ |
{ |
struct route_table *table; |
struct route_table *table; |
struct route_node *rn; |
struct route_node *rn; |
struct rib *rib; |
struct rib *rib; |
struct rib *fib = NULL; |
struct rib *fib = NULL; |
struct rib *same = NULL; |
struct rib *same = NULL; |
struct nexthop *nexthop; | struct nexthop *nexthop, *tnexthop; |
char buf1[INET_ADDRSTRLEN]; | int recursing; |
| char buf1[PREFIX_STRLEN]; |
char buf2[INET_ADDRSTRLEN]; |
char buf2[INET_ADDRSTRLEN]; |
|
|
/* Lookup table. */ |
/* Lookup table. */ |
table = vrf_table (AFI_IP, safi, 0); | table = zebra_vrf_table (AFI_IP, safi, vrf_id); |
if (! table) |
if (! table) |
return 0; |
return 0; |
|
|
/* Apply mask. */ |
/* Apply mask. */ |
apply_mask_ipv4 (p); |
apply_mask_ipv4 (p); |
|
|
if (IS_ZEBRA_DEBUG_KERNEL && gate) | if (IS_ZEBRA_DEBUG_KERNEL) |
zlog_debug ("rib_delete_ipv4(): route delete %s/%d via %s ifindex %d", | { |
inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), | if (gate) |
p->prefixlen, | zlog_debug ("rib_delete_ipv4(): route delete %s vrf %u via %s ifindex %d", |
inet_ntoa (*gate), | prefix2str (p, buf1, sizeof(buf1)), vrf_id, |
ifindex); | inet_ntoa (*gate), |
| ifindex); |
| else |
| zlog_debug ("rib_delete_ipv4(): route delete %s vrf %u ifindex %d", |
| prefix2str (p, buf1, sizeof(buf1)), vrf_id, |
| ifindex); |
| } |
|
|
/* Lookup route node. */ |
/* Lookup route node. */ |
rn = route_node_lookup (table, (struct prefix *) p); |
rn = route_node_lookup (table, (struct prefix *) p); |
Line 1892 rib_delete_ipv4 (int type, int flags, struct prefix_ip
|
Line 2118 rib_delete_ipv4 (int type, int flags, struct prefix_ip
|
if (IS_ZEBRA_DEBUG_KERNEL) |
if (IS_ZEBRA_DEBUG_KERNEL) |
{ |
{ |
if (gate) |
if (gate) |
zlog_debug ("route %s/%d via %s ifindex %d doesn't exist in rib", | zlog_debug ("route %s vrf %u via %s ifindex %d doesn't exist in rib", |
inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), | prefix2str (p, buf1, sizeof(buf1)), vrf_id, |
p->prefixlen, | |
inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN), |
inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN), |
ifindex); |
ifindex); |
else |
else |
zlog_debug ("route %s/%d ifindex %d doesn't exist in rib", | zlog_debug ("route %s vrf %u ifindex %d doesn't exist in rib", |
inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), | prefix2str (p, buf1, sizeof(buf1)), vrf_id, |
p->prefixlen, | |
ifindex); |
ifindex); |
} |
} |
return ZEBRA_ERR_RTNOEXIST; |
return ZEBRA_ERR_RTNOEXIST; |
} |
} |
|
|
/* Lookup same type route. */ |
/* Lookup same type route. */ |
for (rib = rn->info; rib; rib = rib->next) | RNODE_FOREACH_RIB (rn, rib) |
{ |
{ |
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
continue; |
continue; |
|
|
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) | if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) |
fib = rib; |
fib = rib; |
|
|
if (rib->type != type) |
if (rib->type != type) |
Line 1933 rib_delete_ipv4 (int type, int flags, struct prefix_ip
|
Line 2157 rib_delete_ipv4 (int type, int flags, struct prefix_ip
|
break; |
break; |
} |
} |
/* Make sure that the route found has the same gateway. */ |
/* Make sure that the route found has the same gateway. */ |
else if (gate == NULL || | else |
((nexthop = rib->nexthop) && | |
(IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate) || | |
IPV4_ADDR_SAME (&nexthop->rgate.ipv4, gate)))) | |
{ |
{ |
same = rib; | if (gate == NULL) |
break; | { |
} | same = rib; |
| break; |
| } |
| for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) |
| if (IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate)) |
| { |
| same = rib; |
| break; |
| } |
| if (same) |
| break; |
| } |
} |
} |
|
|
/* If same type of route can't be found and this message is from |
/* If same type of route can't be found and this message is from |
kernel. */ |
kernel. */ |
if (! same) |
if (! same) |
Line 1953 rib_delete_ipv4 (int type, int flags, struct prefix_ip
|
Line 2184 rib_delete_ipv4 (int type, int flags, struct prefix_ip
|
for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) |
for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) |
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); |
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); |
|
|
UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); | UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB); |
} |
} |
else |
else |
{ |
{ |
if (IS_ZEBRA_DEBUG_KERNEL) |
if (IS_ZEBRA_DEBUG_KERNEL) |
{ |
{ |
if (gate) |
if (gate) |
zlog_debug ("route %s/%d via %s ifindex %d type %d doesn't exist in rib", | zlog_debug ("route %s vrf %u via %s ifindex %d type %d " |
inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), | "doesn't exist in rib", |
p->prefixlen, | prefix2str (p, buf1, sizeof(buf1)), vrf_id, |
inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN), |
inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN), |
ifindex, |
ifindex, |
type); |
type); |
else |
else |
zlog_debug ("route %s/%d ifindex %d type %d doesn't exist in rib", | zlog_debug ("route %s vrf %u ifindex %d type %d doesn't exist in rib", |
inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), | prefix2str (p, buf1, sizeof(buf1)), vrf_id, |
p->prefixlen, | |
ifindex, |
ifindex, |
type); |
type); |
} |
} |
Line 1984 rib_delete_ipv4 (int type, int flags, struct prefix_ip
|
Line 2214 rib_delete_ipv4 (int type, int flags, struct prefix_ip
|
route_unlock_node (rn); |
route_unlock_node (rn); |
return 0; |
return 0; |
} |
} |
| |
/* Install static route into rib. */ |
/* Install static route into rib. */ |
static void |
static void |
static_install_ipv4 (struct prefix *p, struct static_ipv4 *si) | static_install_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si) |
{ |
{ |
struct rib *rib; |
struct rib *rib; |
struct route_node *rn; |
struct route_node *rn; |
struct route_table *table; |
struct route_table *table; |
|
|
/* Lookup table. */ |
/* Lookup table. */ |
table = vrf_table (AFI_IP, SAFI_UNICAST, 0); | table = zebra_vrf_table (afi, safi, si->vrf_id); |
if (! table) |
if (! table) |
return; |
return; |
|
|
/* Lookup existing route */ |
/* Lookup existing route */ |
rn = route_node_get (table, p); |
rn = route_node_get (table, p); |
for (rib = rn->info; rib; rib = rib->next) | RNODE_FOREACH_RIB (rn, rib) |
{ |
{ |
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
continue; |
continue; |
Line 2016 static_install_ipv4 (struct prefix *p, struct static_i
|
Line 2246 static_install_ipv4 (struct prefix *p, struct static_i
|
route_unlock_node (rn); |
route_unlock_node (rn); |
switch (si->type) |
switch (si->type) |
{ |
{ |
case STATIC_IPV4_GATEWAY: | case STATIC_IPV4_GATEWAY: |
nexthop_ipv4_add (rib, &si->gate.ipv4, NULL); | nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); |
break; | break; |
case STATIC_IPV4_IFNAME: | case STATIC_IPV4_IFNAME: |
nexthop_ifname_add (rib, si->gate.ifname); | nexthop_ifname_add (rib, si->ifname); |
break; | break; |
case STATIC_IPV4_BLACKHOLE: | case STATIC_IPV4_BLACKHOLE: |
nexthop_blackhole_add (rib); | nexthop_blackhole_add (rib); |
break; | break; |
| case STATIC_IPV6_GATEWAY: |
| nexthop_ipv6_add (rib, &si->addr.ipv6); |
| break; |
| case STATIC_IPV6_IFNAME: |
| nexthop_ifname_add (rib, si->ifname); |
| break; |
| case STATIC_IPV6_GATEWAY_IFNAME: |
| nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname); |
| break; |
} |
} |
rib_queue_add (&zebrad, rn); |
rib_queue_add (&zebrad, rn); |
} |
} |
Line 2036 static_install_ipv4 (struct prefix *p, struct static_i
|
Line 2275 static_install_ipv4 (struct prefix *p, struct static_i
|
rib->type = ZEBRA_ROUTE_STATIC; |
rib->type = ZEBRA_ROUTE_STATIC; |
rib->distance = si->distance; |
rib->distance = si->distance; |
rib->metric = 0; |
rib->metric = 0; |
|
rib->vrf_id = si->vrf_id; |
|
rib->table = zebrad.rtm_table_default; |
rib->nexthop_num = 0; |
rib->nexthop_num = 0; |
|
|
switch (si->type) |
switch (si->type) |
{ |
{ |
case STATIC_IPV4_GATEWAY: | case STATIC_IPV4_GATEWAY: |
nexthop_ipv4_add (rib, &si->gate.ipv4, NULL); | nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); |
break; | break; |
case STATIC_IPV4_IFNAME: | case STATIC_IPV4_IFNAME: |
nexthop_ifname_add (rib, si->gate.ifname); | nexthop_ifname_add (rib, si->ifname); |
break; | break; |
case STATIC_IPV4_BLACKHOLE: | case STATIC_IPV4_BLACKHOLE: |
nexthop_blackhole_add (rib); | nexthop_blackhole_add (rib); |
break; | break; |
| case STATIC_IPV6_GATEWAY: |
| nexthop_ipv6_add (rib, &si->addr.ipv6); |
| break; |
| case STATIC_IPV6_IFNAME: |
| nexthop_ifname_add (rib, si->ifname); |
| break; |
| case STATIC_IPV6_GATEWAY_IFNAME: |
| nexthop_ipv6_ifname_add (rib, &si->addr.ipv6, si->ifname); |
| break; |
} |
} |
|
|
/* Save the flags of this static routes (reject, blackhole) */ |
/* Save the flags of this static routes (reject, blackhole) */ |
Line 2060 static_install_ipv4 (struct prefix *p, struct static_i
|
Line 2310 static_install_ipv4 (struct prefix *p, struct static_i
|
} |
} |
|
|
static int |
static int |
static_ipv4_nexthop_same (struct nexthop *nexthop, struct static_ipv4 *si) | static_nexthop_same (struct nexthop *nexthop, struct static_route *si) |
{ |
{ |
if (nexthop->type == NEXTHOP_TYPE_IPV4 |
if (nexthop->type == NEXTHOP_TYPE_IPV4 |
&& si->type == STATIC_IPV4_GATEWAY |
&& si->type == STATIC_IPV4_GATEWAY |
&& IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->gate.ipv4)) | && IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->addr.ipv4)) |
return 1; |
return 1; |
if (nexthop->type == NEXTHOP_TYPE_IFNAME |
if (nexthop->type == NEXTHOP_TYPE_IFNAME |
&& si->type == STATIC_IPV4_IFNAME |
&& si->type == STATIC_IPV4_IFNAME |
&& strcmp (nexthop->ifname, si->gate.ifname) == 0) | && strcmp (nexthop->ifname, si->ifname) == 0) |
return 1; |
return 1; |
if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE |
if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE |
&& si->type == STATIC_IPV4_BLACKHOLE) |
&& si->type == STATIC_IPV4_BLACKHOLE) |
return 1; |
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_IFNAME |
|
&& si->type == STATIC_IPV6_IFNAME |
|
&& strcmp (nexthop->ifname, si->ifname) == 0) |
|
return 1; |
|
if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME |
|
&& si->type == STATIC_IPV6_GATEWAY_IFNAME |
|
&& IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6) |
|
&& strcmp (nexthop->ifname, si->ifname) == 0) |
|
return 1; |
return 0; |
return 0; |
} |
} |
|
|
/* Uninstall static route from RIB. */ |
/* Uninstall static route from RIB. */ |
static void |
static void |
static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si) | static_uninstall_route (afi_t afi, safi_t safi, struct prefix *p, struct static_route *si) |
{ |
{ |
struct route_node *rn; |
struct route_node *rn; |
struct rib *rib; |
struct rib *rib; |
Line 2086 static_uninstall_ipv4 (struct prefix *p, struct static
|
Line 2349 static_uninstall_ipv4 (struct prefix *p, struct static
|
struct route_table *table; |
struct route_table *table; |
|
|
/* Lookup table. */ |
/* Lookup table. */ |
table = vrf_table (AFI_IP, SAFI_UNICAST, 0); | table = zebra_vrf_table (afi, safi, si->vrf_id); |
if (! table) |
if (! table) |
return; |
return; |
|
|
Line 2095 static_uninstall_ipv4 (struct prefix *p, struct static
|
Line 2358 static_uninstall_ipv4 (struct prefix *p, struct static
|
if (! rn) |
if (! rn) |
return; |
return; |
|
|
for (rib = rn->info; rib; rib = rib->next) | RNODE_FOREACH_RIB (rn, rib) |
{ |
{ |
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
continue; |
continue; |
Line 2112 static_uninstall_ipv4 (struct prefix *p, struct static
|
Line 2375 static_uninstall_ipv4 (struct prefix *p, struct static
|
|
|
/* Lookup nexthop. */ |
/* Lookup nexthop. */ |
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) |
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) |
if (static_ipv4_nexthop_same (nexthop, si)) | if (static_nexthop_same (nexthop, si)) |
break; |
break; |
|
|
/* Can't find nexthop. */ |
/* Can't find nexthop. */ |
Line 2137 static_uninstall_ipv4 (struct prefix *p, struct static
|
Line 2400 static_uninstall_ipv4 (struct prefix *p, struct static
|
route_unlock_node (rn); |
route_unlock_node (rn); |
} |
} |
|
|
/* Add static route into static route configuration. */ |
|
int |
int |
static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, | static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, |
u_char flags, u_char distance, u_int32_t vrf_id) | const char *ifname, u_char flags, u_char distance, |
| vrf_id_t vrf_id) |
{ |
{ |
u_char type = 0; |
u_char type = 0; |
struct route_node *rn; |
struct route_node *rn; |
struct static_ipv4 *si; | struct static_route *si; |
struct static_ipv4 *pp; | struct static_route *pp; |
struct static_ipv4 *cp; | struct static_route *cp; |
struct static_ipv4 *update = NULL; | struct static_route *update = NULL; |
struct route_table *stable; | struct zebra_vrf *zvrf = vrf_info_get (vrf_id); |
| struct route_table *stable = zvrf->stable[AFI_IP][safi]; |
|
|
/* Lookup table. */ |
|
stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id); |
|
if (! stable) |
if (! stable) |
return -1; |
return -1; |
|
|
Line 2170 static_add_ipv4 (struct prefix *p, struct in_addr *gat
|
Line 2432 static_add_ipv4 (struct prefix *p, struct in_addr *gat
|
for (si = rn->info; si; si = si->next) |
for (si = rn->info; si; si = si->next) |
{ |
{ |
if (type == si->type |
if (type == si->type |
&& (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4)) | && (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4)) |
&& (! ifname || strcmp (ifname, si->gate.ifname) == 0)) | && (! ifname || strcmp (ifname, si->ifname) == 0)) |
{ |
{ |
if (distance == si->distance) |
if (distance == si->distance) |
{ |
{ |
Line 2185 static_add_ipv4 (struct prefix *p, struct in_addr *gat
|
Line 2447 static_add_ipv4 (struct prefix *p, struct in_addr *gat
|
|
|
/* Distance changed. */ |
/* Distance changed. */ |
if (update) |
if (update) |
static_delete_ipv4 (p, gate, ifname, update->distance, vrf_id); | static_delete_ipv4_safi (safi, p, gate, ifname, update->distance, vrf_id); |
|
|
/* Make new static route structure. */ |
/* Make new static route structure. */ |
si = XCALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4)); | si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route)); |
|
|
si->type = type; |
si->type = type; |
si->distance = distance; |
si->distance = distance; |
si->flags = flags; |
si->flags = flags; |
|
si->vrf_id = vrf_id; |
|
|
if (gate) |
if (gate) |
si->gate.ipv4 = *gate; | si->addr.ipv4 = *gate; |
if (ifname) |
if (ifname) |
si->gate.ifname = XSTRDUP (0, ifname); | si->ifname = XSTRDUP (0, ifname); |
|
|
/* Add new static route information to the tree with sort by |
/* Add new static route information to the tree with sort by |
distance value and gateway address. */ |
distance value and gateway address. */ |
Line 2209 static_add_ipv4 (struct prefix *p, struct in_addr *gat
|
Line 2472 static_add_ipv4 (struct prefix *p, struct in_addr *gat
|
continue; |
continue; |
if (si->type == STATIC_IPV4_GATEWAY && cp->type == STATIC_IPV4_GATEWAY) |
if (si->type == STATIC_IPV4_GATEWAY && cp->type == STATIC_IPV4_GATEWAY) |
{ |
{ |
if (ntohl (si->gate.ipv4.s_addr) < ntohl (cp->gate.ipv4.s_addr)) | if (ntohl (si->addr.ipv4.s_addr) < ntohl (cp->addr.ipv4.s_addr)) |
break; |
break; |
if (ntohl (si->gate.ipv4.s_addr) > ntohl (cp->gate.ipv4.s_addr)) | if (ntohl (si->addr.ipv4.s_addr) > ntohl (cp->addr.ipv4.s_addr)) |
continue; |
continue; |
} |
} |
} |
} |
Line 2227 static_add_ipv4 (struct prefix *p, struct in_addr *gat
|
Line 2490 static_add_ipv4 (struct prefix *p, struct in_addr *gat
|
si->next = cp; |
si->next = cp; |
|
|
/* Install into rib. */ |
/* Install into rib. */ |
static_install_ipv4 (p, si); | static_install_route (AFI_IP, safi, p, si); |
|
|
return 1; |
return 1; |
} |
} |
|
|
/* Delete static route from static route configuration. */ |
|
int |
int |
static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, | static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, |
u_char distance, u_int32_t vrf_id) | const char *ifname, u_char distance, vrf_id_t vrf_id) |
{ |
{ |
u_char type = 0; |
u_char type = 0; |
struct route_node *rn; |
struct route_node *rn; |
struct static_ipv4 *si; | struct static_route *si; |
struct route_table *stable; |
struct route_table *stable; |
|
|
/* Lookup table. */ |
/* Lookup table. */ |
stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id); | stable = zebra_vrf_static_table (AFI_IP, safi, vrf_id); |
if (! stable) |
if (! stable) |
return -1; |
return -1; |
|
|
Line 2263 static_delete_ipv4 (struct prefix *p, struct in_addr *
|
Line 2525 static_delete_ipv4 (struct prefix *p, struct in_addr *
|
/* Find same static route is the tree */ |
/* Find same static route is the tree */ |
for (si = rn->info; si; si = si->next) |
for (si = rn->info; si; si = si->next) |
if (type == si->type |
if (type == si->type |
&& (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4)) | && (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4)) |
&& (! ifname || strcmp (ifname, si->gate.ifname) == 0)) | && (! ifname || strcmp (ifname, si->ifname) == 0)) |
break; |
break; |
|
|
/* Can't find static route. */ |
/* Can't find static route. */ |
Line 2275 static_delete_ipv4 (struct prefix *p, struct in_addr *
|
Line 2537 static_delete_ipv4 (struct prefix *p, struct in_addr *
|
} |
} |
|
|
/* Install into rib. */ |
/* Install into rib. */ |
static_uninstall_ipv4 (p, si); | static_uninstall_route (AFI_IP, safi, p, si); |
|
|
/* Unlink static route from linked list. */ |
/* Unlink static route from linked list. */ |
if (si->prev) |
if (si->prev) |
Line 2288 static_delete_ipv4 (struct prefix *p, struct in_addr *
|
Line 2550 static_delete_ipv4 (struct prefix *p, struct in_addr *
|
|
|
/* Free static route configuration. */ |
/* Free static route configuration. */ |
if (ifname) |
if (ifname) |
XFREE (0, si->gate.ifname); | XFREE (0, si->ifname); |
XFREE (MTYPE_STATIC_IPV4, si); | XFREE (MTYPE_STATIC_ROUTE, si); |
|
|
route_unlock_node (rn); |
route_unlock_node (rn); |
|
|
return 1; |
return 1; |
} |
} |
|
|
|
|
#ifdef HAVE_IPV6 |
|
static int |
|
rib_bogus_ipv6 (int type, struct prefix_ipv6 *p, |
|
struct in6_addr *gate, unsigned int ifindex, int table) |
|
{ |
|
if (type == ZEBRA_ROUTE_CONNECT && IN6_IS_ADDR_UNSPECIFIED (&p->prefix)) { |
|
#if defined (MUSICA) || defined (LINUX) |
|
/* IN6_IS_ADDR_V4COMPAT(&p->prefix) */ |
|
if (p->prefixlen == 96) |
|
return 0; |
|
#endif /* MUSICA */ |
|
return 1; |
|
} |
|
if (type == ZEBRA_ROUTE_KERNEL && IN6_IS_ADDR_UNSPECIFIED (&p->prefix) |
|
&& p->prefixlen == 96 && gate && IN6_IS_ADDR_UNSPECIFIED (gate)) |
|
{ |
|
kernel_delete_ipv6_old (p, gate, ifindex, 0, table); |
|
return 1; |
|
} |
|
return 0; |
|
} |
|
|
|
int |
int |
rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, |
rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, |
struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id, | struct in6_addr *gate, ifindex_t ifindex, |
u_int32_t metric, u_char distance, safi_t safi) | vrf_id_t vrf_id, int table_id, |
| u_int32_t metric, u_int32_t mtu, u_char distance, safi_t safi) |
{ |
{ |
struct rib *rib; |
struct rib *rib; |
struct rib *same = NULL; |
struct rib *same = NULL; |
Line 2331 rib_add_ipv6 (int type, int flags, struct prefix_ipv6
|
Line 2571 rib_add_ipv6 (int type, int flags, struct prefix_ipv6
|
struct nexthop *nexthop; |
struct nexthop *nexthop; |
|
|
/* Lookup table. */ |
/* Lookup table. */ |
table = vrf_table (AFI_IP6, safi, 0); | table = zebra_vrf_table (AFI_IP6, safi, vrf_id); |
if (! table) |
if (! table) |
return 0; |
return 0; |
|
|
Line 2345 rib_add_ipv6 (int type, int flags, struct prefix_ipv6
|
Line 2585 rib_add_ipv6 (int type, int flags, struct prefix_ipv6
|
if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP)) |
if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP)) |
distance = 200; |
distance = 200; |
|
|
/* Filter bogus route. */ |
|
if (rib_bogus_ipv6 (type, p, gate, ifindex, 0)) |
|
return 0; |
|
|
|
/* Lookup route node.*/ |
/* Lookup route node.*/ |
rn = route_node_get (table, (struct prefix *) p); |
rn = route_node_get (table, (struct prefix *) p); |
|
|
/* If same type of route are installed, treat it as a implicit |
/* If same type of route are installed, treat it as a implicit |
withdraw. */ |
withdraw. */ |
for (rib = rn->info; rib; rib = rib->next) | RNODE_FOREACH_RIB (rn, rib) |
{ |
{ |
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
continue; |
continue; |
Line 2382 rib_add_ipv6 (int type, int flags, struct prefix_ipv6
|
Line 2618 rib_add_ipv6 (int type, int flags, struct prefix_ipv6
|
rib->distance = distance; |
rib->distance = distance; |
rib->flags = flags; |
rib->flags = flags; |
rib->metric = metric; |
rib->metric = metric; |
rib->table = vrf_id; | rib->mtu = mtu; |
| rib->vrf_id = vrf_id; |
| rib->table = table_id; |
rib->nexthop_num = 0; |
rib->nexthop_num = 0; |
rib->uptime = time (NULL); |
rib->uptime = time (NULL); |
|
|
Line 2404 rib_add_ipv6 (int type, int flags, struct prefix_ipv6
|
Line 2642 rib_add_ipv6 (int type, int flags, struct prefix_ipv6
|
|
|
/* Link new rib to node.*/ |
/* Link new rib to node.*/ |
rib_addnode (rn, rib); |
rib_addnode (rn, rib); |
|
if (IS_ZEBRA_DEBUG_RIB) |
|
{ |
|
zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry", |
|
__func__, (void *)rn, (void *)rib); |
|
rib_dump (p, rib); |
|
} |
|
|
/* Free implicit route.*/ |
/* Free implicit route.*/ |
if (same) |
if (same) |
|
{ |
|
if (IS_ZEBRA_DEBUG_RIB) |
|
{ |
|
zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry", |
|
__func__, (void *)rn, (void *)same); |
|
rib_dump (p, same); |
|
} |
rib_delnode (rn, same); |
rib_delnode (rn, same); |
|
} |
|
|
route_unlock_node (rn); |
route_unlock_node (rn); |
return 0; |
return 0; |
Line 2416 rib_add_ipv6 (int type, int flags, struct prefix_ipv6
|
Line 2668 rib_add_ipv6 (int type, int flags, struct prefix_ipv6
|
/* XXX factor with rib_delete_ipv6 */ |
/* XXX factor with rib_delete_ipv6 */ |
int |
int |
rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, |
rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, |
struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id, safi_t safi) | struct in6_addr *gate, ifindex_t ifindex, |
| vrf_id_t vrf_id, safi_t safi) |
{ |
{ |
struct route_table *table; |
struct route_table *table; |
struct route_node *rn; |
struct route_node *rn; |
struct rib *rib; |
struct rib *rib; |
struct rib *fib = NULL; |
struct rib *fib = NULL; |
struct rib *same = NULL; |
struct rib *same = NULL; |
struct nexthop *nexthop; | struct nexthop *nexthop, *tnexthop; |
char buf1[INET6_ADDRSTRLEN]; | int recursing; |
| char buf1[PREFIX_STRLEN]; |
char buf2[INET6_ADDRSTRLEN]; |
char buf2[INET6_ADDRSTRLEN]; |
|
|
/* Apply mask. */ |
/* Apply mask. */ |
apply_mask_ipv6 (p); |
apply_mask_ipv6 (p); |
|
|
/* Lookup table. */ |
/* Lookup table. */ |
table = vrf_table (AFI_IP6, safi, 0); | table = zebra_vrf_table (AFI_IP6, safi, vrf_id); |
if (! table) |
if (! table) |
return 0; |
return 0; |
|
|
Line 2442 rib_delete_ipv6 (int type, int flags, struct prefix_ip
|
Line 2696 rib_delete_ipv6 (int type, int flags, struct prefix_ip
|
if (IS_ZEBRA_DEBUG_KERNEL) |
if (IS_ZEBRA_DEBUG_KERNEL) |
{ |
{ |
if (gate) |
if (gate) |
zlog_debug ("route %s/%d via %s ifindex %d doesn't exist in rib", | zlog_debug ("route %s vrf %u via %s ifindex %d doesn't exist in rib", |
inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN), | prefix2str (p, buf1, sizeof(buf1)), vrf_id, |
p->prefixlen, | |
inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN), |
inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN), |
ifindex); |
ifindex); |
else |
else |
zlog_debug ("route %s/%d ifindex %d doesn't exist in rib", | zlog_debug ("route %s vrf %u ifindex %d doesn't exist in rib", |
inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN), | prefix2str (p, buf1, sizeof(buf1)), vrf_id, |
p->prefixlen, | |
ifindex); |
ifindex); |
} |
} |
return ZEBRA_ERR_RTNOEXIST; |
return ZEBRA_ERR_RTNOEXIST; |
} |
} |
|
|
/* Lookup same type route. */ |
/* Lookup same type route. */ |
for (rib = rn->info; rib; rib = rib->next) | RNODE_FOREACH_RIB (rn, rib) |
{ |
{ |
if (CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED)) |
if (CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED)) |
continue; |
continue; |
|
|
if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) | if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) |
fib = rib; |
fib = rib; |
|
|
if (rib->type != type) |
if (rib->type != type) |
Line 2483 rib_delete_ipv6 (int type, int flags, struct prefix_ip
|
Line 2735 rib_delete_ipv6 (int type, int flags, struct prefix_ip
|
break; |
break; |
} |
} |
/* Make sure that the route found has the same gateway. */ |
/* Make sure that the route found has the same gateway. */ |
else if (gate == NULL || | else |
((nexthop = rib->nexthop) && | { |
(IPV6_ADDR_SAME (&nexthop->gate.ipv6, gate) || | if (gate == NULL) |
IPV6_ADDR_SAME (&nexthop->rgate.ipv6, gate)))) | { |
{ | same = rib; |
same = rib; | break; |
break; | } |
} | for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) |
| if (IPV6_ADDR_SAME (&nexthop->gate.ipv6, gate)) |
| { |
| same = rib; |
| break; |
| } |
| if (same) |
| break; |
| } |
} |
} |
|
|
/* If same type of route can't be found and this message is from |
/* If same type of route can't be found and this message is from |
Line 2503 rib_delete_ipv6 (int type, int flags, struct prefix_ip
|
Line 2763 rib_delete_ipv6 (int type, int flags, struct prefix_ip
|
for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) |
for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) |
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); |
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); |
|
|
UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); | UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB); |
} |
} |
else |
else |
{ |
{ |
if (IS_ZEBRA_DEBUG_KERNEL) |
if (IS_ZEBRA_DEBUG_KERNEL) |
{ |
{ |
if (gate) |
if (gate) |
zlog_debug ("route %s/%d via %s ifindex %d type %d doesn't exist in rib", | zlog_debug ("route %s vrf %u via %s ifindex %d type %d " |
inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN), | "doesn't exist in rib", |
p->prefixlen, | prefix2str (p, buf1, sizeof(buf1)), vrf_id, |
inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN), |
inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN), |
ifindex, |
ifindex, |
type); |
type); |
else |
else |
zlog_debug ("route %s/%d ifindex %d type %d doesn't exist in rib", | zlog_debug ("route %s vrf %u ifindex %d type %d doesn't exist in rib", |
inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN), | prefix2str (p, buf1, sizeof(buf1)), vrf_id, |
p->prefixlen, | |
ifindex, |
ifindex, |
type); |
type); |
} |
} |
Line 2534 rib_delete_ipv6 (int type, int flags, struct prefix_ip
|
Line 2793 rib_delete_ipv6 (int type, int flags, struct prefix_ip
|
route_unlock_node (rn); |
route_unlock_node (rn); |
return 0; |
return 0; |
} |
} |
|
|
/* Install static route into rib. */ |
|
static void |
|
static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) |
|
{ |
|
struct rib *rib; |
|
struct route_table *table; |
|
struct route_node *rn; |
|
|
|
/* Lookup table. */ |
|
table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); |
|
if (! table) |
|
return; |
|
|
|
/* Lookup existing route */ |
|
rn = route_node_get (table, p); |
|
for (rib = rn->info; rib; rib = rib->next) |
|
{ |
|
if (CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED)) |
|
continue; |
|
|
|
if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) |
|
break; |
|
} |
|
|
|
if (rib) |
|
{ |
|
/* Same distance static route is there. Update it with new |
|
nexthop. */ |
|
route_unlock_node (rn); |
|
|
|
switch (si->type) |
|
{ |
|
case STATIC_IPV6_GATEWAY: |
|
nexthop_ipv6_add (rib, &si->ipv6); |
|
break; |
|
case STATIC_IPV6_IFNAME: |
|
nexthop_ifname_add (rib, si->ifname); |
|
break; |
|
case STATIC_IPV6_GATEWAY_IFNAME: |
|
nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname); |
|
break; |
|
} |
|
rib_queue_add (&zebrad, rn); |
|
} |
|
else |
|
{ |
|
/* This is new static route. */ |
|
rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); |
|
|
|
rib->type = ZEBRA_ROUTE_STATIC; |
|
rib->distance = si->distance; |
|
rib->metric = 0; |
|
rib->nexthop_num = 0; |
|
|
|
switch (si->type) |
|
{ |
|
case STATIC_IPV6_GATEWAY: |
|
nexthop_ipv6_add (rib, &si->ipv6); |
|
break; |
|
case STATIC_IPV6_IFNAME: |
|
nexthop_ifname_add (rib, si->ifname); |
|
break; |
|
case STATIC_IPV6_GATEWAY_IFNAME: |
|
nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname); |
|
break; |
|
} |
|
|
|
/* Save the flags of this static routes (reject, blackhole) */ |
|
rib->flags = si->flags; |
|
|
|
/* Link this rib to the tree. */ |
|
rib_addnode (rn, rib); |
|
} |
|
} |
|
|
|
static int |
|
static_ipv6_nexthop_same (struct nexthop *nexthop, struct static_ipv6 *si) |
|
{ |
|
if (nexthop->type == NEXTHOP_TYPE_IPV6 |
|
&& si->type == STATIC_IPV6_GATEWAY |
|
&& IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6)) |
|
return 1; |
|
if (nexthop->type == NEXTHOP_TYPE_IFNAME |
|
&& si->type == STATIC_IPV6_IFNAME |
|
&& strcmp (nexthop->ifname, si->ifname) == 0) |
|
return 1; |
|
if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME |
|
&& si->type == STATIC_IPV6_GATEWAY_IFNAME |
|
&& IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6) |
|
&& strcmp (nexthop->ifname, si->ifname) == 0) |
|
return 1; |
|
return 0; |
|
} |
|
|
|
static void |
|
static_uninstall_ipv6 (struct prefix *p, struct static_ipv6 *si) |
|
{ |
|
struct route_table *table; |
|
struct route_node *rn; |
|
struct rib *rib; |
|
struct nexthop *nexthop; |
|
|
|
/* Lookup table. */ |
|
table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); |
|
if (! table) |
|
return; |
|
|
|
/* Lookup existing route with type and distance. */ |
|
rn = route_node_lookup (table, (struct prefix *) p); |
|
if (! rn) |
|
return; |
|
|
|
for (rib = rn->info; rib; rib = rib->next) |
|
{ |
|
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
|
continue; |
|
|
|
if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) |
|
break; |
|
} |
|
|
|
if (! rib) |
|
{ |
|
route_unlock_node (rn); |
|
return; |
|
} |
|
|
|
/* Lookup nexthop. */ |
|
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) |
|
if (static_ipv6_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 |
|
{ |
|
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) |
|
rib_uninstall (rn, rib); |
|
nexthop_delete (rib, nexthop); |
|
nexthop_free (nexthop); |
|
rib_queue_add (&zebrad, rn); |
|
} |
|
/* Unlock node. */ |
|
route_unlock_node (rn); |
|
} |
|
|
|
/* Add static route into static route configuration. */ |
/* Add static route into static route configuration. */ |
int |
int |
static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, |
static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, |
const char *ifname, u_char flags, u_char distance, |
const char *ifname, u_char flags, u_char distance, |
u_int32_t vrf_id) | vrf_id_t vrf_id) |
{ |
{ |
struct route_node *rn; |
struct route_node *rn; |
struct static_ipv6 *si; | struct static_route *si; |
struct static_ipv6 *pp; | struct static_route *pp; |
struct static_ipv6 *cp; | struct static_route *cp; |
struct route_table *stable; | struct static_route *update = NULL; |
| struct zebra_vrf *zvrf = vrf_info_get (vrf_id); |
| struct route_table *stable = zvrf->stable[AFI_IP6][SAFI_UNICAST]; |
|
|
/* Lookup table. */ |
|
stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id); |
|
if (! stable) |
if (! stable) |
return -1; |
return -1; |
|
|
Line 2722 static_add_ipv6 (struct prefix *p, u_char type, struct
|
Line 2826 static_add_ipv6 (struct prefix *p, u_char type, struct
|
/* Do nothing if there is a same static route. */ |
/* Do nothing if there is a same static route. */ |
for (si = rn->info; si; si = si->next) |
for (si = rn->info; si; si = si->next) |
{ |
{ |
if (distance == si->distance | if (type == si->type |
&& type == si->type | && (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6)) |
&& (! gate || IPV6_ADDR_SAME (gate, &si->ipv6)) | |
&& (! ifname || strcmp (ifname, si->ifname) == 0)) |
&& (! ifname || strcmp (ifname, si->ifname) == 0)) |
{ |
{ |
route_unlock_node (rn); | if (distance == si->distance) |
return 0; | { |
| route_unlock_node (rn); |
| return 0; |
| } |
| else |
| update = si; |
} |
} |
} |
} |
|
|
|
if (update) |
|
static_delete_ipv6(p, type, gate, ifname, si->distance, vrf_id); |
|
|
/* Make new static route structure. */ |
/* Make new static route structure. */ |
si = XCALLOC (MTYPE_STATIC_IPV6, sizeof (struct static_ipv6)); | si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route)); |
|
|
si->type = type; |
si->type = type; |
si->distance = distance; |
si->distance = distance; |
si->flags = flags; |
si->flags = flags; |
|
si->vrf_id = vrf_id; |
|
|
switch (type) |
switch (type) |
{ |
{ |
case STATIC_IPV6_GATEWAY: |
case STATIC_IPV6_GATEWAY: |
si->ipv6 = *gate; | si->addr.ipv6 = *gate; |
break; |
break; |
case STATIC_IPV6_IFNAME: |
case STATIC_IPV6_IFNAME: |
si->ifname = XSTRDUP (0, ifname); |
si->ifname = XSTRDUP (0, ifname); |
break; |
break; |
case STATIC_IPV6_GATEWAY_IFNAME: |
case STATIC_IPV6_GATEWAY_IFNAME: |
si->ipv6 = *gate; | si->addr.ipv6 = *gate; |
si->ifname = XSTRDUP (0, ifname); |
si->ifname = XSTRDUP (0, ifname); |
break; |
break; |
} |
} |
Line 2774 static_add_ipv6 (struct prefix *p, u_char type, struct
|
Line 2886 static_add_ipv6 (struct prefix *p, u_char type, struct
|
si->next = cp; |
si->next = cp; |
|
|
/* Install into rib. */ |
/* Install into rib. */ |
static_install_ipv6 (p, si); | static_install_route (AFI_IP6, SAFI_UNICAST, p, si); |
|
|
return 1; |
return 1; |
} |
} |
Line 2782 static_add_ipv6 (struct prefix *p, u_char type, struct
|
Line 2894 static_add_ipv6 (struct prefix *p, u_char type, struct
|
/* Delete static route from static route configuration. */ |
/* Delete static route from static route configuration. */ |
int |
int |
static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, |
static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, |
const char *ifname, u_char distance, u_int32_t vrf_id) | const char *ifname, u_char distance, vrf_id_t vrf_id) |
{ |
{ |
struct route_node *rn; |
struct route_node *rn; |
struct static_ipv6 *si; | struct static_route *si; |
struct route_table *stable; |
struct route_table *stable; |
|
|
/* Lookup table. */ |
/* Lookup table. */ |
stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id); | stable = zebra_vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id); |
if (! stable) |
if (! stable) |
return -1; |
return -1; |
|
|
Line 2802 static_delete_ipv6 (struct prefix *p, u_char type, str
|
Line 2914 static_delete_ipv6 (struct prefix *p, u_char type, str
|
for (si = rn->info; si; si = si->next) |
for (si = rn->info; si; si = si->next) |
if (distance == si->distance |
if (distance == si->distance |
&& type == si->type |
&& type == si->type |
&& (! gate || IPV6_ADDR_SAME (gate, &si->ipv6)) | && (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6)) |
&& (! ifname || strcmp (ifname, si->ifname) == 0)) |
&& (! ifname || strcmp (ifname, si->ifname) == 0)) |
break; |
break; |
|
|
Line 2814 static_delete_ipv6 (struct prefix *p, u_char type, str
|
Line 2926 static_delete_ipv6 (struct prefix *p, u_char type, str
|
} |
} |
|
|
/* Install into rib. */ |
/* Install into rib. */ |
static_uninstall_ipv6 (p, si); | static_uninstall_route (AFI_IP6, SAFI_UNICAST, p, si); |
|
|
/* Unlink static route from linked list. */ |
/* Unlink static route from linked list. */ |
if (si->prev) |
if (si->prev) |
Line 2827 static_delete_ipv6 (struct prefix *p, u_char type, str
|
Line 2939 static_delete_ipv6 (struct prefix *p, u_char type, str
|
/* Free static route configuration. */ |
/* Free static route configuration. */ |
if (ifname) |
if (ifname) |
XFREE (0, si->ifname); |
XFREE (0, si->ifname); |
XFREE (MTYPE_STATIC_IPV6, si); | XFREE (MTYPE_STATIC_ROUTE, si); |
|
|
return 1; |
return 1; |
} |
} |
#endif /* HAVE_IPV6 */ | |
| |
/* RIB update function. */ |
/* RIB update function. */ |
void |
void |
rib_update (void) | rib_update (vrf_id_t vrf_id) |
{ |
{ |
struct route_node *rn; |
struct route_node *rn; |
struct route_table *table; |
struct route_table *table; |
|
|
table = vrf_table (AFI_IP, SAFI_UNICAST, 0); | table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); |
if (table) |
if (table) |
for (rn = route_top (table); rn; rn = route_next (rn)) |
for (rn = route_top (table); rn; rn = route_next (rn)) |
if (rn->info) | if (rnode_to_ribs (rn)) |
rib_queue_add (&zebrad, rn); |
rib_queue_add (&zebrad, rn); |
|
|
table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); | table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); |
if (table) |
if (table) |
for (rn = route_top (table); rn; rn = route_next (rn)) |
for (rn = route_top (table); rn; rn = route_next (rn)) |
if (rn->info) | if (rnode_to_ribs (rn)) |
rib_queue_add (&zebrad, rn); |
rib_queue_add (&zebrad, rn); |
} |
} |
|
|
| |
/* Remove all routes which comes from non main table. */ |
/* Remove all routes which comes from non main table. */ |
static void |
static void |
rib_weed_table (struct route_table *table) |
rib_weed_table (struct route_table *table) |
Line 2864 rib_weed_table (struct route_table *table)
|
Line 2975 rib_weed_table (struct route_table *table)
|
|
|
if (table) |
if (table) |
for (rn = route_top (table); rn; rn = route_next (rn)) |
for (rn = route_top (table); rn; rn = route_next (rn)) |
for (rib = rn->info; rib; rib = next) | RNODE_FOREACH_RIB_SAFE (rn, rib, next) |
{ |
{ |
next = rib->next; |
|
|
|
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
continue; |
continue; |
|
|
Line 2881 rib_weed_table (struct route_table *table)
|
Line 2990 rib_weed_table (struct route_table *table)
|
void |
void |
rib_weed_tables (void) |
rib_weed_tables (void) |
{ |
{ |
rib_weed_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); | vrf_iter_t iter; |
rib_weed_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); | struct zebra_vrf *zvrf; |
| |
| for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) |
| if ((zvrf = vrf_iter2info (iter)) != NULL) |
| { |
| rib_weed_table (zvrf->table[AFI_IP][SAFI_UNICAST]); |
| rib_weed_table (zvrf->table[AFI_IP6][SAFI_UNICAST]); |
| } |
} |
} |
| |
| #if 0 |
/* Delete self installed routes after zebra is relaunched. */ |
/* Delete self installed routes after zebra is relaunched. */ |
static void |
static void |
rib_sweep_table (struct route_table *table) |
rib_sweep_table (struct route_table *table) |
Line 2896 rib_sweep_table (struct route_table *table)
|
Line 3013 rib_sweep_table (struct route_table *table)
|
|
|
if (table) |
if (table) |
for (rn = route_top (table); rn; rn = route_next (rn)) |
for (rn = route_top (table); rn; rn = route_next (rn)) |
for (rib = rn->info; rib; rib = next) | RNODE_FOREACH_RIB_SAFE (rn, rib, next) |
{ |
{ |
next = rib->next; |
|
|
|
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
continue; |
continue; |
|
|
if (rib->type == ZEBRA_ROUTE_KERNEL && |
if (rib->type == ZEBRA_ROUTE_KERNEL && |
CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELFROUTE)) |
CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELFROUTE)) |
{ |
{ |
ret = rib_uninstall_kernel (rn, rib); | ret = rib_update_kernel (rn, rib, NULL); |
if (! ret) |
if (! ret) |
rib_delnode (rn, rib); |
rib_delnode (rn, rib); |
} |
} |
} |
} |
} |
} |
|
#endif |
|
|
/* Sweep all RIB tables. */ |
/* Sweep all RIB tables. */ |
void |
void |
rib_sweep_route (void) |
rib_sweep_route (void) |
{ |
{ |
rib_sweep_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); | vrf_iter_t iter; |
rib_sweep_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); | struct zebra_vrf *zvrf; |
| |
| for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) |
| if ((zvrf = vrf_iter2info (iter)) != NULL) |
| { |
| rib_weed_table (zvrf->table[AFI_IP][SAFI_UNICAST]); |
| rib_weed_table (zvrf->table[AFI_IP6][SAFI_UNICAST]); |
| } |
} |
} |
|
|
/* Remove specific by protocol routes from 'table'. */ |
/* Remove specific by protocol routes from 'table'. */ |
Line 2932 rib_score_proto_table (u_char proto, struct route_tabl
|
Line 3055 rib_score_proto_table (u_char proto, struct route_tabl
|
|
|
if (table) |
if (table) |
for (rn = route_top (table); rn; rn = route_next (rn)) |
for (rn = route_top (table); rn; rn = route_next (rn)) |
for (rib = rn->info; rib; rib = next) | RNODE_FOREACH_RIB_SAFE (rn, rib, next) |
{ |
{ |
next = rib->next; |
|
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) |
continue; |
continue; |
if (rib->type == proto) |
if (rib->type == proto) |
Line 2951 rib_score_proto_table (u_char proto, struct route_tabl
|
Line 3073 rib_score_proto_table (u_char proto, struct route_tabl
|
unsigned long |
unsigned long |
rib_score_proto (u_char proto) |
rib_score_proto (u_char proto) |
{ |
{ |
return rib_score_proto_table (proto, vrf_table (AFI_IP, SAFI_UNICAST, 0)) | vrf_iter_t iter; |
+rib_score_proto_table (proto, vrf_table (AFI_IP6, SAFI_UNICAST, 0)); | struct zebra_vrf *zvrf; |
| unsigned long cnt = 0; |
| |
| for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) |
| if ((zvrf = vrf_iter2info (iter)) != NULL) |
| cnt += rib_score_proto_table (proto, zvrf->table[AFI_IP][SAFI_UNICAST]) |
| +rib_score_proto_table (proto, zvrf->table[AFI_IP6][SAFI_UNICAST]); |
| |
| return cnt; |
} |
} |
|
|
/* Close RIB and clean up kernel routes. */ |
/* Close RIB and clean up kernel routes. */ |
static void | void |
rib_close_table (struct route_table *table) |
rib_close_table (struct route_table *table) |
{ |
{ |
struct route_node *rn; |
struct route_node *rn; |
|
rib_table_info_t *info = table->info; |
struct rib *rib; |
struct rib *rib; |
|
|
if (table) |
if (table) |
for (rn = route_top (table); rn; rn = route_next (rn)) |
for (rn = route_top (table); rn; rn = route_next (rn)) |
for (rib = rn->info; rib; rib = rib->next) | RNODE_FOREACH_RIB (rn, rib) |
{ |
{ |
if (! RIB_SYSTEM_ROUTE (rib) | if (!CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) |
&& CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) | continue; |
rib_uninstall_kernel (rn, rib); | |
| if (info->safi == SAFI_UNICAST) |
| zfpm_trigger_update (rn, NULL); |
| |
| if (! RIB_SYSTEM_ROUTE (rib)) |
| rib_update_kernel (rn, rib, NULL); |
} |
} |
} |
} |
|
|
Line 2976 rib_close_table (struct route_table *table)
|
Line 3112 rib_close_table (struct route_table *table)
|
void |
void |
rib_close (void) |
rib_close (void) |
{ |
{ |
rib_close_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); | vrf_iter_t iter; |
rib_close_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); | struct zebra_vrf *zvrf; |
| |
| for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter)) |
| if ((zvrf = vrf_iter2info (iter)) != NULL) |
| { |
| rib_close_table (zvrf->table[AFI_IP][SAFI_UNICAST]); |
| rib_close_table (zvrf->table[AFI_IP6][SAFI_UNICAST]); |
| } |
} |
} |
| |
/* Routing information base initialize. */ |
/* Routing information base initialize. */ |
void |
void |
rib_init (void) |
rib_init (void) |
{ |
{ |
rib_queue_init (&zebrad); |
rib_queue_init (&zebrad); |
/* VRF initialization. */ |
|
vrf_init (); |
|
} |
} |
|
|
|
/* |
|
* vrf_id_get_next |
|
* |
|
* Get the first vrf id that is greater than the given vrf id if any. |
|
* |
|
* Returns TRUE if a vrf id was found, FALSE otherwise. |
|
*/ |
|
static inline int |
|
vrf_id_get_next (vrf_id_t vrf_id, vrf_id_t *next_id_p) |
|
{ |
|
vrf_iter_t iter = vrf_iterator (vrf_id); |
|
struct zebra_vrf *zvrf = vrf_iter2info (iter); |
|
|
|
/* The same one ? Then find out the next. */ |
|
if (zvrf && (zvrf->vrf_id == vrf_id)) |
|
zvrf = vrf_iter2info (vrf_next (iter)); |
|
|
|
if (zvrf) |
|
{ |
|
*next_id_p = zvrf->vrf_id; |
|
return 1; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
/* |
|
* rib_tables_iter_next |
|
* |
|
* Returns the next table in the iteration. |
|
*/ |
|
struct route_table * |
|
rib_tables_iter_next (rib_tables_iter_t *iter) |
|
{ |
|
struct route_table *table; |
|
|
|
/* |
|
* Array that helps us go over all AFI/SAFI combinations via one |
|
* index. |
|
*/ |
|
static struct { |
|
afi_t afi; |
|
safi_t safi; |
|
} afi_safis[] = { |
|
{ AFI_IP, SAFI_UNICAST }, |
|
{ AFI_IP, SAFI_MULTICAST }, |
|
{ AFI_IP6, SAFI_UNICAST }, |
|
{ AFI_IP6, SAFI_MULTICAST }, |
|
}; |
|
|
|
table = NULL; |
|
|
|
switch (iter->state) |
|
{ |
|
|
|
case RIB_TABLES_ITER_S_INIT: |
|
iter->vrf_id = VRF_DEFAULT; |
|
iter->afi_safi_ix = -1; |
|
|
|
/* Fall through */ |
|
|
|
case RIB_TABLES_ITER_S_ITERATING: |
|
iter->afi_safi_ix++; |
|
while (1) |
|
{ |
|
|
|
while (iter->afi_safi_ix < (int) ZEBRA_NUM_OF (afi_safis)) |
|
{ |
|
table = zebra_vrf_table (afi_safis[iter->afi_safi_ix].afi, |
|
afi_safis[iter->afi_safi_ix].safi, |
|
iter->vrf_id); |
|
if (table) |
|
break; |
|
|
|
iter->afi_safi_ix++; |
|
} |
|
|
|
/* |
|
* Found another table in this vrf. |
|
*/ |
|
if (table) |
|
break; |
|
|
|
/* |
|
* Done with all tables in the current vrf, go to the next |
|
* one. |
|
*/ |
|
if (!vrf_id_get_next (iter->vrf_id, &iter->vrf_id)) |
|
break; |
|
|
|
iter->afi_safi_ix = 0; |
|
} |
|
|
|
break; |
|
|
|
case RIB_TABLES_ITER_S_DONE: |
|
return NULL; |
|
} |
|
|
|
if (table) |
|
iter->state = RIB_TABLES_ITER_S_ITERATING; |
|
else |
|
iter->state = RIB_TABLES_ITER_S_DONE; |
|
|
|
return table; |
|
} |
|
|
|
/* |
|
* Create a routing table for the specific AFI/SAFI in the given VRF. |
|
*/ |
|
static void |
|
zebra_vrf_table_create (struct zebra_vrf *zvrf, afi_t afi, safi_t safi) |
|
{ |
|
rib_table_info_t *info; |
|
struct route_table *table; |
|
|
|
assert (!zvrf->table[afi][safi]); |
|
|
|
table = route_table_init (); |
|
zvrf->table[afi][safi] = table; |
|
|
|
info = XCALLOC (MTYPE_RIB_TABLE_INFO, sizeof (*info)); |
|
info->zvrf = zvrf; |
|
info->afi = afi; |
|
info->safi = safi; |
|
table->info = info; |
|
} |
|
|
|
/* Allocate new zebra VRF. */ |
|
struct zebra_vrf * |
|
zebra_vrf_alloc (vrf_id_t vrf_id) |
|
{ |
|
struct zebra_vrf *zvrf; |
|
#ifdef HAVE_NETLINK |
|
char nl_name[64]; |
|
#endif |
|
|
|
zvrf = XCALLOC (MTYPE_ZEBRA_VRF, sizeof (struct zebra_vrf)); |
|
|
|
/* Allocate routing table and static table. */ |
|
zebra_vrf_table_create (zvrf, AFI_IP, SAFI_UNICAST); |
|
zebra_vrf_table_create (zvrf, AFI_IP6, SAFI_UNICAST); |
|
zvrf->stable[AFI_IP][SAFI_UNICAST] = route_table_init (); |
|
zvrf->stable[AFI_IP6][SAFI_UNICAST] = route_table_init (); |
|
zebra_vrf_table_create (zvrf, AFI_IP, SAFI_MULTICAST); |
|
zebra_vrf_table_create (zvrf, AFI_IP6, SAFI_MULTICAST); |
|
zvrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init (); |
|
zvrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init (); |
|
|
|
/* Set VRF ID */ |
|
zvrf->vrf_id = vrf_id; |
|
|
|
#ifdef HAVE_NETLINK |
|
/* Initialize netlink sockets */ |
|
snprintf (nl_name, 64, "netlink-listen (vrf %u)", vrf_id); |
|
zvrf->netlink.sock = -1; |
|
zvrf->netlink.name = XSTRDUP (MTYPE_NETLINK_NAME, nl_name); |
|
|
|
snprintf (nl_name, 64, "netlink-cmd (vrf %u)", vrf_id); |
|
zvrf->netlink_cmd.sock = -1; |
|
zvrf->netlink_cmd.name = XSTRDUP (MTYPE_NETLINK_NAME, nl_name); |
|
#endif |
|
|
|
return zvrf; |
|
} |
|
|
|
/* Lookup the routing table in an enabled VRF. */ |
|
struct route_table * |
|
zebra_vrf_table (afi_t afi, safi_t safi, vrf_id_t vrf_id) |
|
{ |
|
struct zebra_vrf *zvrf = vrf_info_lookup (vrf_id); |
|
|
|
if (!zvrf) |
|
return NULL; |
|
|
|
if (afi >= AFI_MAX || safi >= SAFI_MAX) |
|
return NULL; |
|
|
|
return zvrf->table[afi][safi]; |
|
} |
|
|
|
/* Lookup the static routing table in a VRF. */ |
|
struct route_table * |
|
zebra_vrf_static_table (afi_t afi, safi_t safi, vrf_id_t vrf_id) |
|
{ |
|
struct zebra_vrf *zvrf = vrf_info_lookup (vrf_id); |
|
|
|
if (!zvrf) |
|
return NULL; |
|
|
|
if (afi >= AFI_MAX || safi >= SAFI_MAX) |
|
return NULL; |
|
|
|
return zvrf->stable[afi][safi]; |
|
} |
|
|