Commit 9ace4223 authored by David S. Miller's avatar David S. Miller

Merge branch 'geneve-next'

Jesse Gross says:

====================
Geneve Cleanups

Much of the basis for the Geneve code comes from VXLAN. However,
Geneve is quite a bit simpler than VXLAN and so this cleans up a
lot of the infrastruction - particularly around locking - where the
extra complexity is not necessary.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7beceebf 46b1e4f9
...@@ -68,13 +68,12 @@ struct geneve_sock; ...@@ -68,13 +68,12 @@ struct geneve_sock;
typedef void (geneve_rcv_t)(struct geneve_sock *gs, struct sk_buff *skb); typedef void (geneve_rcv_t)(struct geneve_sock *gs, struct sk_buff *skb);
struct geneve_sock { struct geneve_sock {
struct hlist_node hlist; struct list_head list;
geneve_rcv_t *rcv; geneve_rcv_t *rcv;
void *rcv_data; void *rcv_data;
struct work_struct del_work;
struct socket *sock; struct socket *sock;
struct rcu_head rcu; struct rcu_head rcu;
atomic_t refcnt; int refcnt;
struct udp_offload udp_offloads; struct udp_offload udp_offloads;
}; };
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/rculist.h> #include <linux/list.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/in.h> #include <linux/in.h>
#include <linux/ip.h> #include <linux/ip.h>
...@@ -26,8 +26,8 @@ ...@@ -26,8 +26,8 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/hash.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/mutex.h>
#include <net/arp.h> #include <net/arp.h>
#include <net/ndisc.h> #include <net/ndisc.h>
#include <net/ip.h> #include <net/ip.h>
...@@ -50,38 +50,30 @@ ...@@ -50,38 +50,30 @@
#include <net/ip6_checksum.h> #include <net/ip6_checksum.h>
#endif #endif
#define PORT_HASH_BITS 8 /* Protects sock_list and refcounts. */
#define PORT_HASH_SIZE (1<<PORT_HASH_BITS) static DEFINE_MUTEX(geneve_mutex);
/* per-network namespace private data for this module */ /* per-network namespace private data for this module */
struct geneve_net { struct geneve_net {
struct hlist_head sock_list[PORT_HASH_SIZE]; struct list_head sock_list;
spinlock_t sock_lock; /* Protects sock_list */
}; };
static int geneve_net_id; static int geneve_net_id;
static struct workqueue_struct *geneve_wq;
static inline struct genevehdr *geneve_hdr(const struct sk_buff *skb) static inline struct genevehdr *geneve_hdr(const struct sk_buff *skb)
{ {
return (struct genevehdr *)(udp_hdr(skb) + 1); return (struct genevehdr *)(udp_hdr(skb) + 1);
} }
static struct hlist_head *gs_head(struct net *net, __be16 port) static struct geneve_sock *geneve_find_sock(struct net *net,
sa_family_t family, __be16 port)
{ {
struct geneve_net *gn = net_generic(net, geneve_net_id); struct geneve_net *gn = net_generic(net, geneve_net_id);
return &gn->sock_list[hash_32(ntohs(port), PORT_HASH_BITS)];
}
/* Find geneve socket based on network namespace and UDP port */
static struct geneve_sock *geneve_find_sock(struct net *net, __be16 port)
{
struct geneve_sock *gs; struct geneve_sock *gs;
hlist_for_each_entry_rcu(gs, gs_head(net, port), hlist) { list_for_each_entry(gs, &gn->sock_list, list) {
if (inet_sk(gs->sock->sk)->inet_sport == port) if (inet_sk(gs->sock->sk)->inet_sport == port &&
inet_sk(gs->sock->sk)->sk.sk_family == family)
return gs; return gs;
} }
...@@ -307,15 +299,6 @@ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb) ...@@ -307,15 +299,6 @@ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
return 1; return 1;
} }
static void geneve_del_work(struct work_struct *work)
{
struct geneve_sock *gs = container_of(work, struct geneve_sock,
del_work);
udp_tunnel_sock_release(gs->sock);
kfree_rcu(gs, rcu);
}
static struct socket *geneve_create_sock(struct net *net, bool ipv6, static struct socket *geneve_create_sock(struct net *net, bool ipv6,
__be16 port) __be16 port)
{ {
...@@ -356,8 +339,6 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port, ...@@ -356,8 +339,6 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
if (!gs) if (!gs)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
INIT_WORK(&gs->del_work, geneve_del_work);
sock = geneve_create_sock(net, ipv6, port); sock = geneve_create_sock(net, ipv6, port);
if (IS_ERR(sock)) { if (IS_ERR(sock)) {
kfree(gs); kfree(gs);
...@@ -365,7 +346,7 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port, ...@@ -365,7 +346,7 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
} }
gs->sock = sock; gs->sock = sock;
atomic_set(&gs->refcnt, 1); gs->refcnt = 1;
gs->rcv = rcv; gs->rcv = rcv;
gs->rcv_data = data; gs->rcv_data = data;
...@@ -373,11 +354,7 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port, ...@@ -373,11 +354,7 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
gs->udp_offloads.port = port; gs->udp_offloads.port = port;
gs->udp_offloads.callbacks.gro_receive = geneve_gro_receive; gs->udp_offloads.callbacks.gro_receive = geneve_gro_receive;
gs->udp_offloads.callbacks.gro_complete = geneve_gro_complete; gs->udp_offloads.callbacks.gro_complete = geneve_gro_complete;
spin_lock(&gn->sock_lock);
hlist_add_head_rcu(&gs->hlist, gs_head(net, port));
geneve_notify_add_rx_port(gs); geneve_notify_add_rx_port(gs);
spin_unlock(&gn->sock_lock);
/* Mark socket as an encapsulation socket */ /* Mark socket as an encapsulation socket */
tunnel_cfg.sk_user_data = gs; tunnel_cfg.sk_user_data = gs;
...@@ -386,6 +363,8 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port, ...@@ -386,6 +363,8 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
tunnel_cfg.encap_destroy = NULL; tunnel_cfg.encap_destroy = NULL;
setup_udp_tunnel_sock(net, sock, &tunnel_cfg); setup_udp_tunnel_sock(net, sock, &tunnel_cfg);
list_add(&gs->list, &gn->sock_list);
return gs; return gs;
} }
...@@ -393,25 +372,21 @@ struct geneve_sock *geneve_sock_add(struct net *net, __be16 port, ...@@ -393,25 +372,21 @@ struct geneve_sock *geneve_sock_add(struct net *net, __be16 port,
geneve_rcv_t *rcv, void *data, geneve_rcv_t *rcv, void *data,
bool no_share, bool ipv6) bool no_share, bool ipv6)
{ {
struct geneve_net *gn = net_generic(net, geneve_net_id);
struct geneve_sock *gs; struct geneve_sock *gs;
gs = geneve_socket_create(net, port, rcv, data, ipv6); mutex_lock(&geneve_mutex);
if (!IS_ERR(gs))
return gs;
if (no_share) /* Return error if sharing is not allowed. */
return ERR_PTR(-EINVAL);
spin_lock(&gn->sock_lock); gs = geneve_find_sock(net, ipv6 ? AF_INET6 : AF_INET, port);
gs = geneve_find_sock(net, port); if (gs) {
if (gs && ((gs->rcv != rcv) || if (!no_share && gs->rcv == rcv)
!atomic_add_unless(&gs->refcnt, 1, 0))) gs->refcnt++;
else
gs = ERR_PTR(-EBUSY); gs = ERR_PTR(-EBUSY);
spin_unlock(&gn->sock_lock); } else {
gs = geneve_socket_create(net, port, rcv, data, ipv6);
}
if (!gs) mutex_unlock(&geneve_mutex);
gs = ERR_PTR(-EINVAL);
return gs; return gs;
} }
...@@ -419,37 +394,32 @@ EXPORT_SYMBOL_GPL(geneve_sock_add); ...@@ -419,37 +394,32 @@ EXPORT_SYMBOL_GPL(geneve_sock_add);
void geneve_sock_release(struct geneve_sock *gs) void geneve_sock_release(struct geneve_sock *gs)
{ {
struct net *net = sock_net(gs->sock->sk); mutex_lock(&geneve_mutex);
struct geneve_net *gn = net_generic(net, geneve_net_id);
if (!atomic_dec_and_test(&gs->refcnt)) if (--gs->refcnt)
return; goto unlock;
spin_lock(&gn->sock_lock); list_del(&gs->list);
hlist_del_rcu(&gs->hlist);
geneve_notify_del_rx_port(gs); geneve_notify_del_rx_port(gs);
spin_unlock(&gn->sock_lock); udp_tunnel_sock_release(gs->sock);
kfree_rcu(gs, rcu);
queue_work(geneve_wq, &gs->del_work); unlock:
mutex_unlock(&geneve_mutex);
} }
EXPORT_SYMBOL_GPL(geneve_sock_release); EXPORT_SYMBOL_GPL(geneve_sock_release);
static __net_init int geneve_init_net(struct net *net) static __net_init int geneve_init_net(struct net *net)
{ {
struct geneve_net *gn = net_generic(net, geneve_net_id); struct geneve_net *gn = net_generic(net, geneve_net_id);
unsigned int h;
spin_lock_init(&gn->sock_lock); INIT_LIST_HEAD(&gn->sock_list);
for (h = 0; h < PORT_HASH_SIZE; ++h)
INIT_HLIST_HEAD(&gn->sock_list[h]);
return 0; return 0;
} }
static struct pernet_operations geneve_net_ops = { static struct pernet_operations geneve_net_ops = {
.init = geneve_init_net, .init = geneve_init_net,
.exit = NULL,
.id = &geneve_net_id, .id = &geneve_net_id,
.size = sizeof(struct geneve_net), .size = sizeof(struct geneve_net),
}; };
...@@ -458,10 +428,6 @@ static int __init geneve_init_module(void) ...@@ -458,10 +428,6 @@ static int __init geneve_init_module(void)
{ {
int rc; int rc;
geneve_wq = alloc_workqueue("geneve", 0, 0);
if (!geneve_wq)
return -ENOMEM;
rc = register_pernet_subsys(&geneve_net_ops); rc = register_pernet_subsys(&geneve_net_ops);
if (rc) if (rc)
return rc; return rc;
...@@ -470,11 +436,10 @@ static int __init geneve_init_module(void) ...@@ -470,11 +436,10 @@ static int __init geneve_init_module(void)
return 0; return 0;
} }
late_initcall(geneve_init_module); module_init(geneve_init_module);
static void __exit geneve_cleanup_module(void) static void __exit geneve_cleanup_module(void)
{ {
destroy_workqueue(geneve_wq);
unregister_pernet_subsys(&geneve_net_ops); unregister_pernet_subsys(&geneve_net_ops);
} }
module_exit(geneve_cleanup_module); module_exit(geneve_cleanup_module);
......
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