Commit dc224822 authored by Toshiaki Makita's avatar Toshiaki Makita Committed by Daniel Borkmann

veth: Avoid drops by oversized packets when XDP is enabled

Oversized packets including GSO packets can be dropped if XDP is
enabled on receiver side, so don't send such packets from peer.

Drop TSO and SCTP fragmentation features so that veth devices themselves
segment packets with XDP enabled. Also cap MTU accordingly.

v4:
- Don't auto-adjust MTU but cap max MTU.
Signed-off-by: default avatarToshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
parent 948d4f21
...@@ -543,6 +543,23 @@ static int veth_get_iflink(const struct net_device *dev) ...@@ -543,6 +543,23 @@ static int veth_get_iflink(const struct net_device *dev)
return iflink; return iflink;
} }
static netdev_features_t veth_fix_features(struct net_device *dev,
netdev_features_t features)
{
struct veth_priv *priv = netdev_priv(dev);
struct net_device *peer;
peer = rtnl_dereference(priv->peer);
if (peer) {
struct veth_priv *peer_priv = netdev_priv(peer);
if (peer_priv->_xdp_prog)
features &= ~NETIF_F_GSO_SOFTWARE;
}
return features;
}
static void veth_set_rx_headroom(struct net_device *dev, int new_hr) static void veth_set_rx_headroom(struct net_device *dev, int new_hr)
{ {
struct veth_priv *peer_priv, *priv = netdev_priv(dev); struct veth_priv *peer_priv, *priv = netdev_priv(dev);
...@@ -572,6 +589,7 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog, ...@@ -572,6 +589,7 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog,
struct veth_priv *priv = netdev_priv(dev); struct veth_priv *priv = netdev_priv(dev);
struct bpf_prog *old_prog; struct bpf_prog *old_prog;
struct net_device *peer; struct net_device *peer;
unsigned int max_mtu;
int err; int err;
old_prog = priv->_xdp_prog; old_prog = priv->_xdp_prog;
...@@ -585,6 +603,15 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog, ...@@ -585,6 +603,15 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog,
goto err; goto err;
} }
max_mtu = PAGE_SIZE - VETH_XDP_HEADROOM -
peer->hard_header_len -
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
if (peer->mtu > max_mtu) {
NL_SET_ERR_MSG_MOD(extack, "Peer MTU is too large to set XDP");
err = -ERANGE;
goto err;
}
if (dev->flags & IFF_UP) { if (dev->flags & IFF_UP) {
err = veth_enable_xdp(dev); err = veth_enable_xdp(dev);
if (err) { if (err) {
...@@ -592,14 +619,29 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog, ...@@ -592,14 +619,29 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog,
goto err; goto err;
} }
} }
if (!old_prog) {
peer->hw_features &= ~NETIF_F_GSO_SOFTWARE;
peer->max_mtu = max_mtu;
}
} }
if (old_prog) { if (old_prog) {
if (!prog && dev->flags & IFF_UP) if (!prog) {
if (dev->flags & IFF_UP)
veth_disable_xdp(dev); veth_disable_xdp(dev);
if (peer) {
peer->hw_features |= NETIF_F_GSO_SOFTWARE;
peer->max_mtu = ETH_MAX_MTU;
}
}
bpf_prog_put(old_prog); bpf_prog_put(old_prog);
} }
if ((!!old_prog ^ !!prog) && peer)
netdev_update_features(peer);
return 0; return 0;
err: err:
priv->_xdp_prog = old_prog; priv->_xdp_prog = old_prog;
...@@ -644,6 +686,7 @@ static const struct net_device_ops veth_netdev_ops = { ...@@ -644,6 +686,7 @@ static const struct net_device_ops veth_netdev_ops = {
.ndo_poll_controller = veth_poll_controller, .ndo_poll_controller = veth_poll_controller,
#endif #endif
.ndo_get_iflink = veth_get_iflink, .ndo_get_iflink = veth_get_iflink,
.ndo_fix_features = veth_fix_features,
.ndo_features_check = passthru_features_check, .ndo_features_check = passthru_features_check,
.ndo_set_rx_headroom = veth_set_rx_headroom, .ndo_set_rx_headroom = veth_set_rx_headroom,
.ndo_bpf = veth_xdp, .ndo_bpf = veth_xdp,
......
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