Signed-off-by: Joe Stringer <j...@wand.net.nz> --- It seems that this commit breaks the following test, I'm not sure quite why:-
504: ofproto-dpif - NetFlow flow expiration --- include/linux/openvswitch.h | 6 +++++ include/sparse/netinet/in.h | 1 + lib/dpif-netdev.c | 6 +++++ lib/flow.c | 34 +++++++++++++++++++++++++-- lib/flow.h | 4 +- lib/odp-util.c | 52 +++++++++++++++++++++++++++++++++++++++++++ lib/packets.c | 20 ++++++++++++++++ lib/packets.h | 10 ++++++++ ofproto/ofproto-dpif.c | 3 ++ 9 files changed, 131 insertions(+), 5 deletions(-) diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h index f5c9cca..63c83cb 100644 --- a/include/linux/openvswitch.h +++ b/include/linux/openvswitch.h @@ -274,6 +274,7 @@ enum ovs_key_attr { OVS_KEY_ATTR_IPV6, /* struct ovs_key_ipv6 */ OVS_KEY_ATTR_TCP, /* struct ovs_key_tcp */ OVS_KEY_ATTR_UDP, /* struct ovs_key_udp */ + OVS_KEY_ATTR_SCTP, /* struct ovs_key_sctp */ OVS_KEY_ATTR_ICMP, /* struct ovs_key_icmp */ OVS_KEY_ATTR_ICMPV6, /* struct ovs_key_icmpv6 */ OVS_KEY_ATTR_ARP, /* struct ovs_key_arp */ @@ -336,6 +337,11 @@ struct ovs_key_udp { __be16 udp_dst; }; +struct ovs_key_sctp { + __be16 sctp_src; + __be16 sctp_dst; +}; + struct ovs_key_icmp { __u8 icmp_type; __u8 icmp_code; diff --git a/include/sparse/netinet/in.h b/include/sparse/netinet/in.h index b3924c3..6082932 100644 --- a/include/sparse/netinet/in.h +++ b/include/sparse/netinet/in.h @@ -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 diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 144b6b6..219f017 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -1175,6 +1175,7 @@ execute_set_action(struct ofpbuf *packet, const struct nlattr *a) const struct ovs_key_ipv4 *ipv4_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_TUN_ID: @@ -1204,6 +1205,11 @@ 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_UNSPEC: case OVS_KEY_ATTR_ENCAP: case OVS_KEY_ATTR_ETHERTYPE: diff --git a/lib/flow.c b/lib/flow.c index f4446c9..754ad2f 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -77,6 +77,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) { @@ -242,6 +248,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) { @@ -327,7 +344,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 @@ -390,6 +407,8 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, ovs_be64 tun_id, 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) { @@ -410,6 +429,8 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, ovs_be64 tun_id, 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; @@ -899,7 +920,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)) { @@ -911,7 +932,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; } } @@ -1054,6 +1075,13 @@ 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; + /* XXX: Do we need to set the csum here? */ } else if (flow->nw_proto == IPPROTO_ICMP) { struct icmp_header *icmp; diff --git a/lib/flow.h b/lib/flow.h index 568e291..7348672 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -65,8 +65,8 @@ struct flow { uint16_t in_port; /* OpenFlow port number of input port. */ 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. */ diff --git a/lib/odp-util.c b/lib/odp-util.c index 901dac3..019f3a6 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -101,6 +101,7 @@ ovs_key_attr_to_string(enum ovs_key_attr attr) 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"; @@ -610,6 +611,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); @@ -664,6 +666,7 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds) 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; const struct ovs_key_icmp *icmp_key; const struct ovs_key_icmpv6 *icmpv6_key; const struct ovs_key_arp *arp_key; @@ -760,6 +763,12 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds) ntohs(udp_key->udp_src), ntohs(udp_key->udp_dst)); break; + case OVS_KEY_ATTR_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: icmp_key = nl_attr_get(a); ds_put_format(ds, "(type=%"PRIu8",code=%"PRIu8")", @@ -1080,6 +1089,22 @@ parse_odp_key_attr(const char *s, const struct simap *port_names, } { + int sctp_src; + int sctp_dst; + int n = -1; + + 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); + return n; + } + } + + { int icmp_type; int icmp_code; int n = -1; @@ -1345,6 +1370,13 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow) sizeof *udp_key); udp_key->udp_src = flow->tp_src; udp_key->udp_dst = flow->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 = flow->tp_src; + sctp_key->sctp_dst = flow->tp_dst; } else if (flow->dl_type == htons(ETH_TYPE_IP) && flow->nw_proto == IPPROTO_ICMP) { struct ovs_key_icmp *icmp_key; @@ -1613,6 +1645,18 @@ parse_l3_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], flow->tp_src = udp_key->udp_src; flow->tp_dst = udp_key->udp_dst; } + } 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)) { + 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; + } } else if (flow->nw_proto == IPPROTO_ICMP && flow->dl_type == htons(ETH_TYPE_IP) && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) { @@ -2002,6 +2046,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)); } } diff --git a/lib/packets.c b/lib/packets.c index 16f4fe6..de4906b 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -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" @@ -467,6 +468,10 @@ packet_set_ipv4_addr(struct ofpbuf *packet, ovs_be32 *addr, ovs_be32 new_addr) uh->udp_csum = htons(0xffff); } } + } else if (nh->ip_proto == IPPROTO_SCTP && packet->l7) { + struct sctp_header *sh = packet->l4; + sh->sctp_csum = 0; + sh->sctp_csum = crc32c(0, packet->data, packet->size); } nh->ip_csum = recalc_csum32(nh->ip_csum, *addr, new_addr); *addr = new_addr; @@ -549,6 +554,21 @@ 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; + + sh->sctp_src = src; + sh->sctp_dst = dst; + + sh->sctp_csum = 0; + sh->sctp_csum = crc32c(0, packet->data, packet->size); +} + /* 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 diff --git a/lib/packets.h b/lib/packets.h index e5be1cb..34f246b 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -371,6 +371,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; @@ -486,6 +495,7 @@ void packet_set_ipv4(struct ofpbuf *, ovs_be32 src, ovs_be32 dst, uint8_t tos, uint8_t ttl); 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); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 78cb186..8da4cca 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -5164,6 +5164,9 @@ execute_controller_action(struct action_xlate_ctx *ctx, int len, } else if (ctx->flow.nw_proto == IPPROTO_UDP) { packet_set_udp_port(packet, ctx->flow.tp_src, ctx->flow.tp_dst); + } else if (ctx->flow.nw_proto == IPPROTO_SCTP) { + packet_set_sctp_port(packet, ctx->flow.tp_src, + ctx->flow.tp_dst); } } } -- 1.7.2.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev