[PATCH ovpn net 8/9] ovpn: disable IPv4 redirects on MP interface after registration
Antonio Quartulli <[email protected]>
| Newsgroups | gmane.network.openvpn.devel |
|---|---|
| Message-ID | <[email protected]> |
From: Antonio Quartulli <[email protected]> ovpn_mp_alloc() tried to disable SEND_REDIRECTS on a multipeer interface, but it runs from ovpn_net_init() (->ndo_init), which register_netdevice() invokes before the NETDEV_REGISTER notifier chain. The IPv4 in_device is only created when that notifier reaches inetdev_event() -> inetdev_init(), so __in_dev_get_rtnl() always returned NULL at ndo_init time and the whole redirect-disabling block (both the per-device and the per-netns IPV4_DEVCONF_ALL write) was dead. MP interfaces therefore kept emitting ICMP redirects. Move the redirect-disabling to ovpn_newlink(), right after a successful register_netdevice(): at that point the NETDEV_REGISTER notifier has run and the in_device exists, and RTNL is held by the newlink path so __in_dev_get_rtnl() is safe. A successful register_netdevice() guarantees the in_device was created (otherwise the notifier would have failed and registration rolled back), so the in_device check is now a real guard rather than dead code. The peer-table allocation stays in ovpn_mp_alloc()/->ndo_init, where it belongs (it does not depend on the in_device and is freed in ->ndo_uninit). Fixes: 05003b408c20 ("ovpn: implement multi-peer support") Signed-off-by: Antonio Quartulli <[email protected]> --- drivers/net/ovpn/main.c | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c index 9993c1dfe471..a881510aaac0 100644 --- a/drivers/net/ovpn/main.c +++ b/drivers/net/ovpn/main.c @@ -35,25 +35,11 @@ static void ovpn_priv_free(struct net_device *net) static int ovpn_mp_alloc(struct ovpn_priv *ovpn) { - struct in_device *dev_v4; int i; if (ovpn->mode != OVPN_MODE_MP) return 0; - dev_v4 = __in_dev_get_rtnl(ovpn->dev); - if (dev_v4) { - /* disable redirects as Linux gets confused by ovpn - * handling same-LAN routing. - * This happens because a multipeer interface is used as - * relay point between hosts in the same subnet, while - * in a classic LAN this would not be needed because the - * two hosts would be able to talk directly. - */ - IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false); - IPV4_DEVCONF_ALL(dev_net(ovpn->dev), SEND_REDIRECTS) = false; - } - /* the peer container is fairly large, therefore we allocate it only in * MP mode */ @@ -183,6 +169,8 @@ static int ovpn_newlink(struct net_device *dev, struct ovpn_priv *ovpn = netdev_priv(dev); struct nlattr **data = params->data; enum ovpn_mode mode = OVPN_MODE_P2P; + struct in_device *dev_v4; + int ret; if (data && data[IFLA_OVPN_MODE]) { mode = nla_get_u8(data[IFLA_OVPN_MODE]); @@ -207,7 +195,30 @@ static int ovpn_newlink(struct net_device *dev, else netif_carrier_off(dev); - return register_netdevice(dev); + ret = register_netdevice(dev); + if (ret < 0) + return ret; + + /* The IPv4 in_device is created by the NETDEV_REGISTER notifier, which + * fires inside register_netdevice() above, so this cannot be done + * earlier (e.g. in ndo_init). RTNL is held by the newlink path. + */ + if (ovpn->mode == OVPN_MODE_MP) { + dev_v4 = __in_dev_get_rtnl(dev); + if (dev_v4) { + /* disable redirects as Linux gets confused by ovpn + * handling same-LAN routing. + * This happens because a multipeer interface is used as + * relay point between hosts in the same subnet, while + * in a classic LAN this would not be needed because the + * two hosts would be able to talk directly. + */ + IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false); + IPV4_DEVCONF_ALL(dev_net(dev), SEND_REDIRECTS) = false; + } + } + + return 0; } static int ovpn_fill_info(struct sk_buff *skb, const struct net_device *dev) -- 2.53.0