diff options
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r-- | drivers/net/tun.c | 42 |
1 files changed, 34 insertions, 8 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index ef09224496e8..85e14adf5207 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -81,6 +81,9 @@ #include <linux/uaccess.h> #include <linux/proc_fs.h> +static void tun_default_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *cmd); + /* Uncomment to enable debugging */ /* #define TUN_DEBUG 1 */ @@ -242,6 +245,7 @@ struct tun_struct { struct bpf_prog __rcu *xdp_prog; struct tun_prog __rcu *steering_prog; struct tun_prog __rcu *filter_prog; + struct ethtool_link_ksettings link_ksettings; }; struct veth { @@ -1654,7 +1658,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, else *skb_xdp = 0; - preempt_disable(); + local_bh_disable(); rcu_read_lock(); xdp_prog = rcu_dereference(tun->xdp_prog); if (xdp_prog && !*skb_xdp) { @@ -1679,7 +1683,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, if (err) goto err_redirect; rcu_read_unlock(); - preempt_enable(); + local_bh_enable(); return NULL; case XDP_TX: get_page(alloc_frag->page); @@ -1687,7 +1691,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, if (tun_xdp_tx(tun->dev, &xdp)) goto err_redirect; rcu_read_unlock(); - preempt_enable(); + local_bh_enable(); return NULL; case XDP_PASS: delta = orig_data - xdp.data; @@ -1707,7 +1711,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, skb = build_skb(buf, buflen); if (!skb) { rcu_read_unlock(); - preempt_enable(); + local_bh_enable(); return ERR_PTR(-ENOMEM); } @@ -1717,7 +1721,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun, alloc_frag->offset += buflen; rcu_read_unlock(); - preempt_enable(); + local_bh_enable(); return skb; @@ -1725,7 +1729,7 @@ err_redirect: put_page(alloc_frag->page); err_xdp: rcu_read_unlock(); - preempt_enable(); + local_bh_enable(); this_cpu_inc(tun->pcpu_stats->rx_dropped); return NULL; } @@ -1921,16 +1925,19 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, struct bpf_prog *xdp_prog; int ret; + local_bh_disable(); rcu_read_lock(); xdp_prog = rcu_dereference(tun->xdp_prog); if (xdp_prog) { ret = do_xdp_generic(xdp_prog, skb); if (ret != XDP_PASS) { rcu_read_unlock(); + local_bh_enable(); return total_len; } } rcu_read_unlock(); + local_bh_enable(); } /* Compute the costly rx hash only if needed for flow updates. @@ -2282,6 +2289,7 @@ static void tun_setup(struct net_device *dev) tun->owner = INVALID_UID; tun->group = INVALID_GID; + tun_default_link_ksettings(dev, &tun->link_ksettings); dev->ethtool_ops = &tun_ethtool_ops; dev->needs_free_netdev = true; @@ -3313,8 +3321,8 @@ static struct miscdevice tun_miscdev = { /* ethtool interface */ -static int tun_get_link_ksettings(struct net_device *dev, - struct ethtool_link_ksettings *cmd) +static void tun_default_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *cmd) { ethtool_link_ksettings_zero_link_mode(cmd, supported); ethtool_link_ksettings_zero_link_mode(cmd, advertising); @@ -3323,6 +3331,23 @@ static int tun_get_link_ksettings(struct net_device *dev, cmd->base.port = PORT_TP; cmd->base.phy_address = 0; cmd->base.autoneg = AUTONEG_DISABLE; +} + +static int tun_get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *cmd) +{ + struct tun_struct *tun = netdev_priv(dev); + + memcpy(cmd, &tun->link_ksettings, sizeof(*cmd)); + return 0; +} + +static int tun_set_link_ksettings(struct net_device *dev, + const struct ethtool_link_ksettings *cmd) +{ + struct tun_struct *tun = netdev_priv(dev); + + memcpy(&tun->link_ksettings, cmd, sizeof(*cmd)); return 0; } @@ -3393,6 +3418,7 @@ static const struct ethtool_ops tun_ethtool_ops = { .get_coalesce = tun_get_coalesce, .set_coalesce = tun_set_coalesce, .get_link_ksettings = tun_get_link_ksettings, + .set_link_ksettings = tun_set_link_ksettings, }; static int tun_queue_resize(struct tun_struct *tun) |