diff options
Diffstat (limited to 'zebra/rt_netlink.c')
| -rw-r--r-- | zebra/rt_netlink.c | 373 |
1 files changed, 193 insertions, 180 deletions
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 795ee2703a..8ce963b37b 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1443,21 +1443,21 @@ static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, 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) +/* + * Routing table change via netlink interface, using a dataplane context object + */ +static int netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx) { int bytelen; struct sockaddr_nl snl; struct nexthop *nexthop = NULL; unsigned int nexthop_num; - int family = PREFIX_FAMILY(p); + int family; const char *routedesc; int setsrc = 0; union g_addr src; + const struct prefix *p, *src_p; + uint32_t table_id; struct { struct nlmsghdr n; @@ -1465,27 +1465,37 @@ static int netlink_route_multipath(int cmd, const struct prefix *p, char buf[NL_PKT_BUF_SIZE]; } req; - struct zebra_ns *zns; - struct zebra_vrf *zvrf = vrf_info_lookup(re->vrf_id); + p = dplane_ctx_get_dest(ctx); + src_p = dplane_ctx_get_src(ctx); - zns = zvrf->zns; - memset(&req, 0, sizeof req - NL_PKT_BUF_SIZE); + family = PREFIX_FAMILY(p); + + 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; + + if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) { + if ((p->family == AF_INET) || v6_rr_semantics) + req.n.nlmsg_flags |= NLM_F_REPLACE; + } + req.n.nlmsg_type = cmd; - req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid; + + req.n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.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; + if (cmd == RTM_DELROUTE) + req.r.rtm_protocol = zebra2proto(dplane_ctx_get_old_type(ctx)); + else + req.r.rtm_protocol = zebra2proto(dplane_ctx_get_type(ctx)); + /* * blackhole routes are not RTN_UNICAST, they are * RTN_ BLACKHOLE|UNREACHABLE|PROHIBIT @@ -1497,9 +1507,9 @@ static int netlink_route_multipath(int cmd, const struct prefix *p, if (cmd != RTM_DELROUTE) req.r.rtm_type = RTN_UNICAST; - addattr_l(&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen); + 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, + addattr_l(&req.n, sizeof(req), RTA_SRC, &src_p->u.prefix, bytelen); /* Metric. */ @@ -1509,20 +1519,31 @@ static int netlink_route_multipath(int cmd, const struct prefix *p, * path(s) * by the routing protocol and for communicating with protocol peers. */ - addattr32(&req.n, sizeof req, RTA_PRIORITY, NL_DEFAULT_ROUTE_METRIC); + 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); + { + route_tag_t tag; + + if (cmd == RTM_DELROUTE) + tag = dplane_ctx_get_old_tag(ctx); + else + tag = dplane_ctx_get_tag(ctx); + + if (tag > 0 && tag <= 255) + addattr32(&req.n, sizeof(req), RTA_FLOW, tag); + } #endif /* Table corresponding to this route. */ - if (re->table < 256) - req.r.rtm_table = re->table; + table_id = dplane_ctx_get_table(ctx); + if (table_id < 256) + req.r.rtm_table = table_id; else { req.r.rtm_table = RT_TABLE_UNSPEC; - addattr32(&req.n, sizeof req, RTA_TABLE, re->table); + addattr32(&req.n, sizeof(req), RTA_TABLE, table_id); } - _netlink_route_debug(cmd, p, family, zvrf_id(zvrf), re->table); + _netlink_route_debug(cmd, p, family, dplane_ctx_get_vrf(ctx), table_id); /* * If we are not updating the route and we have received @@ -1530,41 +1551,42 @@ static int netlink_route_multipath(int cmd, const struct prefix *p, * prefix information to tell the kernel to schwack * it. */ - if (!update && cmd == RTM_DELROUTE) + if (cmd == RTM_DELROUTE) goto skip; - if (re->mtu || re->nexthop_mtu) { + if (dplane_ctx_get_mtu(ctx) || dplane_ctx_get_nh_mtu(ctx)) { 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; + uint32_t mtu = dplane_ctx_get_mtu(ctx); + uint32_t nexthop_mtu = dplane_ctx_get_nh_mtu(ctx); + + if (!mtu || (nexthop_mtu && nexthop_mtu < mtu)) + mtu = 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); + 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. */ + * or multipath case. + */ nexthop_num = 0; - for (ALL_NEXTHOPS(re->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), 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) { + if (nexthop_num == 1) { nexthop_num = 0; - for (ALL_NEXTHOPS(re->ng, nexthop)) { + for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) { /* * So we want to cover 2 types of blackhole * routes here: @@ -1588,70 +1610,61 @@ static int netlink_route_multipath(int cmd, const struct prefix *p, } 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; - } + + if (setsrc) + continue; + + 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))) { + && NEXTHOP_IS_ACTIVE(nexthop->flags))) { routedesc = nexthop->rparent ? "recursive, single-path" : "single-path"; _netlink_route_build_singlepath( routedesc, bytelen, nexthop, &req.n, - &req.r, sizeof req, cmd); + &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, + addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &src.ipv4, bytelen); else if (family == AF_INET6) - addattr_l(&req.n, sizeof req, RTA_PREFSRC, + addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &src.ipv6, bytelen); } - } else { + } else { /* Multipath case */ char buf[NL_PKT_BUF_SIZE]; struct rtattr *rta = (void *)buf; struct rtnexthop *rtnh; @@ -1662,57 +1675,45 @@ static int netlink_route_multipath(int cmd, const struct prefix *p, rtnh = RTA_DATA(rta); nexthop_num = 0; - for (ALL_NEXTHOPS(re->ng, nexthop)) { - if (nexthop_num >= multipath_num) - break; - + for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) { 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; - } + if (setsrc) + continue; + + 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))) { + && NEXTHOP_IS_ACTIVE(nexthop->flags))) { routedesc = nexthop->rparent ? "recursive, multipath" : "multipath"; @@ -1735,10 +1736,10 @@ static int netlink_route_multipath(int cmd, const struct prefix *p, } if (setsrc && (cmd == RTM_NEWROUTE)) { if (family == AF_INET) - addattr_l(&req.n, sizeof req, RTA_PREFSRC, + addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &src.ipv4, bytelen); else if (family == AF_INET6) - addattr_l(&req.n, sizeof req, RTA_PREFSRC, + addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &src.ipv6, bytelen); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("Setting source"); @@ -1760,12 +1761,12 @@ static int netlink_route_multipath(int cmd, const struct prefix *p, skip: /* Destination netlink address. */ - memset(&snl, 0, sizeof snl); + 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); + return netlink_talk_info(netlink_talk_filter, &req.n, + dplane_ctx_get_ns(ctx), 0); } int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) @@ -1821,25 +1822,30 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) 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) +/* + * Update or delete a prefix from the kernel, + * using info from a dataplane context. + */ +enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) { - 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 { + int cmd, ret; + const struct prefix *p = dplane_ctx_get_dest(ctx); + struct nexthop *nexthop; + + if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) { + cmd = RTM_DELROUTE; + } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_INSTALL) { + cmd = RTM_NEWROUTE; + } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) { + + if (p->family == AF_INET || v6_rr_semantics) { + /* Single 'replace' operation */ + cmd = RTM_NEWROUTE; + } 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. + * so let's do a delete then 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. @@ -1848,27 +1854,31 @@ enum zebra_dplane_result kernel_route_rib(struct route_node *rn, * 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); + (void)netlink_route_multipath(RTM_DELROUTE, ctx); + cmd = RTM_NEWROUTE; } - kernel_route_rib_pass_fail(rn, p, new, - (!ret) ? ZEBRA_DPLANE_INSTALL_SUCCESS - : ZEBRA_DPLANE_INSTALL_FAILURE); - return ZEBRA_DPLANE_REQUEST_SUCCESS; + + } else { + return ZEBRA_DPLANE_REQUEST_FAILURE; } - if (old) { - ret = netlink_route_multipath(RTM_DELROUTE, p, src_p, old, 0); + ret = netlink_route_multipath(cmd, ctx); + if ((cmd == RTM_NEWROUTE) && (ret == 0)) { + /* Update installed nexthops to signal which have been + * installed. + */ + for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) { + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + continue; - kernel_route_rib_pass_fail(rn, p, old, - (!ret) ? ZEBRA_DPLANE_DELETE_SUCCESS - : ZEBRA_DPLANE_DELETE_FAILURE); + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) { + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); + } + } } - return ZEBRA_DPLANE_REQUEST_SUCCESS; + return (ret == 0 ? + ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE); } int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, @@ -2255,6 +2265,25 @@ static int netlink_macfdb_update(struct interface *ifp, vlanid_t vid, 0); } +/* + * In the event the kernel deletes ipv4 link-local neighbor entries created for + * 5549 support, re-install them. + */ +static void netlink_handle_5549(struct ndmsg *ndm, struct zebra_if *zif, + struct interface *ifp, struct ipaddr *ip) +{ + if (ndm->ndm_family != AF_INET) + return; + + if (!zif->v6_2_v4_ll_neigh_entry) + return; + + if (ipv4_ll.s_addr != ip->ip._v4_addr.s_addr) + return; + + if_nbr_ipv6ll_to_ipv4ll_neigh_update(ifp, &zif->v6_2_v4_ll_addr6, true); +} + #define NUD_VALID \ (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE | NUD_PROBE | NUD_STALE \ | NUD_DELAY) @@ -2300,29 +2329,16 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) ip.ipa_type = (ndm->ndm_family == AF_INET) ? IPADDR_V4 : IPADDR_V6; memcpy(&ip.ip.addr, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST])); - /* Drop some "permanent" entries. */ - if (ndm->ndm_state & NUD_PERMANENT) { - char b[16] = "169.254.0.1"; - struct in_addr ipv4_ll; - - if (ndm->ndm_family != AF_INET) - return 0; - - if (!zif->v6_2_v4_ll_neigh_entry) - return 0; - - if (h->nlmsg_type != RTM_DELNEIGH) - return 0; - - inet_pton(AF_INET, b, &ipv4_ll); - if (ipv4_ll.s_addr != ip.ip._v4_addr.s_addr) - return 0; - - if_nbr_ipv6ll_to_ipv4ll_neigh_update( - ifp, &zif->v6_2_v4_ll_addr6, true); + /* if kernel deletes our rfc5549 neighbor entry, re-install it */ + if (h->nlmsg_type == RTM_DELNEIGH && (ndm->ndm_state & NUD_PERMANENT)) { + netlink_handle_5549(ndm, zif, ifp, &ip); return 0; } + /* if kernel marks our rfc5549 neighbor entry invalid, re-install it */ + if (h->nlmsg_type == RTM_NEWNEIGH && !(ndm->ndm_state & NUD_VALID)) + netlink_handle_5549(ndm, zif, ifp, &ip); + /* The neighbor is present on an SVI. From this, we locate the * underlying * bridge because we're only interested in neighbors on a VxLAN bridge. @@ -2673,7 +2689,7 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp) /* Fill nexthops (paths) based on single-path or multipath. The paths * chosen depend on the operation. */ - if (nexthop_num == 1 || multipath_num == 1) { + if (nexthop_num == 1) { routedesc = "single-path"; _netlink_mpls_debug(cmd, lsp->ile.in_label, routedesc); @@ -2720,9 +2736,6 @@ int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp) if (!nexthop) continue; - if (nexthop_num >= multipath_num) - break; - if ((cmd == RTM_NEWROUTE && (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED) && CHECK_FLAG(nexthop->flags, |
