Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F147723805
D14547.id39870.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D14547.id39870.diff
View Options
Index: sys/netinet/in.c
===================================================================
--- sys/netinet/in.c
+++ sys/netinet/in.c
@@ -78,6 +78,8 @@
static void in_socktrim(struct sockaddr_in *);
static void in_purgemaddrs(struct ifnet *);
+static void in_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info);
+
static VNET_DEFINE(int, nosameprefix);
#define V_nosameprefix VNET(nosameprefix)
SYSCTL_INT(_net_inet_ip, OID_AUTO, no_same_prefix, CTLFLAG_VNET | CTLFLAG_RW,
@@ -401,6 +403,7 @@
ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask;
callout_init_rw(&ia->ia_garp_timer, &ifp->if_addr_lock,
CALLOUT_RETURNUNLOCKED);
+ ifa->ifa_rtrequest = in_rtrequest;
ia->ia_ifp = ifp;
ia->ia_addr = *addr;
@@ -1497,3 +1500,56 @@
lltable_free(ii->ii_llt);
free(ii, M_IFADDR);
}
+
+/*
+ * Return true if the route described by info is the local subnet route for
+ * ifa, or false otherwise.
+ */
+static int
+in_is_subnet_route(struct ifaddr *ifa, struct rt_addrinfo *info)
+{
+ struct sockaddr *tmp_sa;
+ struct sockaddr_storage tmp_storage;
+
+ if (info->rti_info[RTAX_DST] == NULL || info->rti_info[RTAX_NETMASK] == NULL)
+ return (0);
+
+ /* First test that the ifaddr falls into the subnet described by the route. */
+ tmp_sa = (struct sockaddr*)&tmp_storage;
+ rt_maskedcopy(ifa->ifa_addr, tmp_sa, ifa->ifa_netmask);
+
+ if (!sa_equal(tmp_sa, info->rti_info[RTAX_DST]))
+ return (0);
+
+ /*
+ * Now test that the subnet mask is the same for the address and
+ * the route. If they are different then the route has a different
+ * prefix size and ifa just happens to fall within that route.
+ *
+ * For some reason ifa->ifa_netmask sa_len field is not
+ * sizeof(struct sockaddr_in). This causes attempts to directly
+ * compare against info->rti_info[RTAX_NETMASK] to incorrectly
+ * fail even if the netmasks are the same. Fix this by making a
+ * copy of ifa->ifa_netmask with the length field correct.
+ */
+ bzero(tmp_sa, sizeof(struct sockaddr_in));
+ memcpy(tmp_sa, ifa->ifa_netmask, ifa->ifa_netmask->sa_len);
+ tmp_sa->sa_len = sizeof(struct sockaddr_in);
+
+ return (sa_equal(info->rti_info[RTAX_NETMASK], tmp_sa));
+}
+
+static void
+in_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info)
+{
+
+ /*
+ * If we are modifying a route to a subnet, we need to migrate the IFA_ROUTE
+ * flag to the new source ifa for the route.
+ */
+ if (req == RTM_DELETE && rt->rt_ifa->ifa_flags & IFA_ROUTE &&
+ info->rti_ifa != NULL && in_is_subnet_route(rt->rt_ifa, info)) {
+ rt->rt_ifa->ifa_flags &= ~IFA_ROUTE;
+ info->rti_ifa->ifa_flags |= IFA_ROUTE;
+ }
+}
Index: tests/sys/netinet/fibs_test.sh
===================================================================
--- tests/sys/netinet/fibs_test.sh
+++ tests/sys/netinet/fibs_test.sh
@@ -720,6 +720,83 @@
cleanup_ifaces
}
+atf_test_case ipv4_move_subnet_route cleanup
+ipv4_move_subnet_route_head()
+{
+ atf_set "descr" "moving a subnet route to different ifa should be possible"
+ atf_set "require.user" "root"
+ atf_set "require.config" "fibs"
+}
+
+ipv4_move_subnet_route_body()
+{
+ # Configure the TAP interfaces to use a RFC5737 nonrouteable addresses
+ # and a non-default fib
+ SUBNET_PREFIX="192.0.2"
+ SUBNET="${SUBNET_PREFIX}.0"
+ ADDR0="${SUBNET_PREFIX}.1"
+ ADDR1="${SUBNET_PREFIX}.2"
+
+ MASK="24"
+
+ # Check system configuration
+ if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
+ atf_skip "This test requires net.add_addr_allfibs=0"
+ fi
+ get_fibs 1
+
+ get_epair
+ setup_iface "$EPAIRA" "$FIB0" inet ${ADDR0} $MASK
+ setup_iface "$EPAIRB" "$FIB0" inet ${ADDR1} $MASK
+
+ setfib $FIB0 route change ${SUBNET}/${MASK} -ifp "$EPAIRB"
+ ifconfig "$EPAIRA" inet ${ADDR0}/${MASK} fib "$FIB0" -alias
+ atf_check -s exit:0 ifconfig "$EPAIRB" inet ${ADDR0}/$MASK alias fib "$FIB0"
+}
+
+ipv4_move_subnet_route_cleanup()
+{
+ cleanup_ifaces
+}
+
+atf_test_case ipv6_move_subnet_route cleanup
+ipv6_move_subnet_route_head()
+{
+ atf_set "descr" "moving a subnet route to different ifa should be possible"
+ atf_set "require.user" "root"
+ atf_set "require.config" "fibs"
+}
+
+ipv6_move_subnet_route_body()
+{
+ # Configure the TAP interfaces to use a RFC5737 nonrouteable addresses
+ # and a non-default fib
+ SUBNET_PREFIX="2001:db8:"
+ SUBNET="${SUBNET_PREFIX}:0"
+ ADDR0="${SUBNET_PREFIX}:1"
+ ADDR1="${SUBNET_PREFIX}:2"
+
+ MASK="64"
+
+ # Check system configuration
+ if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
+ atf_skip "This test requires net.add_addr_allfibs=0"
+ fi
+ get_fibs 1
+
+ get_epair
+ setup_iface "$EPAIRA" "$FIB0" inet6 ${ADDR0} $MASK
+ setup_iface "$EPAIRB" "$FIB0" inet6 ${ADDR1} $MASK
+
+ setfib $FIB0 route -6 change ${SUBNET}/${MASK} -ifp "$EPAIRB"
+ ifconfig "$EPAIRA" inet6 ${ADDR0}/${MASK} fib "$FIB0" -alias
+ atf_check -s exit:0 setfib 1 ifconfig "$EPAIRB" inet6 ${ADDR0}/$MASK fib "$FIB0" alias
+}
+
+ipv6_move_subnet_route_cleanup()
+{
+ cleanup_ifaces
+}
atf_init_test_cases()
{
@@ -736,6 +813,8 @@
atf_add_test_case subnet_route_with_multiple_fibs_on_same_subnet_inet6
atf_add_test_case udp_dontroute
atf_add_test_case udp_dontroute6
+ atf_add_test_case ipv4_move_subnet_route
+ atf_add_test_case ipv6_move_subnet_route
}
# Looks up one or more fibs from the configuration data and validates them.
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Mar 14, 5:24 AM (22 h, 29 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29654205
Default Alt Text
D14547.id39870.diff (5 KB)
Attached To
Mode
D14547: Allow IPv4 subnet routes to move to a different ifa
Attached
Detach File
Event Timeline
Log In to Comment