On Mon, Jun 25, 2018 at 10:45 AM, Xin Long <lucien....@gmail.com> wrote:
> This patch implements the feature described in rfc1812#section-5.3.5.2
> and rfc2644. It allows the router to forward directed broadcast when
> sysctl mc_forwarding is enabled.
>
> Note that this feature could be done by iptables -j TEE, but it would
> cause some problems:
>   - target TEE's gateway param has to be set with a specific address,
>     and it's not flexible especially when the route wants forward all
>     directed broadcasts.
>   - this duplicates the directed broadcasts so this may cause side
>     effects to applications.
>
> Besides, to keep consistent with other os router like BSD, it's also
> necessary to implement it in the route rx path.
>
> Signed-off-by: Xin Long <lucien....@gmail.com>
> ---
>  include/linux/inetdevice.h   | 1 +
>  include/uapi/linux/ip.h      | 1 +
>  include/uapi/linux/netconf.h | 1 +
>  net/ipv4/devinet.c           | 7 +++++++
>  net/ipv4/route.c             | 6 +++++-
>  5 files changed, 15 insertions(+), 1 deletion(-)
>
> diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
> index 27650f1..c759d1c 100644
> --- a/include/linux/inetdevice.h
> +++ b/include/linux/inetdevice.h
> @@ -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_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_SRC_VMARK(in_dev)       IN_DEV_ORCONF((in_dev), SRC_VMARK)
>  #define IN_DEV_SOURCE_ROUTE(in_dev)    IN_DEV_ANDCONF((in_dev), \
> diff --git a/include/uapi/linux/ip.h b/include/uapi/linux/ip.h
> index b24a742..2b756b5 100644
> --- a/include/uapi/linux/ip.h
> +++ b/include/uapi/linux/ip.h
> @@ -139,6 +139,7 @@ enum
>  {
>         IPV4_DEVCONF_FORWARDING=1,
>         IPV4_DEVCONF_MC_FORWARDING,
> +       IPV4_DEVCONF_BC_FORWARDING,
>         IPV4_DEVCONF_PROXY_ARP,
>         IPV4_DEVCONF_ACCEPT_REDIRECTS,
>         IPV4_DEVCONF_SECURE_REDIRECTS,
> diff --git a/include/uapi/linux/netconf.h b/include/uapi/linux/netconf.h
> index c84fcdf..a5cd70e 100644
> --- a/include/uapi/linux/netconf.h
> +++ b/include/uapi/linux/netconf.h
> @@ -15,6 +15,7 @@ enum {
>         NETCONFA_FORWARDING,
>         NETCONFA_RP_FILTER,
>         NETCONFA_MC_FORWARDING,
> +       NETCONFA_BC_FORWARDING,
>         NETCONFA_PROXY_NEIGH,
>         NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
>         NETCONFA_INPUT,
> diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
> index d7585ab..ea30ab6 100644
> --- a/net/ipv4/devinet.c
> +++ b/net/ipv4/devinet.c
> @@ -1827,6 +1827,8 @@ static int inet_netconf_msgsize_devconf(int type)
>                 size += nla_total_size(4);
>         if (all || type == NETCONFA_MC_FORWARDING)
>                 size += nla_total_size(4);
> +       if (all || type == NETCONFA_BC_FORWARDING)
> +               size += nla_total_size(4);
>         if (all || type == NETCONFA_PROXY_NEIGH)
>                 size += nla_total_size(4);
>         if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
> @@ -1873,6 +1875,10 @@ static int inet_netconf_fill_devconf(struct sk_buff 
> *skb, int ifindex,
>             nla_put_s32(skb, NETCONFA_MC_FORWARDING,
>                         IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
>                 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) &&
>             nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
>                         IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
> @@ -2259,6 +2265,7 @@ static struct devinet_sysctl_table {
>                 DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
>                                              devinet_sysctl_forward),
>                 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(SECURE_REDIRECTS, "secure_redirects"),
> diff --git a/net/ipv4/route.c b/net/ipv4/route.c
> index 1df6e97..b678466 100644
> --- a/net/ipv4/route.c
> +++ b/net/ipv4/route.c
> @@ -1996,8 +1996,11 @@ static int ip_route_input_slow(struct sk_buff *skb, 
> __be32 daddr, __be32 saddr,
>                 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;
> +       }
>
>         if (res->type == RTN_LOCAL) {
>                 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,
>         if (res->type != RTN_UNICAST)
>                 goto martian_destination;
>
> +make_route:
>         err = ip_mkroute_input(skb, res, in_dev, daddr, saddr, tos, flkeys);
>  out:   return err;
>
> --
> 2.1.0
>
attachment is some testing scipts.
#!/bin/bash

# TOPO:
# host1 172.16.1.1/24 <-> .254/24 RTR  .254/24 <-> 192.168.1.1/24 host2
#                     <-> .253/24 RTR2 .254/24 <-> 192.168.2.1/24 host3

netns_list="host1 host2 host3 RTR RTR2"
for i in $netns_list; do
	ip netns del $i > /dev/null 2>&1
done
for i in $netns_list; do
	ip netns add $i
done
ip link add host1_eth1 type veth peer name RTR_eth1
ip link add host1_eth2 type veth peer name RTR2_eth1
ip link add host2_eth1 type veth peer name RTR_eth2
ip link add host3_eth1 type veth peer name RTR2_eth2
ip link set RTR_eth1 netns RTR
ip link set RTR2_eth1 netns RTR2
ip link set RTR_eth2 netns RTR
ip link set RTR2_eth2 netns RTR2
ip link set host1_eth1 netns host1
ip link set host1_eth2 netns host1
ip link set host2_eth1 netns host2
ip link set host3_eth1 netns host3

ip netns exec host1 brctl addbr host1_br0
ip netns exec host1 brctl addif host1_br0 host1_eth1
ip netns exec host1 brctl addif host1_br0 host1_eth2
ip netns exec host1 ifconfig host1_br0 172.16.1.1/24 up
ip netns exec host1 ip link set host1_eth1 up
ip netns exec host1 ip link set host1_eth2 up

ip netns exec RTR ifconfig RTR_eth1 172.16.1.254/24 up
ip netns exec RTR2 ifconfig RTR2_eth1 172.16.1.253/24 up
ip netns exec RTR ifconfig RTR_eth2 192.168.1.254/24 up
ip netns exec RTR2 ifconfig RTR2_eth2 192.168.2.254/24 up
ip netns exec RTR sysctl -w net.ipv4.conf.all.forwarding=1
ip netns exec RTR2 sysctl -w net.ipv4.conf.all.forwarding=1

ip netns exec RTR sysctl -w net.ipv4.conf.RTR_eth1.bc_forwarding=1
ip netns exec RTR2 sysctl -w net.ipv4.conf.RTR2_eth1.bc_forwarding=1
ip netns exec RTR sysctl -w net.ipv4.conf.all.bc_forwarding=1
ip netns exec RTR2 sysctl -w net.ipv4.conf.all.bc_forwarding=1

ip netns exec host2 ifconfig host2_eth1 192.168.1.1/24 up
ip netns exec host3 ifconfig host3_eth1 192.168.2.1/24 up

ip netns exec host1 ip route add default nexthop via 172.16.1.254 nexthop via 172.16.1.253
ip netns exec host2 ip route add default via 192.168.1.254
ip netns exec host3 ip route add default via 192.168.2.254

ip netns exec host2 sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=0
ip netns exec host3 sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=0
ip netns exec RTR sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=0
ip netns exec RTR2 sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=0

ip netns exec host1 ping 192.168.2.255 -c 1
# ip netns exec host3 tcpdump -i host3_eth1 -p icmp -nn

# ip netns exec host1 ping 192.168.1.255 -c 1
# ip netns exec host2 tcpdump -i host2_eth1 -p icmp -nn

# ip netns exec host1 ping 255.255.255.255 -c 1

Reply via email to