diff options
Diffstat (limited to 'net/ipv4/geneve.c')
-rw-r--r-- | net/ipv4/geneve.c | 47 |
1 files changed, 31 insertions, 16 deletions
diff --git a/net/ipv4/geneve.c b/net/ipv4/geneve.c index 065cd94c640c..95e47c97585e 100644 --- a/net/ipv4/geneve.c +++ b/net/ipv4/geneve.c @@ -104,7 +104,7 @@ static void geneve_build_header(struct genevehdr *geneveh, memcpy(geneveh->options, options, options_len); } -/* Transmit a fully formated Geneve frame. +/* Transmit a fully formatted Geneve frame. * * When calling this function. The skb->data should point * to the geneve header which is fully formed. @@ -131,19 +131,15 @@ int geneve_xmit_skb(struct geneve_sock *gs, struct rtable *rt, if (unlikely(err)) return err; - if (vlan_tx_tag_present(skb)) { - if (unlikely(!__vlan_put_tag(skb, - skb->vlan_proto, - vlan_tx_tag_get(skb)))) { - err = -ENOMEM; - return err; - } - skb->vlan_tci = 0; - } + skb = vlan_hwaccel_push_inside(skb); + if (unlikely(!skb)) + return -ENOMEM; gnvh = (struct genevehdr *)__skb_push(skb, sizeof(*gnvh) + opt_len); geneve_build_header(gnvh, tun_flags, vni, opt_len, opt); + skb_set_inner_protocol(skb, htons(ETH_P_TEB)); + return udp_tunnel_xmit_skb(gs->sock, rt, skb, src, dst, tos, ttl, df, src_port, dst_port, xnet); } @@ -163,6 +159,15 @@ static void geneve_notify_add_rx_port(struct geneve_sock *gs) } } +static void geneve_notify_del_rx_port(struct geneve_sock *gs) +{ + struct sock *sk = gs->sock->sk; + sa_family_t sa_family = sk->sk_family; + + if (sa_family == AF_INET) + udp_del_offload(&gs->udp_offloads); +} + /* Callback from net/ipv4/udp.c to receive packets */ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb) { @@ -291,6 +296,7 @@ struct geneve_sock *geneve_sock_add(struct net *net, __be16 port, geneve_rcv_t *rcv, void *data, bool no_share, bool ipv6) { + struct geneve_net *gn = net_generic(net, geneve_net_id); struct geneve_sock *gs; gs = geneve_socket_create(net, port, rcv, data, ipv6); @@ -300,15 +306,15 @@ struct geneve_sock *geneve_sock_add(struct net *net, __be16 port, if (no_share) /* Return error if sharing is not allowed. */ return ERR_PTR(-EINVAL); + spin_lock(&gn->sock_lock); gs = geneve_find_sock(net, port); - if (gs) { - if (gs->rcv == rcv) - atomic_inc(&gs->refcnt); - else + if (gs && ((gs->rcv != rcv) || + !atomic_add_unless(&gs->refcnt, 1, 0))) gs = ERR_PTR(-EBUSY); - } else { + spin_unlock(&gn->sock_lock); + + if (!gs) gs = ERR_PTR(-EINVAL); - } return gs; } @@ -316,9 +322,17 @@ EXPORT_SYMBOL_GPL(geneve_sock_add); void geneve_sock_release(struct geneve_sock *gs) { + struct net *net = sock_net(gs->sock->sk); + struct geneve_net *gn = net_generic(net, geneve_net_id); + if (!atomic_dec_and_test(&gs->refcnt)) return; + spin_lock(&gn->sock_lock); + hlist_del_rcu(&gs->hlist); + geneve_notify_del_rx_port(gs); + spin_unlock(&gn->sock_lock); + queue_work(geneve_wq, &gs->del_work); } EXPORT_SYMBOL_GPL(geneve_sock_release); @@ -364,6 +378,7 @@ late_initcall(geneve_init_module); static void __exit geneve_cleanup_module(void) { destroy_workqueue(geneve_wq); + unregister_pernet_subsys(&geneve_net_ops); } module_exit(geneve_cleanup_module); |