On upstream kernel datapath OVS make use of networking devices where networking stack does check if device is UP. following patch adds same check in case of compat tunneling implementation. This check also fixes kernel crash in case vxlan device was brought down by user.
CPU: 4 PID: 12988 Comm: handler903 Tainted: RIP: 0010:[<ffffffffa05e5407>] vxlan_xmit_one.constprop.50+0x47/0x1210 [openvswitch] Call Trace: [<ffffffffa05e6625>] rpl_vxlan_xmit+0x55/0x80 [openvswitch] [<ffffffffa05d5ad4>] ovs_vport_send+0x44/0xb0 [openvswitch] [<ffffffffa05c62a5>] do_output+0x65/0x180 [openvswitch] [<ffffffffa05c70dc>] do_execute_actions+0x10c/0x860 [openvswitch] [<ffffffffa05c7870>] ovs_execute_actions+0x40/0x130 [openvswitch] [<ffffffffa05cbb59>] ovs_packet_cmd_execute+0x2c9/0x2f0 [openvswitch] [<ffffffff8155f31d>] genl_family_rcv_msg+0x1cd/0x400 [<ffffffff8155f5e1>] genl_rcv_msg+0x91/0xd0 [<ffffffff8155d549>] netlink_rcv_skb+0xa9/0xc0 [<ffffffff8155da78>] genl_rcv+0x28/0x40 [<ffffffff8155ceba>] netlink_unicast+0x16a/0x210 [<ffffffff8155d277>] netlink_sendmsg+0x317/0x430 [<ffffffff81514fd0>] sock_sendmsg+0xb0/0xf0 [<ffffffff81515409>] ___sys_sendmsg+0x3a9/0x3c0 [<ffffffff815162f1>] __sys_sendmsg+0x51/0x90 [<ffffffff81516342>] SyS_sendmsg+0x12/0x20 [<ffffffff81649609>] system_call_fastpath+0x16/0x1b Reported-by: Huanglili (lee) <huanglili.hu...@huawei.com> Signed-off-by: Pravin B Shelar <pshe...@ovn.org> --- v1-v2: Use dev-kfree-skb() --- datapath/linux/compat/geneve.c | 3 +++ datapath/linux/compat/include/linux/netdevice.h | 12 ++++++++++++ datapath/linux/compat/ip_gre.c | 3 +++ datapath/linux/compat/lisp.c | 3 +++ datapath/linux/compat/stt.c | 3 +++ datapath/linux/compat/vxlan.c | 3 +++ 6 files changed, 27 insertions(+) diff --git a/datapath/linux/compat/geneve.c b/datapath/linux/compat/geneve.c index 0c5b58a..a5d69b4 100644 --- a/datapath/linux/compat/geneve.c +++ b/datapath/linux/compat/geneve.c @@ -1118,6 +1118,9 @@ netdev_tx_t rpl_geneve_xmit(struct sk_buff *skb) struct geneve_dev *geneve = netdev_priv(dev); struct ip_tunnel_info *info = NULL; + if (unlikely(netdev_down_check(dev, skb))) + return NETDEV_TX_OK; + if (geneve->collect_md) info = skb_tunnel_info(skb); diff --git a/datapath/linux/compat/include/linux/netdevice.h b/datapath/linux/compat/include/linux/netdevice.h index dd028f6..2a768a9 100644 --- a/datapath/linux/compat/include/linux/netdevice.h +++ b/datapath/linux/compat/include/linux/netdevice.h @@ -239,6 +239,18 @@ do { \ #ifndef USE_UPSTREAM_TUNNEL #define dev_fill_metadata_dst ovs_dev_fill_metadata_dst int ovs_dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb); + +static inline bool netdev_down_check(struct net_device *dev, struct sk_buff *skb) +{ + if (unlikely(!(dev->flags & IFF_UP))) { + dev->stats.tx_dropped++; + dev_kfree_skb(skb); + return true; + } + return false; +} +#else +#define netdev_down_check(dev, skb) false #endif #ifndef NETDEV_OFFLOAD_PUSH_VXLAN diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index 03c5435..6da6636 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -285,6 +285,9 @@ netdev_tx_t rpl_gre_fb_xmit(struct sk_buff *skb) __be16 df, flags; int err; + if (unlikely(netdev_down_check(dev, skb))) + return NETDEV_TX_OK; + tun_info = skb_tunnel_info(skb); if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) || ip_tunnel_info_af(tun_info) != AF_INET)) diff --git a/datapath/linux/compat/lisp.c b/datapath/linux/compat/lisp.c index 3a4bebc..8ab8646 100644 --- a/datapath/linux/compat/lisp.c +++ b/datapath/linux/compat/lisp.c @@ -325,6 +325,9 @@ netdev_tx_t rpl_lisp_xmit(struct sk_buff *skb) __be16 df; int err; + if (unlikely(netdev_down_check(dev, skb))) + return NETDEV_TX_OK; + info = skb_tunnel_info(skb); if (unlikely(!info)) { err = -EINVAL; diff --git a/datapath/linux/compat/stt.c b/datapath/linux/compat/stt.c index ca9f039..5ffe565 100644 --- a/datapath/linux/compat/stt.c +++ b/datapath/linux/compat/stt.c @@ -1009,6 +1009,9 @@ netdev_tx_t ovs_stt_xmit(struct sk_buff *skb) __be16 df; int err; + if (unlikely(netdev_down_check(dev, skb))) + return NETDEV_TX_OK; + tun_info = skb_tunnel_info(skb); if (unlikely(!tun_info)) { err = -EINVAL; diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c index 47a5a68..64cc1a8 100644 --- a/datapath/linux/compat/vxlan.c +++ b/datapath/linux/compat/vxlan.c @@ -1231,6 +1231,9 @@ netdev_tx_t rpl_vxlan_xmit(struct sk_buff *skb) struct vxlan_dev *vxlan = netdev_priv(dev); const struct ip_tunnel_info *info; + if (unlikely(netdev_down_check(dev, skb))) + return NETDEV_TX_OK; + info = skb_tunnel_info(skb); skb_reset_mac_header(skb); if (vxlan->flags & VXLAN_F_COLLECT_METADATA) { -- 1.8.3.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev