mirror of
https://github.com/openvswitch/ovs
synced 2025-10-15 14:17:18 +00:00
ofproto-dpif: Add SCTP support
Reviewed-by: Simon Horman <horms@verge.net.au> Signed-off-by: Joe Stringer <joe@wand.net.nz> Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
@@ -59,6 +59,7 @@ extern const struct in6_addr in6addr_any;
|
||||
#define IPPROTO_ICMPV6 58
|
||||
#define IPPROTO_NONE 59
|
||||
#define IPPROTO_DSTOPTS 60
|
||||
#define IPPROTO_SCTP 132
|
||||
|
||||
/* All the IP options documented in Linux ip(7). */
|
||||
#define IP_ADD_MEMBERSHIP 0
|
||||
|
33
lib/flow.c
33
lib/flow.c
@@ -81,6 +81,12 @@ pull_udp(struct ofpbuf *packet)
|
||||
return ofpbuf_try_pull(packet, UDP_HEADER_LEN);
|
||||
}
|
||||
|
||||
static struct sctp_header *
|
||||
pull_sctp(struct ofpbuf *packet)
|
||||
{
|
||||
return ofpbuf_try_pull(packet, SCTP_HEADER_LEN);
|
||||
}
|
||||
|
||||
static struct icmp_header *
|
||||
pull_icmp(struct ofpbuf *packet)
|
||||
{
|
||||
@@ -265,6 +271,17 @@ parse_udp(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->sctp_src;
|
||||
flow->tp_dst = sctp->sctp_dst;
|
||||
packet->l7 = b->data;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_icmpv6(struct ofpbuf *b, struct flow *flow)
|
||||
{
|
||||
@@ -352,7 +369,7 @@ invalid:
|
||||
* - packet->l4 to just past the IPv4 header, if one is present and has a
|
||||
* correct length, and otherwise NULL.
|
||||
*
|
||||
* - packet->l7 to just past the TCP or UDP or ICMP header, if one is
|
||||
* - packet->l7 to just past the TCP/UDP/SCTP/ICMP header, if one is
|
||||
* present and has a correct length, and otherwise NULL.
|
||||
*/
|
||||
void
|
||||
@@ -430,6 +447,8 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, uint32_t pkt_mark,
|
||||
parse_tcp(packet, &b, flow);
|
||||
} else if (flow->nw_proto == IPPROTO_UDP) {
|
||||
parse_udp(packet, &b, flow);
|
||||
} else if (flow->nw_proto == IPPROTO_SCTP) {
|
||||
parse_sctp(packet, &b, flow);
|
||||
} else if (flow->nw_proto == IPPROTO_ICMP) {
|
||||
const struct icmp_header *icmp = pull_icmp(&b);
|
||||
if (icmp) {
|
||||
@@ -450,6 +469,8 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, uint32_t pkt_mark,
|
||||
parse_tcp(packet, &b, flow);
|
||||
} else if (flow->nw_proto == IPPROTO_UDP) {
|
||||
parse_udp(packet, &b, flow);
|
||||
} else if (flow->nw_proto == IPPROTO_SCTP) {
|
||||
parse_sctp(packet, &b, flow);
|
||||
} else if (flow->nw_proto == IPPROTO_ICMPV6) {
|
||||
if (parse_icmpv6(&b, flow)) {
|
||||
packet->l7 = b.data;
|
||||
@@ -761,7 +782,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_port = flow->tp_src ^ flow->tp_dst;
|
||||
}
|
||||
} else if (fields.eth_type == htons(ETH_TYPE_IPV6)) {
|
||||
@@ -773,7 +794,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_port = flow->tp_src ^ flow->tp_dst;
|
||||
}
|
||||
}
|
||||
@@ -999,6 +1020,12 @@ flow_compose(struct ofpbuf *b, const struct flow *flow)
|
||||
b->l4 = udp = ofpbuf_put_zeros(b, sizeof *udp);
|
||||
udp->udp_src = flow->tp_src;
|
||||
udp->udp_dst = flow->tp_dst;
|
||||
} else if (flow->nw_proto == IPPROTO_SCTP) {
|
||||
struct sctp_header *sctp;
|
||||
|
||||
b->l4 = sctp = ofpbuf_put_zeros(b, sizeof *sctp);
|
||||
sctp->sctp_src = flow->tp_src;
|
||||
sctp->sctp_dst = flow->tp_dst;
|
||||
} else if (flow->nw_proto == IPPROTO_ICMP) {
|
||||
struct icmp_header *icmp;
|
||||
|
||||
|
@@ -101,8 +101,8 @@ struct flow {
|
||||
uint16_t mpls_depth; /* Depth of MPLS stack. */
|
||||
ovs_be16 vlan_tci; /* If 802.1Q, TCI | VLAN_CFI; otherwise 0. */
|
||||
ovs_be16 dl_type; /* Ethernet frame type. */
|
||||
ovs_be16 tp_src; /* TCP/UDP source port. */
|
||||
ovs_be16 tp_dst; /* TCP/UDP destination port. */
|
||||
ovs_be16 tp_src; /* TCP/UDP/SCTP source port. */
|
||||
ovs_be16 tp_dst; /* TCP/UDP/SCTP destination port. */
|
||||
uint8_t dl_src[6]; /* Ethernet source address. */
|
||||
uint8_t dl_dst[6]; /* Ethernet destination address. */
|
||||
uint8_t nw_proto; /* IP protocol or low 8 bits of ARP opcode. */
|
||||
|
@@ -54,6 +54,7 @@ odp_execute_set_action(struct ofpbuf *packet, const struct nlattr *a,
|
||||
const struct ovs_key_ipv6 *ipv6_key;
|
||||
const struct ovs_key_tcp *tcp_key;
|
||||
const struct ovs_key_udp *udp_key;
|
||||
const struct ovs_key_sctp *sctp_key;
|
||||
|
||||
switch (type) {
|
||||
case OVS_KEY_ATTR_PRIORITY:
|
||||
@@ -96,6 +97,11 @@ odp_execute_set_action(struct ofpbuf *packet, const struct nlattr *a,
|
||||
packet_set_udp_port(packet, udp_key->udp_src, udp_key->udp_dst);
|
||||
break;
|
||||
|
||||
case OVS_KEY_ATTR_SCTP:
|
||||
sctp_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_sctp));
|
||||
packet_set_sctp_port(packet, sctp_key->sctp_src, sctp_key->sctp_dst);
|
||||
break;
|
||||
|
||||
case OVS_KEY_ATTR_MPLS:
|
||||
set_mpls_lse(packet, nl_attr_get_be32(a));
|
||||
break;
|
||||
|
@@ -109,6 +109,7 @@ ovs_key_attr_to_string(enum ovs_key_attr attr, char *namebuf, size_t bufsize)
|
||||
case OVS_KEY_ATTR_IPV6: return "ipv6";
|
||||
case OVS_KEY_ATTR_TCP: return "tcp";
|
||||
case OVS_KEY_ATTR_UDP: return "udp";
|
||||
case OVS_KEY_ATTR_SCTP: return "sctp";
|
||||
case OVS_KEY_ATTR_ICMP: return "icmp";
|
||||
case OVS_KEY_ATTR_ICMPV6: return "icmpv6";
|
||||
case OVS_KEY_ATTR_ARP: return "arp";
|
||||
@@ -746,6 +747,7 @@ odp_flow_key_attr_len(uint16_t type)
|
||||
case OVS_KEY_ATTR_IPV6: return sizeof(struct ovs_key_ipv6);
|
||||
case OVS_KEY_ATTR_TCP: return sizeof(struct ovs_key_tcp);
|
||||
case OVS_KEY_ATTR_UDP: return sizeof(struct ovs_key_udp);
|
||||
case OVS_KEY_ATTR_SCTP: return sizeof(struct ovs_key_sctp);
|
||||
case OVS_KEY_ATTR_ICMP: return sizeof(struct ovs_key_icmp);
|
||||
case OVS_KEY_ATTR_ICMPV6: return sizeof(struct ovs_key_icmpv6);
|
||||
case OVS_KEY_ATTR_ARP: return sizeof(struct ovs_key_arp);
|
||||
@@ -1206,6 +1208,23 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
|
||||
}
|
||||
break;
|
||||
|
||||
case OVS_KEY_ATTR_SCTP:
|
||||
if (ma) {
|
||||
const struct ovs_key_sctp *sctp_mask = nl_attr_get(ma);
|
||||
const struct ovs_key_sctp *sctp_key = nl_attr_get(a);
|
||||
|
||||
ds_put_format(ds, "src=%"PRIu16"/%#"PRIx16
|
||||
",dst=%"PRIu16"/%#"PRIx16,
|
||||
ntohs(sctp_key->sctp_src), ntohs(sctp_mask->sctp_src),
|
||||
ntohs(sctp_key->sctp_dst), ntohs(sctp_mask->sctp_dst));
|
||||
} else {
|
||||
const struct ovs_key_sctp *sctp_key = nl_attr_get(a);
|
||||
|
||||
ds_put_format(ds, "(src=%"PRIu16",dst=%"PRIu16")",
|
||||
ntohs(sctp_key->sctp_src), ntohs(sctp_key->sctp_dst));
|
||||
}
|
||||
break;
|
||||
|
||||
case OVS_KEY_ATTR_ICMP:
|
||||
if (!is_exact) {
|
||||
const struct ovs_key_icmp *icmp_mask = nl_attr_get(ma);
|
||||
@@ -2028,6 +2047,45 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int sctp_src;
|
||||
int sctp_dst;
|
||||
int sctp_src_mask;
|
||||
int sctp_dst_mask;
|
||||
int n = -1;
|
||||
|
||||
if (mask && sscanf(s, "sctp(src=%i/%i,dst=%i/%i)%n",
|
||||
&sctp_src, &sctp_src_mask,
|
||||
&sctp_dst, &sctp_dst_mask, &n) > 0 && n > 0) {
|
||||
struct ovs_key_sctp sctp_key;
|
||||
struct ovs_key_sctp sctp_mask;
|
||||
|
||||
sctp_key.sctp_src = htons(sctp_src);
|
||||
sctp_key.sctp_dst = htons(sctp_dst);
|
||||
nl_msg_put_unspec(key, OVS_KEY_ATTR_SCTP, &sctp_key, sizeof sctp_key);
|
||||
|
||||
sctp_mask.sctp_src = htons(sctp_src_mask);
|
||||
sctp_mask.sctp_dst = htons(sctp_dst_mask);
|
||||
nl_msg_put_unspec(mask, OVS_KEY_ATTR_SCTP,
|
||||
&sctp_mask, sizeof sctp_mask);
|
||||
return n;
|
||||
}
|
||||
if (sscanf(s, "sctp(src=%i,dst=%i)%n", &sctp_src, &sctp_dst, &n) > 0
|
||||
&& n > 0) {
|
||||
struct ovs_key_sctp sctp_key;
|
||||
|
||||
sctp_key.sctp_src = htons(sctp_src);
|
||||
sctp_key.sctp_dst = htons(sctp_dst);
|
||||
nl_msg_put_unspec(key, OVS_KEY_ATTR_SCTP, &sctp_key, sizeof sctp_key);
|
||||
|
||||
if (mask) {
|
||||
memset(&sctp_key, 0xff, sizeof sctp_key);
|
||||
nl_msg_put_unspec(mask, OVS_KEY_ATTR_SCTP, &sctp_key, sizeof sctp_key);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int icmp_type;
|
||||
int icmp_code;
|
||||
@@ -2471,6 +2529,13 @@ odp_flow_key_from_flow__(struct ofpbuf *buf, const struct flow *data,
|
||||
sizeof *udp_key);
|
||||
udp_key->udp_src = data->tp_src;
|
||||
udp_key->udp_dst = data->tp_dst;
|
||||
} else if (flow->nw_proto == IPPROTO_SCTP) {
|
||||
struct ovs_key_sctp *sctp_key;
|
||||
|
||||
sctp_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_SCTP,
|
||||
sizeof *sctp_key);
|
||||
sctp_key->sctp_src = data->tp_src;
|
||||
sctp_key->sctp_dst = data->tp_dst;
|
||||
} else if (flow->dl_type == htons(ETH_TYPE_IP)
|
||||
&& flow->nw_proto == IPPROTO_ICMP) {
|
||||
struct ovs_key_icmp *icmp_key;
|
||||
@@ -2858,6 +2923,21 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
|
||||
flow->tp_dst = udp_key->udp_dst;
|
||||
expected_bit = OVS_KEY_ATTR_UDP;
|
||||
}
|
||||
} else if (flow->nw_proto == IPPROTO_SCTP
|
||||
&& (flow->dl_type == htons(ETH_TYPE_IP) ||
|
||||
flow->dl_type == htons(ETH_TYPE_IPV6))
|
||||
&& !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
|
||||
if (!is_mask) {
|
||||
expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_SCTP;
|
||||
}
|
||||
if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_SCTP)) {
|
||||
const struct ovs_key_sctp *sctp_key;
|
||||
|
||||
sctp_key = nl_attr_get(attrs[OVS_KEY_ATTR_SCTP]);
|
||||
flow->tp_src = sctp_key->sctp_src;
|
||||
flow->tp_dst = sctp_key->sctp_dst;
|
||||
expected_bit = OVS_KEY_ATTR_SCTP;
|
||||
}
|
||||
} else if (src_flow->nw_proto == IPPROTO_ICMP
|
||||
&& src_flow->dl_type == htons(ETH_TYPE_IP)
|
||||
&& !(src_flow->nw_frag & FLOW_NW_FRAG_LATER)) {
|
||||
@@ -3429,6 +3509,14 @@ commit_set_port_action(const struct flow *flow, struct flow *base,
|
||||
|
||||
commit_set_action(odp_actions, OVS_KEY_ATTR_UDP,
|
||||
&port_key, sizeof(port_key));
|
||||
} else if (flow->nw_proto == IPPROTO_SCTP) {
|
||||
struct ovs_key_sctp port_key;
|
||||
|
||||
port_key.sctp_src = base->tp_src = flow->tp_src;
|
||||
port_key.sctp_dst = base->tp_dst = flow->tp_dst;
|
||||
|
||||
commit_set_action(odp_actions, OVS_KEY_ATTR_SCTP,
|
||||
&port_key, sizeof(port_key));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include <stdlib.h>
|
||||
#include "byte-order.h"
|
||||
#include "csum.h"
|
||||
#include "crc32c.h"
|
||||
#include "flow.h"
|
||||
#include "hmap.h"
|
||||
#include "dynamic-string.h"
|
||||
@@ -885,6 +886,27 @@ packet_set_udp_port(struct ofpbuf *packet, ovs_be16 src, ovs_be16 dst)
|
||||
}
|
||||
}
|
||||
|
||||
/* Sets the SCTP source and destination port ('src' and 'dst' respectively) of
|
||||
* the SCTP header contained in 'packet'. 'packet' must be a valid SCTP packet
|
||||
* with its l4 marker properly populated. */
|
||||
void
|
||||
packet_set_sctp_port(struct ofpbuf *packet, ovs_be16 src, ovs_be16 dst)
|
||||
{
|
||||
struct sctp_header *sh = packet->l4;
|
||||
ovs_be32 old_csum, old_correct_csum, new_csum;
|
||||
uint16_t tp_len = packet->size - ((uint8_t*)sh - (uint8_t*)packet->data);
|
||||
|
||||
old_csum = sh->sctp_csum;
|
||||
sh->sctp_csum = 0;
|
||||
old_correct_csum = crc32c(packet->l4, tp_len);
|
||||
|
||||
sh->sctp_src = src;
|
||||
sh->sctp_dst = dst;
|
||||
|
||||
new_csum = crc32c(packet->l4, tp_len);
|
||||
sh->sctp_csum = old_csum ^ old_correct_csum ^ new_csum;
|
||||
}
|
||||
|
||||
/* If 'packet' is a TCP packet, returns the TCP flags. Otherwise, returns 0.
|
||||
*
|
||||
* 'flow' must be the flow corresponding to 'packet' and 'packet''s header
|
||||
|
@@ -471,6 +471,15 @@ struct icmp_header {
|
||||
};
|
||||
BUILD_ASSERT_DECL(ICMP_HEADER_LEN == sizeof(struct icmp_header));
|
||||
|
||||
#define SCTP_HEADER_LEN 12
|
||||
struct sctp_header {
|
||||
ovs_be16 sctp_src;
|
||||
ovs_be16 sctp_dst;
|
||||
ovs_be32 sctp_vtag;
|
||||
ovs_be32 sctp_csum;
|
||||
};
|
||||
BUILD_ASSERT_DECL(SCTP_HEADER_LEN == sizeof(struct sctp_header));
|
||||
|
||||
#define UDP_HEADER_LEN 8
|
||||
struct udp_header {
|
||||
ovs_be16 udp_src;
|
||||
@@ -601,6 +610,7 @@ void packet_set_ipv6(struct ofpbuf *, uint8_t proto, const ovs_be32 src[4],
|
||||
ovs_be32 fl, uint8_t hlmit);
|
||||
void packet_set_tcp_port(struct ofpbuf *, ovs_be16 src, ovs_be16 dst);
|
||||
void packet_set_udp_port(struct ofpbuf *, ovs_be16 src, ovs_be16 dst);
|
||||
void packet_set_sctp_port(struct ofpbuf *, ovs_be16 src, ovs_be16 dst);
|
||||
|
||||
uint8_t packet_get_tcp_flags(const struct ofpbuf *, const struct flow *);
|
||||
void packet_format_tcp_flags(struct ds *, uint8_t);
|
||||
|
Reference in New Issue
Block a user