Page MenuHomeFreeBSD

D14547.id39870.diff
No OneTemporary

D14547.id39870.diff

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

Mime Type
text/plain
Expires
Sat, Mar 14, 10:20 AM (18 h, 3 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29654205
Default Alt Text
D14547.id39870.diff (5 KB)

Event Timeline