X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=datapath%2Fchecksum.h;h=5ea2a52beec7f7ea219c873bfbea00c1d5759593;hb=231ee9b7442e515bc654dee37806ee957f74afd7;hp=bf931798a381e35b54f40b936eb19ebffdc6564c;hpb=dd8d6b8cd4d708553037e306d41d1c501d3cecad;p=sliver-openvswitch.git diff --git a/datapath/checksum.h b/datapath/checksum.h index bf931798a..5ea2a52be 100644 --- a/datapath/checksum.h +++ b/datapath/checksum.h @@ -1,9 +1,19 @@ /* - * Copyright (c) 2010 Nicira Networks. - * Distributed under the terms of the GNU GPL version 2. + * Copyright (c) 2007-2011 Nicira Networks. * - * Significant portions of this file may be copied from parts of the Linux - * kernel, by Linus Torvalds and others. + * 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 @@ -12,6 +22,8 @@ #include #include +#include + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) || \ (defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)) #define NEED_CSUM_NORMALIZE @@ -26,78 +38,112 @@ enum csum_type { }; #ifdef NEED_CSUM_NORMALIZE -void compute_ip_summed(struct sk_buff *skb, bool xmit); +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 void compute_ip_summed(struct sk_buff *skb, bool xmit) { } -static inline u8 get_ip_summed(struct sk_buff *skb) +static inline int compute_ip_summed(struct sk_buff *skb, bool xmit) { - return skb->ip_summed; + return 0; } -#endif -/* This function closely resembles skb_forward_csum() used by the bridge. It - * is slightly different because we are only concerned with bridging and not - * other types of forwarding and can get away with slightly more optimal - * behavior. - */ -static inline void forward_ip_summed(struct sk_buff *skb) -{ -#ifdef CHECKSUM_HW - if (get_ip_summed(skb) == OVS_CSUM_COMPLETE) - skb->ip_summed = CHECKSUM_NONE; -#endif -} +static inline void forward_ip_summed(struct sk_buff *skb, bool xmit) { } -#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID) -int vswitch_skb_checksum_setup(struct sk_buff *skb); -#else -static inline int vswitch_skb_checksum_setup(struct sk_buff *skb) +static inline u8 get_ip_summed(struct sk_buff *skb) { - return 0; + return skb->ip_summed; } -#endif -static inline void set_skb_csum_bits(const struct sk_buff *old_skb, - struct sk_buff *new_skb) +static inline void set_ip_summed(struct sk_buff *skb, u8 ip_summed) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) - /* Before 2.6.24 these fields were not copied when - * doing an skb_copy_expand. */ - new_skb->ip_summed = old_skb->ip_summed; - new_skb->csum = old_skb->csum; -#endif -#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID) - /* These fields are copied in skb_clone but not in - * skb_copy or related functions. We need to manually - * copy them over here. */ - new_skb->proto_data_valid = old_skb->proto_data_valid; - new_skb->proto_csum_blank = old_skb->proto_csum_blank; -#endif + skb->ip_summed = ip_summed; } static inline void get_skb_csum_pointers(const struct sk_buff *skb, u16 *csum_start, u16 *csum_offset) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) - *csum_start = skb->csum_start - skb_headroom(skb); + *csum_start = skb->csum_start; *csum_offset = skb->csum_offset; -#else - *csum_start = skb_transport_header(skb) - skb->data; - *csum_offset = skb->csum; -#endif } static inline void set_skb_csum_pointers(struct sk_buff *skb, u16 csum_start, u16 csum_offset) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) skb->csum_start = csum_start; skb->csum_offset = csum_offset; -#else - skb_set_transport_header(skb, csum_start - skb_headroom(skb)); - skb->csum = 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 + +#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 */