memcpy (&p.prefix, dest, 4);
p.prefixlen = rtm->rtm_dst_len;
- rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0, SAFI_UNICAST);
+ if (!tb[RTA_MULTIPATH])
+ rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index,
- table, metric, 0);
++ table, metric, 0, SAFI_UNICAST);
+ else
+ {
+ /* This is a multipath route */
+
+ struct rib *rib;
+ struct rtnexthop *rtnh =
+ (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
+
+ len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
+
+ rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
+ rib->type = ZEBRA_ROUTE_KERNEL;
+ rib->distance = 0;
+ rib->flags = flags;
+ rib->metric = metric;
+ rib->table = table;
+ rib->nexthop_num = 0;
+ rib->uptime = time (NULL);
+
+ for (;;)
+ {
+ if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
+ break;
+
+ rib->nexthop_num++;
+ index = rtnh->rtnh_ifindex;
+ gate = 0;
+ if (rtnh->rtnh_len > sizeof (*rtnh))
+ {
+ memset (tb, 0, sizeof (tb));
+ netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
+ rtnh->rtnh_len - sizeof (*rtnh));
+ if (tb[RTA_GATEWAY])
+ gate = RTA_DATA (tb[RTA_GATEWAY]);
+ }
+
+ if (gate)
+ {
+ if (index)
+ nexthop_ipv4_ifindex_add (rib, gate, src, index);
+ else
+ nexthop_ipv4_add (rib, gate, src);
+ }
+ else
+ nexthop_ifindex_add (rib, index);
+
+ len -= NLMSG_ALIGN(rtnh->rtnh_len);
+ rtnh = RTNH_NEXT(rtnh);
+ }
+
+ if (rib->nexthop_num == 0)
+ XFREE (MTYPE_RIB, rib);
+ else
- rib_add_ipv4_multipath (&p, rib);
++ rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST);
+ }
}
#ifdef HAVE_IPV6
if (rtm->rtm_family == AF_INET6)
}
if (h->nlmsg_type == RTM_NEWROUTE)
- rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, metric, 0, SAFI_UNICAST);
+ {
+ if (!tb[RTA_MULTIPATH])
+ rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table,
- metric, 0);
++ metric, 0, SAFI_UNICAST);
+ else
+ {
+ /* This is a multipath route */
+
+ struct rib *rib;
+ struct rtnexthop *rtnh =
+ (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
+
+ len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
+
+ rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
+ rib->type = ZEBRA_ROUTE_KERNEL;
+ rib->distance = 0;
+ rib->flags = 0;
+ rib->metric = metric;
+ rib->table = table;
+ rib->nexthop_num = 0;
+ rib->uptime = time (NULL);
+
+ for (;;)
+ {
+ if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
+ break;
+
+ rib->nexthop_num++;
+ index = rtnh->rtnh_ifindex;
+ gate = 0;
+ if (rtnh->rtnh_len > sizeof (*rtnh))
+ {
+ memset (tb, 0, sizeof (tb));
+ netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
+ rtnh->rtnh_len - sizeof (*rtnh));
+ if (tb[RTA_GATEWAY])
+ gate = RTA_DATA (tb[RTA_GATEWAY]);
+ }
+
+ if (gate)
+ {
+ if (index)
+ nexthop_ipv4_ifindex_add (rib, gate, src, index);
+ else
+ nexthop_ipv4_add (rib, gate, src);
+ }
+ else
+ nexthop_ifindex_add (rib, index);
+
+ len -= NLMSG_ALIGN(rtnh->rtnh_len);
+ rtnh = RTNH_NEXT(rtnh);
+ }
+
+ if (rib->nexthop_num == 0)
+ XFREE (MTYPE_RIB, rib);
+ else
- rib_add_ipv4_multipath (&p, rib);
++ rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST);
+ }
+ }
else
- rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
+ rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST);
}
#ifdef HAVE_IPV6
rib_sweep_table (vrf_table (AFI_IP, SAFI_UNICAST, 0));
rib_sweep_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0));
}
+\f
+/* Delete routes learned from a given client. */
+/* TODO(wsun) May need to split the sweep process into multiple batches,
+ * so that the process won't take too long if the table is large. */
+static void
+rib_sweep_client_table (struct route_table *table, int rib_type)
+{
+ struct route_node *rn;
+ struct rib *rib;
+ struct rib *next;
+ int ret = 0;
+
+ if (table)
+ for (rn = route_top (table); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = next)
+ {
+ next = rib->next;
+
+ if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
+ continue;
+
+ if (rib->type == rib_type)
+ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+ {
+ /* TODO(wsun) Is this mandatory? What about graceful restart/
+ * non-stop forwarding */
+ ret = rib_uninstall_kernel (rn, rib);
+ if (! ret)
+ rib_delnode (rn, rib);
+ else
+ zlog_err ("%s: could not delete routes from kernel!",
+ __func__);
+ }
+ else
+ {
+ /* Always delete the node. */
+ rib_delnode (rn, rib);
+ }
+ }
+}
+
+/* Sweep all routes learned from a given client from RIB tables. */
+void
+rib_sweep_client_route (struct zserv *client)
+{
+ assert(client);
+ int route_type = client->route_type;
+ if (route_type != ZEBRA_ROUTE_MAX)
+ {
+ zlog_debug ("%s: Removing existing routes from client type %d",
+ __func__, route_type);
+ rib_sweep_client_table (vrf_table (AFI_IP, SAFI_UNICAST, 0), route_type);
+ rib_sweep_client_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0), route_type);
+ }
+}
+\f
+
+ /* Remove specific by protocol routes from 'table'. */
+ static unsigned long
+ rib_score_proto_table (u_char proto, struct route_table *table)
+ {
+ struct route_node *rn;
+ struct rib *rib;
+ struct rib *next;
+ unsigned long n = 0;
+
+ if (table)
+ for (rn = route_top (table); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = next)
+ {
+ next = rib->next;
+ if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
+ continue;
+ if (rib->type == proto)
+ {
+ rib_delnode (rn, rib);
+ n++;
+ }
+ }
+
+ return n;
+ }
+
+ /* Remove specific by protocol routes. */
+ 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));
+ }
+
/* Close RIB and clean up kernel routes. */
static void
rib_close_table (struct route_table *table)
/* Type, flags, message. */
rib->type = stream_getc (s);
+ /* Update client's route type if it is not done yet. */
+ /* It is done here since only zread_ipv4/6_add() and
+ * zread_ipv4/6_delete() decode Zebra messages and retrieve
+ * route types. */
+ if (client->route_type == ZEBRA_ROUTE_MAX)
+ client->route_type = rib->type;
+
rib->flags = stream_getc (s);
message = stream_getc (s);
+ safi = stream_getw (s);
rib->uptime = time (NULL);
/* IPv4 prefix. */
else
api.metric = 0;
- rib_delete_ipv4 (api.type, api.flags, &p, &nexthop, ifindex,
+ rib_delete_ipv4 (api.type, api.flags, &p, nexthop_p, ifindex,
- client->rtm_table);
+ client->rtm_table, api.safi);
return 0;
}
/* Type, flags, message. */
api.type = stream_getc (s);
+ /* Update the route type of the client.
+ * Same as in zread_ipv4_add(). */
+ if (client->route_type == ZEBRA_ROUTE_MAX)
+ client->route_type = api.type;
+
api.flags = stream_getc (s);
api.message = stream_getc (s);
+ api.safi = stream_getw (s);
/* IPv4 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv6));