|
@@ -16,6 +16,7 @@
|
|
|
|
|
|
#include <net/protocol.h>
|
|
#include <net/protocol.h>
|
|
#include <net/ipv6.h>
|
|
#include <net/ipv6.h>
|
|
|
|
+#include <net/inet_common.h>
|
|
|
|
|
|
#include "ip6_offload.h"
|
|
#include "ip6_offload.h"
|
|
|
|
|
|
@@ -268,6 +269,21 @@ static struct sk_buff **sit_ip6ip6_gro_receive(struct sk_buff **head,
|
|
return ipv6_gro_receive(head, skb);
|
|
return ipv6_gro_receive(head, skb);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static struct sk_buff **ip4ip6_gro_receive(struct sk_buff **head,
|
|
|
|
+ struct sk_buff *skb)
|
|
|
|
+{
|
|
|
|
+ /* Common GRO receive for SIT and IP6IP6 */
|
|
|
|
+
|
|
|
|
+ if (NAPI_GRO_CB(skb)->encap_mark) {
|
|
|
|
+ NAPI_GRO_CB(skb)->flush = 1;
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ NAPI_GRO_CB(skb)->encap_mark = 1;
|
|
|
|
+
|
|
|
|
+ return inet_gro_receive(head, skb);
|
|
|
|
+}
|
|
|
|
+
|
|
static int ipv6_gro_complete(struct sk_buff *skb, int nhoff)
|
|
static int ipv6_gro_complete(struct sk_buff *skb, int nhoff)
|
|
{
|
|
{
|
|
const struct net_offload *ops;
|
|
const struct net_offload *ops;
|
|
@@ -307,6 +323,13 @@ static int ip6ip6_gro_complete(struct sk_buff *skb, int nhoff)
|
|
return ipv6_gro_complete(skb, nhoff);
|
|
return ipv6_gro_complete(skb, nhoff);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int ip4ip6_gro_complete(struct sk_buff *skb, int nhoff)
|
|
|
|
+{
|
|
|
|
+ skb->encapsulation = 1;
|
|
|
|
+ skb_shinfo(skb)->gso_type |= SKB_GSO_IPXIP6;
|
|
|
|
+ return inet_gro_complete(skb, nhoff);
|
|
|
|
+}
|
|
|
|
+
|
|
static struct packet_offload ipv6_packet_offload __read_mostly = {
|
|
static struct packet_offload ipv6_packet_offload __read_mostly = {
|
|
.type = cpu_to_be16(ETH_P_IPV6),
|
|
.type = cpu_to_be16(ETH_P_IPV6),
|
|
.callbacks = {
|
|
.callbacks = {
|
|
@@ -324,6 +347,14 @@ static const struct net_offload sit_offload = {
|
|
},
|
|
},
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static const struct net_offload ip4ip6_offload = {
|
|
|
|
+ .callbacks = {
|
|
|
|
+ .gso_segment = inet_gso_segment,
|
|
|
|
+ .gro_receive = ip4ip6_gro_receive,
|
|
|
|
+ .gro_complete = ip4ip6_gro_complete,
|
|
|
|
+ },
|
|
|
|
+};
|
|
|
|
+
|
|
static const struct net_offload ip6ip6_offload = {
|
|
static const struct net_offload ip6ip6_offload = {
|
|
.callbacks = {
|
|
.callbacks = {
|
|
.gso_segment = ipv6_gso_segment,
|
|
.gso_segment = ipv6_gso_segment,
|
|
@@ -331,7 +362,6 @@ static const struct net_offload ip6ip6_offload = {
|
|
.gro_complete = ip6ip6_gro_complete,
|
|
.gro_complete = ip6ip6_gro_complete,
|
|
},
|
|
},
|
|
};
|
|
};
|
|
-
|
|
|
|
static int __init ipv6_offload_init(void)
|
|
static int __init ipv6_offload_init(void)
|
|
{
|
|
{
|
|
|
|
|
|
@@ -344,6 +374,7 @@ static int __init ipv6_offload_init(void)
|
|
|
|
|
|
inet_add_offload(&sit_offload, IPPROTO_IPV6);
|
|
inet_add_offload(&sit_offload, IPPROTO_IPV6);
|
|
inet6_add_offload(&ip6ip6_offload, IPPROTO_IPV6);
|
|
inet6_add_offload(&ip6ip6_offload, IPPROTO_IPV6);
|
|
|
|
+ inet6_add_offload(&ip4ip6_offload, IPPROTO_IPIP);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|