Commit d05c1ce5 authored by David S. Miller's avatar David S. Miller

Merge branch 'route-add-support-and-selftests-for-directed-broadcast-forwarding'

Xin Long says:

====================
route: add support and selftests for directed broadcast forwarding

Patch 1/2 is the feature and 2/2 is the selftest. Check the changelog
on each of them to know the details.

v1->v2:
  - fix a typo in changelog.
  - fix an uapi break that Davide noticed.
  - flush route cache when bc_forwarding is changed.
  - add the selftest for this patch as Ido's suggestion.

v2->v3:
  - fix an incorrect 'if check' in devinet_conf_proc as David Ahern
    noticed.
  - extend the selftest after one David Ahern fix for vrf.

v3->v4:
  - improve the output log in the selftest as David Ahern suggested.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d0c1f011 40f98b9a
...@@ -93,6 +93,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev) ...@@ -93,6 +93,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
#define IN_DEV_FORWARD(in_dev) IN_DEV_CONF_GET((in_dev), FORWARDING) #define IN_DEV_FORWARD(in_dev) IN_DEV_CONF_GET((in_dev), FORWARDING)
#define IN_DEV_MFORWARD(in_dev) IN_DEV_ANDCONF((in_dev), MC_FORWARDING) #define IN_DEV_MFORWARD(in_dev) IN_DEV_ANDCONF((in_dev), MC_FORWARDING)
#define IN_DEV_BFORWARD(in_dev) IN_DEV_ANDCONF((in_dev), BC_FORWARDING)
#define IN_DEV_RPFILTER(in_dev) IN_DEV_MAXCONF((in_dev), RP_FILTER) #define IN_DEV_RPFILTER(in_dev) IN_DEV_MAXCONF((in_dev), RP_FILTER)
#define IN_DEV_SRC_VMARK(in_dev) IN_DEV_ORCONF((in_dev), SRC_VMARK) #define IN_DEV_SRC_VMARK(in_dev) IN_DEV_ORCONF((in_dev), SRC_VMARK)
#define IN_DEV_SOURCE_ROUTE(in_dev) IN_DEV_ANDCONF((in_dev), \ #define IN_DEV_SOURCE_ROUTE(in_dev) IN_DEV_ANDCONF((in_dev), \
......
...@@ -168,6 +168,7 @@ enum ...@@ -168,6 +168,7 @@ enum
IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN, IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN,
IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST, IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST,
IPV4_DEVCONF_DROP_GRATUITOUS_ARP, IPV4_DEVCONF_DROP_GRATUITOUS_ARP,
IPV4_DEVCONF_BC_FORWARDING,
__IPV4_DEVCONF_MAX __IPV4_DEVCONF_MAX
}; };
......
...@@ -18,6 +18,7 @@ enum { ...@@ -18,6 +18,7 @@ enum {
NETCONFA_PROXY_NEIGH, NETCONFA_PROXY_NEIGH,
NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
NETCONFA_INPUT, NETCONFA_INPUT,
NETCONFA_BC_FORWARDING,
__NETCONFA_MAX __NETCONFA_MAX
}; };
#define NETCONFA_MAX (__NETCONFA_MAX - 1) #define NETCONFA_MAX (__NETCONFA_MAX - 1)
......
...@@ -1827,6 +1827,8 @@ static int inet_netconf_msgsize_devconf(int type) ...@@ -1827,6 +1827,8 @@ static int inet_netconf_msgsize_devconf(int type)
size += nla_total_size(4); size += nla_total_size(4);
if (all || type == NETCONFA_MC_FORWARDING) if (all || type == NETCONFA_MC_FORWARDING)
size += nla_total_size(4); size += nla_total_size(4);
if (all || type == NETCONFA_BC_FORWARDING)
size += nla_total_size(4);
if (all || type == NETCONFA_PROXY_NEIGH) if (all || type == NETCONFA_PROXY_NEIGH)
size += nla_total_size(4); size += nla_total_size(4);
if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
...@@ -1873,6 +1875,10 @@ static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex, ...@@ -1873,6 +1875,10 @@ static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
nla_put_s32(skb, NETCONFA_MC_FORWARDING, nla_put_s32(skb, NETCONFA_MC_FORWARDING,
IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0) IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
goto nla_put_failure; goto nla_put_failure;
if ((all || type == NETCONFA_BC_FORWARDING) &&
nla_put_s32(skb, NETCONFA_BC_FORWARDING,
IPV4_DEVCONF(*devconf, BC_FORWARDING)) < 0)
goto nla_put_failure;
if ((all || type == NETCONFA_PROXY_NEIGH) && if ((all || type == NETCONFA_PROXY_NEIGH) &&
nla_put_s32(skb, NETCONFA_PROXY_NEIGH, nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0) IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
...@@ -2143,6 +2149,10 @@ static int devinet_conf_proc(struct ctl_table *ctl, int write, ...@@ -2143,6 +2149,10 @@ static int devinet_conf_proc(struct ctl_table *ctl, int write,
if ((new_value == 0) && (old_value != 0)) if ((new_value == 0) && (old_value != 0))
rt_cache_flush(net); rt_cache_flush(net);
if (i == IPV4_DEVCONF_BC_FORWARDING - 1 &&
new_value != old_value)
rt_cache_flush(net);
if (i == IPV4_DEVCONF_RP_FILTER - 1 && if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
new_value != old_value) { new_value != old_value) {
ifindex = devinet_conf_ifindex(net, cnf); ifindex = devinet_conf_ifindex(net, cnf);
...@@ -2259,6 +2269,7 @@ static struct devinet_sysctl_table { ...@@ -2259,6 +2269,7 @@ static struct devinet_sysctl_table {
DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding", DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
devinet_sysctl_forward), devinet_sysctl_forward),
DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"), DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
DEVINET_SYSCTL_RW_ENTRY(BC_FORWARDING, "bc_forwarding"),
DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"), DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"), DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
......
...@@ -1996,8 +1996,11 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, ...@@ -1996,8 +1996,11 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
goto no_route; goto no_route;
} }
if (res->type == RTN_BROADCAST) if (res->type == RTN_BROADCAST) {
if (IN_DEV_BFORWARD(in_dev))
goto make_route;
goto brd_input; goto brd_input;
}
if (res->type == RTN_LOCAL) { if (res->type == RTN_LOCAL) {
err = fib_validate_source(skb, saddr, daddr, tos, err = fib_validate_source(skb, saddr, daddr, tos,
...@@ -2014,6 +2017,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, ...@@ -2014,6 +2017,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
if (res->type != RTN_UNICAST) if (res->type != RTN_UNICAST)
goto martian_destination; goto martian_destination;
make_route:
err = ip_mkroute_input(skb, res, in_dev, daddr, saddr, tos, flkeys); err = ip_mkroute_input(skb, res, in_dev, daddr, saddr, tos, flkeys);
out: return err; out: return err;
......
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
ALL_TESTS="ping_ipv4"
NUM_NETIFS=6
source lib.sh
h1_create()
{
vrf_create "vrf-h1"
ip link set dev $h1 master vrf-h1
ip link set dev vrf-h1 up
ip link set dev $h1 up
ip address add 192.0.2.2/24 dev $h1
ip route add 198.51.100.0/24 vrf vrf-h1 nexthop via 192.0.2.1
ip route add 198.51.200.0/24 vrf vrf-h1 nexthop via 192.0.2.1
}
h1_destroy()
{
ip route del 198.51.200.0/24 vrf vrf-h1
ip route del 198.51.100.0/24 vrf vrf-h1
ip address del 192.0.2.2/24 dev $h1
ip link set dev $h1 down
vrf_destroy "vrf-h1"
}
h2_create()
{
vrf_create "vrf-h2"
ip link set dev $h2 master vrf-h2
ip link set dev vrf-h2 up
ip link set dev $h2 up
ip address add 198.51.100.2/24 dev $h2
ip route add 192.0.2.0/24 vrf vrf-h2 nexthop via 198.51.100.1
ip route add 198.51.200.0/24 vrf vrf-h2 nexthop via 198.51.100.1
}
h2_destroy()
{
ip route del 198.51.200.0/24 vrf vrf-h2
ip route del 192.0.2.0/24 vrf vrf-h2
ip address del 198.51.100.2/24 dev $h2
ip link set dev $h2 down
vrf_destroy "vrf-h2"
}
h3_create()
{
vrf_create "vrf-h3"
ip link set dev $h3 master vrf-h3
ip link set dev vrf-h3 up
ip link set dev $h3 up
ip address add 198.51.200.2/24 dev $h3
ip route add 192.0.2.0/24 vrf vrf-h3 nexthop via 198.51.200.1
ip route add 198.51.100.0/24 vrf vrf-h3 nexthop via 198.51.200.1
}
h3_destroy()
{
ip route del 198.51.100.0/24 vrf vrf-h3
ip route del 192.0.2.0/24 vrf vrf-h3
ip address del 198.51.200.2/24 dev $h3
ip link set dev $h3 down
vrf_destroy "vrf-h3"
}
router_create()
{
ip link set dev $rp1 up
ip link set dev $rp2 up
ip link set dev $rp3 up
ip address add 192.0.2.1/24 dev $rp1
ip address add 198.51.100.1/24 dev $rp2
ip address add 198.51.200.1/24 dev $rp3
}
router_destroy()
{
ip address del 198.51.200.1/24 dev $rp3
ip address del 198.51.100.1/24 dev $rp2
ip address del 192.0.2.1/24 dev $rp1
ip link set dev $rp3 down
ip link set dev $rp2 down
ip link set dev $rp1 down
}
setup_prepare()
{
h1=${NETIFS[p1]}
rp1=${NETIFS[p2]}
rp2=${NETIFS[p3]}
h2=${NETIFS[p4]}
rp3=${NETIFS[p5]}
h3=${NETIFS[p6]}
vrf_prepare
h1_create
h2_create
h3_create
router_create
forwarding_enable
}
cleanup()
{
pre_cleanup
forwarding_restore
router_destroy
h3_destroy
h2_destroy
h1_destroy
vrf_cleanup
}
bc_forwarding_disable()
{
sysctl_set net.ipv4.conf.all.bc_forwarding 0
sysctl_set net.ipv4.conf.$rp1.bc_forwarding 0
}
bc_forwarding_enable()
{
sysctl_set net.ipv4.conf.all.bc_forwarding 1
sysctl_set net.ipv4.conf.$rp1.bc_forwarding 1
}
bc_forwarding_restore()
{
sysctl_restore net.ipv4.conf.$rp1.bc_forwarding
sysctl_restore net.ipv4.conf.all.bc_forwarding
}
ping_test_from()
{
local oif=$1
local dip=$2
local from=$3
local fail=${4:-0}
RET=0
log_info "ping $dip, expected reply from $from"
ip vrf exec $(master_name_get $oif) \
$PING -I $oif $dip -c 10 -i 0.1 -w 2 -b 2>&1 | grep $from &> /dev/null
check_err_fail $fail $?
}
ping_ipv4()
{
sysctl_set net.ipv4.icmp_echo_ignore_broadcasts 0
bc_forwarding_disable
log_info "bc_forwarding disabled on r1 =>"
ping_test_from $h1 198.51.100.255 192.0.2.1
log_test "h1 -> net2: reply from r1 (not forwarding)"
ping_test_from $h1 198.51.200.255 192.0.2.1
log_test "h1 -> net3: reply from r1 (not forwarding)"
ping_test_from $h1 192.0.2.255 192.0.2.1
log_test "h1 -> net1: reply from r1 (not dropping)"
ping_test_from $h1 255.255.255.255 192.0.2.1
log_test "h1 -> 255.255.255.255: reply from r1 (not forwarding)"
ping_test_from $h2 192.0.2.255 198.51.100.1
log_test "h2 -> net1: reply from r1 (not forwarding)"
ping_test_from $h2 198.51.200.255 198.51.100.1
log_test "h2 -> net3: reply from r1 (not forwarding)"
ping_test_from $h2 198.51.100.255 198.51.100.1
log_test "h2 -> net2: reply from r1 (not dropping)"
ping_test_from $h2 255.255.255.255 198.51.100.1
log_test "h2 -> 255.255.255.255: reply from r1 (not forwarding)"
bc_forwarding_restore
bc_forwarding_enable
log_info "bc_forwarding enabled on r1 =>"
ping_test_from $h1 198.51.100.255 198.51.100.2
log_test "h1 -> net2: reply from h2 (forwarding)"
ping_test_from $h1 198.51.200.255 198.51.200.2
log_test "h1 -> net3: reply from h3 (forwarding)"
ping_test_from $h1 192.0.2.255 192.0.2.1 1
log_test "h1 -> net1: no reply (dropping)"
ping_test_from $h1 255.255.255.255 192.0.2.1
log_test "h1 -> 255.255.255.255: reply from r1 (not forwarding)"
ping_test_from $h2 192.0.2.255 192.0.2.2
log_test "h2 -> net1: reply from h1 (forwarding)"
ping_test_from $h2 198.51.200.255 198.51.200.2
log_test "h2 -> net3: reply from h3 (forwarding)"
ping_test_from $h2 198.51.100.255 198.51.100.1 1
log_test "h2 -> net2: no reply (dropping)"
ping_test_from $h2 255.255.255.255 198.51.100.1
log_test "h2 -> 255.255.255.255: reply from r1 (not forwarding)"
bc_forwarding_restore
sysctl_restore net.ipv4.icmp_echo_ignore_broadcasts
}
trap cleanup EXIT
setup_prepare
setup_wait
tests_run
exit $EXIT_STATUS
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment