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