diff options
Diffstat (limited to 'net/openvswitch/flow.c')
| -rw-r--r-- | net/openvswitch/flow.c | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 1fceb9653598..2b4785590b56 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c | |||
| @@ -34,6 +34,7 @@ | |||
| 34 | #include <linux/if_arp.h> | 34 | #include <linux/if_arp.h> |
| 35 | #include <linux/ip.h> | 35 | #include <linux/ip.h> |
| 36 | #include <linux/ipv6.h> | 36 | #include <linux/ipv6.h> |
| 37 | #include <linux/sctp.h> | ||
| 37 | #include <linux/tcp.h> | 38 | #include <linux/tcp.h> |
| 38 | #include <linux/udp.h> | 39 | #include <linux/udp.h> |
| 39 | #include <linux/icmp.h> | 40 | #include <linux/icmp.h> |
| @@ -129,6 +130,7 @@ static bool ovs_match_validate(const struct sw_flow_match *match, | |||
| 129 | | (1 << OVS_KEY_ATTR_IPV6) | 130 | | (1 << OVS_KEY_ATTR_IPV6) |
| 130 | | (1 << OVS_KEY_ATTR_TCP) | 131 | | (1 << OVS_KEY_ATTR_TCP) |
| 131 | | (1 << OVS_KEY_ATTR_UDP) | 132 | | (1 << OVS_KEY_ATTR_UDP) |
| 133 | | (1 << OVS_KEY_ATTR_SCTP) | ||
| 132 | | (1 << OVS_KEY_ATTR_ICMP) | 134 | | (1 << OVS_KEY_ATTR_ICMP) |
| 133 | | (1 << OVS_KEY_ATTR_ICMPV6) | 135 | | (1 << OVS_KEY_ATTR_ICMPV6) |
| 134 | | (1 << OVS_KEY_ATTR_ARP) | 136 | | (1 << OVS_KEY_ATTR_ARP) |
| @@ -159,6 +161,12 @@ static bool ovs_match_validate(const struct sw_flow_match *match, | |||
| 159 | mask_allowed |= 1 << OVS_KEY_ATTR_UDP; | 161 | mask_allowed |= 1 << OVS_KEY_ATTR_UDP; |
| 160 | } | 162 | } |
| 161 | 163 | ||
| 164 | if (match->key->ip.proto == IPPROTO_SCTP) { | ||
| 165 | key_expected |= 1 << OVS_KEY_ATTR_SCTP; | ||
| 166 | if (match->mask && (match->mask->key.ip.proto == 0xff)) | ||
| 167 | mask_allowed |= 1 << OVS_KEY_ATTR_SCTP; | ||
| 168 | } | ||
| 169 | |||
| 162 | if (match->key->ip.proto == IPPROTO_TCP) { | 170 | if (match->key->ip.proto == IPPROTO_TCP) { |
| 163 | key_expected |= 1 << OVS_KEY_ATTR_TCP; | 171 | key_expected |= 1 << OVS_KEY_ATTR_TCP; |
| 164 | if (match->mask && (match->mask->key.ip.proto == 0xff)) | 172 | if (match->mask && (match->mask->key.ip.proto == 0xff)) |
| @@ -185,6 +193,12 @@ static bool ovs_match_validate(const struct sw_flow_match *match, | |||
| 185 | mask_allowed |= 1 << OVS_KEY_ATTR_UDP; | 193 | mask_allowed |= 1 << OVS_KEY_ATTR_UDP; |
| 186 | } | 194 | } |
| 187 | 195 | ||
| 196 | if (match->key->ip.proto == IPPROTO_SCTP) { | ||
| 197 | key_expected |= 1 << OVS_KEY_ATTR_SCTP; | ||
| 198 | if (match->mask && (match->mask->key.ip.proto == 0xff)) | ||
| 199 | mask_allowed |= 1 << OVS_KEY_ATTR_SCTP; | ||
| 200 | } | ||
| 201 | |||
| 188 | if (match->key->ip.proto == IPPROTO_TCP) { | 202 | if (match->key->ip.proto == IPPROTO_TCP) { |
| 189 | key_expected |= 1 << OVS_KEY_ATTR_TCP; | 203 | key_expected |= 1 << OVS_KEY_ATTR_TCP; |
| 190 | if (match->mask && (match->mask->key.ip.proto == 0xff)) | 204 | if (match->mask && (match->mask->key.ip.proto == 0xff)) |
| @@ -280,6 +294,12 @@ static bool udphdr_ok(struct sk_buff *skb) | |||
| 280 | sizeof(struct udphdr)); | 294 | sizeof(struct udphdr)); |
| 281 | } | 295 | } |
| 282 | 296 | ||
| 297 | static bool sctphdr_ok(struct sk_buff *skb) | ||
| 298 | { | ||
| 299 | return pskb_may_pull(skb, skb_transport_offset(skb) + | ||
| 300 | sizeof(struct sctphdr)); | ||
| 301 | } | ||
| 302 | |||
| 283 | static bool icmphdr_ok(struct sk_buff *skb) | 303 | static bool icmphdr_ok(struct sk_buff *skb) |
| 284 | { | 304 | { |
| 285 | return pskb_may_pull(skb, skb_transport_offset(skb) + | 305 | return pskb_may_pull(skb, skb_transport_offset(skb) + |
| @@ -891,6 +911,12 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key) | |||
| 891 | key->ipv4.tp.src = udp->source; | 911 | key->ipv4.tp.src = udp->source; |
| 892 | key->ipv4.tp.dst = udp->dest; | 912 | key->ipv4.tp.dst = udp->dest; |
| 893 | } | 913 | } |
| 914 | } else if (key->ip.proto == IPPROTO_SCTP) { | ||
| 915 | if (sctphdr_ok(skb)) { | ||
| 916 | struct sctphdr *sctp = sctp_hdr(skb); | ||
| 917 | key->ipv4.tp.src = sctp->source; | ||
| 918 | key->ipv4.tp.dst = sctp->dest; | ||
| 919 | } | ||
| 894 | } else if (key->ip.proto == IPPROTO_ICMP) { | 920 | } else if (key->ip.proto == IPPROTO_ICMP) { |
| 895 | if (icmphdr_ok(skb)) { | 921 | if (icmphdr_ok(skb)) { |
| 896 | struct icmphdr *icmp = icmp_hdr(skb); | 922 | struct icmphdr *icmp = icmp_hdr(skb); |
| @@ -953,6 +979,12 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key) | |||
| 953 | key->ipv6.tp.src = udp->source; | 979 | key->ipv6.tp.src = udp->source; |
| 954 | key->ipv6.tp.dst = udp->dest; | 980 | key->ipv6.tp.dst = udp->dest; |
| 955 | } | 981 | } |
| 982 | } else if (key->ip.proto == NEXTHDR_SCTP) { | ||
| 983 | if (sctphdr_ok(skb)) { | ||
| 984 | struct sctphdr *sctp = sctp_hdr(skb); | ||
| 985 | key->ipv6.tp.src = sctp->source; | ||
| 986 | key->ipv6.tp.dst = sctp->dest; | ||
| 987 | } | ||
| 956 | } else if (key->ip.proto == NEXTHDR_ICMP) { | 988 | } else if (key->ip.proto == NEXTHDR_ICMP) { |
| 957 | if (icmp6hdr_ok(skb)) { | 989 | if (icmp6hdr_ok(skb)) { |
| 958 | error = parse_icmpv6(skb, key, nh_len); | 990 | error = parse_icmpv6(skb, key, nh_len); |
| @@ -1087,6 +1119,7 @@ const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { | |||
| 1087 | [OVS_KEY_ATTR_IPV6] = sizeof(struct ovs_key_ipv6), | 1119 | [OVS_KEY_ATTR_IPV6] = sizeof(struct ovs_key_ipv6), |
| 1088 | [OVS_KEY_ATTR_TCP] = sizeof(struct ovs_key_tcp), | 1120 | [OVS_KEY_ATTR_TCP] = sizeof(struct ovs_key_tcp), |
| 1089 | [OVS_KEY_ATTR_UDP] = sizeof(struct ovs_key_udp), | 1121 | [OVS_KEY_ATTR_UDP] = sizeof(struct ovs_key_udp), |
| 1122 | [OVS_KEY_ATTR_SCTP] = sizeof(struct ovs_key_sctp), | ||
| 1090 | [OVS_KEY_ATTR_ICMP] = sizeof(struct ovs_key_icmp), | 1123 | [OVS_KEY_ATTR_ICMP] = sizeof(struct ovs_key_icmp), |
| 1091 | [OVS_KEY_ATTR_ICMPV6] = sizeof(struct ovs_key_icmpv6), | 1124 | [OVS_KEY_ATTR_ICMPV6] = sizeof(struct ovs_key_icmpv6), |
| 1092 | [OVS_KEY_ATTR_ARP] = sizeof(struct ovs_key_arp), | 1125 | [OVS_KEY_ATTR_ARP] = sizeof(struct ovs_key_arp), |
| @@ -1500,6 +1533,24 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, | |||
| 1500 | attrs &= ~(1 << OVS_KEY_ATTR_UDP); | 1533 | attrs &= ~(1 << OVS_KEY_ATTR_UDP); |
| 1501 | } | 1534 | } |
| 1502 | 1535 | ||
| 1536 | if (attrs & (1 << OVS_KEY_ATTR_SCTP)) { | ||
| 1537 | const struct ovs_key_sctp *sctp_key; | ||
| 1538 | |||
| 1539 | sctp_key = nla_data(a[OVS_KEY_ATTR_SCTP]); | ||
| 1540 | if (orig_attrs & (1 << OVS_KEY_ATTR_IPV4)) { | ||
| 1541 | SW_FLOW_KEY_PUT(match, ipv4.tp.src, | ||
| 1542 | sctp_key->sctp_src, is_mask); | ||
| 1543 | SW_FLOW_KEY_PUT(match, ipv4.tp.dst, | ||
| 1544 | sctp_key->sctp_dst, is_mask); | ||
| 1545 | } else { | ||
| 1546 | SW_FLOW_KEY_PUT(match, ipv6.tp.src, | ||
| 1547 | sctp_key->sctp_src, is_mask); | ||
| 1548 | SW_FLOW_KEY_PUT(match, ipv6.tp.dst, | ||
| 1549 | sctp_key->sctp_dst, is_mask); | ||
| 1550 | } | ||
| 1551 | attrs &= ~(1 << OVS_KEY_ATTR_SCTP); | ||
| 1552 | } | ||
| 1553 | |||
| 1503 | if (attrs & (1 << OVS_KEY_ATTR_ICMP)) { | 1554 | if (attrs & (1 << OVS_KEY_ATTR_ICMP)) { |
| 1504 | const struct ovs_key_icmp *icmp_key; | 1555 | const struct ovs_key_icmp *icmp_key; |
| 1505 | 1556 | ||
| @@ -1843,6 +1894,20 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, | |||
| 1843 | udp_key->udp_src = output->ipv6.tp.src; | 1894 | udp_key->udp_src = output->ipv6.tp.src; |
| 1844 | udp_key->udp_dst = output->ipv6.tp.dst; | 1895 | udp_key->udp_dst = output->ipv6.tp.dst; |
| 1845 | } | 1896 | } |
| 1897 | } else if (swkey->ip.proto == IPPROTO_SCTP) { | ||
| 1898 | struct ovs_key_sctp *sctp_key; | ||
| 1899 | |||
| 1900 | nla = nla_reserve(skb, OVS_KEY_ATTR_SCTP, sizeof(*sctp_key)); | ||
| 1901 | if (!nla) | ||
| 1902 | goto nla_put_failure; | ||
| 1903 | sctp_key = nla_data(nla); | ||
| 1904 | if (swkey->eth.type == htons(ETH_P_IP)) { | ||
| 1905 | sctp_key->sctp_src = swkey->ipv4.tp.src; | ||
| 1906 | sctp_key->sctp_dst = swkey->ipv4.tp.dst; | ||
| 1907 | } else if (swkey->eth.type == htons(ETH_P_IPV6)) { | ||
| 1908 | sctp_key->sctp_src = swkey->ipv6.tp.src; | ||
| 1909 | sctp_key->sctp_dst = swkey->ipv6.tp.dst; | ||
| 1910 | } | ||
| 1846 | } else if (swkey->eth.type == htons(ETH_P_IP) && | 1911 | } else if (swkey->eth.type == htons(ETH_P_IP) && |
| 1847 | swkey->ip.proto == IPPROTO_ICMP) { | 1912 | swkey->ip.proto == IPPROTO_ICMP) { |
| 1848 | struct ovs_key_icmp *icmp_key; | 1913 | struct ovs_key_icmp *icmp_key; |
