Commit dd357348 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'ipv4-invalidate-broadcast-neigh-upon-address-addition'

Ido Schimmel says:

====================
ipv4: Invalidate neighbour for broadcast address upon address addition

Patch #1 solves a recently reported issue [1]. See detailed description
in the changelog.

Patch #2 adds a matching test case.

Targeting at net-next since as far as I can tell this use case never
worked.

There are no regressions in fib_tests.sh with this change:

 # ./fib_tests.sh
 ...
 Tests passed: 186
 Tests failed:   0

[1] https://lore.kernel.org/netdev/55a04a8f-56f3-f73c-2aea-2195923f09d1@huawei.com/


====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 0f6938eb 25bd462f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ void arp_send(int type, int ptype, __be32 dest_ip,
	      const unsigned char *src_hw, const unsigned char *th);
int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir);
void arp_ifdown(struct net_device *dev);
int arp_invalidate(struct net_device *dev, __be32 ip, bool force);

struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
			   struct net_device *dev, __be32 src_ip,
+7 −2
Original line number Diff line number Diff line
@@ -1116,13 +1116,18 @@ static int arp_req_get(struct arpreq *r, struct net_device *dev)
	return err;
}

static int arp_invalidate(struct net_device *dev, __be32 ip)
int arp_invalidate(struct net_device *dev, __be32 ip, bool force)
{
	struct neighbour *neigh = neigh_lookup(&arp_tbl, &ip, dev);
	int err = -ENXIO;
	struct neigh_table *tbl = &arp_tbl;

	if (neigh) {
		if ((neigh->nud_state & NUD_VALID) && !force) {
			neigh_release(neigh);
			return 0;
		}

		if (neigh->nud_state & ~NUD_NOARP)
			err = neigh_update(neigh, NULL, NUD_FAILED,
					   NEIGH_UPDATE_F_OVERRIDE|
@@ -1169,7 +1174,7 @@ static int arp_req_delete(struct net *net, struct arpreq *r,
		if (!dev)
			return -EINVAL;
	}
	return arp_invalidate(dev, ip);
	return arp_invalidate(dev, ip, true);
}

/*
+4 −1
Original line number Diff line number Diff line
@@ -1124,9 +1124,11 @@ void fib_add_ifaddr(struct in_ifaddr *ifa)
		return;

	/* Add broadcast address, if it is explicitly assigned. */
	if (ifa->ifa_broadcast && ifa->ifa_broadcast != htonl(0xFFFFFFFF))
	if (ifa->ifa_broadcast && ifa->ifa_broadcast != htonl(0xFFFFFFFF)) {
		fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32,
			  prim, 0);
		arp_invalidate(dev, ifa->ifa_broadcast, false);
	}

	if (!ipv4_is_zeronet(prefix) && !(ifa->ifa_flags & IFA_F_SECONDARY) &&
	    (prefix != addr || ifa->ifa_prefixlen < 32)) {
@@ -1140,6 +1142,7 @@ void fib_add_ifaddr(struct in_ifaddr *ifa)
		if (ifa->ifa_prefixlen < 31) {
			fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix | ~mask,
				  32, prim, 0);
			arp_invalidate(dev, prefix | ~mask, false);
		}
	}
}
+57 −1
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ ret=0
ksft_skip=4

# all tests in this script. Can be overridden with -t option
TESTS="unregister down carrier nexthop suppress ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric ipv6_route_metrics ipv4_route_metrics ipv4_route_v6_gw rp_filter ipv4_del_addr ipv4_mangle ipv6_mangle"
TESTS="unregister down carrier nexthop suppress ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric ipv6_route_metrics ipv4_route_metrics ipv4_route_v6_gw rp_filter ipv4_del_addr ipv4_mangle ipv6_mangle ipv4_bcast_neigh"

VERBOSE=0
PAUSE_ON_FAIL=no
@@ -1954,6 +1954,61 @@ ipv6_mangle_test()
	route_cleanup
}

ip_neigh_get_check()
{
	ip neigh help 2>&1 | grep -q 'ip neigh get'
	if [ $? -ne 0 ]; then
		echo "iproute2 command does not support neigh get. Skipping test"
		return 1
	fi

	return 0
}

ipv4_bcast_neigh_test()
{
	local rc

	echo
	echo "IPv4 broadcast neighbour tests"

	ip_neigh_get_check || return 1

	setup

	set -e
	run_cmd "$IP neigh add 192.0.2.111 lladdr 00:11:22:33:44:55 nud perm dev dummy0"
	run_cmd "$IP neigh add 192.0.2.255 lladdr 00:11:22:33:44:55 nud perm dev dummy0"

	run_cmd "$IP neigh get 192.0.2.111 dev dummy0"
	run_cmd "$IP neigh get 192.0.2.255 dev dummy0"

	run_cmd "$IP address add 192.0.2.1/24 broadcast 192.0.2.111 dev dummy0"

	run_cmd "$IP neigh add 203.0.113.111 nud failed dev dummy0"
	run_cmd "$IP neigh add 203.0.113.255 nud failed dev dummy0"

	run_cmd "$IP neigh get 203.0.113.111 dev dummy0"
	run_cmd "$IP neigh get 203.0.113.255 dev dummy0"

	run_cmd "$IP address add 203.0.113.1/24 broadcast 203.0.113.111 dev dummy0"
	set +e

	run_cmd "$IP neigh get 192.0.2.111 dev dummy0"
	log_test $? 0 "Resolved neighbour for broadcast address"

	run_cmd "$IP neigh get 192.0.2.255 dev dummy0"
	log_test $? 0 "Resolved neighbour for network broadcast address"

	run_cmd "$IP neigh get 203.0.113.111 dev dummy0"
	log_test $? 2 "Unresolved neighbour for broadcast address"

	run_cmd "$IP neigh get 203.0.113.255 dev dummy0"
	log_test $? 2 "Unresolved neighbour for network broadcast address"

	cleanup
}

################################################################################
# usage

@@ -2028,6 +2083,7 @@ do
	ipv4_route_v6_gw)		ipv4_route_v6_gw_test;;
	ipv4_mangle)			ipv4_mangle_test;;
	ipv6_mangle)			ipv6_mangle_test;;
	ipv4_bcast_neigh)		ipv4_bcast_neigh_test;;

	help) echo "Test names: $TESTS"; exit 0;;
	esac