0);
}
-/* Routing table change via netlink interface. */
-/* Update flag indicates whether this is a "replace" or not. */
-static int netlink_route_multipath(int cmd, const struct prefix *p,
- const struct prefix *src_p,
- struct route_entry *re,
- int update)
-{
- int bytelen;
- struct sockaddr_nl snl;
- struct nexthop *nexthop = NULL;
- unsigned int nexthop_num;
- int family = PREFIX_FAMILY(p);
- const char *routedesc;
- int setsrc = 0;
- union g_addr src;
-
- struct {
- struct nlmsghdr n;
- struct rtmsg r;
- char buf[NL_PKT_BUF_SIZE];
- } req;
-
- struct zebra_ns *zns;
- struct zebra_vrf *zvrf = vrf_info_lookup(re->vrf_id);
-
- zns = zvrf->zns;
- memset(&req, 0, sizeof req - NL_PKT_BUF_SIZE);
-
- bytelen = (family == AF_INET ? 4 : 16);
-
- req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
- req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
- if ((cmd == RTM_NEWROUTE) && update)
- req.n.nlmsg_flags |= NLM_F_REPLACE;
- req.n.nlmsg_type = cmd;
- req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid;
-
- req.r.rtm_family = family;
- req.r.rtm_dst_len = p->prefixlen;
- req.r.rtm_src_len = src_p ? src_p->prefixlen : 0;
- req.r.rtm_protocol = zebra2proto(re->type);
- req.r.rtm_scope = RT_SCOPE_UNIVERSE;
-
- /*
- * blackhole routes are not RTN_UNICAST, they are
- * RTN_ BLACKHOLE|UNREACHABLE|PROHIBIT
- * so setting this value as a RTN_UNICAST would
- * cause the route lookup of just the prefix
- * to fail. So no need to specify this for
- * the RTM_DELROUTE case
- */
- if (cmd != RTM_DELROUTE)
- req.r.rtm_type = RTN_UNICAST;
-
- addattr_l(&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
- if (src_p)
- addattr_l(&req.n, sizeof req, RTA_SRC, &src_p->u.prefix,
- bytelen);
-
- /* Metric. */
- /* Hardcode the metric for all routes coming from zebra. Metric isn't
- * used
- * either by the kernel or by zebra. Its purely for calculating best
- * path(s)
- * by the routing protocol and for communicating with protocol peers.
- */
- addattr32(&req.n, sizeof req, RTA_PRIORITY, NL_DEFAULT_ROUTE_METRIC);
-#if defined(SUPPORT_REALMS)
- if (re->tag > 0 && re->tag <= 255)
- addattr32(&req.n, sizeof req, RTA_FLOW, re->tag);
-#endif
- /* Table corresponding to this route. */
- if (re->table < 256)
- req.r.rtm_table = re->table;
- else {
- req.r.rtm_table = RT_TABLE_UNSPEC;
- addattr32(&req.n, sizeof req, RTA_TABLE, re->table);
- }
-
- _netlink_route_debug(cmd, p, family, zvrf_id(zvrf), re->table);
-
- /*
- * If we are not updating the route and we have received
- * a route delete, then all we need to fill in is the
- * prefix information to tell the kernel to schwack
- * it.
- */
- if (!update && cmd == RTM_DELROUTE)
- goto skip;
-
- if (re->mtu || re->nexthop_mtu) {
- char buf[NL_PKT_BUF_SIZE];
- struct rtattr *rta = (void *)buf;
- uint32_t mtu = re->mtu;
- if (!mtu || (re->nexthop_mtu && re->nexthop_mtu < mtu))
- mtu = re->nexthop_mtu;
- rta->rta_type = RTA_METRICS;
- rta->rta_len = RTA_LENGTH(0);
- rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTAX_MTU, &mtu, sizeof mtu);
- addattr_l(&req.n, NL_PKT_BUF_SIZE, RTA_METRICS, RTA_DATA(rta),
- RTA_PAYLOAD(rta));
- }
-
- /* Count overall nexthops so we can decide whether to use singlepath
- * or multipath case. */
- nexthop_num = 0;
- for (ALL_NEXTHOPS(re->ng, nexthop)) {
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- continue;
- if (cmd == RTM_NEWROUTE && !NEXTHOP_IS_ACTIVE(nexthop->flags))
- continue;
- if (cmd == RTM_DELROUTE
- && !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
- continue;
-
- nexthop_num++;
- }
-
- /* Singlepath case. */
- if (nexthop_num == 1 || multipath_num == 1) {
- nexthop_num = 0;
- for (ALL_NEXTHOPS(re->ng, nexthop)) {
- /*
- * So we want to cover 2 types of blackhole
- * routes here:
- * 1) A normal blackhole route( ala from a static
- * install.
- * 2) A recursively resolved blackhole route
- */
- if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) {
- switch (nexthop->bh_type) {
- case BLACKHOLE_ADMINPROHIB:
- req.r.rtm_type = RTN_PROHIBIT;
- break;
- case BLACKHOLE_REJECT:
- req.r.rtm_type = RTN_UNREACHABLE;
- break;
- default:
- req.r.rtm_type = RTN_BLACKHOLE;
- break;
- }
- goto skip;
- }
- if (CHECK_FLAG(nexthop->flags,
- NEXTHOP_FLAG_RECURSIVE)) {
- if (!setsrc) {
- if (family == AF_INET) {
- if (nexthop->rmap_src.ipv4
- .s_addr
- != 0) {
- src.ipv4 =
- nexthop->rmap_src
- .ipv4;
- setsrc = 1;
- } else if (nexthop->src.ipv4
- .s_addr
- != 0) {
- src.ipv4 =
- nexthop->src
- .ipv4;
- setsrc = 1;
- }
- } else if (family == AF_INET6) {
- if (!IN6_IS_ADDR_UNSPECIFIED(
- &nexthop->rmap_src
- .ipv6)) {
- src.ipv6 =
- nexthop->rmap_src
- .ipv6;
- setsrc = 1;
- } else if (
- !IN6_IS_ADDR_UNSPECIFIED(
- &nexthop->src
- .ipv6)) {
- src.ipv6 =
- nexthop->src
- .ipv6;
- setsrc = 1;
- }
- }
- }
- continue;
- }
-
- if ((cmd == RTM_NEWROUTE
- && NEXTHOP_IS_ACTIVE(nexthop->flags))
- || (cmd == RTM_DELROUTE
- && CHECK_FLAG(nexthop->flags,
- NEXTHOP_FLAG_FIB))) {
- routedesc = nexthop->rparent
- ? "recursive, single-path"
- : "single-path";
-
- _netlink_route_build_singlepath(
- routedesc, bytelen, nexthop, &req.n,
- &req.r, sizeof req, cmd);
- nexthop_num++;
- break;
- }
- }
- if (setsrc && (cmd == RTM_NEWROUTE)) {
- if (family == AF_INET)
- addattr_l(&req.n, sizeof req, RTA_PREFSRC,
- &src.ipv4, bytelen);
- else if (family == AF_INET6)
- addattr_l(&req.n, sizeof req, RTA_PREFSRC,
- &src.ipv6, bytelen);
- }
- } else { /* Multipath case */
- char buf[NL_PKT_BUF_SIZE];
- struct rtattr *rta = (void *)buf;
- struct rtnexthop *rtnh;
- union g_addr *src1 = NULL;
-
- rta->rta_type = RTA_MULTIPATH;
- rta->rta_len = RTA_LENGTH(0);
- rtnh = RTA_DATA(rta);
-
- nexthop_num = 0;
- for (ALL_NEXTHOPS(re->ng, nexthop)) {
- if (nexthop_num >= multipath_num)
- break;
-
- if (CHECK_FLAG(nexthop->flags,
- NEXTHOP_FLAG_RECURSIVE)) {
- /* This only works for IPv4 now */
- if (!setsrc) {
- if (family == AF_INET) {
- if (nexthop->rmap_src.ipv4
- .s_addr
- != 0) {
- src.ipv4 =
- nexthop->rmap_src
- .ipv4;
- setsrc = 1;
- } else if (nexthop->src.ipv4
- .s_addr
- != 0) {
- src.ipv4 =
- nexthop->src
- .ipv4;
- setsrc = 1;
- }
- } else if (family == AF_INET6) {
- if (!IN6_IS_ADDR_UNSPECIFIED(
- &nexthop->rmap_src
- .ipv6)) {
- src.ipv6 =
- nexthop->rmap_src
- .ipv6;
- setsrc = 1;
- } else if (
- !IN6_IS_ADDR_UNSPECIFIED(
- &nexthop->src
- .ipv6)) {
- src.ipv6 =
- nexthop->src
- .ipv6;
- setsrc = 1;
- }
- }
- }
- continue;
- }
-
- if ((cmd == RTM_NEWROUTE
- && NEXTHOP_IS_ACTIVE(nexthop->flags))
- || (cmd == RTM_DELROUTE
- && CHECK_FLAG(nexthop->flags,
- NEXTHOP_FLAG_FIB))) {
- routedesc = nexthop->rparent
- ? "recursive, multipath"
- : "multipath";
- nexthop_num++;
-
- _netlink_route_build_multipath(
- routedesc, bytelen, nexthop, rta, rtnh,
- &req.r, &src1);
- rtnh = RTNH_NEXT(rtnh);
-
- if (!setsrc && src1) {
- if (family == AF_INET)
- src.ipv4 = src1->ipv4;
- else if (family == AF_INET6)
- src.ipv6 = src1->ipv6;
-
- setsrc = 1;
- }
- }
- }
- if (setsrc && (cmd == RTM_NEWROUTE)) {
- if (family == AF_INET)
- addattr_l(&req.n, sizeof req, RTA_PREFSRC,
- &src.ipv4, bytelen);
- else if (family == AF_INET6)
- addattr_l(&req.n, sizeof req, RTA_PREFSRC,
- &src.ipv6, bytelen);
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("Setting source");
- }
-
- if (rta->rta_len > RTA_LENGTH(0))
- addattr_l(&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH,
- RTA_DATA(rta), RTA_PAYLOAD(rta));
- }
-
- /* If there is no useful nexthop then return. */
- if (nexthop_num == 0) {
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug(
- "netlink_route_multipath(): No useful nexthop.");
- return 0;
- }
-
-skip:
-
- /* Destination netlink address. */
- memset(&snl, 0, sizeof snl);
- snl.nl_family = AF_NETLINK;
-
- /* Talk to netlink socket. */
- return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
- 0);
-}
-
/*
* Routing table change via netlink interface, using a dataplane context object
*/
-static int netlink_route_multipath_ctx(int cmd, dplane_ctx_h ctx)
+static int netlink_route_multipath(int cmd, dplane_ctx_h ctx)
{
int bytelen;
struct sockaddr_nl snl;
return suc;
}
-enum zebra_dplane_result kernel_route_rib(struct route_node *rn,
- const struct prefix *p,
- const struct prefix *src_p,
- struct route_entry *old,
- struct route_entry *new)
-{
- int ret = 0;
-
- assert(old || new);
-
- if (new) {
- if (p->family == AF_INET || v6_rr_semantics)
- ret = netlink_route_multipath(RTM_NEWROUTE, p, src_p,
- new, (old) ? 1 : 0);
- else {
- /*
- * So v6 route replace semantics are not in
- * the kernel at this point as I understand it.
- * So let's do a delete than an add.
- * In the future once v6 route replace semantics
- * are in we can figure out what to do here to
- * allow working with old and new kernels.
- *
- * I'm also intentionally ignoring the failure case
- * of the route delete. If that happens yeah we're
- * screwed.
- */
- if (old)
- netlink_route_multipath(RTM_DELROUTE, p, src_p,
- old, 0);
- ret = netlink_route_multipath(RTM_NEWROUTE, p, src_p,
- new, 0);
- }
- kernel_route_rib_pass_fail(rn, p, new,
- (!ret) ? ZEBRA_DPLANE_INSTALL_SUCCESS
- : ZEBRA_DPLANE_INSTALL_FAILURE);
- return ZEBRA_DPLANE_REQUEST_SUCCESS;
- }
-
- if (old) {
- ret = netlink_route_multipath(RTM_DELROUTE, p, src_p, old, 0);
-
- kernel_route_rib_pass_fail(rn, p, old,
- (!ret) ? ZEBRA_DPLANE_DELETE_SUCCESS
- : ZEBRA_DPLANE_DELETE_FAILURE);
- }
-
- return ZEBRA_DPLANE_REQUEST_SUCCESS;
-}
-
/*
* Update or delete a prefix from the kernel,
* using info from a dataplane context.
* of the route delete. If that happens yeah we're
* screwed.
*/
- (void)netlink_route_multipath_ctx(RTM_DELROUTE, ctx);
+ (void)netlink_route_multipath(RTM_DELROUTE, ctx);
cmd = RTM_NEWROUTE;
}
return ZEBRA_DPLANE_REQUEST_FAILURE;
}
- ret = netlink_route_multipath_ctx(cmd, ctx);
+ ret = netlink_route_multipath(cmd, ctx);
if ((cmd == RTM_NEWROUTE) && (ret == 0)) {
/* Update installed nexthops to signal which have been
* installed.
return 1;
}
-void kernel_route_rib_pass_fail(struct route_node *rn, const struct prefix *p,
- struct route_entry *re,
- enum zebra_dplane_status res)
-{
- struct nexthop *nexthop;
- char buf[PREFIX_STRLEN];
- rib_dest_t *dest;
-
- dest = rib_dest_from_rnode(rn);
-
- switch (res) {
- case ZEBRA_DPLANE_INSTALL_SUCCESS:
- dest->selected_fib = re;
- for (ALL_NEXTHOPS(re->ng, nexthop)) {
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- continue;
-
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
- SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
- else
- UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
- }
- zsend_route_notify_owner(re, p, ZAPI_ROUTE_INSTALLED);
- break;
- case ZEBRA_DPLANE_INSTALL_FAILURE:
- /*
- * I am not sure this is the right thing to do here
- * but the code always set selected_fib before
- * this assignment was moved here.
- */
- dest->selected_fib = re;
-
- zsend_route_notify_owner(re, p, ZAPI_ROUTE_FAIL_INSTALL);
- flog_err(EC_ZEBRA_DP_INSTALL_FAIL,
- "%u:%s: Route install failed", re->vrf_id,
- prefix2str(p, buf, sizeof(buf)));
- break;
- case ZEBRA_DPLANE_DELETE_SUCCESS:
- /*
- * The case where selected_fib is not re is
- * when we have received a system route
- * that is overriding our installed route
- * as such we should leave the selected_fib
- * pointer alone
- */
- if (dest->selected_fib == re)
- dest->selected_fib = NULL;
- for (ALL_NEXTHOPS(re->ng, nexthop))
- UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
-
- zsend_route_notify_owner(re, p, ZAPI_ROUTE_REMOVED);
- break;
- case ZEBRA_DPLANE_DELETE_FAILURE:
- /*
- * Should we set this to NULL if the
- * delete fails?
- */
- dest->selected_fib = NULL;
- flog_err(EC_ZEBRA_DP_DELETE_FAIL,
- "%u:%s: Route Deletion failure", re->vrf_id,
- prefix2str(p, buf, sizeof(buf)));
-
- zsend_route_notify_owner(re, p, ZAPI_ROUTE_REMOVE_FAIL);
- break;
- case ZEBRA_DPLANE_STATUS_NONE:
- break;
- }
-}
-
/* Update flag indicates whether this is a "replace" or not. Currently, this
* is only used for IPv4.
*/