diff options
| author | David S. Miller <davem@davemloft.net> | 2013-11-04 16:25:04 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-11-04 16:25:04 -0500 |
| commit | 6fcf018ae4491dc11b080892fa9f3dbd928fdbb9 (patch) | |
| tree | f28592676e295183581d59149fd1eac913b229a2 /net/openvswitch/flow.c | |
| parent | 5a6e55c461db3364aa5be919101db972bc859133 (diff) | |
| parent | 8ddd094675cfd453fc9838caa46ea108a4107183 (diff) | |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/jesse/openvswitch
Jesse Gross says:
====================
Open vSwitch
A set of updates for net-next/3.13. Major changes are:
* Restructure flow handling code to be more logically organized and
easier to read.
* Rehashing of the flow table is moved from a workqueue to flow
installation time. Before, heavy load could block the workqueue for
excessive periods of time.
* Additional debugging information is provided to help diagnose megaflows.
* It's now possible to match on TCP flags.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/openvswitch/flow.c')
| -rw-r--r-- | net/openvswitch/flow.c | 1605 |
1 files changed, 24 insertions, 1581 deletions
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 410db90db73d..b409f5279601 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c | |||
| @@ -45,202 +45,38 @@ | |||
| 45 | #include <net/ipv6.h> | 45 | #include <net/ipv6.h> |
| 46 | #include <net/ndisc.h> | 46 | #include <net/ndisc.h> |
| 47 | 47 | ||
| 48 | static struct kmem_cache *flow_cache; | 48 | u64 ovs_flow_used_time(unsigned long flow_jiffies) |
| 49 | |||
| 50 | static void ovs_sw_flow_mask_set(struct sw_flow_mask *mask, | ||
| 51 | struct sw_flow_key_range *range, u8 val); | ||
| 52 | |||
| 53 | static void update_range__(struct sw_flow_match *match, | ||
| 54 | size_t offset, size_t size, bool is_mask) | ||
| 55 | { | 49 | { |
| 56 | struct sw_flow_key_range *range = NULL; | 50 | struct timespec cur_ts; |
| 57 | size_t start = rounddown(offset, sizeof(long)); | 51 | u64 cur_ms, idle_ms; |
| 58 | size_t end = roundup(offset + size, sizeof(long)); | ||
| 59 | |||
| 60 | if (!is_mask) | ||
| 61 | range = &match->range; | ||
| 62 | else if (match->mask) | ||
| 63 | range = &match->mask->range; | ||
| 64 | |||
| 65 | if (!range) | ||
| 66 | return; | ||
| 67 | |||
| 68 | if (range->start == range->end) { | ||
| 69 | range->start = start; | ||
| 70 | range->end = end; | ||
| 71 | return; | ||
| 72 | } | ||
| 73 | |||
| 74 | if (range->start > start) | ||
| 75 | range->start = start; | ||
| 76 | 52 | ||
| 77 | if (range->end < end) | 53 | ktime_get_ts(&cur_ts); |
| 78 | range->end = end; | 54 | idle_ms = jiffies_to_msecs(jiffies - flow_jiffies); |
| 79 | } | 55 | cur_ms = (u64)cur_ts.tv_sec * MSEC_PER_SEC + |
| 56 | cur_ts.tv_nsec / NSEC_PER_MSEC; | ||
| 80 | 57 | ||
| 81 | #define SW_FLOW_KEY_PUT(match, field, value, is_mask) \ | 58 | return cur_ms - idle_ms; |
| 82 | do { \ | ||
| 83 | update_range__(match, offsetof(struct sw_flow_key, field), \ | ||
| 84 | sizeof((match)->key->field), is_mask); \ | ||
| 85 | if (is_mask) { \ | ||
| 86 | if ((match)->mask) \ | ||
| 87 | (match)->mask->key.field = value; \ | ||
| 88 | } else { \ | ||
| 89 | (match)->key->field = value; \ | ||
| 90 | } \ | ||
| 91 | } while (0) | ||
| 92 | |||
| 93 | #define SW_FLOW_KEY_MEMCPY(match, field, value_p, len, is_mask) \ | ||
| 94 | do { \ | ||
| 95 | update_range__(match, offsetof(struct sw_flow_key, field), \ | ||
| 96 | len, is_mask); \ | ||
| 97 | if (is_mask) { \ | ||
| 98 | if ((match)->mask) \ | ||
| 99 | memcpy(&(match)->mask->key.field, value_p, len);\ | ||
| 100 | } else { \ | ||
| 101 | memcpy(&(match)->key->field, value_p, len); \ | ||
| 102 | } \ | ||
| 103 | } while (0) | ||
| 104 | |||
| 105 | static u16 range_n_bytes(const struct sw_flow_key_range *range) | ||
| 106 | { | ||
| 107 | return range->end - range->start; | ||
| 108 | } | 59 | } |
| 109 | 60 | ||
| 110 | void ovs_match_init(struct sw_flow_match *match, | 61 | #define TCP_FLAGS_BE16(tp) (*(__be16 *)&tcp_flag_word(tp) & htons(0x0FFF)) |
| 111 | struct sw_flow_key *key, | ||
| 112 | struct sw_flow_mask *mask) | ||
| 113 | { | ||
| 114 | memset(match, 0, sizeof(*match)); | ||
| 115 | match->key = key; | ||
| 116 | match->mask = mask; | ||
| 117 | 62 | ||
| 118 | memset(key, 0, sizeof(*key)); | 63 | void ovs_flow_used(struct sw_flow *flow, struct sk_buff *skb) |
| 119 | |||
| 120 | if (mask) { | ||
| 121 | memset(&mask->key, 0, sizeof(mask->key)); | ||
| 122 | mask->range.start = mask->range.end = 0; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | static bool ovs_match_validate(const struct sw_flow_match *match, | ||
| 127 | u64 key_attrs, u64 mask_attrs) | ||
| 128 | { | 64 | { |
| 129 | u64 key_expected = 1 << OVS_KEY_ATTR_ETHERNET; | 65 | __be16 tcp_flags = 0; |
| 130 | u64 mask_allowed = key_attrs; /* At most allow all key attributes */ | ||
| 131 | |||
| 132 | /* The following mask attributes allowed only if they | ||
| 133 | * pass the validation tests. */ | ||
| 134 | mask_allowed &= ~((1 << OVS_KEY_ATTR_IPV4) | ||
| 135 | | (1 << OVS_KEY_ATTR_IPV6) | ||
| 136 | | (1 << OVS_KEY_ATTR_TCP) | ||
| 137 | | (1 << OVS_KEY_ATTR_UDP) | ||
| 138 | | (1 << OVS_KEY_ATTR_SCTP) | ||
| 139 | | (1 << OVS_KEY_ATTR_ICMP) | ||
| 140 | | (1 << OVS_KEY_ATTR_ICMPV6) | ||
| 141 | | (1 << OVS_KEY_ATTR_ARP) | ||
| 142 | | (1 << OVS_KEY_ATTR_ND)); | ||
| 143 | |||
| 144 | /* Always allowed mask fields. */ | ||
| 145 | mask_allowed |= ((1 << OVS_KEY_ATTR_TUNNEL) | ||
| 146 | | (1 << OVS_KEY_ATTR_IN_PORT) | ||
| 147 | | (1 << OVS_KEY_ATTR_ETHERTYPE)); | ||
| 148 | |||
| 149 | /* Check key attributes. */ | ||
| 150 | if (match->key->eth.type == htons(ETH_P_ARP) | ||
| 151 | || match->key->eth.type == htons(ETH_P_RARP)) { | ||
| 152 | key_expected |= 1 << OVS_KEY_ATTR_ARP; | ||
| 153 | if (match->mask && (match->mask->key.eth.type == htons(0xffff))) | ||
| 154 | mask_allowed |= 1 << OVS_KEY_ATTR_ARP; | ||
| 155 | } | ||
| 156 | 66 | ||
| 157 | if (match->key->eth.type == htons(ETH_P_IP)) { | 67 | if ((flow->key.eth.type == htons(ETH_P_IP) || |
| 158 | key_expected |= 1 << OVS_KEY_ATTR_IPV4; | 68 | flow->key.eth.type == htons(ETH_P_IPV6)) && |
| 159 | if (match->mask && (match->mask->key.eth.type == htons(0xffff))) | 69 | flow->key.ip.proto == IPPROTO_TCP && |
| 160 | mask_allowed |= 1 << OVS_KEY_ATTR_IPV4; | 70 | likely(skb->len >= skb_transport_offset(skb) + sizeof(struct tcphdr))) { |
| 161 | 71 | tcp_flags = TCP_FLAGS_BE16(tcp_hdr(skb)); | |
| 162 | if (match->key->ip.frag != OVS_FRAG_TYPE_LATER) { | ||
| 163 | if (match->key->ip.proto == IPPROTO_UDP) { | ||
| 164 | key_expected |= 1 << OVS_KEY_ATTR_UDP; | ||
| 165 | if (match->mask && (match->mask->key.ip.proto == 0xff)) | ||
| 166 | mask_allowed |= 1 << OVS_KEY_ATTR_UDP; | ||
| 167 | } | ||
| 168 | |||
| 169 | if (match->key->ip.proto == IPPROTO_SCTP) { | ||
| 170 | key_expected |= 1 << OVS_KEY_ATTR_SCTP; | ||
| 171 | if (match->mask && (match->mask->key.ip.proto == 0xff)) | ||
| 172 | mask_allowed |= 1 << OVS_KEY_ATTR_SCTP; | ||
| 173 | } | ||
| 174 | |||
| 175 | if (match->key->ip.proto == IPPROTO_TCP) { | ||
| 176 | key_expected |= 1 << OVS_KEY_ATTR_TCP; | ||
| 177 | if (match->mask && (match->mask->key.ip.proto == 0xff)) | ||
| 178 | mask_allowed |= 1 << OVS_KEY_ATTR_TCP; | ||
| 179 | } | ||
| 180 | |||
| 181 | if (match->key->ip.proto == IPPROTO_ICMP) { | ||
| 182 | key_expected |= 1 << OVS_KEY_ATTR_ICMP; | ||
| 183 | if (match->mask && (match->mask->key.ip.proto == 0xff)) | ||
| 184 | mask_allowed |= 1 << OVS_KEY_ATTR_ICMP; | ||
| 185 | } | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | if (match->key->eth.type == htons(ETH_P_IPV6)) { | ||
| 190 | key_expected |= 1 << OVS_KEY_ATTR_IPV6; | ||
| 191 | if (match->mask && (match->mask->key.eth.type == htons(0xffff))) | ||
| 192 | mask_allowed |= 1 << OVS_KEY_ATTR_IPV6; | ||
| 193 | |||
| 194 | if (match->key->ip.frag != OVS_FRAG_TYPE_LATER) { | ||
| 195 | if (match->key->ip.proto == IPPROTO_UDP) { | ||
| 196 | key_expected |= 1 << OVS_KEY_ATTR_UDP; | ||
| 197 | if (match->mask && (match->mask->key.ip.proto == 0xff)) | ||
| 198 | mask_allowed |= 1 << OVS_KEY_ATTR_UDP; | ||
| 199 | } | ||
| 200 | |||
| 201 | if (match->key->ip.proto == IPPROTO_SCTP) { | ||
| 202 | key_expected |= 1 << OVS_KEY_ATTR_SCTP; | ||
| 203 | if (match->mask && (match->mask->key.ip.proto == 0xff)) | ||
| 204 | mask_allowed |= 1 << OVS_KEY_ATTR_SCTP; | ||
| 205 | } | ||
| 206 | |||
| 207 | if (match->key->ip.proto == IPPROTO_TCP) { | ||
| 208 | key_expected |= 1 << OVS_KEY_ATTR_TCP; | ||
| 209 | |||
