#include <linux/in.h>
#include <linux/ip.h>
#include <linux/openvswitch.h>
+#include <linux/sctp.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/in6.h>
#include <net/ipv6.h>
#include <net/checksum.h>
#include <net/dsfield.h>
+#include <net/sctp/checksum.h>
-#include "checksum.h"
#include "datapath.h"
#include "vlan.h"
#include "vport.h"
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));
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));
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);
+ ether_addr_copy(eth_hdr(skb)->h_source, eth_key->eth_src);
+ ether_addr_copy(eth_hdr(skb)->h_dest, eth_key->eth_dst);
- 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;
}
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)
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)
{
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)
return 0;
}
+static int set_sctp(struct sk_buff *skb,
+ const struct ovs_key_sctp *sctp_port_key)
+{
+ struct sctphdr *sh;
+ int err;
+ unsigned int sctphoff = skb_transport_offset(skb);
+
+ err = make_writable(skb, sctphoff + sizeof(struct sctphdr));
+ if (unlikely(err))
+ return err;
+
+ sh = sctp_hdr(skb);
+ if (sctp_port_key->sctp_src != sh->source ||
+ sctp_port_key->sctp_dst != sh->dest) {
+ __le32 old_correct_csum, new_csum, old_csum;
+
+ old_csum = sh->checksum;
+ old_correct_csum = sctp_compute_cksum(skb, sctphoff);
+
+ sh->source = sctp_port_key->sctp_src;
+ sh->dest = sctp_port_key->sctp_dst;
+
+ new_csum = sctp_compute_cksum(skb, sctphoff);
+
+ /* Carry any checksum errors through. */
+ sh->checksum = old_csum ^ old_correct_csum ^ new_csum;
+
+ skb_clear_rxhash(skb);
+ }
+
+ return 0;
+}
+
static int do_output(struct datapath *dp, struct sk_buff *skb, int out_port)
{
struct vport *vport;
break;
case OVS_KEY_ATTR_SKB_MARK:
- skb_set_mark(skb, nla_get_u32(nested_attr));
+ skb->mark = nla_get_u32(nested_attr);
break;
case OVS_KEY_ATTR_IPV4_TUNNEL:
case OVS_KEY_ATTR_UDP:
err = set_udp(skb, nla_data(nested_attr));
break;
+
+ case OVS_KEY_ATTR_SCTP:
+ err = set_sctp(skb, nla_data(nested_attr));
+ break;
}
return err;