net/mlx4: fix Rx after updating number of queues
authorAdrien Mazarguil <adrien.mazarguil@6wind.com>
Tue, 31 Oct 2017 10:31:04 +0000 (11:31 +0100)
committerFerruh Yigit <ferruh.yigit@intel.com>
Wed, 1 Nov 2017 21:17:06 +0000 (22:17 +0100)
When not in isolated mode, internal flow rules are automatically
maintained by the PMD to receive traffic according to global device
settings (MAC, VLAN, promiscuous mode and so on).

Since RSS support was added to the mix, it must also check whether Rx
queue configuration has changed when refreshing flow rules to prevent
the following from happening:

- With a smaller number of Rx queues, traffic is implicitly dropped
  since the existing RSS context cannot be re-applied.
- With a larger number of Rx queues, traffic remains balanced within the
  original (smaller) set of queues.

One workaround before this commit was to temporarily enter/leave
isolated mode to make it regenerate internal flow rules.

Fixes: 7d8675956f57 ("net/mlx4: add RSS support outside flow API")

Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
drivers/net/mlx4/mlx4_flow.c

index 7a6097f..86bac1b 100644 (file)
@@ -1342,6 +1342,7 @@ next_vlan:
                        assert(flow->ibv_attr->type == IBV_FLOW_ATTR_NORMAL);
                        assert(flow->ibv_attr->num_of_specs == 1);
                        assert(eth->type == IBV_FLOW_SPEC_ETH);
+                       assert(flow->rss);
                        if (rule_vlan &&
                            (eth->val.vlan_tag != *rule_vlan ||
                             eth->mask.vlan_tag != RTE_BE16(0x0fff)))
@@ -1354,8 +1355,13 @@ next_vlan:
                                    eth->val.src_mac[j] != UINT8_C(0x00) ||
                                    eth->mask.src_mac[j] != UINT8_C(0x00))
                                        break;
-                       if (j == sizeof(mac->addr_bytes))
-                               break;
+                       if (j != sizeof(mac->addr_bytes))
+                               continue;
+                       if (flow->rss->queues != queues ||
+                           memcmp(flow->rss->queue_id, rss_conf->queue,
+                                  queues * sizeof(flow->rss->queue_id[0])))
+                               continue;
+                       break;
                }
                if (!flow || !flow->internal) {
                        /* Not found, create a new flow rule. */
@@ -1389,6 +1395,13 @@ next_vlan:
                                        break;
                        }
                }
+               if (flow && flow->internal) {
+                       assert(flow->rss);
+                       if (flow->rss->queues != queues ||
+                           memcmp(flow->rss->queue_id, rss_conf->queue,
+                                  queues * sizeof(flow->rss->queue_id[0])))
+                               flow = NULL;
+               }
                if (!flow || !flow->internal) {
                        /* Not found, create a new flow rule. */
                        if (priv->dev->data->promiscuous) {