|
@@ -14,18 +14,6 @@
|
|
|
#include <net/udp.h>
|
|
|
#include <net/protocol.h>
|
|
|
|
|
|
-static DEFINE_SPINLOCK(udp_offload_lock);
|
|
|
-static struct udp_offload_priv __rcu *udp_offload_base __read_mostly;
|
|
|
-
|
|
|
-#define udp_deref_protected(X) rcu_dereference_protected(X, lockdep_is_held(&udp_offload_lock))
|
|
|
-
|
|
|
-struct udp_offload_priv {
|
|
|
- struct udp_offload *offload;
|
|
|
- possible_net_t net;
|
|
|
- struct rcu_head rcu;
|
|
|
- struct udp_offload_priv __rcu *next;
|
|
|
-};
|
|
|
-
|
|
|
static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
|
|
|
netdev_features_t features,
|
|
|
struct sk_buff *(*gso_inner_segment)(struct sk_buff *skb,
|
|
@@ -179,6 +167,7 @@ out_unlock:
|
|
|
|
|
|
return segs;
|
|
|
}
|
|
|
+EXPORT_SYMBOL(skb_udp_tunnel_segment);
|
|
|
|
|
|
static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
|
|
|
netdev_features_t features)
|
|
@@ -253,64 +242,14 @@ out:
|
|
|
return segs;
|
|
|
}
|
|
|
|
|
|
-int udp_add_offload(struct net *net, struct udp_offload *uo)
|
|
|
-{
|
|
|
- struct udp_offload_priv *new_offload = kzalloc(sizeof(*new_offload), GFP_ATOMIC);
|
|
|
-
|
|
|
- if (!new_offload)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- write_pnet(&new_offload->net, net);
|
|
|
- new_offload->offload = uo;
|
|
|
-
|
|
|
- spin_lock(&udp_offload_lock);
|
|
|
- new_offload->next = udp_offload_base;
|
|
|
- rcu_assign_pointer(udp_offload_base, new_offload);
|
|
|
- spin_unlock(&udp_offload_lock);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(udp_add_offload);
|
|
|
-
|
|
|
-static void udp_offload_free_routine(struct rcu_head *head)
|
|
|
-{
|
|
|
- struct udp_offload_priv *ou_priv = container_of(head, struct udp_offload_priv, rcu);
|
|
|
- kfree(ou_priv);
|
|
|
-}
|
|
|
-
|
|
|
-void udp_del_offload(struct udp_offload *uo)
|
|
|
-{
|
|
|
- struct udp_offload_priv __rcu **head = &udp_offload_base;
|
|
|
- struct udp_offload_priv *uo_priv;
|
|
|
-
|
|
|
- spin_lock(&udp_offload_lock);
|
|
|
-
|
|
|
- uo_priv = udp_deref_protected(*head);
|
|
|
- for (; uo_priv != NULL;
|
|
|
- uo_priv = udp_deref_protected(*head)) {
|
|
|
- if (uo_priv->offload == uo) {
|
|
|
- rcu_assign_pointer(*head,
|
|
|
- udp_deref_protected(uo_priv->next));
|
|
|
- goto unlock;
|
|
|
- }
|
|
|
- head = &uo_priv->next;
|
|
|
- }
|
|
|
- pr_warn("udp_del_offload: didn't find offload for port %d\n", ntohs(uo->port));
|
|
|
-unlock:
|
|
|
- spin_unlock(&udp_offload_lock);
|
|
|
- if (uo_priv)
|
|
|
- call_rcu(&uo_priv->rcu, udp_offload_free_routine);
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(udp_del_offload);
|
|
|
-
|
|
|
struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb,
|
|
|
- struct udphdr *uh)
|
|
|
+ struct udphdr *uh, udp_lookup_t lookup)
|
|
|
{
|
|
|
- struct udp_offload_priv *uo_priv;
|
|
|
struct sk_buff *p, **pp = NULL;
|
|
|
struct udphdr *uh2;
|
|
|
unsigned int off = skb_gro_offset(skb);
|
|
|
int flush = 1;
|
|
|
+ struct sock *sk;
|
|
|
|
|
|
if (NAPI_GRO_CB(skb)->encap_mark ||
|
|
|
(skb->ip_summed != CHECKSUM_PARTIAL &&
|
|
@@ -322,13 +261,10 @@ struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb,
|
|
|
NAPI_GRO_CB(skb)->encap_mark = 1;
|
|
|
|
|
|
rcu_read_lock();
|
|
|
- uo_priv = rcu_dereference(udp_offload_base);
|
|
|
- for (; uo_priv != NULL; uo_priv = rcu_dereference(uo_priv->next)) {
|
|
|
- if (net_eq(read_pnet(&uo_priv->net), dev_net(skb->dev)) &&
|
|
|
- uo_priv->offload->port == uh->dest &&
|
|
|
- uo_priv->offload->callbacks.gro_receive)
|
|
|
- goto unflush;
|
|
|
- }
|
|
|
+ sk = (*lookup)(skb, uh->source, uh->dest);
|
|
|
+
|
|
|
+ if (sk && udp_sk(sk)->gro_receive)
|
|
|
+ goto unflush;
|
|
|
goto out_unlock;
|
|
|
|
|
|
unflush:
|
|
@@ -352,9 +288,7 @@ unflush:
|
|
|
|
|
|
skb_gro_pull(skb, sizeof(struct udphdr)); /* pull encapsulating udp header */
|
|
|
skb_gro_postpull_rcsum(skb, uh, sizeof(struct udphdr));
|
|
|
- NAPI_GRO_CB(skb)->proto = uo_priv->offload->ipproto;
|
|
|
- pp = uo_priv->offload->callbacks.gro_receive(head, skb,
|
|
|
- uo_priv->offload);
|
|
|
+ pp = udp_sk(sk)->gro_receive(sk, head, skb);
|
|
|
|
|
|
out_unlock:
|
|
|
rcu_read_unlock();
|
|
@@ -362,6 +296,7 @@ out:
|
|
|
NAPI_GRO_CB(skb)->flush |= flush;
|
|
|
return pp;
|
|
|
}
|
|
|
+EXPORT_SYMBOL(udp_gro_receive);
|
|
|
|
|
|
static struct sk_buff **udp4_gro_receive(struct sk_buff **head,
|
|
|
struct sk_buff *skb)
|
|
@@ -383,39 +318,28 @@ static struct sk_buff **udp4_gro_receive(struct sk_buff **head,
|
|
|
inet_gro_compute_pseudo);
|
|
|
skip:
|
|
|
NAPI_GRO_CB(skb)->is_ipv6 = 0;
|
|
|
- return udp_gro_receive(head, skb, uh);
|
|
|
+ return udp_gro_receive(head, skb, uh, udp4_lib_lookup_skb);
|
|
|
|
|
|
flush:
|
|
|
NAPI_GRO_CB(skb)->flush = 1;
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
-int udp_gro_complete(struct sk_buff *skb, int nhoff)
|
|
|
+int udp_gro_complete(struct sk_buff *skb, int nhoff,
|
|
|
+ udp_lookup_t lookup)
|
|
|
{
|
|
|
- struct udp_offload_priv *uo_priv;
|
|
|
__be16 newlen = htons(skb->len - nhoff);
|
|
|
struct udphdr *uh = (struct udphdr *)(skb->data + nhoff);
|
|
|
int err = -ENOSYS;
|
|
|
+ struct sock *sk;
|
|
|
|
|
|
uh->len = newlen;
|
|
|
|
|
|
rcu_read_lock();
|
|
|
-
|
|
|
- uo_priv = rcu_dereference(udp_offload_base);
|
|
|
- for (; uo_priv != NULL; uo_priv = rcu_dereference(uo_priv->next)) {
|
|
|
- if (net_eq(read_pnet(&uo_priv->net), dev_net(skb->dev)) &&
|
|
|
- uo_priv->offload->port == uh->dest &&
|
|
|
- uo_priv->offload->callbacks.gro_complete)
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (uo_priv) {
|
|
|
- NAPI_GRO_CB(skb)->proto = uo_priv->offload->ipproto;
|
|
|
- err = uo_priv->offload->callbacks.gro_complete(skb,
|
|
|
- nhoff + sizeof(struct udphdr),
|
|
|
- uo_priv->offload);
|
|
|
- }
|
|
|
-
|
|
|
+ sk = (*lookup)(skb, uh->source, uh->dest);
|
|
|
+ if (sk && udp_sk(sk)->gro_complete)
|
|
|
+ err = udp_sk(sk)->gro_complete(sk, skb,
|
|
|
+ nhoff + sizeof(struct udphdr));
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
if (skb->remcsum_offload)
|
|
@@ -426,6 +350,7 @@ int udp_gro_complete(struct sk_buff *skb, int nhoff)
|
|
|
|
|
|
return err;
|
|
|
}
|
|
|
+EXPORT_SYMBOL(udp_gro_complete);
|
|
|
|
|
|
static int udp4_gro_complete(struct sk_buff *skb, int nhoff)
|
|
|
{
|
|
@@ -440,7 +365,7 @@ static int udp4_gro_complete(struct sk_buff *skb, int nhoff)
|
|
|
skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL;
|
|
|
}
|
|
|
|
|
|
- return udp_gro_complete(skb, nhoff);
|
|
|
+ return udp_gro_complete(skb, nhoff, udp4_lib_lookup_skb);
|
|
|
}
|
|
|
|
|
|
static const struct net_offload udpv4_offload = {
|