--- embedaddon/quagga/zebra/zebra_rib.c 2013/07/21 23:54:41 1.1.1.3 +++ embedaddon/quagga/zebra/zebra_rib.c 2016/11/02 10:09:10 1.1.1.4 @@ -34,6 +34,7 @@ #include "workqueue.h" #include "prefix.h" #include "routemap.h" +#include "vrf.h" #include "zebra/rib.h" #include "zebra/rt.h" @@ -71,112 +72,44 @@ static const struct [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 95}, /* no entry/default: 150 */ }; - -/* Vector for routing table. */ -static vector vrf_vector; -/* - * vrf_table_create - */ -static void -vrf_table_create (struct vrf *vrf, afi_t afi, safi_t safi) -{ - rib_table_info_t *info; - struct route_table *table; +/* RPF lookup behaviour */ +static enum multicast_mode ipv4_multicast_mode = MCAST_NO_CONFIG; - assert (!vrf->table[afi][safi]); - - table = route_table_init (); - vrf->table[afi][safi] = table; - - info = XCALLOC (MTYPE_RIB_TABLE_INFO, sizeof (*info)); - info->vrf = vrf; - info->afi = afi; - info->safi = safi; - table->info = info; -} - -/* Allocate new VRF. */ -static struct vrf * -vrf_alloc (const char *name) +static void __attribute__((format (printf, 4, 5))) +_rnode_zlog(const char *_func, struct route_node *rn, int priority, + const char *msgfmt, ...) { - struct vrf *vrf; + char prefix[PREFIX_STRLEN], buf[256]; + char msgbuf[512]; + va_list ap; - vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf)); + va_start(ap, msgfmt); + vsnprintf(msgbuf, sizeof(msgbuf), msgfmt, ap); + va_end(ap); - /* Put name. */ - if (name) - vrf->name = XSTRDUP (MTYPE_VRF_NAME, name); + if (rn) + { + rib_table_info_t *info = rn->table->info; - /* Allocate routing table and static table. */ - vrf_table_create (vrf, AFI_IP, SAFI_UNICAST); - vrf_table_create (vrf, AFI_IP6, SAFI_UNICAST); - vrf->stable[AFI_IP][SAFI_UNICAST] = route_table_init (); - vrf->stable[AFI_IP6][SAFI_UNICAST] = route_table_init (); - vrf_table_create (vrf, AFI_IP, SAFI_MULTICAST); - vrf_table_create (vrf, AFI_IP6, SAFI_MULTICAST); - vrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init (); - vrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init (); + snprintf(buf, sizeof(buf), "%s%s vrf %u", + prefix2str(&rn->p, prefix, sizeof(prefix)), + info->safi == SAFI_MULTICAST ? " (MRIB)" : "", + info->zvrf->vrf_id); + } + else + { + snprintf(buf, sizeof(buf), "{(route_node *) NULL}"); + } - - return vrf; + zlog (NULL, priority, "%s: %s: %s", _func, buf, msgbuf); } -/* Lookup VRF by identifier. */ -struct vrf * -vrf_lookup (u_int32_t id) -{ - return vector_lookup (vrf_vector, id); -} +#define rnode_debug(node, ...) \ + _rnode_zlog(__func__, node, LOG_DEBUG, __VA_ARGS__) +#define rnode_info(node, ...) \ + _rnode_zlog(__func__, node, LOG_INFO, __VA_ARGS__) -/* Initialize VRF. */ -static void -vrf_init (void) -{ - struct vrf *default_table; - - /* Allocate VRF vector. */ - vrf_vector = vector_init (1); - - /* Allocate default main table. */ - default_table = vrf_alloc ("Default-IP-Routing-Table"); - - /* Default table index must be 0. */ - vector_set_index (vrf_vector, 0, default_table); -} - -/* Lookup route table. */ -struct route_table * -vrf_table (afi_t afi, safi_t safi, u_int32_t id) -{ - struct vrf *vrf; - - vrf = vrf_lookup (id); - if (! vrf) - return NULL; - - if( afi >= AFI_MAX || safi >= SAFI_MAX ) - return NULL; - - return vrf->table[afi][safi]; -} - -/* Lookup static route table. */ -struct route_table * -vrf_static_table (afi_t afi, safi_t safi, u_int32_t id) -{ - struct vrf *vrf; - - vrf = vrf_lookup (id); - if (! vrf) - return NULL; - - if( afi >= AFI_MAX || safi >= SAFI_MAX ) - return NULL; - - return vrf->stable[afi][safi]; -} - /* * nexthop_type_to_str */ @@ -202,20 +135,26 @@ nexthop_type_to_str (enum nexthop_types_t nh_type) return desc[nh_type]; } -/* Add nexthop to the end of the list. */ +/* Add nexthop to the end of a nexthop list. */ static void -nexthop_add (struct rib *rib, struct nexthop *nexthop) +_nexthop_add (struct nexthop **target, struct nexthop *nexthop) { struct nexthop *last; - for (last = rib->nexthop; last && last->next; last = last->next) + for (last = *target; last && last->next; last = last->next) ; if (last) last->next = nexthop; else - rib->nexthop = nexthop; + *target = nexthop; 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++; } @@ -232,17 +171,34 @@ nexthop_delete (struct rib *rib, struct nexthop *nexth rib->nexthop_num--; } +static void nexthops_free(struct nexthop *nexthop); + /* Free nexthop. */ static void nexthop_free (struct nexthop *nexthop) { if (nexthop->ifname) XFREE (0, nexthop->ifname); + if (nexthop->resolved) + nexthops_free(nexthop->resolved); XFREE (MTYPE_NEXTHOP, nexthop); } +/* Frees a list of nexthops */ +static void +nexthops_free (struct nexthop *nexthop) +{ + struct nexthop *nh, *next; + + for (nh = nexthop; nh; nh = next) + { + next = nh->next; + nexthop_free (nh); + } +} + struct nexthop * -nexthop_ifindex_add (struct rib *rib, unsigned int ifindex) +nexthop_ifindex_add (struct rib *rib, ifindex_t ifindex) { struct nexthop *nexthop; @@ -287,7 +243,7 @@ nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv struct nexthop * 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; @@ -303,7 +259,6 @@ nexthop_ipv4_ifindex_add (struct rib *rib, struct in_a return nexthop; } -#ifdef HAVE_IPV6 struct nexthop * nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6) { @@ -336,7 +291,7 @@ nexthop_ipv6_ifname_add (struct rib *rib, struct in6_a static struct nexthop * nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6, - unsigned int ifindex) + ifindex_t ifindex) { struct nexthop *nexthop; @@ -349,7 +304,6 @@ nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_ return nexthop; } -#endif /* HAVE_IPV6 */ struct nexthop * nexthop_blackhole_add (struct rib *rib) @@ -365,6 +319,24 @@ nexthop_blackhole_add (struct rib *rib) 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 the route from FIB. */ static int @@ -375,13 +347,20 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop * struct route_table *table; struct route_node *rn; struct rib *match; + int resolved; struct nexthop *newhop; + struct nexthop *resolved_hop; if (nexthop->type == NEXTHOP_TYPE_IPV4) nexthop->ifindex = 0; 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. */ memset (&p, 0, sizeof (struct prefix_ipv4)); @@ -390,7 +369,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop * p.prefix = nexthop->gate.ipv4; /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, rib->vrf_id); if (! table) return 0; @@ -408,7 +387,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop * { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) break; } @@ -425,6 +404,12 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop * } 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) { /* Directly point connected route. */ @@ -436,6 +421,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop * } else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) { + resolved = 0; for (newhop = match->nexthop; newhop; newhop = newhop->next) if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB) && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE)) @@ -443,18 +429,39 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop * if (set) { SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); - nexthop->rtype = newhop->type; - if (newhop->type == NEXTHOP_TYPE_IPV4 || - newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) - nexthop->rgate.ipv4 = newhop->gate.ipv4; + + resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop)); + SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE); + /* If the resolving route specifies a gateway, use it */ + if (newhop->type == NEXTHOP_TYPE_IPV4 + || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX + || newhop->type == NEXTHOP_TYPE_IPV4_IFNAME) + { + resolved_hop->type = newhop->type; + resolved_hop->gate.ipv4 = newhop->gate.ipv4; + 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 - || newhop->type == NEXTHOP_TYPE_IFNAME - || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) - nexthop->rifindex = newhop->ifindex; + || newhop->type == NEXTHOP_TYPE_IFNAME) + { + 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 { @@ -465,7 +472,6 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop * return 0; } -#ifdef HAVE_IPV6 /* If force flag is not set, do not modify falgs at all for uninstall the route from FIB. */ static int @@ -476,13 +482,19 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop * struct route_table *table; struct route_node *rn; struct rib *match; + int resolved; struct nexthop *newhop; + struct nexthop *resolved_hop; if (nexthop->type == NEXTHOP_TYPE_IPV6) nexthop->ifindex = 0; 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. */ memset (&p, 0, sizeof (struct prefix_ipv6)); @@ -491,7 +503,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop * p.prefix = nexthop->gate.ipv6; /* Lookup table. */ - table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, rib->vrf_id); if (! table) return 0; @@ -509,7 +521,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop * { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) break; } @@ -526,6 +538,12 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop * } 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) { /* Directly point connected route. */ @@ -538,6 +556,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop * } else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) { + resolved = 0; for (newhop = match->nexthop; newhop; newhop = newhop->next) if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB) && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE)) @@ -545,20 +564,39 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop * if (set) { 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 || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX || 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 - || newhop->type == NEXTHOP_TYPE_IFNAME - || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX - || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) - nexthop->rifindex = newhop->ifindex; + || newhop->type == NEXTHOP_TYPE_IFNAME) + { + resolved_hop->flags |= NEXTHOP_FLAG_ONLINK; + resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX; + resolved_hop->gate.ipv6 = nexthop->gate.ipv6; + resolved_hop->ifindex = newhop->ifindex; + } + + _nexthop_add(&nexthop->resolved, resolved_hop); } - return 1; + resolved = 1; } - return 0; + return resolved; } else { @@ -568,46 +606,40 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop * } return 0; } -#endif /* HAVE_IPV6 */ 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_node *rn; struct rib *match; - struct nexthop *newhop; + struct nexthop *newhop, *tnewhop; + int recursing; /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, safi, vrf_id); if (! table) return 0; - memset (&p, 0, sizeof (struct prefix_ipv4)); - p.family = AF_INET; - p.prefixlen = IPV4_MAX_PREFIXLEN; - p.prefix = addr; + rn = route_node_match_ipv4 (table, &addr); - rn = route_node_match (table, (struct prefix *) &p); - while (rn) { route_unlock_node (rn); - + /* Pick up selected route. */ RNODE_FOREACH_RIB (rn, match) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) break; } /* If there is no selected route or matched route is EGP, go up tree. */ - if (! match - || match->type == ZEBRA_ROUTE_BGP) + if (!match || (skip_bgp && (match->type == ZEBRA_ROUTE_BGP))) { do { rn = rn->parent; @@ -617,31 +649,119 @@ rib_match_ipv4 (struct in_addr addr) } else { - if (match->type == ZEBRA_ROUTE_CONNECT) - /* Directly point connected route. */ - return match; - else + if (match->type != ZEBRA_ROUTE_CONNECT) { - 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)) - return match; - return NULL; + { + found = 1; + break; + } + if (!found) + return NULL; } + + if (rn_out) + *rn_out = rn; + return match; } } return NULL; } 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_node *rn; struct rib *match; - struct nexthop *nexthop; + struct nexthop *nexthop, *tnexthop; + int recursing; /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (! table) return 0; @@ -658,7 +778,7 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) break; } @@ -668,7 +788,7 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p) if (match->type == ZEBRA_ROUTE_CONNECT) 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)) return match; @@ -688,15 +808,18 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p) * 3: no matches found */ 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_node *rn; struct rib *match; - struct nexthop *nexthop; + struct nexthop *nexthop, *tnexthop; + int recursing; + int nexthops_active; /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (! table) return ZEBRA_RIB_LOOKUP_ERROR; @@ -715,7 +838,7 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union so { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) break; } @@ -727,42 +850,41 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union so return ZEBRA_RIB_FOUND_CONNECTED; /* 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)) - { - /* We are happy with either direct or recursive hexthop */ - if (nexthop->gate.ipv4.s_addr == sockunion2ip (qgate) || - nexthop->rgate.ipv4.s_addr == sockunion2ip (qgate)) - 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) - { - char gate_buf[INET_ADDRSTRLEN], rgate_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->rgate.ipv4.s_addr, rgate_buf, INET_ADDRSTRLEN); - inet_ntop (AF_INET, &sockunion2ip (qgate), qgate_buf, INET_ADDRSTRLEN); - zlog_debug ("%s: qgate == %s, gate == %s, rgate == %s", __func__, qgate_buf, gate_buf, rgate_buf); - } - return ZEBRA_RIB_FOUND_NOGATE; + { + 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, &sockunion2ip(qgate), qgate_buf, INET_ADDRSTRLEN); + zlog_debug ("%s: qgate == %s, %s == %s", __func__, + qgate_buf, recursing ? "rgate" : "gate", gate_buf); + } } - } + if (nexthops_active) + return ZEBRA_RIB_FOUND_NOGATE; + return ZEBRA_RIB_NOTFOUND; } -#ifdef HAVE_IPV6 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 route_table *table; struct route_node *rn; struct rib *match; - struct nexthop *newhop; + struct nexthop *newhop, *tnewhop; + int recursing; /* Lookup table. */ - table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! table) return 0; @@ -782,7 +904,7 @@ rib_match_ipv6 (struct in6_addr *addr) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (match->status, RIB_ENTRY_SELECTED_FIB)) break; } @@ -804,7 +926,7 @@ rib_match_ipv6 (struct in6_addr *addr) return match; 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)) return match; return NULL; @@ -813,7 +935,6 @@ rib_match_ipv6 (struct in6_addr *addr) } return NULL; } -#endif /* HAVE_IPV6 */ #define RIB_SYSTEM_ROUTE(R) \ ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT) @@ -832,6 +953,7 @@ static unsigned nexthop_active_check (struct route_node *rn, struct rib *rib, struct nexthop *nexthop, int set) { + rib_table_info_t *info = rn->table->info; struct interface *ifp; route_map_result_t ret = RMAP_MATCH; extern char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; @@ -842,7 +964,7 @@ nexthop_active_check (struct route_node *rn, struct ri switch (nexthop->type) { 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)) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); else @@ -851,7 +973,7 @@ nexthop_active_check (struct route_node *rn, struct ri case NEXTHOP_TYPE_IPV6_IFNAME: family = AFI_IP6; 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 (set) @@ -873,7 +995,6 @@ nexthop_active_check (struct route_node *rn, struct ri else UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); break; -#ifdef HAVE_IPV6 case NEXTHOP_TYPE_IPV6: family = AFI_IP6; if (nexthop_active_ipv6 (rib, nexthop, set, rn)) @@ -885,7 +1006,7 @@ nexthop_active_check (struct route_node *rn, struct ri family = AFI_IP6; 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)) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); else @@ -899,7 +1020,6 @@ nexthop_active_check (struct route_node *rn, struct ri UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); } break; -#endif /* HAVE_IPV6 */ case NEXTHOP_TYPE_BLACKHOLE: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); break; @@ -909,11 +1029,22 @@ nexthop_active_check (struct route_node *rn, struct ri if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) 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) || (family == AFI_IP && rn->p.family != AF_INET) || (family == AFI_IP6 && rn->p.family != AF_INET6)) 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; if (rib->type >= 0 && rib->type < ZEBRA_ROUTE_MAX && proto_rm[family][rib->type]) @@ -921,7 +1052,8 @@ nexthop_active_check (struct route_node *rn, struct ri if (!rmap && proto_rm[family][ZEBRA_ROUTE_MAX]) rmap = route_map_lookup_by_name (proto_rm[family][ZEBRA_ROUTE_MAX]); 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) @@ -932,7 +1064,7 @@ nexthop_active_check (struct route_node *rn, struct ri /* Iterate over all nexthops of the given RIB entry and refresh their * ACTIVE flag. rib->nexthop_active_num is updated accordingly. If any * 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(). * * Return value is the new number of active nexthops. @@ -942,10 +1074,11 @@ static int nexthop_active_update (struct route_node *rn, struct rib *rib, int set) { 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; - UNSET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); + UNSET_FLAG (rib->status, RIB_ENTRY_CHANGED); for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { @@ -955,72 +1088,49 @@ nexthop_active_update (struct route_node *rn, struct r rib->nexthop_active_num++; if (prev_active != new_active || prev_index != nexthop->ifindex) - SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); + SET_FLAG (rib->status, RIB_ENTRY_CHANGED); } 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; - struct nexthop *nexthop; + struct nexthop *nexthop, *tnexthop; + rib_table_info_t *info = rn->table->info; + int recursing; - /* - * Make sure we update the FPM any time we send new information to - * the kernel. - */ - zfpm_trigger_update (rn, "installing in kernel"); - switch (PREFIX_FAMILY (&rn->p)) + if (info->safi != SAFI_UNICAST) { - case AF_INET: - ret = kernel_add_ipv4 (&rn->p, rib); - break; -#ifdef HAVE_IPV6 - case AF_INET6: - ret = kernel_add_ipv6 (&rn->p, rib); - break; -#endif /* HAVE_IPV6 */ + if (new) + for (ALL_NEXTHOPS_RO(new->nexthop, nexthop, tnexthop, recursing)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + if (old) + for (ALL_NEXTHOPS_RO(old->nexthop, nexthop, tnexthop, recursing)) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + return 0; } - /* This condition is never met, if we are using rt_socket.c */ - if (ret < 0) - { - for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - } -} - -/* Uninstall the route from kernel. */ -static int -rib_uninstall_kernel (struct route_node *rn, struct rib *rib) -{ - int ret = 0; - struct nexthop *nexthop; - /* * Make sure we update the FPM any time we send new information to * the kernel. */ - zfpm_trigger_update (rn, "uninstalling from kernel"); + zfpm_trigger_update (rn, "updating in kernel"); - switch (PREFIX_FAMILY (&rn->p)) - { - case AF_INET: - ret = kernel_delete_ipv4 (&rn->p, rib); - break; -#ifdef HAVE_IPV6 - case AF_INET6: - ret = kernel_delete_ipv6 (&rn->p, rib); - break; -#endif /* HAVE_IPV6 */ - } + ret = kernel_route_rib (&rn->p, old, new); - for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + /* This condition is never met, if we are using rt_socket.c */ + if (ret < 0 && new) + for (ALL_NEXTHOPS_RO(new->nexthop, nexthop, tnexthop, recursing)) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + if (old) + for (ALL_NEXTHOPS_RO(old->nexthop, nexthop, tnexthop, recursing)) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + return ret; } @@ -1028,13 +1138,16 @@ rib_uninstall_kernel (struct route_node *rn, struct ri static void 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)) { - zfpm_trigger_update (rn, "rib_uninstall"); + if (info->safi == SAFI_UNICAST) + zfpm_trigger_update (rn, "rib_uninstall"); redistribute_delete (&rn->p, rib); if (! RIB_SYSTEM_ROUTE (rib)) - rib_uninstall_kernel (rn, rib); + rib_update_kernel (rn, rib, NULL); UNSET_FLAG (rib->flags, ZEBRA_FLAG_SELECTED); } } @@ -1077,7 +1190,6 @@ int rib_gc_dest (struct route_node *rn) { rib_dest_t *dest; - char buf[INET6_ADDRSTRLEN]; dest = rib_dest_from_rnode (rn); if (!dest) @@ -1087,11 +1199,7 @@ rib_gc_dest (struct route_node *rn) return 0; if (IS_ZEBRA_DEBUG_RIB) - { - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, sizeof (buf)); - zlog_debug ("%s: %s/%d: removing dest from table", __func__, - buf, rn->p.prefixlen); - } + rnode_debug (rn, "removing dest from table"); dest->rnode = NULL; XFREE (MTYPE_RIB_DEST, dest); @@ -1104,50 +1212,84 @@ rib_gc_dest (struct route_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. */ static void rib_process (struct route_node *rn) { struct rib *rib; struct rib *next; - struct rib *fib = NULL; - struct rib *select = NULL; - struct rib *del = NULL; + struct rib *old_selected = NULL; + struct rib *new_selected = NULL; + struct rib *old_fib = NULL; + struct rib *new_fib = NULL; int installed = 0; - struct nexthop *nexthop = NULL; - char buf[INET6_ADDRSTRLEN]; - + struct nexthop *nexthop = NULL, *tnexthop; + int recursing; + rib_table_info_t *info; + assert (rn); - - if (IS_ZEBRA_DEBUG_RIB || IS_ZEBRA_DEBUG_RIB_Q) - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); - RNODE_FOREACH_RIB_SAFE (rn, rib, next) + info = rn->table->info; + + RNODE_FOREACH_RIB (rn, rib) { /* Currently installed rib. */ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) { - assert (fib == NULL); - fib = rib; + assert (old_selected == NULL); + old_selected = rib; } - - /* 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 (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) { - if (rib != fib) - { - 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; + assert (old_fib == NULL); + old_fib = rib; } + + /* Skip deleted entries from selection */ + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + continue; /* Skip unreachable nexthop. */ if (! nexthop_active_update (rn, rib, 0)) @@ -1157,152 +1299,104 @@ rib_process (struct route_node *rn) if (rib->distance == DISTANCE_INFINITY) continue; - /* Newly selected rib, the common case. */ - if (!select) - { - select = rib; - continue; - } - - /* 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; + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_FIB_OVERRIDE)) + new_fib = rib_choose_best(new_fib, rib); + else + new_selected = rib_choose_best(new_selected, rib); } /* RNODE_FOREACH_RIB_SAFE */ + /* 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: - * select --- the winner RIB entry, if any was found, otherwise NULL - * fib --- the SELECTED RIB entry, if any, otherwise NULL - * del --- equal to fib, if fib is queued for deletion, NULL otherwise - * rib --- NULL + * old_selected --- RIB entry currently having SELECTED + * new_selected --- RIB entry that is newly SELECTED + * old_fib --- RIB entry currently in kernel FIB + * 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. */ - if (select && select == fib) + /* Set real nexthops. */ + 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) - zlog_debug ("%s: %s/%d: Updating existing route, select %p, fib %p", - __func__, buf, rn->p.prefixlen, select, fib); - if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED)) - { - zfpm_trigger_update (rn, "updating existing route"); + if (old_fib && old_fib != new_fib) + { + if (! RIB_SYSTEM_ROUTE (old_fib) && (! new_fib || RIB_SYSTEM_ROUTE (new_fib))) + 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); + if (new_fib) + { + /* Install new or replace existing FIB entry */ + SET_FLAG (new_fib->status, RIB_ENTRY_SELECTED_FIB); + if (! RIB_SYSTEM_ROUTE (new_fib)) + rib_update_kernel (rn, old_fib, new_fib); + } - /* Set real nexthop. */ - nexthop_active_update (rn, select, 1); - - if (! RIB_SYSTEM_ROUTE (select)) - rib_install_kernel (rn, select); - redistribute_add (&rn->p, select); - } - 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 (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) - { - installed = 1; - break; - } - if (! installed) - rib_install_kernel (rn, select); - } - goto end; + if (info->safi == SAFI_UNICAST) + zfpm_trigger_update (rn, "updating existing route"); } - - /* 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) + else if (old_fib == new_fib && new_fib && ! RIB_SYSTEM_ROUTE (new_fib)) { - if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: %s/%d: Removing existing route, fib %p", __func__, - buf, rn->p.prefixlen, fib); - - zfpm_trigger_update (rn, "removing existing route"); - - redistribute_delete (&rn->p, fib); - if (! RIB_SYSTEM_ROUTE (fib)) - rib_uninstall_kernel (rn, fib); - UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); - - /* Set real nexthop. */ - nexthop_active_update (rn, fib, 1); + /* 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 routes are IN the kernel. + */ + for (ALL_NEXTHOPS_RO(new_fib->nexthop, nexthop, tnexthop, recursing)) + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + { + installed = 1; + break; + } + if (! installed) + rib_update_kernel (rn, NULL, new_fib); } - /* Regardless of some RIB entry being SELECTED or not before, now we can - * tell, that if a new winner exists, FIB is still not updated with this - * data, but ready to be. - */ - if (select) + /* Redistribute SELECTED entry */ + if (old_selected != new_selected + || (new_selected && CHECK_FLAG (new_selected->status, RIB_ENTRY_CHANGED))) { - if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: %s/%d: Adding route, select %p", __func__, buf, - rn->p.prefixlen, select); + if (old_selected) + { + if (! new_selected) + redistribute_delete (&rn->p, old_selected); + if (old_selected != new_selected) + UNSET_FLAG (old_selected->flags, ZEBRA_FLAG_SELECTED); + } - zfpm_trigger_update (rn, "new route selected"); + if (new_selected) + { + /* Install new or replace existing redistributed entry */ + SET_FLAG (new_selected->flags, ZEBRA_FLAG_SELECTED); + redistribute_add (&rn->p, new_selected); + } + } - /* Set real nexthop. */ - nexthop_active_update (rn, select, 1); - - if (! RIB_SYSTEM_ROUTE (select)) - rib_install_kernel (rn, select); - SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED); - redistribute_add (&rn->p, select); - } - - /* FIB route was removed, should be deleted */ - if (del) + /* Remove all RIB entries queued for removal */ + RNODE_FOREACH_RIB_SAFE (rn, rib, next) { - if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: %s/%d: Deleting fib %p, rn %p", __func__, buf, - rn->p.prefixlen, del, rn); - rib_unlink (rn, del); + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + { + if (IS_ZEBRA_DEBUG_RIB) + rnode_debug (rn, "rn %p, removing rib %p", + (void *)rn, (void *)rib); + rib_unlink (rn, rib); + } } -end: 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. @@ -1386,11 +1480,7 @@ static void rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) { struct rib *rib; - char buf[INET6_ADDRSTRLEN]; - if (IS_ZEBRA_DEBUG_RIB_Q) - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); - RNODE_FOREACH_RIB (rn, rib) { u_char qindex = meta_queue_map[rib->type]; @@ -1400,8 +1490,8 @@ rib_meta_queue_add (struct meta_queue *mq, struct rout RIB_ROUTE_QUEUED (qindex))) { if (IS_ZEBRA_DEBUG_RIB_Q) - zlog_debug ("%s: %s/%d: rn %p is already queued in sub-queue %u", - __func__, buf, rn->p.prefixlen, rn, qindex); + rnode_debug (rn, "rn %p is already queued in sub-queue %u", + (void *)rn, qindex); continue; } @@ -1411,8 +1501,8 @@ rib_meta_queue_add (struct meta_queue *mq, struct rout mq->size++; if (IS_ZEBRA_DEBUG_RIB_Q) - zlog_debug ("%s: %s/%d: queued rn %p into sub-queue %u", - __func__, buf, rn->p.prefixlen, rn, qindex); + rnode_debug (rn, "queued rn %p into sub-queue %u", + (void *)rn, qindex); } } @@ -1420,23 +1510,19 @@ rib_meta_queue_add (struct meta_queue *mq, struct rout static void rib_queue_add (struct zebra_t *zebra, struct route_node *rn) { - char buf[INET_ADDRSTRLEN]; 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 */ if (!rnode_to_ribs (rn)) { 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); return; } 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); @@ -1460,7 +1546,7 @@ rib_queue_add (struct zebra_t *zebra, struct route_nod rib_meta_queue_add (zebra->mq, rn); 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; } @@ -1520,7 +1606,7 @@ rib_queue_init (struct zebra_t *zebra) * as a route_node will not be requeued, if already queued. * * 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. * Order of add/delete state changes are preserved for any given RIB. * @@ -1557,25 +1643,17 @@ rib_link (struct route_node *rn, struct rib *rib) { struct rib *head; rib_dest_t *dest; - char buf[INET6_ADDRSTRLEN]; assert (rib && rn); if (IS_ZEBRA_DEBUG_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); - } + rnode_debug (rn, "rn %p, rib %p", (void *)rn, (void *)rib); dest = rib_dest_from_rnode (rn); if (!dest) { if (IS_ZEBRA_DEBUG_RIB) - { - zlog_debug ("%s: %s/%d: adding dest to table", __func__, - buf, rn->p.prefixlen); - } + rnode_debug (rn, "adding dest to table"); dest = XCALLOC (MTYPE_RIB_DEST, sizeof (rib_dest_t)); route_lock_node (rn); /* rn route table reference */ @@ -1602,12 +1680,8 @@ rib_addnode (struct route_node *rn, struct rib *rib) if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) { if (IS_ZEBRA_DEBUG_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); - } + rnode_debug (rn, "rn %p, un-removed rib %p", (void *)rn, (void *)rib); + UNSET_FLAG (rib->status, RIB_ENTRY_REMOVED); return; } @@ -1626,18 +1700,12 @@ rib_addnode (struct route_node *rn, struct rib *rib) static void rib_unlink (struct route_node *rn, struct rib *rib) { - struct nexthop *nexthop, *next; - char buf[INET6_ADDRSTRLEN]; rib_dest_t *dest; assert (rn && rib); if (IS_ZEBRA_DEBUG_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); - } + rnode_debug (rn, "rn %p, rib %p", (void *)rn, (void *)rib); dest = rib_dest_from_rnode (rn); @@ -1652,11 +1720,7 @@ rib_unlink (struct route_node *rn, struct rib *rib) } /* free RIB and nexthops */ - for (nexthop = rib->nexthop; nexthop; nexthop = next) - { - next = nexthop->next; - nexthop_free (nexthop); - } + nexthops_free(rib->nexthop); XFREE (MTYPE_RIB, rib); } @@ -1665,12 +1729,7 @@ static void rib_delnode (struct route_node *rn, struct rib *rib) { if (IS_ZEBRA_DEBUG_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); - } + rnode_debug (rn, "rn %p, rib %p, removing", (void *)rn, (void *)rib); SET_FLAG (rib->status, RIB_ENTRY_REMOVED); rib_queue_add (&zebrad, rn); } @@ -1678,8 +1737,8 @@ rib_delnode (struct route_node *rn, struct rib *rib) int rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct in_addr *gate, struct in_addr *src, - unsigned int ifindex, u_int32_t vrf_id, - u_int32_t metric, u_char distance, safi_t safi) + ifindex_t ifindex, 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 *same = NULL; @@ -1688,7 +1747,7 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 struct nexthop *nexthop; /* Lookup table. */ - table = vrf_table (AFI_IP, safi, 0); + table = zebra_vrf_table (AFI_IP, safi, vrf_id); if (! table) return 0; @@ -1742,7 +1801,9 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 rib->distance = distance; rib->flags = flags; rib->metric = metric; - rib->table = vrf_id; + rib->mtu = mtu; + rib->vrf_id = vrf_id; + rib->table = table_id; rib->nexthop_num = 0; rib->uptime = time (NULL); @@ -1764,14 +1825,16 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 /* Link new rib to node.*/ 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); /* Free implicit route.*/ if (same) { 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); } @@ -1784,13 +1847,16 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 * 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]; - struct nexthop *nexthop; + const struct prefix *p = pp.p; + 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/%d", func, rib, straddr1, p->prefixlen); + zlog_debug ("%s: dumping RIB entry %p for %s vrf %u", func, (void *)rib, + prefix2str(p, straddr, sizeof(straddr)), rib->vrf_id); zlog_debug ( "%s: refcnt == %lu, uptime == %lu, type == %u, table == %d", @@ -1817,21 +1883,21 @@ void rib_dump (const char * func, const struct prefix_ rib->nexthop_active_num, rib->nexthop_fib_num ); - for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - { - inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, straddr1, INET_ADDRSTRLEN); - inet_ntop (AF_INET, &nexthop->rgate.ipv4.s_addr, straddr2, INET_ADDRSTRLEN); - zlog_debug - ( - "%s: NH %s (%s) with flags %s%s%s", - func, - straddr1, - straddr2, - (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE " : ""), - (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? "FIB " : ""), - (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) ? "RECURSIVE" : "") - ); - } + + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) + { + inet_ntop (p->family, &nexthop->gate, straddr, INET6_ADDRSTRLEN); + zlog_debug + ( + "%s: %s %s with flags %s%s%s", + func, + (recursing ? " NH" : "NH"), + straddr, + (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE " : ""), + (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? "FIB " : ""), + (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) ? "RECURSIVE" : "") + ); + } zlog_debug ("%s: dump complete", func); } @@ -1847,21 +1913,21 @@ void rib_lookup_and_dump (struct prefix_ipv4 * p) char prefix_buf[INET_ADDRSTRLEN]; /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (! table) { - zlog_err ("%s: vrf_table() returned NULL", __func__); + zlog_err ("%s: zebra_vrf_table() returned NULL", __func__); return; } - inet_ntop (AF_INET, &p->prefix.s_addr, prefix_buf, INET_ADDRSTRLEN); /* Scan the RIB table for exactly matching RIB entry. */ rn = route_node_lookup (table, (struct prefix *) p); /* No route for this prefix. */ 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; } @@ -1875,12 +1941,12 @@ void rib_lookup_and_dump (struct prefix_ipv4 * p) ( "%s: rn %p, rib %p: %s, %s", __func__, - rn, - rib, + (void *)rn, + (void *)rib, (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED) ? "removed" : "NOT removed"), (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) ? "selected" : "NOT selected") ); - rib_dump (__func__, p, rib); + rib_dump (p, rib); } } @@ -1896,9 +1962,9 @@ void rib_lookup_and_pushup (struct prefix_ipv4 * p) struct rib *rib; 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; } @@ -1918,16 +1984,16 @@ void rib_lookup_and_pushup (struct prefix_ipv4 * p) */ 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)) { changed = 1; if (IS_ZEBRA_DEBUG_RIB) { - char buf[INET_ADDRSTRLEN]; - inet_ntop (rn->p.family, &p->prefix, buf, INET_ADDRSTRLEN); - zlog_debug ("%s: freeing way for connected prefix %s/%d", __func__, buf, p->prefixlen); - rib_dump (__func__, (struct prefix_ipv4 *)&rn->p, rib); + char buf[PREFIX_STRLEN]; + zlog_debug ("%s: freeing way for connected prefix %s", __func__, + prefix2str(&rn->p, buf, sizeof(buf))); + rib_dump (&rn->p, rib); } rib_uninstall (rn, rib); } @@ -1945,7 +2011,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct struct nexthop *nexthop; /* Lookup table. */ - table = vrf_table (AFI_IP, safi, 0); + table = zebra_vrf_table (AFI_IP, safi, rib->vrf_id); if (! table) return 0; @@ -1988,8 +2054,8 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct if (IS_ZEBRA_DEBUG_RIB) { zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry", - __func__, rn, rib); - rib_dump (__func__, p, rib); + __func__, (void *)rn, (void *)rib); + rib_dump (p, rib); } /* Free implicit route.*/ @@ -1998,8 +2064,8 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct if (IS_ZEBRA_DEBUG_RIB) { zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry", - __func__, rn, same); - rib_dump (__func__, p, same); + __func__, (void *)rn, (void *)same); + rib_dump (p, same); } rib_delnode (rn, same); } @@ -2011,31 +2077,39 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct /* XXX factor with rib_delete_ipv6 */ int 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_node *rn; struct rib *rib; struct rib *fib = NULL; struct rib *same = NULL; - struct nexthop *nexthop; - char buf1[INET_ADDRSTRLEN]; + struct nexthop *nexthop, *tnexthop; + int recursing; + char buf1[PREFIX_STRLEN]; char buf2[INET_ADDRSTRLEN]; /* Lookup table. */ - table = vrf_table (AFI_IP, safi, 0); + table = zebra_vrf_table (AFI_IP, safi, vrf_id); if (! table) return 0; /* Apply mask. */ apply_mask_ipv4 (p); - if (IS_ZEBRA_DEBUG_KERNEL && gate) - zlog_debug ("rib_delete_ipv4(): route delete %s/%d via %s ifindex %d", - inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), - p->prefixlen, - inet_ntoa (*gate), - ifindex); + if (IS_ZEBRA_DEBUG_KERNEL) + { + if (gate) + zlog_debug ("rib_delete_ipv4(): route delete %s vrf %u via %s ifindex %d", + prefix2str (p, buf1, sizeof(buf1)), vrf_id, + 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. */ rn = route_node_lookup (table, (struct prefix *) p); @@ -2044,15 +2118,13 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ip if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) - zlog_debug ("route %s/%d via %s ifindex %d doesn't exist in rib", - inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), - p->prefixlen, + zlog_debug ("route %s vrf %u via %s ifindex %d doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), vrf_id, inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN), ifindex); else - zlog_debug ("route %s/%d ifindex %d doesn't exist in rib", - inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), - p->prefixlen, + zlog_debug ("route %s vrf %u ifindex %d doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), vrf_id, ifindex); } return ZEBRA_ERR_RTNOEXIST; @@ -2064,7 +2136,7 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ip if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) fib = rib; if (rib->type != type) @@ -2085,16 +2157,23 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ip break; } /* Make sure that the route found has the same gateway. */ - else if (gate == NULL || - ((nexthop = rib->nexthop) && - (IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate) || - IPV4_ADDR_SAME (&nexthop->rgate.ipv4, gate)))) + else { - same = rib; - break; - } + if (gate == NULL) + { + 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 kernel. */ if (! same) @@ -2105,23 +2184,22 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ip for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); + UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB); } else { if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) - zlog_debug ("route %s/%d via %s ifindex %d type %d doesn't exist in rib", - inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), - p->prefixlen, + zlog_debug ("route %s vrf %u via %s ifindex %d type %d " + "doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), vrf_id, inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN), ifindex, type); else - zlog_debug ("route %s/%d ifindex %d type %d doesn't exist in rib", - inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), - p->prefixlen, + zlog_debug ("route %s vrf %u ifindex %d type %d doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), vrf_id, ifindex, type); } @@ -2136,17 +2214,17 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ip route_unlock_node (rn); return 0; } - + /* Install static route into rib. */ 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 route_node *rn; struct route_table *table; /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (afi, safi, si->vrf_id); if (! table) return; @@ -2168,15 +2246,24 @@ static_install_ipv4 (struct prefix *p, struct static_i route_unlock_node (rn); switch (si->type) { - case STATIC_IPV4_GATEWAY: - nexthop_ipv4_add (rib, &si->gate.ipv4, NULL); - break; - case STATIC_IPV4_IFNAME: - nexthop_ifname_add (rib, si->gate.ifname); - break; - case STATIC_IPV4_BLACKHOLE: - nexthop_blackhole_add (rib); - break; + case STATIC_IPV4_GATEWAY: + nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); + break; + case STATIC_IPV4_IFNAME: + nexthop_ifname_add (rib, si->ifname); + break; + case STATIC_IPV4_BLACKHOLE: + nexthop_blackhole_add (rib); + 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); } @@ -2188,20 +2275,30 @@ static_install_ipv4 (struct prefix *p, struct static_i rib->type = ZEBRA_ROUTE_STATIC; rib->distance = si->distance; rib->metric = 0; + rib->vrf_id = si->vrf_id; rib->table = zebrad.rtm_table_default; rib->nexthop_num = 0; switch (si->type) { - case STATIC_IPV4_GATEWAY: - nexthop_ipv4_add (rib, &si->gate.ipv4, NULL); - break; - case STATIC_IPV4_IFNAME: - nexthop_ifname_add (rib, si->gate.ifname); - break; - case STATIC_IPV4_BLACKHOLE: - nexthop_blackhole_add (rib); - break; + case STATIC_IPV4_GATEWAY: + nexthop_ipv4_add (rib, &si->addr.ipv4, NULL); + break; + case STATIC_IPV4_IFNAME: + nexthop_ifname_add (rib, si->ifname); + break; + case STATIC_IPV4_BLACKHOLE: + nexthop_blackhole_add (rib); + 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) */ @@ -2213,25 +2310,38 @@ static_install_ipv4 (struct prefix *p, struct static_i } 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 && 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; if (nexthop->type == NEXTHOP_TYPE_IFNAME && si->type == STATIC_IPV4_IFNAME - && strcmp (nexthop->ifname, si->gate.ifname) == 0) + && strcmp (nexthop->ifname, si->ifname) == 0) return 1; if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE && si->type == STATIC_IPV4_BLACKHOLE) return 1; + if (nexthop->type == NEXTHOP_TYPE_IPV6 + && si->type == STATIC_IPV6_GATEWAY + && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->addr.ipv6)) + return 1; + if (nexthop->type == NEXTHOP_TYPE_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; } /* Uninstall static route from RIB. */ 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 rib *rib; @@ -2239,7 +2349,7 @@ static_uninstall_ipv4 (struct prefix *p, struct static struct route_table *table; /* Lookup table. */ - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (afi, safi, si->vrf_id); if (! table) return; @@ -2265,7 +2375,7 @@ static_uninstall_ipv4 (struct prefix *p, struct static /* Lookup nexthop. */ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - if (static_ipv4_nexthop_same (nexthop, si)) + if (static_nexthop_same (nexthop, si)) break; /* Can't find nexthop. */ @@ -2290,21 +2400,20 @@ static_uninstall_ipv4 (struct prefix *p, struct static route_unlock_node (rn); } -/* Add static route into static route configuration. */ int -static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, - u_char flags, u_char distance, u_int32_t vrf_id) +static_add_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, + const char *ifname, u_char flags, u_char distance, + vrf_id_t vrf_id) { u_char type = 0; struct route_node *rn; - struct static_ipv4 *si; - struct static_ipv4 *pp; - struct static_ipv4 *cp; - struct static_ipv4 *update = NULL; - struct route_table *stable; + struct static_route *si; + struct static_route *pp; + struct static_route *cp; + struct static_route *update = NULL; + 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) return -1; @@ -2323,8 +2432,8 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gat for (si = rn->info; si; si = si->next) { if (type == si->type - && (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4)) - && (! ifname || strcmp (ifname, si->gate.ifname) == 0)) + && (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4)) + && (! ifname || strcmp (ifname, si->ifname) == 0)) { if (distance == si->distance) { @@ -2338,19 +2447,20 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gat /* Distance changed. */ 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. */ - si = XCALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4)); + si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route)); si->type = type; si->distance = distance; si->flags = flags; + si->vrf_id = vrf_id; if (gate) - si->gate.ipv4 = *gate; + si->addr.ipv4 = *gate; if (ifname) - si->gate.ifname = XSTRDUP (0, ifname); + si->ifname = XSTRDUP (0, ifname); /* Add new static route information to the tree with sort by distance value and gateway address. */ @@ -2362,9 +2472,9 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gat continue; 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; - 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; } } @@ -2380,23 +2490,22 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gat si->next = cp; /* Install into rib. */ - static_install_ipv4 (p, si); + static_install_route (AFI_IP, safi, p, si); return 1; } -/* Delete static route from static route configuration. */ int -static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, - u_char distance, u_int32_t vrf_id) +static_delete_ipv4_safi (safi_t safi, struct prefix *p, struct in_addr *gate, + const char *ifname, u_char distance, vrf_id_t vrf_id) { u_char type = 0; struct route_node *rn; - struct static_ipv4 *si; + struct static_route *si; struct route_table *stable; /* Lookup table. */ - stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id); + stable = zebra_vrf_static_table (AFI_IP, safi, vrf_id); if (! stable) return -1; @@ -2416,8 +2525,8 @@ static_delete_ipv4 (struct prefix *p, struct in_addr * /* Find same static route is the tree */ for (si = rn->info; si; si = si->next) if (type == si->type - && (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4)) - && (! ifname || strcmp (ifname, si->gate.ifname) == 0)) + && (! gate || IPV4_ADDR_SAME (gate, &si->addr.ipv4)) + && (! ifname || strcmp (ifname, si->ifname) == 0)) break; /* Can't find static route. */ @@ -2428,7 +2537,7 @@ static_delete_ipv4 (struct prefix *p, struct in_addr * } /* Install into rib. */ - static_uninstall_ipv4 (p, si); + static_uninstall_route (AFI_IP, safi, p, si); /* Unlink static route from linked list. */ if (si->prev) @@ -2441,41 +2550,19 @@ static_delete_ipv4 (struct prefix *p, struct in_addr * /* Free static route configuration. */ if (ifname) - XFREE (0, si->gate.ifname); - XFREE (MTYPE_STATIC_IPV4, si); + XFREE (0, si->ifname); + XFREE (MTYPE_STATIC_ROUTE, si); route_unlock_node (rn); 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 rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, - struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id, - u_int32_t metric, u_char distance, safi_t safi) + struct in6_addr *gate, ifindex_t ifindex, + 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 *same = NULL; @@ -2484,7 +2571,7 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 struct nexthop *nexthop; /* Lookup table. */ - table = vrf_table (AFI_IP6, safi, 0); + table = zebra_vrf_table (AFI_IP6, safi, vrf_id); if (! table) return 0; @@ -2498,10 +2585,6 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP)) distance = 200; - /* Filter bogus route. */ - if (rib_bogus_ipv6 (type, p, gate, ifindex, 0)) - return 0; - /* Lookup route node.*/ rn = route_node_get (table, (struct prefix *) p); @@ -2535,7 +2618,9 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 rib->distance = distance; rib->flags = flags; rib->metric = metric; - rib->table = vrf_id; + rib->mtu = mtu; + rib->vrf_id = vrf_id; + rib->table = table_id; rib->nexthop_num = 0; rib->uptime = time (NULL); @@ -2557,10 +2642,24 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 /* Link new rib to node.*/ 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.*/ 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); + } route_unlock_node (rn); return 0; @@ -2569,22 +2668,24 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 /* XXX factor with rib_delete_ipv6 */ int 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_node *rn; struct rib *rib; struct rib *fib = NULL; struct rib *same = NULL; - struct nexthop *nexthop; - char buf1[INET6_ADDRSTRLEN]; + struct nexthop *nexthop, *tnexthop; + int recursing; + char buf1[PREFIX_STRLEN]; char buf2[INET6_ADDRSTRLEN]; /* Apply mask. */ apply_mask_ipv6 (p); /* Lookup table. */ - table = vrf_table (AFI_IP6, safi, 0); + table = zebra_vrf_table (AFI_IP6, safi, vrf_id); if (! table) return 0; @@ -2595,15 +2696,13 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ip if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) - zlog_debug ("route %s/%d via %s ifindex %d doesn't exist in rib", - inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN), - p->prefixlen, + zlog_debug ("route %s vrf %u via %s ifindex %d doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), vrf_id, inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN), ifindex); else - zlog_debug ("route %s/%d ifindex %d doesn't exist in rib", - inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN), - p->prefixlen, + zlog_debug ("route %s vrf %u ifindex %d doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), vrf_id, ifindex); } return ZEBRA_ERR_RTNOEXIST; @@ -2615,7 +2714,7 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ip if (CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED)) continue; - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) fib = rib; if (rib->type != type) @@ -2636,14 +2735,22 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ip break; } /* Make sure that the route found has the same gateway. */ - else if (gate == NULL || - ((nexthop = rib->nexthop) && - (IPV6_ADDR_SAME (&nexthop->gate.ipv6, gate) || - IPV6_ADDR_SAME (&nexthop->rgate.ipv6, gate)))) - { - same = rib; - break; - } + else + { + if (gate == NULL) + { + same = rib; + 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 @@ -2656,23 +2763,22 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ip for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); + UNSET_FLAG (fib->status, RIB_ENTRY_SELECTED_FIB); } else { if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) - zlog_debug ("route %s/%d via %s ifindex %d type %d doesn't exist in rib", - inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN), - p->prefixlen, + zlog_debug ("route %s vrf %u via %s ifindex %d type %d " + "doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), vrf_id, inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN), ifindex, type); else - zlog_debug ("route %s/%d ifindex %d type %d doesn't exist in rib", - inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN), - p->prefixlen, + zlog_debug ("route %s vrf %u ifindex %d type %d doesn't exist in rib", + prefix2str (p, buf1, sizeof(buf1)), vrf_id, ifindex, type); } @@ -2687,177 +2793,22 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ip route_unlock_node (rn); 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); - RNODE_FOREACH_RIB (rn, rib) - { - if (CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED)) - continue; - - if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) - break; - } - - if (rib) - { - /* 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; - - RNODE_FOREACH_RIB (rn, rib) - { - if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) - continue; - - if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) - break; - } - - if (! rib) - { - 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. */ int static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, const char *ifname, u_char flags, u_char distance, - u_int32_t vrf_id) + vrf_id_t vrf_id) { struct route_node *rn; - struct static_ipv6 *si; - struct static_ipv6 *pp; - struct static_ipv6 *cp; - struct route_table *stable; + struct static_route *si; + struct static_route *pp; + struct static_route *cp; + 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) return -1; @@ -2875,33 +2826,41 @@ static_add_ipv6 (struct prefix *p, u_char type, struct /* Do nothing if there is a same static route. */ for (si = rn->info; si; si = si->next) { - if (distance == si->distance - && type == si->type - && (! gate || IPV6_ADDR_SAME (gate, &si->ipv6)) + if (type == si->type + && (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6)) && (! ifname || strcmp (ifname, si->ifname) == 0)) { - route_unlock_node (rn); - return 0; + if (distance == si->distance) + { + 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. */ - si = XCALLOC (MTYPE_STATIC_IPV6, sizeof (struct static_ipv6)); + si = XCALLOC (MTYPE_STATIC_ROUTE, sizeof (struct static_route)); si->type = type; si->distance = distance; si->flags = flags; + si->vrf_id = vrf_id; switch (type) { case STATIC_IPV6_GATEWAY: - si->ipv6 = *gate; + si->addr.ipv6 = *gate; break; case STATIC_IPV6_IFNAME: si->ifname = XSTRDUP (0, ifname); break; case STATIC_IPV6_GATEWAY_IFNAME: - si->ipv6 = *gate; + si->addr.ipv6 = *gate; si->ifname = XSTRDUP (0, ifname); break; } @@ -2927,7 +2886,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct si->next = cp; /* Install into rib. */ - static_install_ipv6 (p, si); + static_install_route (AFI_IP6, SAFI_UNICAST, p, si); return 1; } @@ -2935,14 +2894,14 @@ static_add_ipv6 (struct prefix *p, u_char type, struct /* Delete static route from static route configuration. */ int static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - const char *ifname, u_char distance, u_int32_t vrf_id) + const char *ifname, u_char distance, vrf_id_t vrf_id) { struct route_node *rn; - struct static_ipv6 *si; + struct static_route *si; struct route_table *stable; /* 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) return -1; @@ -2955,7 +2914,7 @@ static_delete_ipv6 (struct prefix *p, u_char type, str for (si = rn->info; si; si = si->next) if (distance == si->distance && type == si->type - && (! gate || IPV6_ADDR_SAME (gate, &si->ipv6)) + && (! gate || IPV6_ADDR_SAME (gate, &si->addr.ipv6)) && (! ifname || strcmp (ifname, si->ifname) == 0)) break; @@ -2967,7 +2926,7 @@ static_delete_ipv6 (struct prefix *p, u_char type, str } /* Install into rib. */ - static_uninstall_ipv6 (p, si); + static_uninstall_route (AFI_IP6, SAFI_UNICAST, p, si); /* Unlink static route from linked list. */ if (si->prev) @@ -2980,33 +2939,32 @@ static_delete_ipv6 (struct prefix *p, u_char type, str /* Free static route configuration. */ if (ifname) XFREE (0, si->ifname); - XFREE (MTYPE_STATIC_IPV6, si); + XFREE (MTYPE_STATIC_ROUTE, si); return 1; } -#endif /* HAVE_IPV6 */ - + /* RIB update function. */ void -rib_update (void) +rib_update (vrf_id_t vrf_id) { struct route_node *rn; struct route_table *table; - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) if (rnode_to_ribs (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) for (rn = route_top (table); rn; rn = route_next (rn)) if (rnode_to_ribs (rn)) rib_queue_add (&zebrad, rn); } - + /* Remove all routes which comes from non main table. */ static void rib_weed_table (struct route_table *table) @@ -3032,10 +2990,18 @@ rib_weed_table (struct route_table *table) void rib_weed_tables (void) { - rib_weed_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); - rib_weed_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); + vrf_iter_t iter; + 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. */ static void rib_sweep_table (struct route_table *table) @@ -3055,19 +3021,27 @@ rib_sweep_table (struct route_table *table) if (rib->type == ZEBRA_ROUTE_KERNEL && CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELFROUTE)) { - ret = rib_uninstall_kernel (rn, rib); + ret = rib_update_kernel (rn, rib, NULL); if (! ret) rib_delnode (rn, rib); } } } +#endif /* Sweep all RIB tables. */ void rib_sweep_route (void) { - rib_sweep_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); - rib_sweep_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); + vrf_iter_t iter; + 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'. */ @@ -3099,28 +3073,38 @@ rib_score_proto_table (u_char proto, struct route_tabl unsigned long rib_score_proto (u_char proto) { - return rib_score_proto_table (proto, vrf_table (AFI_IP, SAFI_UNICAST, 0)) - +rib_score_proto_table (proto, vrf_table (AFI_IP6, SAFI_UNICAST, 0)); + vrf_iter_t iter; + 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. */ -static void +void rib_close_table (struct route_table *table) { struct route_node *rn; + rib_table_info_t *info = table->info; struct rib *rib; if (table) for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) { - if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + if (!CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB)) continue; - zfpm_trigger_update (rn, NULL); + if (info->safi == SAFI_UNICAST) + zfpm_trigger_update (rn, NULL); if (! RIB_SYSTEM_ROUTE (rib)) - rib_uninstall_kernel (rn, rib); + rib_update_kernel (rn, rib, NULL); } } @@ -3128,17 +3112,22 @@ rib_close_table (struct route_table *table) void rib_close (void) { - rib_close_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); - rib_close_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); + vrf_iter_t iter; + 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. */ void rib_init (void) { rib_queue_init (&zebrad); - /* VRF initialization. */ - vrf_init (); } /* @@ -3149,15 +3138,19 @@ rib_init (void) * Returns TRUE if a vrf id was found, FALSE otherwise. */ static inline int -vrf_id_get_next (uint32_t id, uint32_t *next_id_p) +vrf_id_get_next (vrf_id_t vrf_id, vrf_id_t *next_id_p) { - while (++id < vector_active (vrf_vector)) + 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) { - if (vrf_lookup (id)) - { - *next_id_p = id; - return 1; - } + *next_id_p = zvrf->vrf_id; + return 1; } return 0; @@ -3193,7 +3186,7 @@ rib_tables_iter_next (rib_tables_iter_t *iter) { case RIB_TABLES_ITER_S_INIT: - iter->vrf_id = 0; + iter->vrf_id = VRF_DEFAULT; iter->afi_safi_ix = -1; /* Fall through */ @@ -3205,7 +3198,7 @@ rib_tables_iter_next (rib_tables_iter_t *iter) while (iter->afi_safi_ix < (int) ZEBRA_NUM_OF (afi_safis)) { - table = vrf_table (afi_safis[iter->afi_safi_ix].afi, + table = zebra_vrf_table (afi_safis[iter->afi_safi_ix].afi, afi_safis[iter->afi_safi_ix].safi, iter->vrf_id); if (table) @@ -3243,3 +3236,93 @@ rib_tables_iter_next (rib_tables_iter_t *iter) 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]; +} +