Page MenuHomeFreeBSD

D28186.diff
No OneTemporary

D28186.diff

diff --git a/sys/net/if_spppsubr.c b/sys/net/if_spppsubr.c
--- a/sys/net/if_spppsubr.c
+++ b/sys/net/if_spppsubr.c
@@ -47,6 +47,7 @@
#include <net/route.h>
#include <net/vnet.h>
#include <netinet/in.h>
+#include <netinet/in_var.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <net/slcompress.h>
@@ -4881,9 +4882,12 @@
if (ifa != NULL) {
int error;
+ int fibnum = ifp->if_fib;
+ rt_addrmsg(RTM_DELETE, ifa, fibnum);
/* delete old route */
- error = rtinit(ifa, (int)RTM_DELETE, RTF_HOST);
+ ia = ifatoia(ifa);
+ error = in_handle_ifaddr_route(RTM_DELETE, ia);
if (debug && error) {
log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addr: rtinit DEL failed, error=%d\n",
SPP_ARGS(ifp), error);
@@ -4891,14 +4895,14 @@
/* set new address */
si->sin_addr.s_addr = htonl(src);
- ia = ifatoia(ifa);
IN_IFADDR_WLOCK();
LIST_REMOVE(ia, ia_hash);
LIST_INSERT_HEAD(INADDR_HASH(si->sin_addr.s_addr), ia, ia_hash);
IN_IFADDR_WUNLOCK();
+ rt_addrmsg(RTM_ADD, ifa, fibnum);
/* add new route */
- error = rtinit(ifa, (int)RTM_ADD, RTF_HOST);
+ error = in_handle_ifaddr_route(RTM_ADD, ia);
if (debug && error) {
log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addr: rtinit ADD failed, error=%d",
SPP_ARGS(ifp), error);
diff --git a/sys/net/route.h b/sys/net/route.h
--- a/sys/net/route.h
+++ b/sys/net/route.h
@@ -415,7 +415,6 @@
void rt_ifmsg(struct ifnet *);
void rt_missmsg(int, struct rt_addrinfo *, int, int);
void rt_missmsg_fib(int, struct rt_addrinfo *, int, int, int);
-void rt_newaddrmsg_fib(int, struct ifaddr *, struct rtentry *, int);
int rt_addrmsg(int, struct ifaddr *, int);
int rt_routemsg(int, struct rtentry *, struct nhop_object *, int);
int rt_routemsg_info(int, struct rt_addrinfo *, int);
@@ -433,10 +432,6 @@
void rt_flushifroutes_af(struct ifnet *, int);
void rt_flushifroutes(struct ifnet *ifp);
-/* XXX MRT COMPAT VERSIONS THAT SET UNIVERSE to 0 */
-/* Thes are used by old code not yet converted to use multiple FIBS */
-int rtinit(struct ifaddr *, int, int);
-
/* XXX MRT NEW VERSIONS THAT USE FIBs
* For now the protocol indepedent versions are the same as the AF_INET ones
* but this will change..
diff --git a/sys/net/route.c b/sys/net/route.c
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -767,27 +767,3 @@
return (rtsock_routemsg_info(cmd, info, fibnum));
}
-
-/*
- * This is called to generate messages from the routing socket
- * indicating a network interface has had addresses associated with it.
- */
-void
-rt_newaddrmsg_fib(int cmd, struct ifaddr *ifa, struct rtentry *rt, int fibnum)
-{
-
- KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE,
- ("unexpected cmd %u", cmd));
- KASSERT((fibnum >= 0 && fibnum < rt_numfibs),
- ("%s: fib out of range 0 <=%d<%d", __func__, fibnum, rt_numfibs));
-
- if (cmd == RTM_ADD) {
- rt_addrmsg(cmd, ifa, fibnum);
- if (rt != NULL)
- rt_routemsg(cmd, rt, nhop_select(rt->rt_nhop, 0), fibnum);
- } else {
- if (rt != NULL)
- rt_routemsg(cmd, rt, nhop_select(rt->rt_nhop, 0), fibnum);
- rt_addrmsg(cmd, ifa, fibnum);
- }
-}
diff --git a/sys/net/route/route_ctl.h b/sys/net/route/route_ctl.h
--- a/sys/net/route/route_ctl.h
+++ b/sys/net/route/route_ctl.h
@@ -52,6 +52,7 @@
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);
typedef void route_notification_t(struct rib_cmd_info *rc, void *);
void rib_decompose_notification(struct rib_cmd_info *rc,
diff --git a/sys/net/route/route_ifaddrs.c b/sys/net/route/route_ifaddrs.c
--- a/sys/net/route/route_ifaddrs.c
+++ b/sys/net/route/route_ifaddrs.c
@@ -65,176 +65,74 @@
&VNET_NAME(rt_add_addr_allfibs), 0, "");
/*
- * Set up a routing table entry, normally
- * for an interface.
+ * 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 inline int
-rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum)
+static int
+rib_handle_ifaddr_one(uint32_t fibnum, int cmd, struct rt_addrinfo *info)
{
- RIB_RLOCK_TRACKER;
- struct epoch_tracker et;
- struct sockaddr *dst;
- struct sockaddr *netmask;
struct rib_cmd_info rc;
- struct rt_addrinfo info;
- int error = 0;
- int startfib, endfib;
- struct sockaddr_storage ss;
- int didwork = 0;
- int a_failure = 0;
- struct sockaddr_dl_short sdl;
- struct rib_head *rnh;
+ struct nhop_object *nh;
+ int error;
- if (flags & RTF_HOST) {
- dst = ifa->ifa_dstaddr;
- netmask = NULL;
- } else {
- dst = ifa->ifa_addr;
- netmask = ifa->ifa_netmask;
- }
- if (dst->sa_len == 0)
- return(EINVAL);
- switch (dst->sa_family) {
- case AF_INET6:
- case AF_INET:
- /* We support multiple FIBs. */
- break;
- default:
- fibnum = RT_DEFAULT_FIB;
- break;
- }
- if (fibnum == RT_ALL_FIBS) {
- if (V_rt_add_addr_allfibs == 0 && cmd == (int)RTM_ADD)
- startfib = endfib = ifa->ifa_ifp->if_fib;
- else {
- startfib = 0;
- endfib = rt_numfibs - 1;
- }
- } else {
- KASSERT((fibnum < rt_numfibs), ("rtinit1: bad fibnum"));
- startfib = fibnum;
- endfib = fibnum;
+ 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 it's a delete, check that if it exists,
- * it's on the correct interface or we might scrub
- * a route to another ifa which would
- * be confusing at best and possibly worse.
- */
- if (cmd == RTM_DELETE) {
- /*
- * It's a delete, so it should already exist..
- * If it's a net, mask off the host bits
- * (Assuming we have a mask)
- * XXX this is kinda inet specific..
- */
- if (netmask != NULL) {
- rt_maskedcopy(dst, (struct sockaddr *)&ss, netmask);
- dst = (struct sockaddr *)&ss;
- }
- }
- bzero(&sdl, sizeof(struct sockaddr_dl_short));
- sdl.sdl_family = AF_LINK;
- sdl.sdl_len = sizeof(struct sockaddr_dl_short);
- sdl.sdl_type = ifa->ifa_ifp->if_type;
- sdl.sdl_index = ifa->ifa_ifp->if_index;
- /*
- * Now go through all the requested tables (fibs) and do the
- * requested action. Realistically, this will either be fib 0
- * for protocols that don't do multiple tables or all the
- * tables for those that do.
- */
- for ( fibnum = startfib; fibnum <= endfib; fibnum++) {
- if (cmd == RTM_DELETE) {
- struct radix_node *rn;
- /*
- * Look up an rtentry that is in the routing tree and
- * contains the correct info.
- */
- rnh = rt_tables_get_rnh(fibnum, dst->sa_family);
- if (rnh == NULL)
- /* this table doesn't exist but others might */
- continue;
- RIB_RLOCK(rnh);
- rn = rnh->rnh_lookup(dst, netmask, &rnh->head);
- error = (rn == NULL ||
- (rn->rn_flags & RNF_ROOT) ||
- RNTORT(rn)->rt_nhop->nh_ifa != ifa);
- RIB_RUNLOCK(rnh);
- if (error) {
- /* this is only an error if bad on ALL tables */
- continue;
- }
- }
- /*
- * Do the actual request
- */
- bzero((caddr_t)&info, sizeof(info));
- info.rti_ifa = ifa;
- info.rti_flags = flags |
- (ifa->ifa_flags & ~IFA_RTSELF) | RTF_PINNED;
- info.rti_info[RTAX_DST] = dst;
- info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&sdl;
- info.rti_info[RTAX_NETMASK] = netmask;
- NET_EPOCH_ENTER(et);
- error = rib_action(fibnum, cmd, &info, &rc);
- if (error == 0 && rc.rc_rt != NULL) {
- /*
- * notify any listening routing agents of the change
- */
+ return (error);
+}
- /* TODO: interface routes/aliases */
- rt_newaddrmsg_fib(cmd, ifa, rc.rc_rt, fibnum);
- didwork = 1;
+/*
+ * 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)
+{
+ int error, 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;
}
- NET_EPOCH_EXIT(et);
- if (error)
- a_failure = error;
}
+
if (cmd == RTM_DELETE) {
if (didwork) {
error = 0;
} else {
/* we only give an error if it wasn't in any table */
- error = ((flags & RTF_HOST) ?
+ error = ((info->rti_flags & RTF_HOST) ?
EHOSTUNREACH : ENETUNREACH);
}
} else {
- if (a_failure) {
+ if (last_error != 0) {
/* return an error if any of them failed */
- error = a_failure;
+ error = last_error;
}
}
return (error);
}
-/*
- * Set up a routing table entry, normally
- * for an interface.
- */
-int
-rtinit(struct ifaddr *ifa, int cmd, int flags)
-{
- struct sockaddr *dst;
- int fib = RT_DEFAULT_FIB;
-
- if (flags & RTF_HOST) {
- dst = ifa->ifa_dstaddr;
- } else {
- dst = ifa->ifa_addr;
- }
-
- switch (dst->sa_family) {
- case AF_INET6:
- case AF_INET:
- /* We do support multiple FIBs. */
- fib = RT_ALL_FIBS;
- break;
- }
- return (rtinit1(ifa, cmd, flags, fib));
-}
-
static int
ifa_maintain_loopback_route(int cmd, const char *otype, struct ifaddr *ifa,
struct sockaddr *ia)
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -58,6 +58,8 @@
#include <net/if_llatbl.h>
#include <net/if_types.h>
#include <net/route.h>
+#include <net/route/nhop.h>
+#include <net/route/route_ctl.h>
#include <net/vnet.h>
#include <netinet/if_ether.h>
@@ -709,6 +711,125 @@
return (0);
}
+static int
+in_match_ifaddr(const struct rtentry *rt, const struct nhop_object *nh, void *arg)
+{
+
+ if (nh->nh_ifa == (struct ifaddr *)arg)
+ return (1);
+
+ return (0);
+}
+
+static int
+in_handle_prefix_route(uint32_t fibnum, int cmd,
+ struct sockaddr_in *dst, struct sockaddr_in *netmask, struct ifaddr *ifa)
+{
+
+ 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_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));
+}
+
+/*
+ * Adds or delete interface route corresponding to @ifa.
+ * There can be multiple options:
+ * 1) Adding addr with prefix on non-p2p/non-lo interface.
+ * Example: 192.0.2.1/24. Action: add route towards
+ * 192.0.2.0/24 via this interface, using ifa as an address source.
+ * Note: route to 192.0.2.1 will be installed separately via
+ * ifa_maintain_loopback_route().
+ * 2) Adding addr with "host" mask.
+ * Example: 192.0.2.2/32. In this case no action is performed,
+ * as the route should be installed by ifa_maintain_loopback_route().
+ * Returns 0 to indicate success.
+ * 3) Adding address with or without prefix to p2p interface.
+ * Example: 10.0.0.1/24->10.0.0.2. In this case, all other addresses
+ * covered by prefix, does not make sense in the context of p2p link.
+ * Action: add route towards 10.0.0.2 via this interface, using ifa as an
+ * address source.
+ * Similar to (1), route to 10.0.0.1 will be installed by
+ * ifa_maintain_loopback_route().
+ * 4) Adding address with or without prefix to loopback interface.
+ * Example: 192.0.2.1/24. In this case, trafic to non-host addresses cannot
+ * be forwarded, as it would introduce an infinite cycle.
+ * Similar to (2), perform no action and return 0. Loopback route
+ * will be installed by ifa_maintain_loopback_route().
+ */
+int
+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;
+
+ /* Case 4: ignore loopbacks */
+ if (ifa->ifa_ifp->if_flags & IFF_LOOPBACK)
+ return (0);
+
+ if (ifa->ifa_ifp->if_flags & IFF_POINTOPOINT) {
+ /* Case 3: install route towards dst addr */
+ daddr = ia->ia_dstaddr.sin_addr;
+ pmask = NULL;
+ maddr.s_addr = INADDR_BROADCAST;
+ } else {
+ daddr = ia->ia_addr.sin_addr;
+ pmask = &ia->ia_sockmask;
+ maddr = pmask->sin_addr;
+
+ if (maddr.s_addr == INADDR_BROADCAST) {
+ /* Case 2: ignore /32 routes */
+ return (0);
+ }
+ }
+
+ struct sockaddr_in mask = {
+ .sin_family = AF_INET,
+ .sin_len = sizeof(struct sockaddr_in),
+ .sin_addr = maddr,
+ };
+
+ if (pmask != NULL)
+ pmask = &mask;
+
+ struct sockaddr_in dst = {
+ .sin_family = AF_INET,
+ .sin_len = sizeof(struct sockaddr_in),
+ .sin_addr.s_addr = daddr.s_addr & maddr.s_addr,
+ };
+
+ uint32_t fibnum = ifa->ifa_ifp->if_fib;
+ NET_EPOCH_ENTER(et);
+ error = in_handle_prefix_route(fibnum, cmd, &dst, pmask, ifa);
+ NET_EPOCH_EXIT(et);
+
+ return (error);
+}
+
+
#define rtinitflags(x) \
((((x)->ia_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) != 0) \
? RTF_HOST : 0)
@@ -785,7 +906,8 @@
/*
* No-one seem to have this prefix route, so we try to insert it.
*/
- error = rtinit(&target->ia_ifa, (int)RTM_ADD, flags);
+ rt_addrmsg(RTM_ADD, &target->ia_ifa, target->ia_ifp->if_fib);
+ error = in_handle_ifaddr_route(RTM_ADD, target);
if (!error)
target->ia_flags |= IFA_ROUTE;
return (error);
@@ -917,8 +1039,7 @@
if ((ia->ia_flags & IFA_ROUTE) == 0) {
ifa_ref(&ia->ia_ifa);
IN_IFADDR_RUNLOCK(&in_ifa_tracker);
- error = rtinit(&(target->ia_ifa), (int)RTM_DELETE,
- rtinitflags(target));
+ error = in_handle_ifaddr_route(RTM_DELETE, target);
if (error == 0)
target->ia_flags &= ~IFA_ROUTE;
else
@@ -927,8 +1048,7 @@
/* Scrub all entries IFF interface is different */
in_scrubprefixlle(target, target->ia_ifp != ia->ia_ifp,
flags);
- error = rtinit(&ia->ia_ifa, (int)RTM_ADD,
- rtinitflags(ia) | RTF_UP);
+ error = in_handle_ifaddr_route(RTM_ADD, ia);
if (error == 0)
ia->ia_flags |= IFA_ROUTE;
else
@@ -948,7 +1068,8 @@
/*
* As no-one seem to have this prefix, we can remove the route.
*/
- error = rtinit(&(target->ia_ifa), (int)RTM_DELETE, rtinitflags(target));
+ rt_addrmsg(RTM_DELETE, &target->ia_ifa, target->ia_ifp->if_fib);
+ error = in_handle_ifaddr_route(RTM_DELETE, target);
if (error == 0)
target->ia_flags &= ~IFA_ROUTE;
else
diff --git a/sys/netinet/in_var.h b/sys/netinet/in_var.h
--- a/sys/netinet/in_var.h
+++ b/sys/netinet/in_var.h
@@ -464,6 +464,7 @@
int in_addprefix(struct in_ifaddr *, int);
int in_scrubprefix(struct in_ifaddr *, u_int);
void in_ifscrub_all(void);
+int in_handle_ifaddr_route(int, struct in_ifaddr *);
void ip_input(struct mbuf *);
void ip_direct_input(struct mbuf *);
void in_ifadown(struct ifaddr *ifa, int);
diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c
--- a/sys/netinet/raw_ip.c
+++ b/sys/netinet/raw_ip.c
@@ -64,6 +64,7 @@
#include <net/if.h>
#include <net/if_var.h>
#include <net/route.h>
+#include <net/route/route_ctl.h>
#include <net/vnet.h>
#include <netinet/in.h>
@@ -864,7 +865,8 @@
err = ifa_del_loopback_route((struct ifaddr *)ia, sa);
- err = rtinit(&ia->ia_ifa, RTM_ADD, flags);
+ rt_addrmsg(RTM_ADD, &ia->ia_ifa, ia->ia_ifp->if_fib);
+ err = in_handle_ifaddr_route(RTM_ADD, ia);
if (err == 0)
ia->ia_flags |= IFA_ROUTE;
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -91,6 +91,7 @@
#include <net/if_var.h>
#include <net/if_types.h>
#include <net/route.h>
+#include <net/route/route_ctl.h>
#include <net/route/nhop.h>
#include <net/if_dl.h>
#include <net/vnet.h>
@@ -1272,6 +1273,48 @@
return (error);
}
+/*
+ * Adds or deletes interface route for p2p ifa.
+ * Returns 0 on success or errno.
+ */
+static int
+in6_handle_dstaddr_rtrequest(int cmd, struct in6_ifaddr *ia)
+{
+ struct epoch_tracker et;
+ struct ifaddr *ifa = &ia->ia_ifa;
+ 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_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);
+ NET_EPOCH_EXIT(et);
+
+ return (error);
+}
+
void
in6_purgeaddr(struct ifaddr *ifa)
{
@@ -1305,10 +1348,12 @@
in6_leavegroup(imm->i6mm_maddr, NULL);
free(imm, M_IP6MADDR);
}
+ /* Check if we need to remove p2p route */
plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
+ if (ia->ia_dstaddr.sin6_family != AF_INET6)
+ plen = 0;
if ((ia->ia_flags & IFA_ROUTE) && plen == 128) {
- error = rtinit(&(ia->ia_ifa), RTM_DELETE, ia->ia_flags |
- (ia->ia_dstaddr.sin6_family == AF_INET6 ? RTF_HOST : 0));
+ error = in6_handle_dstaddr_rtrequest(RTM_DELETE, ia);
if (error != 0)
log(LOG_INFO, "%s: err=%d, destination address delete "
"failed\n", __func__, error);
@@ -1416,7 +1461,7 @@
if (pdst->sin6_family == AF_INET6 &&
!IN6_ARE_ADDR_EQUAL(&pdst->sin6_addr, &ia->ia_dstaddr.sin6_addr)) {
if ((ia->ia_flags & IFA_ROUTE) != 0 &&
- (rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST) != 0)) {
+ (in6_handle_dstaddr_rtrequest(RTM_DELETE, ia) != 0)) {
nd6log((LOG_ERR, "in6_update_ifa_internal: failed to "
"remove a route to the old destination: %s\n",
ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr)));
@@ -1436,13 +1481,12 @@
plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 &&
ia->ia_dstaddr.sin6_family == AF_INET6) {
- int rtflags = RTF_UP | RTF_HOST;
/*
* Handle the case for ::1 .
*/
if (ifp->if_flags & IFF_LOOPBACK)
ia->ia_flags |= IFA_RTSELF;
- error = rtinit(&ia->ia_ifa, RTM_ADD, ia->ia_flags | rtflags);
+ error = in6_handle_dstaddr_rtrequest(RTM_ADD, ia);
if (error)
goto done;
ia->ia_flags |= IFA_ROUTE;
diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c
--- a/sys/netinet6/nd6_rtr.c
+++ b/sys/netinet6/nd6_rtr.c
@@ -2020,73 +2020,61 @@
ND6_ONLINK_UNLOCK();
}
+/*
+ * 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)
+{
+ 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,
+ };
+
+ struct rt_addrinfo info = {
+ .rti_ifa = ifa,
+ .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 */
+
+ NET_EPOCH_ENTER(et);
+ error = rib_handle_ifaddr_info(fibnum, cmd, &info);
+ NET_EPOCH_EXIT(et);
+ return (error);
+}
+
static int
nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa)
{
- struct sockaddr_dl_short sdl;
- struct sockaddr_in6 mask6;
- u_long rtflags;
- int error, a_failure, fibnum, maxfib;
-
- bzero(&mask6, sizeof(mask6));
- mask6.sin6_len = sizeof(mask6);
- mask6.sin6_addr = pr->ndpr_mask;
- rtflags = (ifa->ifa_flags & ~IFA_RTSELF) | RTF_UP;
-
- bzero(&sdl, sizeof(struct sockaddr_dl_short));
- sdl.sdl_len = sizeof(struct sockaddr_dl_short);
- sdl.sdl_family = AF_LINK;
- sdl.sdl_type = ifa->ifa_ifp->if_type;
- sdl.sdl_index = ifa->ifa_ifp->if_index;
-
- if(V_rt_add_addr_allfibs) {
- fibnum = 0;
- maxfib = rt_numfibs;
- } else {
- fibnum = ifa->ifa_ifp->if_fib;
- maxfib = fibnum + 1;
- }
- a_failure = 0;
- for (; fibnum < maxfib; fibnum++) {
- struct rt_addrinfo info;
- struct rib_cmd_info rc;
-
- bzero((caddr_t)&info, sizeof(info));
- info.rti_flags = rtflags;
- info.rti_info[RTAX_DST] = (struct sockaddr *)&pr->ndpr_prefix;
- info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&sdl;
- info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask6;
-
- NET_EPOCH_ASSERT();
- error = rib_action(fibnum, RTM_ADD, &info, &rc);
- if (error != 0) {
- char ip6buf[INET6_ADDRSTRLEN];
- char ip6bufg[INET6_ADDRSTRLEN];
- char ip6bufm[INET6_ADDRSTRLEN];
- struct sockaddr_in6 *sin6;
-
- sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
- nd6log((LOG_ERR, "%s: failed to add "
- "route for a prefix (%s/%d) on %s, gw=%s, mask=%s, "
- "flags=%lx errno = %d\n", __func__,
- ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
- pr->ndpr_plen, if_name(pr->ndpr_ifp),
- ip6_sprintf(ip6bufg, &sin6->sin6_addr),
- ip6_sprintf(ip6bufm, &mask6.sin6_addr),
- rtflags, error));
+ int error;
- /* Save last error to return, see rtinit(). */
- a_failure = error;
- continue;
- }
+ 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);
+ if (error == 0)
pr->ndpr_stateflags |= NDPRF_ONLINK;
- struct nhop_object *nh = nhop_select(rc.rc_nh_new, 0);
- rt_routemsg(RTM_ADD, rc.rc_rt, nh, fibnum);
- }
- /* Return the last error we got. */
- return (a_failure);
+ return (error);
}
static int
@@ -2178,11 +2166,10 @@
int error = 0;
struct ifnet *ifp = pr->ndpr_ifp;
struct nd_prefix *opr;
- struct sockaddr_in6 sa6, mask6;
+ struct sockaddr_in6 sa6;
char ip6buf[INET6_ADDRSTRLEN];
uint64_t genid;
- int fibnum, maxfib, a_failure;
- struct epoch_tracker et;
+ int a_failure;
ND6_ONLINK_LOCK_ASSERT();
ND6_UNLOCK_ASSERT();
@@ -2190,50 +2177,16 @@
if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0)
return (EEXIST);
- bzero(&sa6, sizeof(sa6));
- sa6.sin6_family = AF_INET6;
- sa6.sin6_len = sizeof(sa6);
- bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr,
- sizeof(struct in6_addr));
- bzero(&mask6, sizeof(mask6));
- mask6.sin6_family = AF_INET6;
- mask6.sin6_len = sizeof(sa6);
- bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr));
-
- if (V_rt_add_addr_allfibs) {
- fibnum = 0;
- maxfib = rt_numfibs;
- } else {
- fibnum = ifp->if_fib;
- maxfib = fibnum + 1;
- }
+ 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;
- a_failure = 0;
- NET_EPOCH_ENTER(et);
- for (; fibnum < maxfib; fibnum++) {
- struct rt_addrinfo info;
- struct rib_cmd_info rc;
-
- bzero((caddr_t)&info, sizeof(info));
- info.rti_flags = RTF_GATEWAY;
- info.rti_info[RTAX_DST] = (struct sockaddr *)&sa6;
- info.rti_info[RTAX_GATEWAY] = NULL;
- info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask6;
-
- NET_EPOCH_ASSERT();
- error = rib_action(fibnum, RTM_DELETE, &info, &rc);
- if (error != 0) {
- /* Save last error to return, see rtinit(). */
- a_failure = error;
- continue;
- }
+ error = nd6_prefix_rtrequest(ifp->if_fib, RTM_DELETE,
+ &pr->ndpr_prefix, pmask6, ifp, NULL);
- /* report route deletion to the routing socket. */
- struct nhop_object *nh = nhop_select(rc.rc_nh_old, 0);
- rt_routemsg(RTM_DELETE, rc.rc_rt, nh, fibnum);
- }
- NET_EPOCH_EXIT(et);
- error = a_failure;
a_failure = 1;
if (error == 0) {
pr->ndpr_stateflags &= ~NDPRF_ONLINK;
@@ -2283,7 +2236,7 @@
/* XXX: can we still set the NDPRF_ONLINK flag? */
nd6log((LOG_ERR,
"%s: failed to delete route: %s/%d on %s (errno=%d)\n",
- __func__, ip6_sprintf(ip6buf, &sa6.sin6_addr),
+ __func__, ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
pr->ndpr_plen, if_name(ifp), error));
}
diff --git a/tests/sys/net/routing/test_rtsock_l3.c b/tests/sys/net/routing/test_rtsock_l3.c
--- a/tests/sys/net/routing/test_rtsock_l3.c
+++ b/tests/sys/net/routing/test_rtsock_l3.c
@@ -1127,8 +1127,7 @@
/* gateway should be link sdl with ifindex of an address interface */
verify_link_gateway(rtm, c->ifindex);
- /* TODO: PINNED? */
- int expected_rt_flags = RTF_UP | RTF_DONE;
+ int expected_rt_flags = RTF_UP | RTF_DONE | RTF_PINNED;
verify_route_message_extra(rtm, c->ifindex, expected_rt_flags);
}
@@ -1257,7 +1256,7 @@
/* gateway should be link sdl with ifindex of an address interface */
verify_link_gateway(rtm, c->ifindex);
- int expected_rt_flags = RTF_DONE;
+ int expected_rt_flags = RTF_DONE | RTF_PINNED;
verify_route_message_extra(rtm, c->ifindex, expected_rt_flags);
}

File Metadata

Mime Type
text/plain
Expires
Thu, Jan 16, 6:16 AM (19 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15821136
Default Alt Text
D28186.diff (25 KB)

Event Timeline