diff options
| author | Eyal Perry <eyalpe@mellanox.com> | 2013-11-07 05:19:49 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-11-07 19:22:47 -0500 |
| commit | 75a353d4761ae25f5b7676720bab81a8ad2abf0b (patch) | |
| tree | 49a52772ba34a96f5294a21f0b1b264b5dc81800 | |
| parent | 3cdcf1334cd76bbcabd0f273ee9a13e4cc7816bc (diff) | |
net/mlx4_en: Add RFS support in UDP
Modify RFS code to support applying filters for incoming UDP streams.
Signed-off-by: Eyal Perry <eyalpe@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 45 |
1 files changed, 34 insertions, 11 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index b5554121aca4..cd61e26f434d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c | |||
| @@ -102,6 +102,7 @@ struct mlx4_en_filter { | |||
| 102 | struct list_head next; | 102 | struct list_head next; |
| 103 | struct work_struct work; | 103 | struct work_struct work; |
| 104 | 104 | ||
| 105 | u8 ip_proto; | ||
| 105 | __be32 src_ip; | 106 | __be32 src_ip; |
| 106 | __be32 dst_ip; | 107 | __be32 dst_ip; |
| 107 | __be16 src_port; | 108 | __be16 src_port; |
| @@ -120,14 +121,26 @@ struct mlx4_en_filter { | |||
| 120 | 121 | ||
| 121 | static void mlx4_en_filter_rfs_expire(struct mlx4_en_priv *priv); | 122 | static void mlx4_en_filter_rfs_expire(struct mlx4_en_priv *priv); |
| 122 | 123 | ||
| 124 | static enum mlx4_net_trans_rule_id mlx4_ip_proto_to_trans_rule_id(u8 ip_proto) | ||
| 125 | { | ||
| 126 | switch (ip_proto) { | ||
| 127 | case IPPROTO_UDP: | ||
| 128 | return MLX4_NET_TRANS_RULE_ID_UDP; | ||
| 129 | case IPPROTO_TCP: | ||
| 130 | return MLX4_NET_TRANS_RULE_ID_TCP; | ||
| 131 | default: | ||
| 132 | return -EPROTONOSUPPORT; | ||
| 133 | } | ||
| 134 | }; | ||
| 135 | |||
| 123 | static void mlx4_en_filter_work(struct work_struct *work) | 136 | static void mlx4_en_filter_work(struct work_struct *work) |
| 124 | { | 137 | { |
| 125 | struct mlx4_en_filter *filter = container_of(work, | 138 | struct mlx4_en_filter *filter = container_of(work, |
| 126 | struct mlx4_en_filter, | 139 | struct mlx4_en_filter, |
| 127 | work); | 140 | work); |
| 128 | struct mlx4_en_priv *priv = filter->priv; | 141 | struct mlx4_en_priv *priv = filter->priv; |
| 129 | struct mlx4_spec_list spec_tcp = { | 142 | struct mlx4_spec_list spec_tcp_udp = { |
| 130 | .id = MLX4_NET_TRANS_RULE_ID_TCP, | 143 | .id = mlx4_ip_proto_to_trans_rule_id(filter->ip_proto), |
| 131 | { | 144 | { |
| 132 | .tcp_udp = { | 145 | .tcp_udp = { |
| 133 | .dst_port = filter->dst_port, | 146 | .dst_port = filter->dst_port, |
| @@ -163,9 +176,14 @@ static void mlx4_en_filter_work(struct work_struct *work) | |||
| 163 | int rc; | 176 | int rc; |
| 164 | __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16); | 177 | __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16); |
| 165 | 178 | ||
| 179 | if (spec_tcp_udp.id < 0) { | ||
| 180 | en_warn(priv, "RFS: ignoring unsupported ip protocol (%d)\n", | ||
| 181 | filter->ip_proto); | ||
| 182 | goto ignore; | ||
| 183 | } | ||
| 166 | list_add_tail(&spec_eth.list, &rule.list); | 184 | list_add_tail(&spec_eth.list, &rule.list); |
| 167 | list_add_tail(&spec_ip.list, &rule.list); | 185 | list_add_tail(&spec_ip.list, &rule.list); |
| 168 | list_add_tail(&spec_tcp.list, &rule.list); | 186 | list_add_tail(&spec_tcp_udp.list, &rule.list); |
| 169 | 187 | ||
| 170 | rule.qpn = priv->rss_map.qps[filter->rxq_index].qpn; | 188 | rule.qpn = priv->rss_map.qps[filter->rxq_index].qpn; |
| 171 | memcpy(spec_eth.eth.dst_mac, priv->dev->dev_addr, ETH_ALEN); | 189 | memcpy(spec_eth.eth.dst_mac, priv->dev->dev_addr, ETH_ALEN); |
| @@ -183,6 +201,7 @@ static void mlx4_en_filter_work(struct work_struct *work) | |||
| 183 | if (rc) | 201 | if (rc) |
| 184 | en_err(priv, "Error attaching flow. err = %d\n", rc); | 202 | en_err(priv, "Error attaching flow. err = %d\n", rc); |
| 185 | 203 | ||
| 204 | ignore: | ||
| 186 | mlx4_en_filter_rfs_expire(priv); | 205 | mlx4_en_filter_rfs_expire(priv); |
| 187 | 206 | ||
| 188 | filter->activated = 1; | 207 | filter->activated = 1; |
| @@ -206,8 +225,8 @@ filter_hash_bucket(struct mlx4_en_priv *priv, __be32 src_ip, __be32 dst_ip, | |||
| 206 | 225 | ||
| 207 | static struct mlx4_en_filter * | 226 | static struct mlx4_en_filter * |
| 208 | mlx4_en_filter_alloc(struct mlx4_en_priv *priv, int rxq_index, __be32 src_ip, | 227 | mlx4_en_filter_alloc(struct mlx4_en_priv *priv, int rxq_index, __be32 src_ip, |
| 209 | __be32 dst_ip, __be16 src_port, __be16 dst_port, | 228 | __be32 dst_ip, u8 ip_proto, __be16 src_port, |
| 210 | u32 flow_id) | 229 | __be16 dst_port, u32 flow_id) |
| 211 | { | 230 | { |
| 212 | struct mlx4_en_filter *filter = NULL; | 231 | struct mlx4_en_filter *filter = NULL; |
| 213 | 232 | ||
| @@ -221,6 +240,7 @@ mlx4_en_filter_alloc(struct mlx4_en_priv *priv, int rxq_index, __be32 src_ip, | |||
| 221 | 240 | ||
| 222 | filter->src_ip = src_ip; | 241 | filter->src_ip = src_ip; |
| 223 | filter->dst_ip = dst_ip; | 242 | filter->dst_ip = dst_ip; |
| 243 | filter->ip_proto = ip_proto; | ||
| 224 | filter->src_port = src_port; | 244 | filter->src_port = src_port; |
| 225 | filter->dst_port = dst_port; | 245 | filter->dst_port = dst_port; |
| 226 | 246 | ||
| @@ -252,7 +272,7 @@ static void mlx4_en_filter_free(struct mlx4_en_filter *filter) | |||
| 252 | 272 | ||
| 253 | static inline struct mlx4_en_filter * | 273 | static inline struct mlx4_en_filter * |
| 254 | mlx4_en_filter_find(struct mlx4_en_priv *priv, __be32 src_ip, __be32 dst_ip, | 274 | mlx4_en_filter_find(struct mlx4_en_priv *priv, __be32 src_ip, __be32 dst_ip, |
| 255 | __be16 src_port, __be16 dst_port) | 275 | u8 ip_proto, __be16 src_port, __be16 dst_port) |
| 256 | { | 276 | { |
| 257 | struct mlx4_en_filter *filter; | 277 | struct mlx4_en_filter *filter; |
| 258 | struct mlx4_en_filter *ret = NULL; | 278 | struct mlx4_en_filter *ret = NULL; |
| @@ -263,6 +283,7 @@ mlx4_en_filter_find(struct mlx4_en_priv *priv, __be32 src_ip, __be32 dst_ip, | |||
| 263 | filter_chain) { | 283 | filter_chain) { |
| 264 | if (filter->src_ip == src_ip && | 284 | if (filter->src_ip == src_ip && |
| 265 | filter->dst_ip == dst_ip && | 285 | filter->dst_ip == dst_ip && |
| 286 | filter->ip_proto == ip_proto && | ||
| 266 | filter->src_port == src_port && | 287 | filter->src_port == src_port && |
| 267 | filter->dst_port == dst_port) { | 288 | filter->dst_port == dst_port) { |
| 268 | ret = filter; | 289 | ret = filter; |
| @@ -281,6 +302,7 @@ mlx4_en_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, | |||
| 281 | struct mlx4_en_filter *filter; | 302 | struct mlx4_en_filter *filter; |
| 282 | const struct iphdr *ip; | 303 | const struct iphdr *ip; |
| 283 | const __be16 *ports; | 304 | const __be16 *ports; |
| 305 | u8 ip_proto; | ||
| 284 | __be32 src_ip; | 306 | __be32 src_ip; |
| 285 | __be32 dst_ip; | 307 | __be32 dst_ip; |
| 286 | __be16 src_port; | 308 | __be16 src_port; |
| @@ -295,18 +317,19 @@ mlx4_en_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, | |||
| 295 | if (ip_is_fragment(ip)) | 317 | if (ip_is_fragment(ip)) |
| 296 | return -EPROTONOSUPPORT; | 318 | return -EPROTONOSUPPORT; |
| 297 | 319 | ||
| 320 | if ((ip->protocol != IPPROTO_TCP) && (ip->protocol != IPPROTO_UDP)) | ||
| 321 | return -EPROTONOSUPPORT; | ||
| 298 | ports = (const __be16 *)(skb->data + nhoff + 4 * ip->ihl); | 322 | ports = (const __be16 *)(skb->data + nhoff + 4 * ip->ihl); |
| 299 | 323 | ||
| 324 | ip_proto = ip->protocol; | ||
| 300 | src_ip = ip->saddr; | 325 | src_ip = ip->saddr; |
| 301 | dst_ip = ip->daddr; | 326 | dst_ip = ip->daddr; |
| 302 | src_port = ports[0]; | 327 | src_port = ports[0]; |
| 303 | dst_port = ports[1]; | 328 | dst_port = ports[1]; |
| 304 | 329 | ||
| 305 | if (ip->protocol != IPPROTO_TCP) | ||
| 306 | return -EPROTONOSUPPORT; | ||
| 307 | |||
| 308 | spin_lock_bh(&priv->filters_lock); | 330 | spin_lock_bh(&priv->filters_lock); |
| 309 | filter = mlx4_en_filter_find(priv, src_ip, dst_ip, src_port, dst_port); | 331 | filter = mlx4_en_filter_find(priv, src_ip, dst_ip, ip_proto, |
| 332 | src_port, dst_port); | ||
| 310 | if (filter) { | 333 | if (filter) { |
| 311 | if (filter->rxq_index == rxq_index) | 334 | if (filter->rxq_index == rxq_index) |
| 312 | goto out; | 335 | goto out; |
| @@ -314,7 +337,7 @@ mlx4_en_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, | |||
| 314 | filter->rxq_index = rxq_index; | 337 | filter->rxq_index = rxq_index; |
| 315 | } else { | 338 | } else { |
| 316 | filter = mlx4_en_filter_alloc(priv, rxq_index, | 339 | filter = mlx4_en_filter_alloc(priv, rxq_index, |
| 317 | src_ip, dst_ip, | 340 | src_ip, dst_ip, ip_proto, |
| 318 | src_port, dst_port, flow_id); | 341 | src_port, dst_port, flow_id); |
| 319 | if (!filter) { | 342 | if (!filter) { |
| 320 | ret = -ENOMEM; | ||
