net: Combine GENEVE and VXLAN port notifiers into single functions
This patch merges the GENEVE and VXLAN code so that both functions pass through a shared code path. This way we can start the effort of using a single function on the network device drivers to handle both of these tunnel types. Signed-off-by: Alexander Duyck <aduyck@mirantis.com> Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
86a9805725
Коммит
e7b3db5e60
|
@ -396,23 +396,6 @@ static struct socket *geneve_create_sock(struct net *net, bool ipv6,
|
||||||
return sock;
|
return sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void geneve_notify_add_rx_port(struct geneve_sock *gs)
|
|
||||||
{
|
|
||||||
struct net_device *dev;
|
|
||||||
struct sock *sk = gs->sock->sk;
|
|
||||||
struct net *net = sock_net(sk);
|
|
||||||
sa_family_t sa_family = geneve_get_sk_family(gs);
|
|
||||||
__be16 port = inet_sk(sk)->inet_sport;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
for_each_netdev_rcu(net, dev) {
|
|
||||||
if (dev->netdev_ops->ndo_add_geneve_port)
|
|
||||||
dev->netdev_ops->ndo_add_geneve_port(dev, sa_family,
|
|
||||||
port);
|
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
static int geneve_hlen(struct genevehdr *gh)
|
static int geneve_hlen(struct genevehdr *gh)
|
||||||
{
|
{
|
||||||
return sizeof(*gh) + gh->opt_len * 4;
|
return sizeof(*gh) + gh->opt_len * 4;
|
||||||
|
@ -532,7 +515,7 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
|
||||||
INIT_HLIST_HEAD(&gs->vni_list[h]);
|
INIT_HLIST_HEAD(&gs->vni_list[h]);
|
||||||
|
|
||||||
/* Initialize the geneve udp offloads structure */
|
/* Initialize the geneve udp offloads structure */
|
||||||
geneve_notify_add_rx_port(gs);
|
udp_tunnel_notify_add_rx_port(gs->sock, UDP_TUNNEL_TYPE_GENEVE);
|
||||||
|
|
||||||
/* Mark socket as an encapsulation socket */
|
/* Mark socket as an encapsulation socket */
|
||||||
memset(&tunnel_cfg, 0, sizeof(tunnel_cfg));
|
memset(&tunnel_cfg, 0, sizeof(tunnel_cfg));
|
||||||
|
@ -547,31 +530,13 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
|
||||||
return gs;
|
return gs;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void geneve_notify_del_rx_port(struct geneve_sock *gs)
|
|
||||||
{
|
|
||||||
struct net_device *dev;
|
|
||||||
struct sock *sk = gs->sock->sk;
|
|
||||||
struct net *net = sock_net(sk);
|
|
||||||
sa_family_t sa_family = geneve_get_sk_family(gs);
|
|
||||||
__be16 port = inet_sk(sk)->inet_sport;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
for_each_netdev_rcu(net, dev) {
|
|
||||||
if (dev->netdev_ops->ndo_del_geneve_port)
|
|
||||||
dev->netdev_ops->ndo_del_geneve_port(dev, sa_family,
|
|
||||||
port);
|
|
||||||
}
|
|
||||||
|
|
||||||
rcu_read_unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __geneve_sock_release(struct geneve_sock *gs)
|
static void __geneve_sock_release(struct geneve_sock *gs)
|
||||||
{
|
{
|
||||||
if (!gs || --gs->refcnt)
|
if (!gs || --gs->refcnt)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
list_del(&gs->list);
|
list_del(&gs->list);
|
||||||
geneve_notify_del_rx_port(gs);
|
udp_tunnel_notify_del_rx_port(gs->sock, UDP_TUNNEL_TYPE_GENEVE);
|
||||||
udp_tunnel_sock_release(gs->sock);
|
udp_tunnel_sock_release(gs->sock);
|
||||||
kfree_rcu(gs, rcu);
|
kfree_rcu(gs, rcu);
|
||||||
}
|
}
|
||||||
|
@ -1164,29 +1129,20 @@ static struct device_type geneve_type = {
|
||||||
.name = "geneve",
|
.name = "geneve",
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Calls the ndo_add_geneve_port of the caller in order to
|
/* Calls the ndo_add_udp_enc_port of the caller in order to
|
||||||
* supply the listening GENEVE udp ports. Callers are expected
|
* supply the listening GENEVE udp ports. Callers are expected
|
||||||
* to implement the ndo_add_geneve_port.
|
* to implement the ndo_add_udp_enc_port.
|
||||||
*/
|
*/
|
||||||
static void geneve_push_rx_ports(struct net_device *dev)
|
static void geneve_push_rx_ports(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct net *net = dev_net(dev);
|
struct net *net = dev_net(dev);
|
||||||
struct geneve_net *gn = net_generic(net, geneve_net_id);
|
struct geneve_net *gn = net_generic(net, geneve_net_id);
|
||||||
struct geneve_sock *gs;
|
struct geneve_sock *gs;
|
||||||
sa_family_t sa_family;
|
|
||||||
struct sock *sk;
|
|
||||||
__be16 port;
|
|
||||||
|
|
||||||
if (!dev->netdev_ops->ndo_add_geneve_port)
|
|
||||||
return;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
list_for_each_entry_rcu(gs, &gn->sock_list, list) {
|
list_for_each_entry_rcu(gs, &gn->sock_list, list)
|
||||||
sk = gs->sock->sk;
|
udp_tunnel_push_rx_port(dev, gs->sock,
|
||||||
sa_family = sk->sk_family;
|
UDP_TUNNEL_TYPE_GENEVE);
|
||||||
port = inet_sk(sk)->inet_sport;
|
|
||||||
dev->netdev_ops->ndo_add_geneve_port(dev, sa_family, port);
|
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -602,42 +602,6 @@ static int vxlan_gro_complete(struct sock *sk, struct sk_buff *skb, int nhoff)
|
||||||
return eth_gro_complete(skb, nhoff + sizeof(struct vxlanhdr));
|
return eth_gro_complete(skb, nhoff + sizeof(struct vxlanhdr));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Notify netdevs that UDP port started listening */
|
|
||||||
static void vxlan_notify_add_rx_port(struct vxlan_sock *vs)
|
|
||||||
{
|
|
||||||
struct net_device *dev;
|
|
||||||
struct sock *sk = vs->sock->sk;
|
|
||||||
struct net *net = sock_net(sk);
|
|
||||||
sa_family_t sa_family = vxlan_get_sk_family(vs);
|
|
||||||
__be16 port = inet_sk(sk)->inet_sport;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
for_each_netdev_rcu(net, dev) {
|
|
||||||
if (dev->netdev_ops->ndo_add_vxlan_port)
|
|
||||||
dev->netdev_ops->ndo_add_vxlan_port(dev, sa_family,
|
|
||||||
port);
|
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Notify netdevs that UDP port is no more listening */
|
|
||||||
static void vxlan_notify_del_rx_port(struct vxlan_sock *vs)
|
|
||||||
{
|
|
||||||
struct net_device *dev;
|
|
||||||
struct sock *sk = vs->sock->sk;
|
|
||||||
struct net *net = sock_net(sk);
|
|
||||||
sa_family_t sa_family = vxlan_get_sk_family(vs);
|
|
||||||
__be16 port = inet_sk(sk)->inet_sport;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
for_each_netdev_rcu(net, dev) {
|
|
||||||
if (dev->netdev_ops->ndo_del_vxlan_port)
|
|
||||||
dev->netdev_ops->ndo_del_vxlan_port(dev, sa_family,
|
|
||||||
port);
|
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add new entry to forwarding table -- assumes lock held */
|
/* Add new entry to forwarding table -- assumes lock held */
|
||||||
static int vxlan_fdb_create(struct vxlan_dev *vxlan,
|
static int vxlan_fdb_create(struct vxlan_dev *vxlan,
|
||||||
const u8 *mac, union vxlan_addr *ip,
|
const u8 *mac, union vxlan_addr *ip,
|
||||||
|
@ -1033,7 +997,8 @@ static bool __vxlan_sock_release_prep(struct vxlan_sock *vs)
|
||||||
vn = net_generic(sock_net(vs->sock->sk), vxlan_net_id);
|
vn = net_generic(sock_net(vs->sock->sk), vxlan_net_id);
|
||||||
spin_lock(&vn->sock_lock);
|
spin_lock(&vn->sock_lock);
|
||||||
hlist_del_rcu(&vs->hlist);
|
hlist_del_rcu(&vs->hlist);
|
||||||
vxlan_notify_del_rx_port(vs);
|
udp_tunnel_notify_del_rx_port(vs->sock,
|
||||||
|
UDP_TUNNEL_TYPE_VXLAN);
|
||||||
spin_unlock(&vn->sock_lock);
|
spin_unlock(&vn->sock_lock);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -2508,30 +2473,22 @@ static struct device_type vxlan_type = {
|
||||||
.name = "vxlan",
|
.name = "vxlan",
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Calls the ndo_add_vxlan_port of the caller in order to
|
/* Calls the ndo_add_udp_enc_port of the caller in order to
|
||||||
* supply the listening VXLAN udp ports. Callers are expected
|
* supply the listening VXLAN udp ports. Callers are expected
|
||||||
* to implement the ndo_add_vxlan_port.
|
* to implement the ndo_add_udp_enc_port.
|
||||||
*/
|
*/
|
||||||
static void vxlan_push_rx_ports(struct net_device *dev)
|
static void vxlan_push_rx_ports(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct vxlan_sock *vs;
|
struct vxlan_sock *vs;
|
||||||
struct net *net = dev_net(dev);
|
struct net *net = dev_net(dev);
|
||||||
struct vxlan_net *vn = net_generic(net, vxlan_net_id);
|
struct vxlan_net *vn = net_generic(net, vxlan_net_id);
|
||||||
sa_family_t sa_family;
|
|
||||||
__be16 port;
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
if (!dev->netdev_ops->ndo_add_vxlan_port)
|
|
||||||
return;
|
|
||||||
|
|
||||||
spin_lock(&vn->sock_lock);
|
spin_lock(&vn->sock_lock);
|
||||||
for (i = 0; i < PORT_HASH_SIZE; ++i) {
|
for (i = 0; i < PORT_HASH_SIZE; ++i) {
|
||||||
hlist_for_each_entry_rcu(vs, &vn->sock_list[i], hlist) {
|
hlist_for_each_entry_rcu(vs, &vn->sock_list[i], hlist)
|
||||||
port = inet_sk(vs->sock->sk)->inet_sport;
|
udp_tunnel_push_rx_port(dev, vs->sock,
|
||||||
sa_family = vxlan_get_sk_family(vs);
|
UDP_TUNNEL_TYPE_VXLAN);
|
||||||
dev->netdev_ops->ndo_add_vxlan_port(dev, sa_family,
|
|
||||||
port);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
spin_unlock(&vn->sock_lock);
|
spin_unlock(&vn->sock_lock);
|
||||||
}
|
}
|
||||||
|
@ -2733,7 +2690,8 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, bool ipv6,
|
||||||
|
|
||||||
spin_lock(&vn->sock_lock);
|
spin_lock(&vn->sock_lock);
|
||||||
hlist_add_head_rcu(&vs->hlist, vs_head(net, port));
|
hlist_add_head_rcu(&vs->hlist, vs_head(net, port));
|
||||||
vxlan_notify_add_rx_port(vs);
|
udp_tunnel_notify_add_rx_port(sock,
|
||||||
|
UDP_TUNNEL_TYPE_VXLAN);
|
||||||
spin_unlock(&vn->sock_lock);
|
spin_unlock(&vn->sock_lock);
|
||||||
|
|
||||||
/* Mark socket as an encapsulation socket. */
|
/* Mark socket as an encapsulation socket. */
|
||||||
|
|
|
@ -84,6 +84,39 @@ struct udp_tunnel_sock_cfg {
|
||||||
void setup_udp_tunnel_sock(struct net *net, struct socket *sock,
|
void setup_udp_tunnel_sock(struct net *net, struct socket *sock,
|
||||||
struct udp_tunnel_sock_cfg *sock_cfg);
|
struct udp_tunnel_sock_cfg *sock_cfg);
|
||||||
|
|
||||||
|
/* -- List of parsable UDP tunnel types --
|
||||||
|
*
|
||||||
|
* Adding to this list will result in serious debate. The main issue is
|
||||||
|
* that this list is essentially a list of workarounds for either poorly
|
||||||
|
* designed tunnels, or poorly designed device offloads.
|
||||||
|
*
|
||||||
|
* The parsing supported via these types should really be used for Rx
|
||||||
|
* traffic only as the network stack will have already inserted offsets for
|
||||||
|
* the location of the headers in the skb. In addition any ports that are
|
||||||
|
* pushed should be kept within the namespace without leaking to other
|
||||||
|
* devices such as VFs or other ports on the same device.
|
||||||
|
*
|
||||||
|
* It is strongly encouraged to use CHECKSUM_COMPLETE for Rx to avoid the
|
||||||
|
* need to use this for Rx checksum offload. It should not be necessary to
|
||||||
|
* call this function to perform Tx offloads on outgoing traffic.
|
||||||
|
*/
|
||||||
|
enum udp_parsable_tunnel_type {
|
||||||
|
UDP_TUNNEL_TYPE_VXLAN, /* RFC 7348 */
|
||||||
|
UDP_TUNNEL_TYPE_GENEVE, /* draft-ietf-nvo3-geneve */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct udp_tunnel_info {
|
||||||
|
unsigned short type;
|
||||||
|
sa_family_t sa_family;
|
||||||
|
__be16 port;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 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_notify_add_rx_port(struct socket *sock, unsigned short type);
|
||||||
|
void udp_tunnel_notify_del_rx_port(struct socket *sock, unsigned short type);
|
||||||
|
|
||||||
/* Transmit the skb using UDP encapsulation. */
|
/* Transmit the skb using UDP encapsulation. */
|
||||||
void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb,
|
void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb,
|
||||||
__be32 src, __be32 dst, __u8 tos, __u8 ttl,
|
__be32 src, __be32 dst, __u8 tos, __u8 ttl,
|
||||||
|
|
|
@ -76,6 +76,108 @@ void setup_udp_tunnel_sock(struct net *net, struct socket *sock,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(setup_udp_tunnel_sock);
|
EXPORT_SYMBOL_GPL(setup_udp_tunnel_sock);
|
||||||
|
|
||||||
|
static void __udp_tunnel_push_rx_port(struct net_device *dev,
|
||||||
|
struct udp_tunnel_info *ti)
|
||||||
|
{
|
||||||
|
switch (ti->type) {
|
||||||
|
case UDP_TUNNEL_TYPE_VXLAN:
|
||||||
|
if (!dev->netdev_ops->ndo_add_vxlan_port)
|
||||||
|
break;
|
||||||
|
|
||||||
|
dev->netdev_ops->ndo_add_vxlan_port(dev,
|
||||||
|
ti->sa_family,
|
||||||
|
ti->port);
|
||||||
|
break;
|
||||||
|
case UDP_TUNNEL_TYPE_GENEVE:
|
||||||
|
if (!dev->netdev_ops->ndo_add_geneve_port)
|
||||||
|
break;
|
||||||
|
|
||||||
|
dev->netdev_ops->ndo_add_geneve_port(dev,
|
||||||
|
ti->sa_family,
|
||||||
|
ti->port);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void udp_tunnel_push_rx_port(struct net_device *dev, struct socket *sock,
|
||||||
|
unsigned short type)
|
||||||
|
{
|
||||||
|
struct sock *sk = sock->sk;
|
||||||
|
struct udp_tunnel_info ti;
|
||||||
|
|
||||||
|
ti.type = type;
|
||||||
|
ti.sa_family = sk->sk_family;
|
||||||
|
ti.port = inet_sk(sk)->inet_sport;
|
||||||
|
|
||||||
|
__udp_tunnel_push_rx_port(dev, &ti);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(udp_tunnel_push_rx_port);
|
||||||
|
|
||||||
|
/* Notify netdevs that UDP port started listening */
|
||||||
|
void udp_tunnel_notify_add_rx_port(struct socket *sock, unsigned short type)
|
||||||
|
{
|
||||||
|
struct sock *sk = sock->sk;
|
||||||
|
struct net *net = sock_net(sk);
|
||||||
|
struct udp_tunnel_info ti;
|
||||||
|
struct net_device *dev;
|
||||||
|
|
||||||
|
ti.type = type;
|
||||||
|
ti.sa_family = sk->sk_family;
|
||||||
|
ti.port = inet_sk(sk)->inet_sport;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
for_each_netdev_rcu(net, dev)
|
||||||
|
__udp_tunnel_push_rx_port(dev, &ti);
|
||||||
|
rcu_read_unlock();
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(udp_tunnel_notify_add_rx_port);
|
||||||
|
|
||||||
|
static void __udp_tunnel_pull_rx_port(struct net_device *dev,
|
||||||
|
struct udp_tunnel_info *ti)
|
||||||
|
{
|
||||||
|
switch (ti->type) {
|
||||||
|
case UDP_TUNNEL_TYPE_VXLAN:
|
||||||
|
if (!dev->netdev_ops->ndo_del_vxlan_port)
|
||||||
|
break;
|
||||||
|
|
||||||
|
dev->netdev_ops->ndo_del_vxlan_port(dev,
|
||||||
|
ti->sa_family,
|
||||||
|
ti->port);
|
||||||
|
break;
|
||||||
|
case UDP_TUNNEL_TYPE_GENEVE:
|
||||||
|
if (!dev->netdev_ops->ndo_del_geneve_port)
|
||||||
|
break;
|
||||||
|
|
||||||
|
dev->netdev_ops->ndo_del_geneve_port(dev,
|
||||||
|
ti->sa_family,
|
||||||
|
ti->port);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Notify netdevs that UDP port is no more listening */
|
||||||
|
void udp_tunnel_notify_del_rx_port(struct socket *sock, unsigned short type)
|
||||||
|
{
|
||||||
|
struct sock *sk = sock->sk;
|
||||||
|
struct net *net = sock_net(sk);
|
||||||
|
struct udp_tunnel_info ti;
|
||||||
|
struct net_device *dev;
|
||||||
|
|
||||||
|
ti.type = type;
|
||||||
|
ti.sa_family = sk->sk_family;
|
||||||
|
ti.port = inet_sk(sk)->inet_sport;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
for_each_netdev_rcu(net, dev)
|
||||||
|
__udp_tunnel_pull_rx_port(dev, &ti);
|
||||||
|
rcu_read_unlock();
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(udp_tunnel_notify_del_rx_port);
|
||||||
|
|
||||||
void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb,
|
void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb,
|
||||||
__be32 src, __be32 dst, __u8 tos, __u8 ttl,
|
__be32 src, __be32 dst, __u8 tos, __u8 ttl,
|
||||||
__be16 df, __be16 src_port, __be16 dst_port,
|
__be16 df, __be16 src_port, __be16 dst_port,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче