Merge branch 'udp-tunnel-offloads-toggle'
Sabrina Dubroca says: ==================== Allow to switch off UDP-based tunnel offloads per netdevice This patchset adds a new netdevice feature to toggle RX offloads of UDP-based tunnel via ethtool. This is useful if the offload is causing issues, for example if the hardware is buggy. The feature is added to all devices providing the ->ndo_udp_tunnel_add op, and enabled by default to preserve current behavior. When the administrator disables this feature on a device, all currently offloaded ports are cleared from the device. When the feature is turned on, the stack notifies the device about all current ports. v2: - rename feature bit to NETIF_F_RX_UDP_TUNNEL_PORT - rename ethtool feature to rx-udp_tunnel-port-offload ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
56eda01d53
|
@ -1016,16 +1016,22 @@ static struct device_type geneve_type = {
|
|||
* supply the listening GENEVE udp ports. Callers are expected
|
||||
* to implement the ndo_udp_tunnel_add.
|
||||
*/
|
||||
static void geneve_push_rx_ports(struct net_device *dev)
|
||||
static void geneve_offload_rx_ports(struct net_device *dev, bool push)
|
||||
{
|
||||
struct net *net = dev_net(dev);
|
||||
struct geneve_net *gn = net_generic(net, geneve_net_id);
|
||||
struct geneve_sock *gs;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(gs, &gn->sock_list, list)
|
||||
udp_tunnel_push_rx_port(dev, gs->sock,
|
||||
UDP_TUNNEL_TYPE_GENEVE);
|
||||
list_for_each_entry_rcu(gs, &gn->sock_list, list) {
|
||||
if (push) {
|
||||
udp_tunnel_push_rx_port(dev, gs->sock,
|
||||
UDP_TUNNEL_TYPE_GENEVE);
|
||||
} else {
|
||||
udp_tunnel_drop_rx_port(dev, gs->sock,
|
||||
UDP_TUNNEL_TYPE_GENEVE);
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
|
@ -1560,8 +1566,14 @@ static int geneve_netdevice_event(struct notifier_block *unused,
|
|||
{
|
||||
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
||||
|
||||
if (event == NETDEV_UDP_TUNNEL_PUSH_INFO)
|
||||
geneve_push_rx_ports(dev);
|
||||
if (event == NETDEV_UDP_TUNNEL_PUSH_INFO ||
|
||||
event == NETDEV_UDP_TUNNEL_DROP_INFO) {
|
||||
geneve_offload_rx_ports(dev, event == NETDEV_UDP_TUNNEL_PUSH_INFO);
|
||||
} else if (event == NETDEV_UNREGISTER) {
|
||||
geneve_offload_rx_ports(dev, false);
|
||||
} else if (event == NETDEV_REGISTER) {
|
||||
geneve_offload_rx_ports(dev, true);
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
|
|
@ -2608,7 +2608,7 @@ static struct device_type vxlan_type = {
|
|||
* supply the listening VXLAN udp ports. Callers are expected
|
||||
* to implement the ndo_udp_tunnel_add.
|
||||
*/
|
||||
static void vxlan_push_rx_ports(struct net_device *dev)
|
||||
static void vxlan_offload_rx_ports(struct net_device *dev, bool push)
|
||||
{
|
||||
struct vxlan_sock *vs;
|
||||
struct net *net = dev_net(dev);
|
||||
|
@ -2617,11 +2617,19 @@ static void vxlan_push_rx_ports(struct net_device *dev)
|
|||
|
||||
spin_lock(&vn->sock_lock);
|
||||
for (i = 0; i < PORT_HASH_SIZE; ++i) {
|
||||
hlist_for_each_entry_rcu(vs, &vn->sock_list[i], hlist)
|
||||
udp_tunnel_push_rx_port(dev, vs->sock,
|
||||
(vs->flags & VXLAN_F_GPE) ?
|
||||
UDP_TUNNEL_TYPE_VXLAN_GPE :
|
||||
UDP_TUNNEL_TYPE_VXLAN);
|
||||
hlist_for_each_entry_rcu(vs, &vn->sock_list[i], hlist) {
|
||||
unsigned short type;
|
||||
|
||||
if (vs->flags & VXLAN_F_GPE)
|
||||
type = UDP_TUNNEL_TYPE_VXLAN_GPE;
|
||||
else
|
||||
type = UDP_TUNNEL_TYPE_VXLAN;
|
||||
|
||||
if (push)
|
||||
udp_tunnel_push_rx_port(dev, vs->sock, type);
|
||||
else
|
||||
udp_tunnel_drop_rx_port(dev, vs->sock, type);
|
||||
}
|
||||
}
|
||||
spin_unlock(&vn->sock_lock);
|
||||
}
|
||||
|
@ -3630,10 +3638,15 @@ static int vxlan_netdevice_event(struct notifier_block *unused,
|
|||
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
||||
struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
|
||||
|
||||
if (event == NETDEV_UNREGISTER)
|
||||
if (event == NETDEV_UNREGISTER) {
|
||||
vxlan_offload_rx_ports(dev, false);
|
||||
vxlan_handle_lowerdev_unregister(vn, dev);
|
||||
else if (event == NETDEV_UDP_TUNNEL_PUSH_INFO)
|
||||
vxlan_push_rx_ports(dev);
|
||||
} else if (event == NETDEV_REGISTER) {
|
||||
vxlan_offload_rx_ports(dev, true);
|
||||
} else if (event == NETDEV_UDP_TUNNEL_PUSH_INFO ||
|
||||
event == NETDEV_UDP_TUNNEL_DROP_INFO) {
|
||||
vxlan_offload_rx_ports(dev, event == NETDEV_UDP_TUNNEL_PUSH_INFO);
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
|
|
@ -75,6 +75,7 @@ enum {
|
|||
NETIF_F_HW_TC_BIT, /* Offload TC infrastructure */
|
||||
NETIF_F_HW_ESP_BIT, /* Hardware ESP transformation offload */
|
||||
NETIF_F_HW_ESP_TX_CSUM_BIT, /* ESP with TX checksum offload */
|
||||
NETIF_F_RX_UDP_TUNNEL_PORT_BIT, /* Offload of RX port for UDP tunnels */
|
||||
|
||||
/*
|
||||
* Add your fresh new feature above and remember to update
|
||||
|
@ -138,6 +139,7 @@ enum {
|
|||
#define NETIF_F_HW_TC __NETIF_F(HW_TC)
|
||||
#define NETIF_F_HW_ESP __NETIF_F(HW_ESP)
|
||||
#define NETIF_F_HW_ESP_TX_CSUM __NETIF_F(HW_ESP_TX_CSUM)
|
||||
#define NETIF_F_RX_UDP_TUNNEL_PORT __NETIF_F(RX_UDP_TUNNEL_PORT)
|
||||
|
||||
#define for_each_netdev_feature(mask_addr, bit) \
|
||||
for_each_set_bit(bit, (unsigned long *)mask_addr, NETDEV_FEATURE_COUNT)
|
||||
|
|
|
@ -2317,6 +2317,7 @@ struct netdev_lag_lower_state_info {
|
|||
#define NETDEV_PRECHANGEUPPER 0x001A
|
||||
#define NETDEV_CHANGELOWERSTATE 0x001B
|
||||
#define NETDEV_UDP_TUNNEL_PUSH_INFO 0x001C
|
||||
#define NETDEV_UDP_TUNNEL_DROP_INFO 0x001D
|
||||
#define NETDEV_CHANGE_TX_QUEUE_LEN 0x001E
|
||||
|
||||
int register_netdevice_notifier(struct notifier_block *nb);
|
||||
|
|
|
@ -115,6 +115,8 @@ struct udp_tunnel_info {
|
|||
/* Notify network devices of offloadable types */
|
||||
void udp_tunnel_push_rx_port(struct net_device *dev, struct socket *sock,
|
||||
unsigned short type);
|
||||
void udp_tunnel_drop_rx_port(struct net_device *dev, struct socket *sock,
|
||||
unsigned short type);
|
||||
void udp_tunnel_notify_add_rx_port(struct socket *sock, unsigned short type);
|
||||
void udp_tunnel_notify_del_rx_port(struct socket *sock, unsigned short type);
|
||||
|
||||
|
@ -124,6 +126,12 @@ static inline void udp_tunnel_get_rx_info(struct net_device *dev)
|
|||
call_netdevice_notifiers(NETDEV_UDP_TUNNEL_PUSH_INFO, dev);
|
||||
}
|
||||
|
||||
static inline void udp_tunnel_drop_rx_info(struct net_device *dev)
|
||||
{
|
||||
ASSERT_RTNL();
|
||||
call_netdevice_notifiers(NETDEV_UDP_TUNNEL_DROP_INFO, dev);
|
||||
}
|
||||
|
||||
/* Transmit the skb using UDP encapsulation. */
|
||||
void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb,
|
||||
__be32 src, __be32 dst, __u8 tos, __u8 ttl,
|
||||
|
|
|
@ -144,6 +144,7 @@
|
|||
#include <linux/netfilter_ingress.h>
|
||||
#include <linux/crash_dump.h>
|
||||
#include <linux/sctp.h>
|
||||
#include <net/udp_tunnel.h>
|
||||
|
||||
#include "net-sysfs.h"
|
||||
|
||||
|
@ -7327,8 +7328,27 @@ sync_lower:
|
|||
netdev_for_each_lower_dev(dev, lower, iter)
|
||||
netdev_sync_lower_features(dev, lower, features);
|
||||
|
||||
if (!err)
|
||||
if (!err) {
|
||||
netdev_features_t diff = features ^ dev->features;
|
||||
|
||||
if (diff & NETIF_F_RX_UDP_TUNNEL_PORT) {
|
||||
/* udp_tunnel_{get,drop}_rx_info both need
|
||||
* NETIF_F_RX_UDP_TUNNEL_PORT enabled on the
|
||||
* device, or they won't do anything.
|
||||
* Thus we need to update dev->features
|
||||
* *before* calling udp_tunnel_get_rx_info,
|
||||
* but *after* calling udp_tunnel_drop_rx_info.
|
||||
*/
|
||||
if (features & NETIF_F_RX_UDP_TUNNEL_PORT) {
|
||||
dev->features = features;
|
||||
udp_tunnel_get_rx_info(dev);
|
||||
} else {
|
||||
udp_tunnel_drop_rx_info(dev);
|
||||
}
|
||||
}
|
||||
|
||||
dev->features = features;
|
||||
}
|
||||
|
||||
return err < 0 ? 0 : 1;
|
||||
}
|
||||
|
@ -7530,6 +7550,12 @@ int register_netdevice(struct net_device *dev)
|
|||
*/
|
||||
dev->hw_features |= NETIF_F_SOFT_FEATURES;
|
||||
dev->features |= NETIF_F_SOFT_FEATURES;
|
||||
|
||||
if (dev->netdev_ops->ndo_udp_tunnel_add) {
|
||||
dev->features |= NETIF_F_RX_UDP_TUNNEL_PORT;
|
||||
dev->hw_features |= NETIF_F_RX_UDP_TUNNEL_PORT;
|
||||
}
|
||||
|
||||
dev->wanted_features = dev->features & dev->hw_features;
|
||||
|
||||
if (!(dev->flags & IFF_LOOPBACK))
|
||||
|
|
|
@ -105,6 +105,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
|
|||
[NETIF_F_HW_TC_BIT] = "hw-tc-offload",
|
||||
[NETIF_F_HW_ESP_BIT] = "esp-hw-offload",
|
||||
[NETIF_F_HW_ESP_TX_CSUM_BIT] = "esp-tx-csum-hw-offload",
|
||||
[NETIF_F_RX_UDP_TUNNEL_PORT_BIT] = "rx-udp_tunnel-port-offload",
|
||||
};
|
||||
|
||||
static const char
|
||||
|
|
|
@ -82,7 +82,8 @@ void udp_tunnel_push_rx_port(struct net_device *dev, struct socket *sock,
|
|||
struct sock *sk = sock->sk;
|
||||
struct udp_tunnel_info ti;
|
||||
|
||||
if (!dev->netdev_ops->ndo_udp_tunnel_add)
|
||||
if (!dev->netdev_ops->ndo_udp_tunnel_add ||
|
||||
!(dev->features & NETIF_F_RX_UDP_TUNNEL_PORT))
|
||||
return;
|
||||
|
||||
ti.type = type;
|
||||
|
@ -93,6 +94,24 @@ void udp_tunnel_push_rx_port(struct net_device *dev, struct socket *sock,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(udp_tunnel_push_rx_port);
|
||||
|
||||
void udp_tunnel_drop_rx_port(struct net_device *dev, struct socket *sock,
|
||||
unsigned short type)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct udp_tunnel_info ti;
|
||||
|
||||
if (!dev->netdev_ops->ndo_udp_tunnel_del ||
|
||||
!(dev->features & NETIF_F_RX_UDP_TUNNEL_PORT))
|
||||
return;
|
||||
|
||||
ti.type = type;
|
||||
ti.sa_family = sk->sk_family;
|
||||
ti.port = inet_sk(sk)->inet_sport;
|
||||
|
||||
dev->netdev_ops->ndo_udp_tunnel_del(dev, &ti);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(udp_tunnel_drop_rx_port);
|
||||
|
||||
/* Notify netdevs that UDP port started listening */
|
||||
void udp_tunnel_notify_add_rx_port(struct socket *sock, unsigned short type)
|
||||
{
|
||||
|
@ -109,6 +128,8 @@ void udp_tunnel_notify_add_rx_port(struct socket *sock, unsigned short type)
|
|||
for_each_netdev_rcu(net, dev) {
|
||||
if (!dev->netdev_ops->ndo_udp_tunnel_add)
|
||||
continue;
|
||||
if (!(dev->features & NETIF_F_RX_UDP_TUNNEL_PORT))
|
||||
continue;
|
||||
dev->netdev_ops->ndo_udp_tunnel_add(dev, &ti);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
@ -131,6 +152,8 @@ void udp_tunnel_notify_del_rx_port(struct socket *sock, unsigned short type)
|
|||
for_each_netdev_rcu(net, dev) {
|
||||
if (!dev->netdev_ops->ndo_udp_tunnel_del)
|
||||
continue;
|
||||
if (!(dev->features & NETIF_F_RX_UDP_TUNNEL_PORT))
|
||||
continue;
|
||||
dev->netdev_ops->ndo_udp_tunnel_del(dev, &ti);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
|
Загрузка…
Ссылка в новой задаче