Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F107511425
D28186.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
25 KB
Referenced Files
None
Subscribers
None
D28186.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D28186: Split rtinit() into multiple functions.
Attached
Detach File
Event Timeline
Log In to Comment