Hello,

I would like to add SCTP support to OVS but I'm running into a couple
difficulties.

After making my chances for sctp when I go to load openvswitch_mod.ko
I get the following message from dmesg:
 openvswitch_mod: Unknown symbol sctp_statistics (err 0)


SCTP has near the same packet header as TCP and UDP as the first 4
bytes of the header contain the source/dest ports.  One of the major
differences though is that SCTP has a 4byte checksum vs UDP/TCP's 2. I
see in datapath/action.c you handle UDP/TCP the same here. I've added
some code here which checks OVS_CB(skb)->flow->key.ip.proto to check
for the protocol type and then perform the checksum correctly for each
type.

In lib/dpif-netdev.c, dp_netdev_set_addr() I'm not exactly sure how to
update the checksum here.

I'm sure I have several other changes I need to make.

I've attached my chances so far.

Any help here would be greatly appreciated.

Thanks,

Aaron






-- 
Aaron O. Rosen
Masters Student - Network Communication
306B Fluor Daniel
From 5b49d7f38c43b09a1d00571aa63cf895f95ac1fc Mon Sep 17 00:00:00 2001
From: arosen <arosen@arosen-desktop.(none)>
Date: Tue, 2 Aug 2011 17:37:57 -0400
Subject: [PATCH] initial changes for SCTP support in OVS

---
 datapath/actions.c                          |   56 ++++++++++++++++++++++++-
 datapath/checksum.c                         |    6 +++
 datapath/datapath.h                         |    3 +
 datapath/flow.c                             |   61 ++++++++++++++++++++++++--
 datapath/flow.h                             |    8 ++--
 datapath/linux/compat/include/linux/types.h |   13 ++++++
 include/openflow/nicira-ext.h               |    8 ++++
 include/openvswitch/datapath-protocol.h     |    6 +++
 include/sparse/netinet/in.h                 |    1 +
 lib/classifier.c                            |    4 ++
 lib/dpif-netdev.c                           |   11 ++++-
 lib/flow.c                                  |   34 ++++++++++++++-
 lib/nx-match.c                              |   35 +++++++++++++++
 lib/nx-match.def                            |    2 +
 lib/odp-util.c                              |   30 +++++++++++++
 lib/odp-util.h                              |    2 +-
 lib/ofp-parse.c                             |    2 +
 lib/ofp-print.c                             |    2 +
 lib/ofp-util.c                              |    4 +-
 lib/packets.h                               |   24 ++++++++++
 20 files changed, 297 insertions(+), 15 deletions(-)

diff --git a/datapath/actions.c b/datapath/actions.c
index 78712c6..6661986 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -12,6 +12,8 @@
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
+#include <linux/sctp.h>
+#include <net/sctp/checksum.h>
 #include <linux/udp.h>
 #include <linux/in6.h>
 #include <linux/if_arp.h>
@@ -109,10 +111,23 @@ static __sum16 *get_l4_checksum(struct sk_buff *skb)
 	return NULL;
 }
 
+/* remove arosen  
+static __le32 *get_l4_checksum_sctp(struct sk_buff *skb) 
+{ 
+	int transport_len = skb->len - skb_transport_offset(skb);
+	if (likely(transport_len >= sizeof(struct sctphdr)))
+		return &sctp_hdr(skb)->checksum;
+
+	return NULL; 
+}
+*/ 
+
 static int set_nw_addr(struct sk_buff *skb, const struct nlattr *a)
 {
 	__be32 new_nwaddr = nla_get_be32(a);
 	struct iphdr *nh;
+
+
 	__sum16 *check;
 	__be32 *nwaddr;
 	int err;
@@ -164,6 +179,7 @@ static int set_nw_tos(struct sk_buff *skb, u8 nw_tos)
 	return 0;
 }
 
+
 static int set_tp_port(struct sk_buff *skb, const struct nlattr *a)
 {
 	struct udphdr *th;
@@ -180,6 +196,44 @@ static int set_tp_port(struct sk_buff *skb, const struct nlattr *a)
 		return err;
 
 	/* Must follow make_writable() since that can move the skb data. */
+
+	if (OVS_CB(skb)->flow->key.ip.proto == IPPROTO_SCTP) 
+	{ 
+	
+		/*
+		 * Code below taken frmo net/sctp/input:
+		 *  static inline int sctp_rcv_checksum(struct sk_buff *skb)
+		 *
+		 */ 
+
+		struct sctphdr *sh = sctp_hdr(skb);
+
+		port = nla_type(a) == ODP_ACTION_ATTR_SET_TP_SRC ? &sh->source : &sh->dest;
+
+		__le32 cmp = sh->checksum;  /* warning?? */ 
+
+		struct sk_buff *list; 
+		__le32 val; 
+		__u32 tmp = sctp_start_cksum((__u8*)sh, skb_headlen(skb));
+
+		skb_walk_frags(skb, list)
+			tmp = sctp_update_cksum((__u8*)list->data, skb_headlen(list), tmp);
+
+		val = sctp_end_cksum(tmp); 
+		if( val != cmp) 
+		{ 
+			/* CRC failure, dump it */ 
+			SCTP_INC_STATS_BH(SCTP_MIB_CHECKSUMERRORS);
+			return -1; 
+		}
+		
+		*port = nla_get_be16(a);
+		skb_clear_rxhash(skb);
+	
+
+		return 0;
+	}
+
 	check = get_l4_checksum(skb);
 	if (unlikely(!check))
 		return 0;
@@ -188,7 +242,7 @@ static int set_tp_port(struct sk_buff *skb, const struct nlattr *a)
 	 * Update port and checksum.
 	 *
 	 * This is OK because source and destination port numbers are at the
-	 * same offsets in both UDP and TCP headers, and get_l4_checksum() only
+	 * same offsets in both UDP and  TCP headers, and get_l4_checksum() only
 	 * supports those protocols.
 	 */
 	th = udp_hdr(skb);
diff --git a/datapath/checksum.c b/datapath/checksum.c
index 3a131f4..9885ede 100644
--- a/datapath/checksum.c
+++ b/datapath/checksum.c
@@ -11,6 +11,7 @@
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
+#include <linux/sctp.h>
 #include <linux/udp.h>
 
 #include "checksum.h"
@@ -46,6 +47,11 @@ static int vswitch_skb_checksum_setup(struct sk_buff *skb)
 	case IPPROTO_TCP:
 		csum_offset = offsetof(struct tcphdr, check);
 		break;
+	case IPPROTO_SCTP:
+		csum_offset = offsetof(struct sctphdr, check);
+		break;
+
+
 	case IPPROTO_UDP:
 		csum_offset = offsetof(struct udphdr, check);
 		break;
diff --git a/datapath/datapath.h b/datapath/datapath.h
index 15a9898..4db6ae4 100644
--- a/datapath/datapath.h
+++ b/datapath/datapath.h
@@ -34,6 +34,9 @@ struct vport;
 
 #define DP_MAX_PORTS 1024
 
+/* arosen FIXME- this probably shouldn't be defined here  */ 
+#define NEXTHDR_SCTP  132
+
 /**
  * struct dp_stats_percpu - per-cpu packet processing statistics for a given
  * datapath.
diff --git a/datapath/flow.c b/datapath/flow.c
index 27038ec..6bd71e6 100644
--- a/datapath/flow.c
+++ b/datapath/flow.c
@@ -500,6 +500,13 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
 				key->ipv4.tp.src = tcp->source;
 				key->ipv4.tp.dst = tcp->dest;
 			}
+		} else if (key->ip.proto == IPPROTO_SCTP) {
+			key_len = SW_FLOW_KEY_OFFSET(ipv4.tp);
+			if (!*is_frag && tcphdr_ok(skb)) {
+				struct tcphdr *tcp = tcp_hdr(skb);
+				key->ipv4.tp.src = tcp->source;
+				key->ipv4.tp.dst = tcp->dest;
+			}
 		} else if (key->ip.proto == IPPROTO_UDP) {
 			key_len = SW_FLOW_KEY_OFFSET(ipv4.tp);
 			if (!*is_frag && udphdr_ok(skb)) {
@@ -562,6 +569,13 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
 				key->ipv6.tp.src = tcp->source;
 				key->ipv6.tp.dst = tcp->dest;
 			}
+		} else if (key->ip.proto == NEXTHDR_SCTP) {
+			key_len = SW_FLOW_KEY_OFFSET(ipv6.tp);
+			if (tcphdr_ok(skb)) {
+				struct tcphdr *tcp = tcp_hdr(skb);
+				key->ipv6.tp.src = tcp->source;
+				key->ipv6.tp.dst = tcp->dest;
+			}
 		} else if (key->ip.proto == NEXTHDR_UDP) {
 			key_len = SW_FLOW_KEY_OFFSET(ipv6.tp);
 			if (udphdr_ok(skb)) {
@@ -607,6 +621,7 @@ static const u32 key_lens[ODP_KEY_ATTR_MAX + 1] = {
 	[ODP_KEY_ATTR_IPV4] = sizeof(struct odp_key_ipv4),
 	[ODP_KEY_ATTR_IPV6] = sizeof(struct odp_key_ipv6),
 	[ODP_KEY_ATTR_TCP] = sizeof(struct odp_key_tcp),
+	[ODP_KEY_ATTR_SCTP] = sizeof(struct odp_key_sctp),
 	[ODP_KEY_ATTR_UDP] = sizeof(struct odp_key_udp),
 	[ODP_KEY_ATTR_ICMP] = sizeof(struct odp_key_icmp),
 	[ODP_KEY_ATTR_ICMPV6] = sizeof(struct odp_key_icmpv6),
@@ -740,6 +755,25 @@ int flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
 			swkey->ipv6.tp.dst = tcp_key->tcp_dst;
 			break;
 
+		case TRANSITION(ODP_KEY_ATTR_IPV4, ODP_KEY_ATTR_SCTP):
+			key_len = SW_FLOW_KEY_OFFSET(ipv4.tp);
+			if (swkey->ip.proto != IPPROTO_SCTP)
+				goto invalid;
+			tcp_key = nla_data(nla);
+			swkey->ipv4.tp.src = tcp_key->tcp_src;
+			swkey->ipv4.tp.dst = tcp_key->tcp_dst;
+			break;
+
+		case TRANSITION(ODP_KEY_ATTR_IPV6, ODP_KEY_ATTR_SCTP):
+			key_len = SW_FLOW_KEY_OFFSET(ipv6.tp);
+			if (swkey->ip.proto != IPPROTO_SCTP)
+				goto invalid;
+			tcp_key = nla_data(nla);
+			swkey->ipv6.tp.src = tcp_key->tcp_src;
+			swkey->ipv6.tp.dst = tcp_key->tcp_dst;
+			break;
+
+
 		case TRANSITION(ODP_KEY_ATTR_IPV4, ODP_KEY_ATTR_UDP):
 			key_len = SW_FLOW_KEY_OFFSET(ipv4.tp);
 			if (swkey->ip.proto != IPPROTO_UDP)
@@ -830,15 +864,17 @@ int flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
 		goto ok;
 
 	case ODP_KEY_ATTR_IPV4:
-		if (swkey->ip.proto == IPPROTO_TCP ||
-		    swkey->ip.proto == IPPROTO_UDP ||
+		if (swkey->ip.proto == IPPROTO_TCP  ||
+		    swkey->ip.proto == IPPROTO_SCTP ||
+		    swkey->ip.proto == IPPROTO_UDP  ||
 		    swkey->ip.proto == IPPROTO_ICMP)
 			goto invalid;
 		goto ok;
 
 	case ODP_KEY_ATTR_IPV6:
-		if (swkey->ip.proto == IPPROTO_TCP ||
-		    swkey->ip.proto == IPPROTO_UDP ||
+		if (swkey->ip.proto == IPPROTO_TCP  ||
+		    swkey->ip.proto == IPPROTO_SCTP ||
+		    swkey->ip.proto == IPPROTO_UDP  ||
 		    swkey->ip.proto == IPPROTO_ICMPV6)
 			goto invalid;
 		goto ok;
@@ -850,6 +886,7 @@ int flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
 		goto ok;
 
 	case ODP_KEY_ATTR_TCP:
+	case ODP_KEY_ATTR_SCTP:
 	case ODP_KEY_ATTR_UDP:
 	case ODP_KEY_ATTR_ICMP:
 	case ODP_KEY_ATTR_ARP:
@@ -933,7 +970,7 @@ int flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
 	/* This is an imperfect sanity-check that FLOW_BUFSIZE doesn't need
 	 * to be updated, but will at least raise awareness when new ODP key
 	 * types are added. */
-	BUILD_BUG_ON(__ODP_KEY_ATTR_MAX != 14);
+	BUILD_BUG_ON(__ODP_KEY_ATTR_MAX != 15);
 
 	if (swkey->eth.tun_id != cpu_to_be64(0))
 		NLA_PUT_BE64(skb, ODP_KEY_ATTR_TUN_ID, swkey->eth.tun_id);
@@ -1018,6 +1055,20 @@ int flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
 				tcp_key->tcp_src = swkey->ipv6.tp.src;
 				tcp_key->tcp_dst = swkey->ipv6.tp.dst;
 			}
+		} if (swkey->ip.proto == IPPROTO_SCTP) {
+			struct odp_key_sctp *sctp_key;
+
+			nla = nla_reserve(skb, ODP_KEY_ATTR_SCTP, sizeof(*sctp_key));
+			if (!nla)
+				goto nla_put_failure;
+			sctp_key = nla_data(nla);
+			if (swkey->eth.type == htons(ETH_P_IP)) {
+				sctp_key->sctp_src = swkey->ipv4.tp.src;
+				sctp_key->sctp_dst = swkey->ipv4.tp.dst;
+			} else if (swkey->eth.type == htons(ETH_P_IPV6)) {
+				sctp_key->sctp_src = swkey->ipv6.tp.src;
+				sctp_key->sctp_dst = swkey->ipv6.tp.dst;
+			}
 		} else if (swkey->ip.proto == IPPROTO_UDP) {
 			struct odp_key_udp *udp_key;
 
diff --git a/datapath/flow.h b/datapath/flow.h
index 6a3c539..db8b2e1 100644
--- a/datapath/flow.h
+++ b/datapath/flow.h
@@ -51,8 +51,8 @@ struct sw_flow_key {
 			} addr;
 			union {
 				struct {
-					__be16 src;		/* TCP/UDP source port. */
-					__be16 dst;		/* TCP/UDP destination port. */
+					__be16 src;		/* TCP/UDP/SCTP source port. */
+					__be16 dst;		/* TCP/UDP/SCTP destination port. */
 				} tp;
 				struct {
 					u8 sha[ETH_ALEN];	/* ARP source hardware address. */
@@ -66,8 +66,8 @@ struct sw_flow_key {
 				struct in6_addr dst;	/* IPv6 destination address. */
 			} addr;
 			struct {
-				__be16 src;		/* TCP/UDP source port. */
-				__be16 dst;		/* TCP/UDP destination port. */
+				__be16 src;		/* TCP/UDP/SCTP source port. */
+				__be16 dst;		/* TCP/UDP/SCTP destination port. */
 			} tp;
 			struct {
 				struct in6_addr target;	/* ND target address. */
diff --git a/datapath/linux/compat/include/linux/types.h b/datapath/linux/compat/include/linux/types.h
index b989d96..26afc56 100644
--- a/datapath/linux/compat/include/linux/types.h
+++ b/datapath/linux/compat/include/linux/types.h
@@ -8,6 +8,19 @@ typedef __u16 __bitwise __sum16;
 typedef __u32 __bitwise __wsum;
 #endif
 
+
+
+/* 
+*  SCTP uses a 32 bit checksum and TCP/UDP uses 16 bit 
+*  arosen (probably a better way to do this...)  
+*/            
+/*
+struct sum16_or_sum32 { 
+	__u16 *check16;
+	__u32 *check32; 
+};
+*/
+
 #ifndef HAVE_BOOL_TYPE
 typedef _Bool bool;
 #endif /* !HAVE_BOOL_TYPE */
diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index 5cf02e7..2d2fd31 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -1104,6 +1104,10 @@ enum nx_bd_algorithm {
 #define NXM_OF_UDP_SRC    NXM_HEADER  (0x0000, 11, 2)
 #define NXM_OF_UDP_DST    NXM_HEADER  (0x0000, 12, 2)
 
+/* not sure if this is right arosen */ 
+#define NXM_OF_SCTP_SRC    NXM_HEADER  (0x0000, 13, 2)
+#define NXM_OF_SCTP_DST    NXM_HEADER  (0x0000, 14, 2)
+
 /* The type or code in the ICMP header.
  *
  * Prereqs:
@@ -1143,6 +1147,10 @@ enum nx_bd_algorithm {
 #define NXM_OF_ARP_TPA    NXM_HEADER  (0x0000, 17, 4)
 #define NXM_OF_ARP_TPA_W  NXM_HEADER_W(0x0000, 17, 4)
 
+
+/* not quite sure if this is right?
+ * arosen */ 
+
 /* ## ------------------------ ## */
 /* ## Nicira match extensions. ## */
 /* ## ------------------------ ## */
diff --git a/include/openvswitch/datapath-protocol.h b/include/openvswitch/datapath-protocol.h
index 0b755e8..3eb3060 100644
--- a/include/openvswitch/datapath-protocol.h
+++ b/include/openvswitch/datapath-protocol.h
@@ -298,6 +298,7 @@ enum odp_key_type {
 	ODP_KEY_ATTR_IPV4,      /* struct odp_key_ipv4 */
 	ODP_KEY_ATTR_IPV6,      /* struct odp_key_ipv6 */
 	ODP_KEY_ATTR_TCP,       /* struct odp_key_tcp */
+	ODP_KEY_ATTR_SCTP,      /* struct odp_key_sctp */
 	ODP_KEY_ATTR_UDP,       /* struct odp_key_udp */
 	ODP_KEY_ATTR_ICMP,      /* struct odp_key_icmp */
 	ODP_KEY_ATTR_ICMPV6,    /* struct odp_key_icmpv6 */
@@ -337,6 +338,11 @@ struct odp_key_tcp {
 	ovs_be16 tcp_dst;
 };
 
+struct odp_key_sctp {
+	ovs_be16 sctp_src;
+	ovs_be16 sctp_dst;
+};
+
 struct odp_key_udp {
 	ovs_be16 udp_src;
 	ovs_be16 udp_dst;
diff --git a/include/sparse/netinet/in.h b/include/sparse/netinet/in.h
index d86431a..9675c57 100644
--- a/include/sparse/netinet/in.h
+++ b/include/sparse/netinet/in.h
@@ -52,6 +52,7 @@ extern const struct in6_addr in6addr_any;
 #define IPPROTO_HOPOPTS 0
 #define IPPROTO_ICMP 1
 #define IPPROTO_TCP 6
+#define IPPROTO_SCTP 132
 #define IPPROTO_UDP 17
 #define IPPROTO_ROUTING 43
 #define IPPROTO_FRAGMENT 44
diff --git a/lib/classifier.c b/lib/classifier.c
index faaeaf5..d73de24 100644
--- a/lib/classifier.c
+++ b/lib/classifier.c
@@ -480,6 +480,8 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
                     ds_put_cstr(s, "icmp,");
                 } else if (f->nw_proto == IPPROTO_TCP) {
                     ds_put_cstr(s, "tcp,");
+                } else if (f->nw_proto == IPPROTO_SCTP) {
+                    ds_put_cstr(s, "sctp,");
                 } else if (f->nw_proto == IPPROTO_UDP) {
                     ds_put_cstr(s, "udp,");
                 } else {
@@ -496,6 +498,8 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
                     ds_put_cstr(s, "icmp6,");
                 } else if (f->nw_proto == IPPROTO_TCP) {
                     ds_put_cstr(s, "tcp6,");
+                } else if (f->nw_proto == IPPROTO_SCTP) {
+                    ds_put_cstr(s, "sctp6,");
                 } else if (f->nw_proto == IPPROTO_UDP) {
                     ds_put_cstr(s, "udp6,");
                 } else {
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index d48d7ae..c686666 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -1183,7 +1183,16 @@ dp_netdev_set_nw_addr(struct ofpbuf *packet, const struct flow *key,
         if (key->nw_proto == IPPROTO_TCP && packet->l7) {
             struct tcp_header *th = packet->l4;
             th->tcp_csum = recalc_csum32(th->tcp_csum, *field, ip);
-        } else if (key->nw_proto == IPPROTO_UDP && packet->l7) {
+        } else if (key->nw_proto == IPPROTO_SCTP && packet->l7) {
+            struct sctp_header *th = packet->l4;
+
+			 // FIXME arosen 
+			 // check out net/sctp/input.c 
+          //  th->checksum = recalc_csum32(th->checksum, *field, ip);
+        } 
+		   
+		  
+		  else if (key->nw_proto == IPPROTO_UDP && packet->l7) {
             struct udp_header *uh = packet->l4;
             if (uh->udp_csum) {
                 uh->udp_csum = recalc_csum32(uh->udp_csum, *field, ip);
diff --git a/lib/flow.c b/lib/flow.c
index fc09a77..a448828 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -72,6 +72,17 @@ pull_tcp(struct ofpbuf *packet)
     return NULL;
 }
 
+/* FIXME arosen */ 
+static struct sctp_header *
+pull_sctp(struct ofpbuf *packet)
+{
+    if (packet->size >= SCTP_HEADER_LEN) {
+		  /* SCTP has fixed header size */ 
+        return ofpbuf_pull(packet, SCTP_HEADER_LEN);
+    }
+    return NULL;
+}
+
 static struct udp_header *
 pull_udp(struct ofpbuf *packet)
 {
@@ -226,6 +237,17 @@ parse_tcp(struct ofpbuf *packet, struct ofpbuf *b, struct flow *flow)
 }
 
 static void
+parse_sctp(struct ofpbuf *packet, struct ofpbuf *b, struct flow *flow)
+{
+    const struct sctp_header *sctp = pull_sctp(b);
+    if (sctp) {
+        flow->tp_src = sctp->source;
+        flow->tp_dst = sctp->dest;
+        packet->l7 = b->data;
+    }
+}
+
+static void
 parse_udp(struct ofpbuf *packet, struct ofpbuf *b, struct flow *flow)
 {
     const struct udp_header *udp = pull_udp(b);
@@ -370,6 +392,8 @@ flow_extract(struct ofpbuf *packet, ovs_be64 tun_id, uint16_t ofp_in_port,
             if (!IP_IS_FRAGMENT(nh->ip_frag_off)) {
                 if (flow->nw_proto == IPPROTO_TCP) {
                     parse_tcp(packet, &b, flow);
+                } else if (flow->nw_proto == IPPROTO_SCTP) {
+                    parse_sctp(packet, &b, flow);
                 } else if (flow->nw_proto == IPPROTO_UDP) {
                     parse_udp(packet, &b, flow);
                 } else if (flow->nw_proto == IPPROTO_ICMP) {
@@ -394,6 +418,8 @@ flow_extract(struct ofpbuf *packet, ovs_be64 tun_id, uint16_t ofp_in_port,
         packet->l4 = b.data;
         if (flow->nw_proto == IPPROTO_TCP) {
             parse_tcp(packet, &b, flow);
+        } else if (flow->nw_proto == IPPROTO_SCTP) {
+            parse_sctp(packet, &b, flow);
         } else if (flow->nw_proto == IPPROTO_UDP) {
             parse_udp(packet, &b, flow);
         } else if (flow->nw_proto == IPPROTO_ICMPV6) {
@@ -438,6 +464,10 @@ flow_extract_stats(const struct flow *flow, struct ofpbuf *packet,
         if ((flow->nw_proto == IPPROTO_TCP) && packet->l7) {
             struct tcp_header *tcp = packet->l4;
             stats->tcp_flags = TCP_FLAGS(tcp->tcp_ctl);
+        } else if ((flow->nw_proto == IPPROTO_SCTP) && packet->l7) {
+            struct sctp_header *sctp = packet->l4;
+			 //  arosen FIXME
+          //  stats->tcp_flags = TCP_FLAGS(tcp->tcp_ctl);
         }
     }
 
@@ -834,7 +864,7 @@ flow_hash_symmetric_l4(const struct flow *flow, uint32_t basis)
     if (fields.eth_type == htons(ETH_TYPE_IP)) {
         fields.ipv4_addr = flow->nw_src ^ flow->nw_dst;
         fields.ip_proto = flow->nw_proto;
-        if (fields.ip_proto == IPPROTO_TCP) {
+        if (fields.ip_proto == IPPROTO_TCP || fields.ip_proto == IPPROTO_SCTP) {
             fields.tp_addr = flow->tp_src ^ flow->tp_dst;
         }
     } else if (fields.eth_type == htons(ETH_TYPE_IPV6)) {
@@ -846,7 +876,7 @@ flow_hash_symmetric_l4(const struct flow *flow, uint32_t basis)
             ipv6_addr[i] = a[i] ^ b[i];
         }
         fields.ip_proto = flow->nw_proto;
-        if (fields.ip_proto == IPPROTO_TCP) {
+        if (fields.ip_proto == IPPROTO_TCP || fields.ip_proto == IPPROTO_SCTP) {
             fields.tp_addr = flow->tp_src ^ flow->tp_dst;
         }
     }
diff --git a/lib/nx-match.c b/lib/nx-match.c
index e698cc6..a207a35 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -318,6 +318,14 @@ parse_nxm_entry(struct cls_rule *rule, const struct nxm_field *f,
         flow->tp_dst = get_unaligned_be16(value);
         return 0;
 
+        /* SCTP header. */
+    case NFI_NXM_OF_SCTP_SRC:
+        flow->tp_src = get_unaligned_be16(value);
+        return 0;
+    case NFI_NXM_OF_SCTP_DST:
+        flow->tp_dst = get_unaligned_be16(value);
+        return 0;
+
         /* UDP header. */
     case NFI_NXM_OF_UDP_SRC:
         flow->tp_src = get_unaligned_be16(value);
@@ -747,6 +755,16 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
                 }
                 break;
 
+					/* SCTP. */ 
+				case IPPROTO_SCTP:
+                if (!(wc & FWW_TP_SRC)) {
+                    nxm_put_16(b, NXM_OF_SCTP_SRC, flow->tp_src);
+                }
+                if (!(wc & FWW_TP_DST)) {
+                    nxm_put_16(b, NXM_OF_SCTP_DST, flow->tp_dst);
+                }
+                break;
+
                 /* UDP. */
             case IPPROTO_UDP:
                 if (!(wc & FWW_TP_SRC)) {
@@ -792,6 +810,19 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
                 }
                 break;
 
+
+					/* SCTP. */ 
+            case IPPROTO_SCTP:
+                if (!(wc & FWW_TP_SRC)) {
+                    nxm_put_16(b, NXM_OF_SCTP_SRC, flow->tp_src);
+                }
+                if (!(wc & FWW_TP_DST)) {
+                    nxm_put_16(b, NXM_OF_SCTP_DST, flow->tp_dst);
+                }
+                break;
+
+
+
                 /* UDP. */
             case IPPROTO_UDP:
                 if (!(wc & FWW_TP_SRC)) {
@@ -1296,10 +1327,12 @@ nxm_read_field(const struct nxm_field *src, const struct flow *flow)
         return ntohl(flow->nw_dst);
 
     case NFI_NXM_OF_TCP_SRC:
+    case NFI_NXM_OF_SCTP_SRC:
     case NFI_NXM_OF_UDP_SRC:
         return ntohs(flow->tp_src);
 
     case NFI_NXM_OF_TCP_DST:
+    case NFI_NXM_OF_SCTP_DST:
     case NFI_NXM_OF_UDP_DST:
         return ntohs(flow->tp_dst);
 
@@ -1416,11 +1449,13 @@ nxm_write_field(const struct nxm_field *dst, struct flow *flow,
         break;
 
     case NFI_NXM_OF_TCP_SRC:
+    case NFI_NXM_OF_SCTP_SRC:
     case NFI_NXM_OF_UDP_SRC:
         flow->tp_src = htons(new_value);
         break;
 
     case NFI_NXM_OF_TCP_DST:
+    case NFI_NXM_OF_SCTP_DST:
     case NFI_NXM_OF_UDP_DST:
         flow->tp_dst = htons(new_value);
         break;
diff --git a/lib/nx-match.def b/lib/nx-match.def
index 3fcb59c..1ff2466 100644
--- a/lib/nx-match.def
+++ b/lib/nx-match.def
@@ -40,6 +40,8 @@ DEFINE_FIELD_M(OF_IP_SRC,     0,            NXM_DL_IP,     0,            true)
 DEFINE_FIELD_M(OF_IP_DST,     0,            NXM_DL_IP,     0,            true)
 DEFINE_FIELD  (OF_TCP_SRC,    FWW_TP_SRC,   NXM_DL_IP_ANY, IPPROTO_TCP,  true)
 DEFINE_FIELD  (OF_TCP_DST,    FWW_TP_DST,   NXM_DL_IP_ANY, IPPROTO_TCP,  true)
+DEFINE_FIELD  (OF_SCTP_SRC,   FWW_TP_SRC,   NXM_DL_IP_ANY, IPPROTO_SCTP, true)
+DEFINE_FIELD  (OF_SCTP_DST,   FWW_TP_DST,   NXM_DL_IP_ANY, IPPROTO_SCTP, true)
 DEFINE_FIELD  (OF_UDP_SRC,    FWW_TP_SRC,   NXM_DL_IP_ANY, IPPROTO_UDP,  true)
 DEFINE_FIELD  (OF_UDP_DST,    FWW_TP_DST,   NXM_DL_IP_ANY, IPPROTO_UDP,  true)
 DEFINE_FIELD  (OF_ICMP_TYPE,  FWW_TP_SRC,   NXM_DL_IP,     IPPROTO_ICMP, false)
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 93f8f8a..a2f5a2f 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -194,6 +194,7 @@ odp_flow_key_attr_len(uint16_t type)
     case ODP_KEY_ATTR_IPV4: return sizeof(struct odp_key_ipv4);
     case ODP_KEY_ATTR_IPV6: return sizeof(struct odp_key_ipv6);
     case ODP_KEY_ATTR_TCP: return sizeof(struct odp_key_tcp);
+    case ODP_KEY_ATTR_SCTP: return sizeof(struct odp_key_sctp);
     case ODP_KEY_ATTR_UDP: return sizeof(struct odp_key_udp);
     case ODP_KEY_ATTR_ICMP: return sizeof(struct odp_key_icmp);
     case ODP_KEY_ATTR_ICMPV6: return sizeof(struct odp_key_icmpv6);
@@ -236,6 +237,7 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds)
     const struct odp_key_ipv4 *ipv4_key;
     const struct odp_key_ipv6 *ipv6_key;
     const struct odp_key_tcp *tcp_key;
+    const struct odp_key_sctp *sctp_key;
     const struct odp_key_udp *udp_key;
     const struct odp_key_icmp *icmp_key;
     const struct odp_key_icmpv6 *icmpv6_key;
@@ -311,6 +313,12 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds)
                       ntohs(tcp_key->tcp_src), ntohs(tcp_key->tcp_dst));
         break;
 
+    case ODP_KEY_ATTR_SCTP:
+        sctp_key = nl_attr_get(a);
+        ds_put_format(ds, "sctp(src=%"PRIu16",dst=%"PRIu16")",
+                      ntohs(sctp_key->sctp_src), ntohs(sctp_key->sctp_dst));
+        break;
+
     case ODP_KEY_ATTR_UDP:
         udp_key = nl_attr_get(a);
         ds_put_format(ds, "udp(src=%"PRIu16",dst=%"PRIu16")",
@@ -465,6 +473,13 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow)
                                                sizeof *tcp_key);
             tcp_key->tcp_src = flow->tp_src;
             tcp_key->tcp_dst = flow->tp_dst;
+        } else if (flow->nw_proto == IPPROTO_SCTP) {
+            struct odp_key_sctp *sctp_key;
+
+            sctp_key = nl_msg_put_unspec_uninit(buf, ODP_KEY_ATTR_SCTP,
+                                               sizeof *sctp_key);
+            sctp_key->sctp_src = flow->tp_src;
+            sctp_key->sctp_dst = flow->tp_dst;
         } else if (flow->nw_proto == IPPROTO_UDP) {
             struct odp_key_udp *udp_key;
 
@@ -524,6 +539,7 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t key_len,
         const struct odp_key_ipv4 *ipv4_key;
         const struct odp_key_ipv6 *ipv6_key;
         const struct odp_key_tcp *tcp_key;
+        const struct odp_key_sctp *sctp_key;
         const struct odp_key_udp *udp_key;
         const struct odp_key_icmp *icmp_key;
         const struct odp_key_icmpv6 *icmpv6_key;
@@ -615,6 +631,17 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t key_len,
             flow->tp_dst = tcp_key->tcp_dst;
             break;
 
+        case TRANSITION(ODP_KEY_ATTR_IPV4, ODP_KEY_ATTR_SCTP):
+        case TRANSITION(ODP_KEY_ATTR_IPV6, ODP_KEY_ATTR_SCTP):
+            if (flow->nw_proto != IPPROTO_SCTP) {
+                return EINVAL;
+            }
+            sctp_key = nl_attr_get(nla);
+            flow->tp_src = sctp_key->sctp_src;
+            flow->tp_dst = sctp_key->sctp_dst;
+            break;
+
+
         case TRANSITION(ODP_KEY_ATTR_IPV4, ODP_KEY_ATTR_UDP):
         case TRANSITION(ODP_KEY_ATTR_IPV6, ODP_KEY_ATTR_UDP):
             if (flow->nw_proto != IPPROTO_UDP) {
@@ -705,6 +732,7 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t key_len,
 
     case ODP_KEY_ATTR_IPV4:
         if (flow->nw_proto == IPPROTO_TCP
+            || flow->nw_proto == IPPROTO_SCTP
             || flow->nw_proto == IPPROTO_UDP
             || flow->nw_proto == IPPROTO_ICMP) {
             return EINVAL;
@@ -713,6 +741,7 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t key_len,
 
     case ODP_KEY_ATTR_IPV6:
         if (flow->nw_proto == IPPROTO_TCP
+            || flow->nw_proto == IPPROTO_SCTP
             || flow->nw_proto == IPPROTO_UDP
             || flow->nw_proto == IPPROTO_ICMPV6) {
             return EINVAL;
@@ -727,6 +756,7 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t key_len,
         return 0;
 
     case ODP_KEY_ATTR_TCP:
+    case ODP_KEY_ATTR_SCTP:
     case ODP_KEY_ATTR_UDP:
     case ODP_KEY_ATTR_ICMP:
     case ODP_KEY_ATTR_ARP:
diff --git a/lib/odp-util.h b/lib/odp-util.h
index a88c7ee..4407671 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -84,7 +84,7 @@ void format_odp_actions(struct ds *, const struct nlattr *odp_actions,
 /* This is an imperfect sanity-check that ODPUTIL_FLOW_KEY_BYTES doesn't
  * need to be updated, but will at least raise awareness when new ODP
  * key types are added. */
-BUILD_ASSERT_DECL(__ODP_KEY_ATTR_MAX == 14);
+BUILD_ASSERT_DECL(__ODP_KEY_ATTR_MAX == 15);
 
 /* A buffer with sufficient size and alignment to hold an nlattr-formatted flow
  * key.  An array of "struct nlattr" might not, in theory, be sufficiently
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 58b0da1..6217a10 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -563,11 +563,13 @@ parse_protocol(const char *name, const struct protocol **p_out)
         { "arp", ETH_TYPE_ARP, 0 },
         { "icmp", ETH_TYPE_IP, IPPROTO_ICMP },
         { "tcp", ETH_TYPE_IP, IPPROTO_TCP },
+        { "sctp", ETH_TYPE_IP, IPPROTO_SCTP },
         { "udp", ETH_TYPE_IP, IPPROTO_UDP },
         { "ipv6", ETH_TYPE_IPV6, 0 },
         { "ip6", ETH_TYPE_IPV6, 0 },
         { "icmp6", ETH_TYPE_IPV6, IPPROTO_ICMPV6 },
         { "tcp6", ETH_TYPE_IPV6, IPPROTO_TCP },
+        { "sctp6", ETH_TYPE_IPV6, IPPROTO_SCTP },
         { "udp6", ETH_TYPE_IPV6, IPPROTO_UDP },
     };
     const struct protocol *p;
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 0265f30..a26ceed 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -703,6 +703,8 @@ ofp_match_to_string(const struct ofp_match *om, int verbosity)
                     ds_put_cstr(&f, "icmp,");
                 } else if (om->nw_proto == IPPROTO_TCP) {
                     ds_put_cstr(&f, "tcp,");
+                } else if (om->nw_proto == IPPROTO_SCTP) {
+                    ds_put_cstr(&f, "sctp,");
                 } else if (om->nw_proto == IPPROTO_UDP) {
                     ds_put_cstr(&f, "udp,");
                 } else {
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index df3377a..fac8268 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -2253,6 +2253,7 @@ ofputil_normalize_rule(struct cls_rule *rule, enum nx_flow_format flow_format)
     if (rule->flow.dl_type == htons(ETH_TYPE_IP)) {
         may_match = MAY_NW_PROTO | MAY_NW_TOS | MAY_NW_ADDR;
         if (rule->flow.nw_proto == IPPROTO_TCP ||
+            rule->flow.nw_proto == IPPROTO_SCTP ||
             rule->flow.nw_proto == IPPROTO_UDP ||
             rule->flow.nw_proto == IPPROTO_ICMP) {
             may_match |= MAY_TP_ADDR;
@@ -2260,7 +2261,8 @@ ofputil_normalize_rule(struct cls_rule *rule, enum nx_flow_format flow_format)
     } else if (rule->flow.dl_type == htons(ETH_TYPE_IPV6)
                && flow_format == NXFF_NXM) {
         may_match = MAY_NW_PROTO | MAY_NW_TOS | MAY_IPV6_ADDR;
-        if (rule->flow.nw_proto == IPPROTO_TCP ||
+        if (rule->flow.nw_proto == IPPROTO_TCP  ||
+		  		rule->flow.nw_proto == IPPROTO_SCTP || 
             rule->flow.nw_proto == IPPROTO_UDP) {
             may_match |= MAY_TP_ADDR;
         } else if (rule->flow.nw_proto == IPPROTO_ICMPV6) {
diff --git a/lib/packets.h b/lib/packets.h
index 8e13a25..22b10e8 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -344,6 +344,30 @@ struct tcp_header {
 };
 BUILD_ASSERT_DECL(TCP_HEADER_LEN == sizeof(struct tcp_header));
 
+
+
+/* from include/linux/sctp.h struct sctphdr */ 
+#define SCTP_HEADER_LEN 12
+struct sctp_header {
+    ovs_be16 source;
+    ovs_be16 dest;
+    ovs_be32 vtag;
+   
+	/* checksum is really __le32 
+	 *  include/linux/types.h
+	 * Maybe i need to convert between le and be? 
+	 *  typedef __u32 __bitwise __le32;
+	 *  typedef __u32 __bitwise __be32;
+	 */
+
+    ovs_be32 checksum;
+	
+};
+BUILD_ASSERT_DECL(SCTP_HEADER_LEN == sizeof(struct sctp_header));
+
+
+
+
 #define ARP_HRD_ETHERNET 1
 #define ARP_PRO_IP 0x0800
 #define ARP_OP_REQUEST 1
-- 
1.7.3.4

_______________________________________________
discuss mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/discuss

Reply via email to