mirror of
https://github.com/openvswitch/ovs
synced 2025-10-29 15:28:56 +00:00
datapath: Remove checksum compat support
Signed-off-by: Pravin B Shelar <pshelar@nicira.com> Acked-by: Jesse Gross <jesse@nicira.com>
This commit is contained in:
@@ -8,7 +8,6 @@ dist_modules = $(both_modules) # Modules to distribute
|
||||
|
||||
openvswitch_sources = \
|
||||
actions.c \
|
||||
checksum.c \
|
||||
datapath.c \
|
||||
dp_notify.c \
|
||||
flow.c \
|
||||
@@ -21,7 +20,6 @@ openvswitch_sources = \
|
||||
vport-vxlan.c
|
||||
|
||||
openvswitch_headers = \
|
||||
checksum.h \
|
||||
compat.h \
|
||||
datapath.h \
|
||||
flow.h \
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include <net/dsfield.h>
|
||||
#include <net/sctp/checksum.h>
|
||||
|
||||
#include "checksum.h"
|
||||
#include "datapath.h"
|
||||
#include "vlan.h"
|
||||
#include "vport.h"
|
||||
@@ -60,7 +59,7 @@ static int __pop_vlan_tci(struct sk_buff *skb, __be16 *current_tci)
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
|
||||
if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
|
||||
if (skb->ip_summed == CHECKSUM_COMPLETE)
|
||||
skb->csum = csum_sub(skb->csum, csum_partial(skb->data
|
||||
+ (2 * ETH_ALEN), VLAN_HLEN, 0));
|
||||
|
||||
@@ -117,7 +116,7 @@ static int push_vlan(struct sk_buff *skb, const struct ovs_action_push_vlan *vla
|
||||
if (!__vlan_put_tag(skb, skb->vlan_proto, current_tag))
|
||||
return -ENOMEM;
|
||||
|
||||
if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
|
||||
if (skb->ip_summed == CHECKSUM_COMPLETE)
|
||||
skb->csum = csum_add(skb->csum, csum_partial(skb->data
|
||||
+ (2 * ETH_ALEN), VLAN_HLEN, 0));
|
||||
|
||||
@@ -134,16 +133,12 @@ static int set_eth_addr(struct sk_buff *skb,
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
|
||||
if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
|
||||
skb->csum = csum_sub(skb->csum, csum_partial(eth_hdr(skb),
|
||||
ETH_ALEN * 2, 0));
|
||||
skb_postpull_rcsum(skb, eth_hdr(skb), ETH_ALEN * 2);
|
||||
|
||||
memcpy(eth_hdr(skb)->h_source, eth_key->eth_src, ETH_ALEN);
|
||||
memcpy(eth_hdr(skb)->h_dest, eth_key->eth_dst, ETH_ALEN);
|
||||
|
||||
if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
|
||||
skb->csum = csum_add(skb->csum, csum_partial(eth_hdr(skb),
|
||||
ETH_ALEN * 2, 0));
|
||||
ovs_skb_postpush_rcsum(skb, eth_hdr(skb), ETH_ALEN * 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -161,8 +156,7 @@ static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
|
||||
if (likely(transport_len >= sizeof(struct udphdr))) {
|
||||
struct udphdr *uh = udp_hdr(skb);
|
||||
|
||||
if (uh->check ||
|
||||
get_ip_summed(skb) == OVS_CSUM_PARTIAL) {
|
||||
if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
|
||||
inet_proto_csum_replace4(&uh->check, skb,
|
||||
*addr, new_addr, 1);
|
||||
if (!uh->check)
|
||||
@@ -189,8 +183,7 @@ static void update_ipv6_checksum(struct sk_buff *skb, u8 l4_proto,
|
||||
if (likely(transport_len >= sizeof(struct udphdr))) {
|
||||
struct udphdr *uh = udp_hdr(skb);
|
||||
|
||||
if (uh->check ||
|
||||
get_ip_summed(skb) == OVS_CSUM_PARTIAL) {
|
||||
if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
|
||||
inet_proto_csum_replace16(&uh->check, skb,
|
||||
addr, new_addr, 1);
|
||||
if (!uh->check)
|
||||
@@ -311,7 +304,7 @@ static void set_udp_port(struct sk_buff *skb, __be16 *port, __be16 new_port)
|
||||
{
|
||||
struct udphdr *uh = udp_hdr(skb);
|
||||
|
||||
if (uh->check && get_ip_summed(skb) != OVS_CSUM_PARTIAL) {
|
||||
if (uh->check && skb->ip_summed != CHECKSUM_PARTIAL) {
|
||||
set_tp_port(skb, port, new_port, &uh->check);
|
||||
|
||||
if (!uh->check)
|
||||
|
||||
@@ -1,271 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011 Nicira, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/in.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.h>
|
||||
|
||||
#include "checksum.h"
|
||||
#include "datapath.h"
|
||||
|
||||
#ifdef NEED_CSUM_NORMALIZE
|
||||
|
||||
#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
|
||||
/* This code is based on skb_checksum_setup() from Xen's net/dev/core.c. We
|
||||
* can't call this function directly because it isn't exported in all
|
||||
* versions. */
|
||||
static int vswitch_skb_checksum_setup(struct sk_buff *skb)
|
||||
{
|
||||
struct iphdr *iph;
|
||||
unsigned char *th;
|
||||
int err = -EPROTO;
|
||||
__u16 csum_start, csum_offset;
|
||||
|
||||
if (!skb->proto_csum_blank)
|
||||
return 0;
|
||||
|
||||
if (skb->protocol != htons(ETH_P_IP))
|
||||
goto out;
|
||||
|
||||
if (!pskb_may_pull(skb, skb_network_header(skb) + sizeof(struct iphdr) - skb->data))
|
||||
goto out;
|
||||
|
||||
iph = ip_hdr(skb);
|
||||
th = skb_network_header(skb) + 4 * iph->ihl;
|
||||
|
||||
csum_start = th - skb->head;
|
||||
switch (iph->protocol) {
|
||||
case IPPROTO_TCP:
|
||||
csum_offset = offsetof(struct tcphdr, check);
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
csum_offset = offsetof(struct udphdr, check);
|
||||
break;
|
||||
default:
|
||||
if (net_ratelimit())
|
||||
pr_err("Attempting to checksum a non-TCP/UDP packet, "
|
||||
"dropping a protocol %d packet",
|
||||
iph->protocol);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!pskb_may_pull(skb, th + csum_offset + 2 - skb->data))
|
||||
goto out;
|
||||
|
||||
skb->proto_csum_blank = 0;
|
||||
set_ip_summed(skb, OVS_CSUM_PARTIAL);
|
||||
set_skb_csum_pointers(skb, csum_start, csum_offset);
|
||||
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
static int vswitch_skb_checksum_setup(struct sk_buff *skb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* not Xen old style checksums */
|
||||
|
||||
/*
|
||||
* compute_ip_summed - map external checksum state onto OVS representation
|
||||
*
|
||||
* @skb: Packet to manipulate.
|
||||
* @xmit: Whether we were on transmit path of network stack. For example,
|
||||
* this is true for the internal dev vport because it receives skbs
|
||||
* that passed through dev_queue_xmit() but false for the netdev vport
|
||||
* because its packets come from netif_receive_skb().
|
||||
*
|
||||
* Older kernels (and various versions of Xen) were not explicit enough about
|
||||
* checksum offload parameters and rely on a combination of context and
|
||||
* non standard fields. This deals with all those variations so that we
|
||||
* can internally manipulate checksum offloads without worrying about kernel
|
||||
* version.
|
||||
*
|
||||
* Types of checksums that we can receive (these all refer to L4 checksums):
|
||||
* 1. CHECKSUM_NONE: Device that did not compute checksum, contains full
|
||||
* (though not verified) checksum in packet but not in skb->csum. Packets
|
||||
* from the bridge local port will also have this type.
|
||||
* 2. CHECKSUM_COMPLETE (CHECKSUM_HW): Good device that computes checksums,
|
||||
* also the GRE module. This is the same as CHECKSUM_NONE, except it has
|
||||
* a valid skb->csum. Importantly, both contain a full checksum (not
|
||||
* verified) in the packet itself. The only difference is that if the
|
||||
* packet gets to L4 processing on this machine (not in DomU) we won't
|
||||
* have to recompute the checksum to verify. Most hardware devices do not
|
||||
* produce packets with this type, even if they support receive checksum
|
||||
* offloading (they produce type #5).
|
||||
* 3. CHECKSUM_PARTIAL (CHECKSUM_HW): Packet without full checksum and needs to
|
||||
* be computed if it is sent off box. Unfortunately on earlier kernels,
|
||||
* this case is impossible to distinguish from #2, despite having opposite
|
||||
* meanings. Xen adds an extra field on earlier kernels (see #4) in order
|
||||
* to distinguish the different states.
|
||||
* 4. CHECKSUM_UNNECESSARY (with proto_csum_blank true): This packet was
|
||||
* generated locally by a Xen DomU and has a partial checksum. If it is
|
||||
* handled on this machine (Dom0 or DomU), then the checksum will not be
|
||||
* computed. If it goes off box, the checksum in the packet needs to be
|
||||
* completed. Calling skb_checksum_setup converts this to CHECKSUM_HW
|
||||
* (CHECKSUM_PARTIAL) so that the checksum can be completed. In later
|
||||
* kernels, this combination is replaced with CHECKSUM_PARTIAL.
|
||||
* 5. CHECKSUM_UNNECESSARY (with proto_csum_blank false): Packet with a correct
|
||||
* full checksum or using a protocol without a checksum. skb->csum is
|
||||
* undefined. This is common from devices with receive checksum
|
||||
* offloading. This is somewhat similar to CHECKSUM_NONE, except that
|
||||
* nobody will try to verify the checksum with CHECKSUM_UNNECESSARY.
|
||||
*
|
||||
* Note that on earlier kernels, CHECKSUM_COMPLETE and CHECKSUM_PARTIAL are
|
||||
* both defined as CHECKSUM_HW. Normally the meaning of CHECKSUM_HW is clear
|
||||
* based on whether it is on the transmit or receive path. After the datapath
|
||||
* it will be intepreted as CHECKSUM_PARTIAL. If the packet already has a
|
||||
* checksum, we will panic. Since we can receive packets with checksums, we
|
||||
* assume that all CHECKSUM_HW packets have checksums and map them to
|
||||
* CHECKSUM_NONE, which has a similar meaning (the it is only different if the
|
||||
* packet is processed by the local IP stack, in which case it will need to
|
||||
* be reverified). If we receive a packet with CHECKSUM_HW that really means
|
||||
* CHECKSUM_PARTIAL, it will be sent with the wrong checksum. However, there
|
||||
* shouldn't be any devices that do this with bridging.
|
||||
*/
|
||||
int compute_ip_summed(struct sk_buff *skb, bool xmit)
|
||||
{
|
||||
/* For our convenience these defines change repeatedly between kernel
|
||||
* versions, so we can't just copy them over...
|
||||
*/
|
||||
switch (skb->ip_summed) {
|
||||
case CHECKSUM_NONE:
|
||||
set_ip_summed(skb, OVS_CSUM_NONE);
|
||||
break;
|
||||
case CHECKSUM_UNNECESSARY:
|
||||
set_ip_summed(skb, OVS_CSUM_UNNECESSARY);
|
||||
break;
|
||||
#ifdef CHECKSUM_HW
|
||||
/* In theory this could be either CHECKSUM_PARTIAL or CHECKSUM_COMPLETE.
|
||||
* However, on the receive side we should only get CHECKSUM_PARTIAL
|
||||
* packets from Xen, which uses some special fields to represent this
|
||||
* (see vswitch_skb_checksum_setup()). Since we can only make one type
|
||||
* work, pick the one that actually happens in practice.
|
||||
*
|
||||
* On the transmit side (basically after skb_checksum_setup()
|
||||
* has been run or on internal dev transmit), packets with
|
||||
* CHECKSUM_COMPLETE aren't generated, so assume CHECKSUM_PARTIAL.
|
||||
*/
|
||||
case CHECKSUM_HW:
|
||||
if (!xmit)
|
||||
set_ip_summed(skb, OVS_CSUM_COMPLETE);
|
||||
else
|
||||
set_ip_summed(skb, OVS_CSUM_PARTIAL);
|
||||
break;
|
||||
#else
|
||||
case CHECKSUM_COMPLETE:
|
||||
set_ip_summed(skb, OVS_CSUM_COMPLETE);
|
||||
break;
|
||||
case CHECKSUM_PARTIAL:
|
||||
set_ip_summed(skb, OVS_CSUM_PARTIAL);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
OVS_CB(skb)->csum_start = skb_headroom(skb) + skb_transport_offset(skb);
|
||||
|
||||
return vswitch_skb_checksum_setup(skb);
|
||||
}
|
||||
|
||||
/*
|
||||
* forward_ip_summed - map internal checksum state back onto native
|
||||
* kernel fields.
|
||||
*
|
||||
* @skb: Packet to manipulate.
|
||||
* @xmit: Whether we are about send on the transmit path the network stack.
|
||||
* This follows the same logic as the @xmit field in compute_ip_summed().
|
||||
* Generally, a given vport will have opposite values for @xmit passed to
|
||||
* these two functions.
|
||||
*
|
||||
* When a packet is about to egress from OVS take our internal fields (including
|
||||
* any modifications we have made) and recreate the correct representation for
|
||||
* this kernel. This may do things like change the transport header offset.
|
||||
*/
|
||||
void forward_ip_summed(struct sk_buff *skb, bool xmit)
|
||||
{
|
||||
switch (get_ip_summed(skb)) {
|
||||
case OVS_CSUM_NONE:
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
break;
|
||||
case OVS_CSUM_UNNECESSARY:
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
|
||||
skb->proto_data_valid = 1;
|
||||
#endif
|
||||
break;
|
||||
#ifdef CHECKSUM_HW
|
||||
case OVS_CSUM_COMPLETE:
|
||||
if (!xmit)
|
||||
skb->ip_summed = CHECKSUM_HW;
|
||||
else
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
break;
|
||||
case OVS_CSUM_PARTIAL:
|
||||
if (!xmit) {
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
|
||||
skb->proto_csum_blank = 1;
|
||||
#endif
|
||||
} else {
|
||||
skb->ip_summed = CHECKSUM_HW;
|
||||
}
|
||||
break;
|
||||
#else
|
||||
case OVS_CSUM_COMPLETE:
|
||||
skb->ip_summed = CHECKSUM_COMPLETE;
|
||||
break;
|
||||
case OVS_CSUM_PARTIAL:
|
||||
skb->ip_summed = CHECKSUM_PARTIAL;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (get_ip_summed(skb) == OVS_CSUM_PARTIAL)
|
||||
skb_set_transport_header(skb, OVS_CB(skb)->csum_start -
|
||||
skb_headroom(skb));
|
||||
}
|
||||
|
||||
u8 get_ip_summed(struct sk_buff *skb)
|
||||
{
|
||||
return OVS_CB(skb)->ip_summed;
|
||||
}
|
||||
|
||||
void set_ip_summed(struct sk_buff *skb, u8 ip_summed)
|
||||
{
|
||||
OVS_CB(skb)->ip_summed = ip_summed;
|
||||
}
|
||||
|
||||
void get_skb_csum_pointers(const struct sk_buff *skb, u16 *csum_start,
|
||||
u16 *csum_offset)
|
||||
{
|
||||
*csum_start = OVS_CB(skb)->csum_start;
|
||||
*csum_offset = skb->csum;
|
||||
}
|
||||
|
||||
void set_skb_csum_pointers(struct sk_buff *skb, u16 csum_start,
|
||||
u16 csum_offset)
|
||||
{
|
||||
OVS_CB(skb)->csum_start = csum_start;
|
||||
skb->csum = csum_offset;
|
||||
}
|
||||
#endif /* NEED_CSUM_NORMALIZE */
|
||||
@@ -1,173 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011 Nicira, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef CHECKSUM_H
|
||||
#define CHECKSUM_H 1
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include <net/checksum.h>
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) || \
|
||||
(defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID))
|
||||
#define NEED_CSUM_NORMALIZE
|
||||
#endif
|
||||
|
||||
/* These are the same values as the checksum constants in 2.6.22+. */
|
||||
enum csum_type {
|
||||
OVS_CSUM_NONE = 0,
|
||||
OVS_CSUM_UNNECESSARY = 1,
|
||||
OVS_CSUM_COMPLETE = 2,
|
||||
OVS_CSUM_PARTIAL = 3,
|
||||
};
|
||||
|
||||
#ifdef NEED_CSUM_NORMALIZE
|
||||
int compute_ip_summed(struct sk_buff *skb, bool xmit);
|
||||
void forward_ip_summed(struct sk_buff *skb, bool xmit);
|
||||
u8 get_ip_summed(struct sk_buff *skb);
|
||||
void set_ip_summed(struct sk_buff *skb, u8 ip_summed);
|
||||
void get_skb_csum_pointers(const struct sk_buff *skb, u16 *csum_start,
|
||||
u16 *csum_offset);
|
||||
void set_skb_csum_pointers(struct sk_buff *skb, u16 csum_start,
|
||||
u16 csum_offset);
|
||||
#else
|
||||
static inline int compute_ip_summed(struct sk_buff *skb, bool xmit)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void forward_ip_summed(struct sk_buff *skb, bool xmit) { }
|
||||
|
||||
static inline u8 get_ip_summed(struct sk_buff *skb)
|
||||
{
|
||||
return skb->ip_summed;
|
||||
}
|
||||
|
||||
static inline void set_ip_summed(struct sk_buff *skb, u8 ip_summed)
|
||||
{
|
||||
skb->ip_summed = ip_summed;
|
||||
}
|
||||
|
||||
static inline void get_skb_csum_pointers(const struct sk_buff *skb,
|
||||
u16 *csum_start, u16 *csum_offset)
|
||||
{
|
||||
*csum_start = skb->csum_start;
|
||||
*csum_offset = skb->csum_offset;
|
||||
}
|
||||
|
||||
static inline void set_skb_csum_pointers(struct sk_buff *skb, u16 csum_start,
|
||||
u16 csum_offset)
|
||||
{
|
||||
skb->csum_start = csum_start;
|
||||
skb->csum_offset = csum_offset;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This is really compatibility code that belongs in the compat directory.
|
||||
* However, it needs access to our normalized checksum values, so put it here.
|
||||
*/
|
||||
#if defined(NEED_CSUM_NORMALIZE) || LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
|
||||
#define inet_proto_csum_replace4 rpl_inet_proto_csum_replace4
|
||||
static inline void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
|
||||
__be32 from, __be32 to,
|
||||
int pseudohdr)
|
||||
{
|
||||
__be32 diff[] = { ~from, to };
|
||||
|
||||
if (get_ip_summed(skb) != OVS_CSUM_PARTIAL) {
|
||||
*sum = csum_fold(csum_partial((char *)diff, sizeof(diff),
|
||||
~csum_unfold(*sum)));
|
||||
if (get_ip_summed(skb) == OVS_CSUM_COMPLETE && pseudohdr)
|
||||
skb->csum = ~csum_partial((char *)diff, sizeof(diff),
|
||||
~skb->csum);
|
||||
} else if (pseudohdr)
|
||||
*sum = ~csum_fold(csum_partial((char *)diff, sizeof(diff),
|
||||
csum_unfold(*sum)));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(NEED_CSUM_NORMALIZE) || LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
|
||||
#define inet_proto_csum_replace16 rpl_inet_proto_csum_replace16
|
||||
static inline void inet_proto_csum_replace16(__sum16 *sum,
|
||||
struct sk_buff *skb,
|
||||
const __be32 *from,
|
||||
const __be32 *to,
|
||||
int pseudohdr)
|
||||
{
|
||||
__be32 diff[] = {
|
||||
~from[0], ~from[1], ~from[2], ~from[3],
|
||||
to[0], to[1], to[2], to[3],
|
||||
};
|
||||
if (get_ip_summed(skb) != OVS_CSUM_PARTIAL) {
|
||||
*sum = csum_fold(csum_partial(diff, sizeof(diff),
|
||||
~csum_unfold(*sum)));
|
||||
if (get_ip_summed(skb) == OVS_CSUM_COMPLETE && pseudohdr)
|
||||
skb->csum = ~csum_partial(diff, sizeof(diff),
|
||||
~skb->csum);
|
||||
} else if (pseudohdr)
|
||||
*sum = ~csum_fold(csum_partial(diff, sizeof(diff),
|
||||
csum_unfold(*sum)));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NEED_CSUM_NORMALIZE
|
||||
static inline void update_csum_start(struct sk_buff *skb, int delta)
|
||||
{
|
||||
if (get_ip_summed(skb) == OVS_CSUM_PARTIAL) {
|
||||
u16 csum_start, csum_offset;
|
||||
|
||||
get_skb_csum_pointers(skb, &csum_start, &csum_offset);
|
||||
set_skb_csum_pointers(skb, csum_start + delta, csum_offset);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int rpl_pskb_expand_head(struct sk_buff *skb, int nhead,
|
||||
int ntail, gfp_t gfp_mask)
|
||||
{
|
||||
int err;
|
||||
int old_headroom = skb_headroom(skb);
|
||||
|
||||
err = pskb_expand_head(skb, nhead, ntail, gfp_mask);
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
|
||||
update_csum_start(skb, skb_headroom(skb) - old_headroom);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#define pskb_expand_head rpl_pskb_expand_head
|
||||
|
||||
static inline unsigned char *rpl__pskb_pull_tail(struct sk_buff *skb,
|
||||
int delta)
|
||||
{
|
||||
unsigned char *ret;
|
||||
int old_headroom = skb_headroom(skb);
|
||||
|
||||
ret = __pskb_pull_tail(skb, delta);
|
||||
if (unlikely(!ret))
|
||||
return ret;
|
||||
|
||||
update_csum_start(skb, skb_headroom(skb) - old_headroom);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#define __pskb_pull_tail rpl__pskb_pull_tail
|
||||
#endif
|
||||
|
||||
#endif /* checksum.h */
|
||||
@@ -54,7 +54,6 @@
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/netns/generic.h>
|
||||
|
||||
#include "checksum.h"
|
||||
#include "datapath.h"
|
||||
#include "flow.h"
|
||||
#include "vlan.h"
|
||||
@@ -295,8 +294,6 @@ int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
|
||||
goto err;
|
||||
}
|
||||
|
||||
forward_ip_summed(skb, true);
|
||||
|
||||
if (!skb_is_gso(skb))
|
||||
err = queue_userspace_packet(ovs_dp_get_net(dp), dp_ifindex, skb, upcall_info);
|
||||
else
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/u64_stats_sync.h>
|
||||
|
||||
#include "checksum.h"
|
||||
#include "compat.h"
|
||||
#include "flow.h"
|
||||
#include "vlan.h"
|
||||
@@ -94,11 +93,6 @@ struct datapath {
|
||||
* @pkt_key: The flow information extracted from the packet. Must be nonnull.
|
||||
* @tun_key: Key for the tunnel that encapsulated this packet. NULL if the
|
||||
* packet is not being tunneled.
|
||||
* @ip_summed: Consistently stores L4 checksumming status across different
|
||||
* kernel versions.
|
||||
* @csum_start: Stores the offset from which to start checksumming independent
|
||||
* of the transport header on all kernel versions.
|
||||
* packet was not received on a tunnel.
|
||||
* @vlan_tci: Provides a substitute for the skb->vlan_tci field on kernels
|
||||
* before 2.6.27.
|
||||
*/
|
||||
@@ -106,10 +100,6 @@ struct ovs_skb_cb {
|
||||
struct sw_flow *flow;
|
||||
struct sw_flow_key *pkt_key;
|
||||
struct ovs_key_ipv4_tunnel *tun_key;
|
||||
#ifdef NEED_CSUM_NORMALIZE
|
||||
enum csum_type ip_summed;
|
||||
u16 csum_start;
|
||||
#endif
|
||||
#ifdef NEED_VLAN_FIELD
|
||||
u16 vlan_tci;
|
||||
#endif
|
||||
|
||||
@@ -16,7 +16,8 @@ openvswitch_sources += \
|
||||
linux/compat/skbuff-openvswitch.c \
|
||||
linux/compat/time.c \
|
||||
linux/compat/vxlan.c \
|
||||
linux/compat/workqueue.c
|
||||
linux/compat/workqueue.c \
|
||||
linux/compat/utils.c
|
||||
openvswitch_headers += \
|
||||
linux/compat/gso.h \
|
||||
linux/compat/include/asm/percpu.h \
|
||||
|
||||
@@ -82,13 +82,6 @@ extern void unregister_netdevice_many(struct list_head *head);
|
||||
extern void dev_disable_lro(struct net_device *dev);
|
||||
#endif
|
||||
|
||||
#define skb_checksum_help rpl_skb_checksum_help
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||
extern int skb_checksum_help(struct sk_buff *skb, int);
|
||||
#else
|
||||
extern int skb_checksum_help(struct sk_buff *skb);
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) || \
|
||||
defined HAVE_RHEL_OVS_HOOK
|
||||
static inline int netdev_rx_handler_register(struct net_device *dev,
|
||||
|
||||
@@ -32,14 +32,13 @@ static inline void csum_replace2(__sum16 *sum, __be16 from, __be16 to)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
|
||||
#define inet_proto_csum_replace2(sum, skb, from, to, pseudohdr) \
|
||||
inet_proto_csum_replace4(sum, skb, (__force __be32)(from), \
|
||||
(__force __be32)(to), pseudohdr)
|
||||
#endif
|
||||
|
||||
#ifndef CSUM_MANGLED_0
|
||||
#define CSUM_MANGLED_0 ((__force __sum16)0xffff)
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
|
||||
void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
|
||||
const __be32 *from, const __be32 *to,
|
||||
int pseudohdr);
|
||||
#endif
|
||||
#endif /* checksum.h */
|
||||
|
||||
@@ -2,12 +2,7 @@
|
||||
#define __SCTP_CHECKSUM_WRAPPER_H 1
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
|
||||
#include <net/sctp/sctp.h>
|
||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25) */
|
||||
#include_next <net/sctp/checksum.h>
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0)
|
||||
static inline __le32 sctp_compute_cksum(const struct sk_buff *skb,
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include <net/route.h>
|
||||
#include <net/xfrm.h>
|
||||
|
||||
#include "checksum.h"
|
||||
#include "compat.h"
|
||||
#include "gso.h"
|
||||
|
||||
@@ -100,9 +99,6 @@ int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto)
|
||||
skb->protocol = inner_proto;
|
||||
}
|
||||
|
||||
if (unlikely(compute_ip_summed(skb, false)))
|
||||
return -EPROTO;
|
||||
|
||||
nf_reset(skb);
|
||||
secpath_reset(skb);
|
||||
skb_clear_rxhash(skb);
|
||||
|
||||
@@ -14,25 +14,3 @@ void __skb_warn_lro_forwarding(const struct sk_buff *skb)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||
int skb_checksum_help(struct sk_buff *skb, int inward)
|
||||
#else
|
||||
int skb_checksum_help(struct sk_buff *skb)
|
||||
#endif
|
||||
{
|
||||
if (unlikely(skb_is_nonlinear(skb))) {
|
||||
int err;
|
||||
|
||||
err = __skb_linearize(skb);
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
}
|
||||
|
||||
#undef skb_checksum_help
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||
return skb_checksum_help(skb, 0);
|
||||
#else
|
||||
return skb_checksum_help(skb);
|
||||
#endif
|
||||
}
|
||||
|
||||
39
datapath/linux/compat/utils.c
Normal file
39
datapath/linux/compat/utils.c
Normal file
@@ -0,0 +1,39 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/inet.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/net.h>
|
||||
#include <net/checksum.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ratelimit.h>
|
||||
|
||||
#include <net/sock.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
|
||||
void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
|
||||
const __be32 *from, const __be32 *to,
|
||||
int pseudohdr)
|
||||
{
|
||||
__be32 diff[] = {
|
||||
~from[0], ~from[1], ~from[2], ~from[3],
|
||||
to[0], to[1], to[2], to[3],
|
||||
};
|
||||
if (skb->ip_summed != CHECKSUM_PARTIAL) {
|
||||
*sum = csum_fold(csum_partial(diff, sizeof(diff),
|
||||
~csum_unfold(*sum)));
|
||||
if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
|
||||
skb->csum = ~csum_partial(diff, sizeof(diff),
|
||||
~skb->csum);
|
||||
} else if (pseudohdr)
|
||||
*sum = ~csum_fold(csum_partial(diff, sizeof(diff),
|
||||
csum_unfold(*sum)));
|
||||
}
|
||||
#endif
|
||||
@@ -51,7 +51,6 @@
|
||||
#include <net/netns/generic.h>
|
||||
#include <net/vxlan.h>
|
||||
|
||||
#include "checksum.h"
|
||||
#include "compat.h"
|
||||
#include "gso.h"
|
||||
#include "vlan.h"
|
||||
|
||||
@@ -93,10 +93,9 @@ static inline int vlan_deaccel_tag(struct sk_buff *skb)
|
||||
if (unlikely(!skb))
|
||||
return -ENOMEM;
|
||||
|
||||
if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
|
||||
skb->csum = csum_add(skb->csum,
|
||||
csum_partial(skb->data + (2 * ETH_ALEN),
|
||||
VLAN_HLEN, 0));
|
||||
if (skb->ip_summed == CHECKSUM_COMPLETE)
|
||||
skb->csum = csum_add(skb->csum, csum_partial(skb->data
|
||||
+ (2 * ETH_ALEN), VLAN_HLEN, 0));
|
||||
|
||||
vlan_set_tci(skb, 0);
|
||||
return 0;
|
||||
|
||||
@@ -129,8 +129,6 @@ static int __send(struct vport *vport, struct sk_buff *skb,
|
||||
__be32 saddr;
|
||||
int err;
|
||||
|
||||
forward_ip_summed(skb, true);
|
||||
|
||||
/* Route lookup */
|
||||
saddr = OVS_CB(skb)->tun_key->ipv4_src;
|
||||
rt = find_route(ovs_dp_get_net(vport->dp),
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include <net/dst.h>
|
||||
#include <net/xfrm.h>
|
||||
|
||||
#include "checksum.h"
|
||||
#include "datapath.h"
|
||||
#include "vlan.h"
|
||||
#include "vport-internal_dev.h"
|
||||
@@ -80,11 +79,6 @@ static struct net_device_stats *internal_dev_sys_stats(struct net_device *netdev
|
||||
/* Called with rcu_read_lock_bh. */
|
||||
static int internal_dev_xmit(struct sk_buff *skb, struct net_device *netdev)
|
||||
{
|
||||
if (unlikely(compute_ip_summed(skb, true))) {
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vlan_copy_skb_tci(skb);
|
||||
|
||||
rcu_read_lock();
|
||||
@@ -274,7 +268,6 @@ static int internal_dev_recv(struct vport *vport, struct sk_buff *skb)
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
skb->protocol = eth_type_trans(skb, netdev);
|
||||
skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
|
||||
forward_ip_summed(skb, false);
|
||||
|
||||
netif_rx(skb);
|
||||
|
||||
|
||||
@@ -238,11 +238,6 @@ static void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb,
|
||||
secpath_reset(skb);
|
||||
vlan_set_tci(skb, 0);
|
||||
|
||||
if (unlikely(compute_ip_summed(skb, false))) {
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
ovs_vport_receive(vport, skb, tun_key);
|
||||
}
|
||||
|
||||
@@ -441,9 +436,6 @@ static struct sk_buff *handle_offloads(struct sk_buff *skb)
|
||||
{
|
||||
int err;
|
||||
|
||||
forward_ip_summed(skb, true);
|
||||
|
||||
|
||||
if (skb_is_gso(skb)) {
|
||||
struct sk_buff *nskb;
|
||||
char cb[sizeof(skb->cb)];
|
||||
@@ -462,7 +454,7 @@ static struct sk_buff *handle_offloads(struct sk_buff *skb)
|
||||
memcpy(nskb->cb, cb, sizeof(cb));
|
||||
nskb = nskb->next;
|
||||
}
|
||||
} else if (get_ip_summed(skb) == OVS_CSUM_PARTIAL) {
|
||||
} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
|
||||
/* Pages aren't locked and could change at any time.
|
||||
* If this happens after we compute the checksum, the
|
||||
* checksum will be wrong. We linearize now to avoid
|
||||
@@ -479,8 +471,7 @@ static struct sk_buff *handle_offloads(struct sk_buff *skb)
|
||||
goto error;
|
||||
}
|
||||
|
||||
set_ip_summed(skb, OVS_CSUM_NONE);
|
||||
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
return skb;
|
||||
|
||||
error:
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
|
||||
#include <net/llc.h>
|
||||
|
||||
#include "checksum.h"
|
||||
#include "datapath.h"
|
||||
#include "vlan.h"
|
||||
#include "vport-internal_dev.h"
|
||||
@@ -240,9 +239,6 @@ static void netdev_port_receive(struct vport *vport, struct sk_buff *skb)
|
||||
if (unlikely(!skb))
|
||||
return;
|
||||
|
||||
if (unlikely(compute_ip_summed(skb, false)))
|
||||
goto error;
|
||||
|
||||
skb_push(skb, ETH_HLEN);
|
||||
ovs_skb_postpush_rcsum(skb, skb->data, ETH_HLEN);
|
||||
|
||||
@@ -292,7 +288,6 @@ static int netdev_send(struct vport *vport, struct sk_buff *skb)
|
||||
}
|
||||
|
||||
skb->dev = netdev_vport->dev;
|
||||
forward_ip_summed(skb, true);
|
||||
|
||||
if (vlan_tx_tag_present(skb) && !dev_supports_vlan_tx(skb->dev)) {
|
||||
int features;
|
||||
|
||||
@@ -156,8 +156,6 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
|
||||
goto error;
|
||||
}
|
||||
|
||||
forward_ip_summed(skb, true);
|
||||
|
||||
/* Route lookup */
|
||||
saddr = OVS_CB(skb)->tun_key->ipv4_src;
|
||||
rt = find_route(ovs_dp_get_net(vport->dp),
|
||||
|
||||
Reference in New Issue
Block a user