From nobody Mon Aug 29 10:23:47 2022 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4MGRNz4QRdz4Zp8T; Mon, 29 Aug 2022 10:23:47 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4MGRNz3mjfz3tYb; Mon, 29 Aug 2022 10:23:47 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1661768627; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=7dIimcQZXOrJmxzZXa0F5WBAa5xKXkVqDsO5Habi5LA=; b=PnPueOQ1mOUBEXEaAlQg13Q7BvNWfz0gLWvbZJdUsp6uX5ebtFXdRsZJ+RBQj4YuhSHrz5 uhsGYARvfJT6AG4zWYIitXRP+pqkslwlApSGQ102DkoX1Rc/NEEUVcKnZLQzUBhUrDxsYj spyjAXuwRvUwRAKXQSq8m+QM59ZMxypj9UugJ5SOdCi4/mh/zwgoOBYw5z8RboI5FjKUC2 oTuoAfHD39UXpcFixTCkH+pI4xFQxWXNJvI1wG2+S6Wwj4uaG/2LY8xq7LwQz9gp5vxQrm RyQ1VLzR+h9r99wht6hvRtx+eCDozmRo3BrnepdqoBR3w5loJ0+HlKHrJCNNKg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4MGRNz2mq8zP2Y; Mon, 29 Aug 2022 10:23:47 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 27TANlQJ015010; Mon, 29 Aug 2022 10:23:47 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 27TANlE3015009; Mon, 29 Aug 2022 10:23:47 GMT (envelope-from git) Date: Mon, 29 Aug 2022 10:23:47 GMT Message-Id: <202208291023.27TANlE3015009@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: "Alexander V. Chernikov" Subject: git: a1b59379db7d - main - routing: install prefix and loopback routes using new nhop-based KPI. List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: melifaro X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: a1b59379db7d879551118b921f6e9692b4bf200c Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1661768627; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=7dIimcQZXOrJmxzZXa0F5WBAa5xKXkVqDsO5Habi5LA=; b=l3AK4Hu+Y+npw0CNzXTWUgYu6RcTn895p3MzD4O69IQaBZ+f50j7EWB3KHgDWkiM2UQx/l omzEEZXD10iUCdH7oB94gh8d6pzNLAa9fCsNK9geDJKUZl22stPNlNknweiQovlL0tOFrX 9wNmrgBEnZiDMSUZR1I4E3zKjGRtSYPfgc4zXpVCPnyongFEkggSKep+TRrqr5dOur/zua 5zMOeI6aDBVIsWLI2B9aRksCnk7bzRFejIMVCFGeZ9l0sG/j9EHUOLjdnlv1kn27t1Jfch rh7avhlTgKX2fKPkRfzBQrWl36uF2X7I6tsjsrfYDC7/h8v3pxaG4C/Qxo5Dmg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1661768627; a=rsa-sha256; cv=none; b=yCr4KqogarEFNokkPxjIPg7EPoCPM6Qrq/441vIBim8uSz1JAkLTzL7LDrYXhKM2O8XIxt lsWcE3POy0j0Qr5Z/kD+E5r/6S3GP+CfR/E4S2pHVMECBk73d9IWnIzjkGEusg67MDjN0x UtgR0wZGhELtk3TfbYn/NVQaPG/okYRg9L7rAasZYcj8dlYOUXt7qHdI35OnP02cj+XjjG AiGt05412qoMK9K5B5LKDBENx8CAQc9JF3O8CsnUXSL6+QFQ0cFYUW1LpTKo8aDqwbELIK 42/qrNNcaAbZyZCJL0+u6cUOX3XY4hq5TYp8vbJB+bVeVhOAyLaT6DTsIt9VVQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by melifaro: URL: https://cgit.FreeBSD.org/src/commit/?id=a1b59379db7d879551118b921f6e9692b4bf200c commit a1b59379db7d879551118b921f6e9692b4bf200c Author: Alexander V. Chernikov AuthorDate: 2022-08-08 19:24:26 +0000 Commit: Alexander V. Chernikov CommitDate: 2022-08-29 10:07:58 +0000 routing: install prefix and loopback routes using new nhop-based KPI. Construct the desired hexthops directly instead of using the "translation" layer in form of filling rt_addrinfo data. Simplify V_rt_add_addr_allfibs handling by using recently-added rib_copy_route() to propagate the routes to the non-primary address fibs. MFC after: 1 month Differential Revision: https://reviews.freebsd.org/D36166 --- sys/net/route/route_ctl.h | 8 +- sys/net/route/route_ifaddrs.c | 190 +++++++++++++++++++++++------------------- sys/netinet/in.c | 62 ++++++-------- sys/netinet6/in6.c | 54 +++++++----- sys/netinet6/nd6_rtr.c | 70 +++++++++------- 5 files changed, 210 insertions(+), 174 deletions(-) diff --git a/sys/net/route/route_ctl.h b/sys/net/route/route_ctl.h index 19fe5362b6ec..2d43679ad183 100644 --- a/sys/net/route/route_ctl.h +++ b/sys/net/route/route_ctl.h @@ -75,7 +75,13 @@ int rib_change_route(uint32_t fibnum, struct rt_addrinfo *info, struct rib_cmd_info *rc); int rib_action(uint32_t fibnum, int action, struct rt_addrinfo *info, struct rib_cmd_info *rc); -int rib_handle_ifaddr_info(uint32_t fibnum, int cmd, struct rt_addrinfo *info); +int rib_add_kernel_px(uint32_t fibnum, struct sockaddr *dst, int plen, + struct route_nhop_data *rnd, int op_flags); +int rib_del_kernel_px(uint32_t fibnum, struct sockaddr *dst, int plen, + rib_filter_f_t *filter_func, void *filter_arg, int op_flags); + +int rib_match_gw(const struct rtentry *rt, const struct nhop_object *nh, + void *_data); int rib_match_gw(const struct rtentry *rt, const struct nhop_object *nh, void *gw_sa); diff --git a/sys/net/route/route_ifaddrs.c b/sys/net/route/route_ifaddrs.c index a456ffa28696..d88284c2e008 100644 --- a/sys/net/route/route_ifaddrs.c +++ b/sys/net/route/route_ifaddrs.c @@ -64,112 +64,103 @@ VNET_DEFINE(u_int, rt_add_addr_allfibs) = 0; SYSCTL_UINT(_net, OID_AUTO, add_addr_allfibs, CTLFLAG_RWTUN | CTLFLAG_VNET, &VNET_NAME(rt_add_addr_allfibs), 0, ""); -/* - * Executes routing tables change specified by @cmd and @info for the fib - * @fibnum. Generates routing message on success. - * Note: it assumes there is only single route (interface route) for the - * provided prefix. - * Returns 0 on success or errno. - */ -static int -rib_handle_ifaddr_one(uint32_t fibnum, int cmd, struct rt_addrinfo *info) +static void +report_operation(uint32_t fibnum, struct rib_cmd_info *rc) { - struct rib_cmd_info rc; struct nhop_object *nh; - int error; - error = rib_action(fibnum, cmd, info, &rc); - if (error == 0) { - if (cmd == RTM_ADD) - nh = nhop_select(rc.rc_nh_new, 0); - else - nh = nhop_select(rc.rc_nh_old, 0); - rt_routemsg(cmd, rc.rc_rt, nh, fibnum); + if (rc->rc_cmd == RTM_DELETE) + nh = nhop_select(rc->rc_nh_old, 0); + else + nh = nhop_select(rc->rc_nh_new, 0); + rt_routemsg(rc->rc_cmd, rc->rc_rt, nh, fibnum); +} + +int +rib_add_kernel_px(uint32_t fibnum, struct sockaddr *dst, int plen, + struct route_nhop_data *rnd, int op_flags) +{ + struct rib_cmd_info rc = {}; + + NET_EPOCH_ASSERT(); + + int error = rib_add_route_px(fibnum, dst, plen, rnd, op_flags, &rc); + if (error != 0) + return (error); + report_operation(fibnum, &rc); + + if (V_rt_add_addr_allfibs != 0) { + for (int i = 0; i < V_rt_numfibs; i++) { + if (i == fibnum) + continue; + struct rib_head *rnh = rt_tables_get_rnh(fibnum, dst->sa_family); + /* Don't care much about the errors in non-primary fib */ + if (rnh != NULL) { + if (rib_copy_route(rc.rc_rt, rnd, rnh, &rc) == 0) + report_operation(i, &rc); + } + } } return (error); } -/* - * Adds/deletes interface prefix specified by @info to the routing table. - * If V_rt_add_addr_allfibs is set, iterates over all existing routing - * tables, otherwise uses fib in @fibnum. Generates routing message for - * each table. - * Returns 0 on success or errno. - */ int -rib_handle_ifaddr_info(uint32_t fibnum, int cmd, struct rt_addrinfo *info) +rib_del_kernel_px(uint32_t fibnum, struct sockaddr *dst, int plen, + rib_filter_f_t *filter_func, void *filter_arg, int op_flags) { - int error = 0, last_error = 0; - bool didwork = false; - - if (V_rt_add_addr_allfibs == 0) { - error = rib_handle_ifaddr_one(fibnum, cmd, info); - didwork = (error == 0); - } else { - for (fibnum = 0; fibnum < V_rt_numfibs; fibnum++) { - error = rib_handle_ifaddr_one(fibnum, cmd, info); - if (error == 0) - didwork = true; - else - last_error = error; - } - } + struct rib_cmd_info rc = {}; - if (cmd == RTM_DELETE) { - if (didwork) { - error = 0; - } else { - /* we only give an error if it wasn't in any table */ - error = ((info->rti_flags & RTF_HOST) ? - EHOSTUNREACH : ENETUNREACH); - } - } else { - if (last_error != 0) { - /* return an error if any of them failed */ - error = last_error; + NET_EPOCH_ASSERT(); + + int error = rib_del_route_px(fibnum, dst, plen, filter_func, filter_arg, + op_flags, &rc); + if (error != 0) + return (error); + report_operation(fibnum, &rc); + + if (V_rt_add_addr_allfibs != 0) { + for (int i = 0; i < V_rt_numfibs; i++) { + if (i == fibnum) + continue; + /* Don't care much about the errors in non-primary fib */ + if (rib_del_route_px(fibnum, dst, plen, filter_func, filter_arg, + op_flags, &rc) == 0) + report_operation(i, &rc); } } + return (error); } static int -ifa_maintain_loopback_route(int cmd, const char *otype, struct ifaddr *ifa, - struct sockaddr *ia) +add_loopback_route_flags(struct ifaddr *ifa, struct sockaddr *ia, int op_flags) { struct rib_cmd_info rc; - struct epoch_tracker et; int error; - struct rt_addrinfo info; - struct sockaddr_dl null_sdl; - struct ifnet *ifp; - - ifp = ifa->ifa_ifp; - NET_EPOCH_ENTER(et); - bzero(&info, sizeof(info)); - if (cmd != RTM_DELETE) - info.rti_ifp = V_loif; - if (cmd == RTM_ADD) { - /* explicitly specify (loopback) ifa */ - if (info.rti_ifp != NULL) - info.rti_ifa = ifaof_ifpforaddr(ifa->ifa_addr, info.rti_ifp); - } - info.rti_flags = ifa->ifa_flags | RTF_HOST | RTF_STATIC | RTF_PINNED; - info.rti_info[RTAX_DST] = ia; - info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&null_sdl; - link_init_sdl(ifp, (struct sockaddr *)&null_sdl, ifp->if_type); + NET_EPOCH_ASSERT(); - error = rib_action(ifp->if_fib, cmd, &info, &rc); - NET_EPOCH_EXIT(et); + struct ifnet *ifp = ifa->ifa_ifp; + struct nhop_object *nh = nhop_alloc(ifp->if_fib, ia->sa_family); + struct route_nhop_data rnd = { .rnd_weight = RT_DEFAULT_WEIGHT }; + if (nh == NULL) + return (ENOMEM); - if (error == 0 || - (cmd == RTM_ADD && error == EEXIST) || - (cmd == RTM_DELETE && (error == ENOENT || error == ESRCH))) + nhop_set_direct_gw(nh, ifp); + nhop_set_transmit_ifp(nh, V_loif); + nhop_set_src(nh, ifaof_ifpforaddr(ifa->ifa_addr, ifp)); + nhop_set_pinned(nh, true); + nhop_set_rtflags(nh, RTF_STATIC); + nhop_set_pxtype_flag(nh, NHF_HOST); + rnd.rnd_nhop = nhop_get_nhop(nh, &error); + if (error != 0) return (error); + error = rib_add_route_px(ifp->if_fib, ia, -1, &rnd, op_flags, &rc); - log(LOG_DEBUG, "%s: %s failed for interface %s: %u\n", - __func__, otype, if_name(ifp), error); + if (error != 0) + log(LOG_DEBUG, "%s: failed to update interface %s route: %u\n", + __func__, if_name(ifp), error); return (error); } @@ -177,22 +168,49 @@ ifa_maintain_loopback_route(int cmd, const char *otype, struct ifaddr *ifa, int ifa_add_loopback_route(struct ifaddr *ifa, struct sockaddr *ia) { + struct epoch_tracker et; - return (ifa_maintain_loopback_route(RTM_ADD, "insertion", ifa, ia)); + NET_EPOCH_ENTER(et); + int error = add_loopback_route_flags(ifa, ia, RTM_F_CREATE | RTM_F_FORCE); + NET_EPOCH_EXIT(et); + + return (error); } int -ifa_del_loopback_route(struct ifaddr *ifa, struct sockaddr *ia) +ifa_switch_loopback_route(struct ifaddr *ifa, struct sockaddr *ia) { + struct epoch_tracker et; + + NET_EPOCH_ENTER(et); + int error = add_loopback_route_flags(ifa, ia, RTM_F_REPLACE | RTM_F_FORCE); + NET_EPOCH_EXIT(et); - return (ifa_maintain_loopback_route(RTM_DELETE, "deletion", ifa, ia)); + return (error); } int -ifa_switch_loopback_route(struct ifaddr *ifa, struct sockaddr *ia) +ifa_del_loopback_route(struct ifaddr *ifa, struct sockaddr *ia) { + struct ifnet *ifp = ifa->ifa_ifp; + struct sockaddr_dl link_sdl; + struct sockaddr *gw = (struct sockaddr *)&link_sdl; + struct rib_cmd_info rc; + struct epoch_tracker et; + int error; - return (ifa_maintain_loopback_route(RTM_CHANGE, "switch", ifa, ia)); + NET_EPOCH_ENTER(et); + + link_init_sdl(ifp, gw, ifp->if_type); + error = rib_del_route_px_gw(ifp->if_fib, ia, -1, gw, RTM_F_FORCE, &rc); + + NET_EPOCH_EXIT(et); + + if (error != 0) + log(LOG_DEBUG, "%s: failed to delete interface %s route: %u\n", + __func__, if_name(ifp), error); + + return (error); } static bool diff --git a/sys/netinet/in.c b/sys/netinet/in.c index 790740456160..e097698c27dd 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -821,36 +821,34 @@ in_match_ifaddr(const struct rtentry *rt, const struct nhop_object *nh, void *ar } static int -in_handle_prefix_route(uint32_t fibnum, int cmd, - struct sockaddr_in *dst, struct sockaddr_in *netmask, struct ifaddr *ifa, - struct ifnet *ifp) +in_handle_prefix_route(uint32_t fibnum, int cmd, struct sockaddr *dst, + int plen, struct ifaddr *ifa, struct ifnet *ifp) { + int error = 0; NET_EPOCH_ASSERT(); - /* Prepare gateway */ - struct sockaddr_dl_short sdl = { - .sdl_family = AF_LINK, - .sdl_len = sizeof(struct sockaddr_dl_short), - .sdl_type = ifa->ifa_ifp->if_type, - .sdl_index = ifa->ifa_ifp->if_index, - }; - - struct rt_addrinfo info = { - .rti_ifa = ifa, - .rti_ifp = ifp, - .rti_flags = RTF_PINNED | ((netmask != NULL) ? 0 : RTF_HOST), - .rti_info = { - [RTAX_DST] = (struct sockaddr *)dst, - [RTAX_NETMASK] = (struct sockaddr *)netmask, - [RTAX_GATEWAY] = (struct sockaddr *)&sdl, - }, - /* Ensure we delete the prefix IFF prefix ifa matches */ - .rti_filter = in_match_ifaddr, - .rti_filterdata = ifa, - }; - - return (rib_handle_ifaddr_info(fibnum, cmd, &info)); + if (cmd == RTM_DELETE) { + error = rib_del_kernel_px(fibnum, dst, plen, in_match_ifaddr, ifa, + RTM_F_FORCE); + } else { + struct nhop_object *nh = nhop_alloc(fibnum, dst->sa_family); + struct route_nhop_data rnd = { .rnd_weight = RT_DEFAULT_WEIGHT }; + + if (nh == NULL) + return (ENOMEM); + nhop_set_direct_gw(nh, ifa->ifa_ifp); + nhop_set_transmit_ifp(nh, ifp); + nhop_set_src(nh, ifa); + nhop_set_pinned(nh, true); + nhop_set_pxtype_flag(nh, plen == 32 ? NHF_HOST : 0); + rnd.rnd_nhop = nhop_get_nhop(nh, &error); + if (error != 0) + return (error); + int op_flags = RTM_F_CREATE | RTM_F_REPLACE | RTM_F_FORCE; + error = rib_add_kernel_px(fibnum, dst, plen, &rnd, op_flags); + } + return (error); } /* @@ -959,19 +957,12 @@ in_handle_ifaddr_route(int cmd, struct in_ifaddr *ia) { struct ifaddr *ifa = &ia->ia_ifa; struct in_addr daddr, maddr; - struct sockaddr_in *pmask; struct epoch_tracker et; int error; ia_getrtprefix(ia, &daddr, &maddr); - struct sockaddr_in mask = { - .sin_family = AF_INET, - .sin_len = sizeof(struct sockaddr_in), - .sin_addr = maddr, - }; - - pmask = (maddr.s_addr != INADDR_BROADCAST) ? &mask : NULL; + int plen = bitcount32(maddr.s_addr); struct sockaddr_in dst = { .sin_family = AF_INET, @@ -989,7 +980,8 @@ in_handle_ifaddr_route(int cmd, struct in_ifaddr *ia) uint32_t fibnum = ifa->ifa_ifp->if_fib; NET_EPOCH_ENTER(et); - error = in_handle_prefix_route(fibnum, cmd, &dst, pmask, ifa, ifp); + error = in_handle_prefix_route(fibnum, cmd, (struct sockaddr *)&dst, + plen, ifa, ifp); NET_EPOCH_EXIT(et); return (error); diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index ccdf71cfc01c..4b3f30a7ee7c 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -1267,6 +1267,29 @@ in6_broadcast_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, return (error); } +static int +in6_handle_dstaddr_rtadd(uint32_t fibnum, struct sockaddr *dst, struct ifaddr *ifa) +{ + struct nhop_object *nh = nhop_alloc(fibnum, dst->sa_family); + struct route_nhop_data rnd = { .rnd_weight = RT_DEFAULT_WEIGHT }; + int error = 0; + + if (nh == NULL) + return (ENOMEM); + nhop_set_direct_gw(nh, ifa->ifa_ifp); + nhop_set_transmit_ifp(nh, ifa->ifa_ifp); + nhop_set_src(nh, ifa); + nhop_set_pinned(nh, true); + nhop_set_pxtype_flag(nh, NHF_HOST); + rnd.rnd_nhop = nhop_get_nhop(nh, &error); + if (error == 0) { + int op_flags = RTM_F_CREATE | RTM_F_REPLACE | RTM_F_FORCE; + error = rib_add_kernel_px(fibnum, dst, -1, &rnd, op_flags); + } + + return (error); +} + /* * Adds or deletes interface route for p2p ifa. * Returns 0 on success or errno. @@ -1276,35 +1299,26 @@ in6_handle_dstaddr_rtrequest(int cmd, struct in6_ifaddr *ia) { struct epoch_tracker et; struct ifaddr *ifa = &ia->ia_ifa; + uint32_t fibnum = ifa->ifa_ifp->if_fib; int error; - /* Prepare gateway */ - struct sockaddr_dl_short sdl = { - .sdl_family = AF_LINK, - .sdl_len = sizeof(struct sockaddr_dl_short), - .sdl_type = ifa->ifa_ifp->if_type, - .sdl_index = ifa->ifa_ifp->if_index, - }; - struct sockaddr_in6 dst = { .sin6_family = AF_INET6, .sin6_len = sizeof(struct sockaddr_in6), .sin6_addr = ia->ia_dstaddr.sin6_addr, }; - struct rt_addrinfo info = { - .rti_ifa = ifa, - .rti_ifp = ifa->ifa_ifp, - .rti_flags = RTF_PINNED | RTF_HOST, - .rti_info = { - [RTAX_DST] = (struct sockaddr *)&dst, - [RTAX_GATEWAY] = (struct sockaddr *)&sdl, - }, - }; - /* Don't set additional per-gw filters on removal */ - NET_EPOCH_ENTER(et); - error = rib_handle_ifaddr_info(ifa->ifa_ifp->if_fib, cmd, &info); + if (cmd == RTM_DELETE) { + struct sockaddr_dl link_sdl; + struct sockaddr *gw = (struct sockaddr *)&link_sdl; + struct ifnet *ifp = ifa->ifa_ifp; + + link_init_sdl(ifp, gw, ifp->if_type); + error = rib_del_kernel_px(fibnum, (struct sockaddr *)&dst, 128, + rib_match_gw, gw, RTM_F_FORCE); + } else + error = in6_handle_dstaddr_rtadd(fibnum, (struct sockaddr *)&dst, ifa); NET_EPOCH_EXIT(et); return (error); diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index 9b33d0ea9b24..032d019702ac 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -2014,41 +2014,55 @@ restart: ND6_ONLINK_UNLOCK(); } +static int +nd6_prefix_rtadd(uint32_t fibnum, struct sockaddr *dst, int plen, + struct ifnet *ifp, struct ifaddr *ifa) +{ + struct route_nhop_data rnd = { .rnd_weight = RT_DEFAULT_WEIGHT }; + int error = 0; + + struct nhop_object *nh = nhop_alloc(fibnum, dst->sa_family); + if (nh == NULL) + return (ENOMEM); + nhop_set_direct_gw(nh, ifp); + nhop_set_transmit_ifp(nh, ifp); + nhop_set_src(nh, ifa); + nhop_set_pinned(nh, true); + nhop_set_pxtype_flag(nh, plen == 128 ? NHF_HOST : 0); + rnd.rnd_nhop = nhop_get_nhop(nh, &error); + if (error == 0) { + int op_flags = RTM_F_CREATE | RTM_F_REPLACE | RTM_F_FORCE; + error = rib_add_kernel_px(fibnum, dst, plen, &rnd, op_flags); + } + + return (error); +} + /* * Add or remove interface route specified by @dst, @netmask and @ifp. * ifa can be NULL. * Returns 0 on success */ static int -nd6_prefix_rtrequest(uint32_t fibnum, int cmd, struct sockaddr_in6 *dst, - struct sockaddr_in6 *netmask, struct ifnet *ifp, struct ifaddr *ifa) +nd6_prefix_rtrequest(uint32_t fibnum, int cmd, struct sockaddr *dst, + int plen, struct ifnet *ifp, struct ifaddr *ifa) { struct epoch_tracker et; int error; - /* Prepare gateway */ - struct sockaddr_dl_short sdl = { - .sdl_family = AF_LINK, - .sdl_len = sizeof(struct sockaddr_dl_short), - .sdl_type = ifp->if_type, - .sdl_index = ifp->if_index, - }; + NET_EPOCH_ENTER(et); + if (cmd == RTM_DELETE) { + struct sockaddr_dl link_sdl; + struct sockaddr *gw = (struct sockaddr *)&link_sdl; - struct rt_addrinfo info = { - .rti_ifa = ifa, - .rti_ifp = ifp, - .rti_flags = RTF_PINNED | ((netmask != NULL) ? 0 : RTF_HOST), - .rti_info = { - [RTAX_DST] = (struct sockaddr *)dst, - [RTAX_NETMASK] = (struct sockaddr *)netmask, - [RTAX_GATEWAY] = (struct sockaddr *)&sdl, - }, - }; - /* Don't set additional per-gw filters on removal */ + link_init_sdl(ifp, gw, ifp->if_type); + error = rib_del_kernel_px(fibnum, dst, plen, + rib_match_gw, gw, RTM_F_FORCE); + } else + error = nd6_prefix_rtadd(fibnum, dst, plen, ifp, ifa); - NET_EPOCH_ENTER(et); - error = rib_handle_ifaddr_info(fibnum, cmd, &info); NET_EPOCH_EXIT(et); + return (error); } @@ -2057,15 +2071,8 @@ nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa) { int error; - struct sockaddr_in6 mask6 = { - .sin6_family = AF_INET6, - .sin6_len = sizeof(struct sockaddr_in6), - .sin6_addr = pr->ndpr_mask, - }; - struct sockaddr_in6 *pmask6 = (pr->ndpr_plen != 128) ? &mask6 : NULL; - error = nd6_prefix_rtrequest(pr->ndpr_ifp->if_fib, RTM_ADD, - &pr->ndpr_prefix, pmask6, pr->ndpr_ifp, ifa); + (struct sockaddr *)&pr->ndpr_prefix, pr->ndpr_plen, pr->ndpr_ifp, ifa); if (error == 0) pr->ndpr_stateflags |= NDPRF_ONLINK; @@ -2176,10 +2183,9 @@ nd6_prefix_offlink(struct nd_prefix *pr) .sin6_len = sizeof(struct sockaddr_in6), .sin6_addr = pr->ndpr_mask, }; - struct sockaddr_in6 *pmask6 = (pr->ndpr_plen != 128) ? &mask6 : NULL; error = nd6_prefix_rtrequest(ifp->if_fib, RTM_DELETE, - &pr->ndpr_prefix, pmask6, ifp, NULL); + (struct sockaddr *)&pr->ndpr_prefix, pr->ndpr_plen, ifp, NULL); a_failure = 1; if (error == 0) {