#ifdef HAVE_IPV6
extern struct nexthop *nexthop_ipv6_add (struct rib *, struct in6_addr *);
+extern struct nexthop *nexthop_ipv6_ifindex_add (struct rib *rib,
+ struct in6_addr *ipv6, unsigned int ifindex);
+extern struct nexthop *nexthop_ipv6_ifname_add (struct rib *rib,
+ struct in6_addr *ipv6,
+ char *ifname);
+extern int
+rib_bogus_ipv6 (int type, struct prefix_ipv6 *p,
+ struct in6_addr *gate, unsigned int ifindex, int table);
#endif /* HAVE_IPV6 */
extern struct vrf *vrf_lookup (u_int32_t);
const char *ifname, u_char flags, u_char distance,
u_int32_t vrf_id);
+extern int
+rib_add_ipv6_multipath (struct prefix_ipv6 *, struct rib *, safi_t,
+ unsigned long);
+
extern 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);
return nexthop;
}
-static struct nexthop *
+struct nexthop *
nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6,
char *ifname)
{
return nexthop;
}
-static struct nexthop *
+struct nexthop *
nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6,
unsigned int ifindex)
{
#ifdef HAVE_IPV6
-static int
+int
rib_bogus_ipv6 (int type, struct prefix_ipv6 *p,
struct in6_addr *gate, unsigned int ifindex, int table)
{
return 0;
}
+int
+rib_add_ipv6_multipath (struct prefix_ipv6 *p, struct rib *rib, safi_t safi,
+ unsigned long ifindex)
+{
+ struct route_table *table;
+ struct route_node *rn;
+ struct rib *same = NULL;
+ struct nexthop *nexthop;
+ int ret = 0;
+ int table_id = 0;
+
+ if (rib)
+ table_id = rib->table;
+ else
+ return 0; /* why are we getting called with NULL rib */
+
+ /* Lookup table. */
+ table = vrf_table (AFI_IP6, safi, 0);
+
+ if (! table)
+ return 0;
+
+ /* Make sure mask is applied. */
+ apply_mask_ipv6 (p);
+
+ /* Set default distance by route type. */
+ if (rib->distance == 0)
+ {
+ rib->distance = route_info[rib->type].distance;
+
+ /* iBGP distance is 200. */
+ if (rib->type == ZEBRA_ROUTE_BGP
+ && CHECK_FLAG (rib->flags, ZEBRA_FLAG_IBGP))
+ rib->distance = 200;
+ }
+
+ /* Lookup route node.*/
+ rn = route_node_get (table, (struct prefix *) p);
+
+ /* If same type of route are installed, treat it as a implicit
+ withdraw. */
+ RNODE_FOREACH_RIB (rn, same) {
+ if (CHECK_FLAG (same->status, RIB_ENTRY_REMOVED)) {
+ continue;
+ }
+ if (same->type != rib->type) {
+ continue;
+ }
+
+ if (same->table != rib->table) {
+ continue;
+ }
+ if (same->type != ZEBRA_ROUTE_CONNECT) {
+ break;
+ }
+ else if ((nexthop = same->nexthop) &&
+ nexthop->type == NEXTHOP_TYPE_IFINDEX &&
+ nexthop->ifindex == ifindex) {
+ same->refcnt++;
+ return 0;
+ }
+ }
+
+ /* If this route is kernel route, set FIB flag to the route. */
+ if (rib->type == ZEBRA_ROUTE_KERNEL || rib->type == ZEBRA_ROUTE_CONNECT) {
+ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) {
+ SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
+ }
+ }
+
+ /* Link new rib to node.*/
+ rib_addnode (rn, rib);
+ ret = 1;
+ /* Free implicit route.*/
+ if (same)
+ {
+ if (IS_ZEBRA_DEBUG_RIB)
+ {
+ zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry",
+ __func__, rn, same);
+ rib_dump ((struct prefix *)p, same);
+ }
+ rib_delnode (rn, same);
+ ret = -1;
+ }
+
+ route_unlock_node (rn);
+ return ret;
+}
+
/* XXX factor with rib_delete_ipv6 */
int
rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
{
int i;
struct stream *s;
- struct zapi_ipv6 api;
struct in6_addr nexthop;
+ struct rib *rib;
+ u_char message;
+ u_char nexthop_num;
+ u_char nexthop_type;
unsigned long ifindex;
struct prefix_ipv6 p;
-
+ u_char ifname_len;
+ safi_t safi;
+ static struct in6_addr nexthops[MULTIPATH_NUM];
+ static unsigned int ifindices[MULTIPATH_NUM];
+
+ /* Get input stream. */
s = client->ibuf;
+
ifindex = 0;
memset (&nexthop, 0, sizeof (struct in6_addr));
+ /* Allocate new rib. */
+ rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
+
/* Type, flags, message. */
- api.type = stream_getc (s);
- api.flags = stream_getc (s);
- api.message = stream_getc (s);
- api.safi = stream_getw (s);
+ rib->type = stream_getc (s);
+ rib->flags = stream_getc (s);
+ message = stream_getc (s);
+ safi = stream_getw (s);
+ rib->uptime = time (NULL);
- /* IPv4 prefix. */
+ /* IPv6 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv6));
p.family = AF_INET6;
p.prefixlen = stream_getc (s);
stream_get (&p.prefix, s, PSIZE (p.prefixlen));
- /* Nexthop, ifindex, distance, metric. */
- if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+ /* We need to give nh-addr, nh-ifindex with the same next-hop object
+ * to the rib to ensure that IPv6 multipathing works; need to coalesce
+ * these. Clients should send the same number of paired set of
+ * next-hop-addr/next-hop-ifindices. */
+ if (CHECK_FLAG (message, ZAPI_MESSAGE_NEXTHOP))
{
- u_char nexthop_type;
+ int nh_count = 0;
+ int if_count = 0;
+ int max_nh_if = 0;
- api.nexthop_num = stream_getc (s);
- for (i = 0; i < api.nexthop_num; i++)
+ nexthop_num = stream_getc (s);
+ for (i = 0; i < nexthop_num; i++)
{
nexthop_type = stream_getc (s);
{
case ZEBRA_NEXTHOP_IPV6:
stream_get (&nexthop, s, 16);
+ if (nh_count < MULTIPATH_NUM) {
+ nexthops[nh_count++] = nexthop;
+ }
break;
case ZEBRA_NEXTHOP_IFINDEX:
- ifindex = stream_getl (s);
+ if (if_count < MULTIPATH_NUM) {
+ ifindices[if_count++] = stream_getl (s);
+ }
break;
}
}
+
+ max_nh_if = (nh_count > if_count) ? nh_count : if_count;
+ for (i = 0; i < max_nh_if; i++)
+ {
+ if ((i < nh_count) && !IN6_IS_ADDR_UNSPECIFIED (&nexthops[i])) {
+ if ((i < if_count) && ifindices[i]) {
+ if (rib_bogus_ipv6 (rib->type, &p, &nexthops[i], ifindices[i], 0)) {
+ continue;
+ }
+ nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]);
+ }
+ else {
+ if (rib_bogus_ipv6 (rib->type, &p, &nexthops[i], 0, 0)) {
+ continue;
+ }
+ nexthop_ipv6_add (rib, &nexthops[i]);
+ }
+ }
+ else {
+ if ((i < if_count) && ifindices[i]) {
+ if (rib_bogus_ipv6 (rib->type, &p, NULL, ifindices[i], 0)) {
+ continue;
+ }
+ nexthop_ifindex_add (rib, ifindices[i]);
+ }
+ }
+ }
}
- if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
- api.distance = stream_getc (s);
- else
- api.distance = 0;
+ /* Distance. */
+ if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE))
+ rib->distance = stream_getc (s);
- if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
- api.metric = stream_getl (s);
- else
- api.metric = 0;
+ /* Metric. */
+ if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC))
+ rib->metric = stream_getl (s);
- if (IN6_IS_ADDR_UNSPECIFIED (&nexthop))
- rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex, zebrad.rtm_table_default, api.metric,
- api.distance, api.safi);
- else
- rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, zebrad.rtm_table_default, api.metric,
- api.distance, api.safi);
+ /* Table */
+ rib->table=zebrad.rtm_table_default;
+ rib_add_ipv6_multipath (&p, rib, safi, ifindex);
return 0;
}