datapath: Add SCTP support
[sliver-openvswitch.git] / datapath / actions.c
index 2c09d57..fa4b904 100644 (file)
@@ -22,6 +22,7 @@
 #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>
@@ -31,6 +32,7 @@
 #include <net/ipv6.h>
 #include <net/checksum.h>
 #include <net/dsfield.h>
+#include <net/sctp/checksum.h>
 
 #include "checksum.h"
 #include "datapath.h"
@@ -360,6 +362,39 @@ static int set_tcp(struct sk_buff *skb, const struct ovs_key_tcp *tcp_port_key)
        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;
@@ -469,6 +504,10 @@ static int execute_set_action(struct sk_buff *skb,
        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;