On Mon, 2018-07-02 at 14:30 +0800, Xin Long 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 bc_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. > > Note that route cache needs to be flushed when bc_forwarding is > changed. > > 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 | 11 +++++++++++ > net/ipv4/route.c | 6 +++++- > 5 files changed, 19 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..e42d13b 100644 > --- a/include/uapi/linux/ip.h > +++ b/include/uapi/linux/ip.h > @@ -168,6 +168,7 @@ enum > IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN, > IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST, > IPV4_DEVCONF_DROP_GRATUITOUS_ARP, > + IPV4_DEVCONF_BC_FORWARDING, > __IPV4_DEVCONF_MAX > }; > > diff --git a/include/uapi/linux/netconf.h b/include/uapi/linux/netconf.h > index c84fcdf..fac4edd 100644 > --- a/include/uapi/linux/netconf.h > +++ b/include/uapi/linux/netconf.h > @@ -18,6 +18,7 @@ enum { > NETCONFA_PROXY_NEIGH, > NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, > NETCONFA_INPUT, > + NETCONFA_BC_FORWARDING, > __NETCONFA_MAX > }; > #define NETCONFA_MAX (__NETCONFA_MAX - 1) > diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c > index d7585ab..80cb464 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) > @@ -2143,6 +2149,10 @@ static int devinet_conf_proc(struct ctl_table *ctl, > int write, > if ((new_value == 0) && (old_value != 0)) > 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 && > new_value != old_value) { > ifindex = devinet_conf_ifindex(net, cnf); > @@ -2259,6 +2269,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; >
Acked-by: Davide Caratti <dcara...@redhat.com>