bnxt_en: do not allow wildcard matches for L2 flows
authorAndy Gospodarek <gospo@broadcom.com>
Wed, 11 Apr 2018 15:50:14 +0000 (11:50 -0400)
committerDavid S. Miller <davem@davemloft.net>
Wed, 11 Apr 2018 18:41:59 +0000 (14:41 -0400)
Before this patch the following commands would succeed as far as the
user was concerned:

$ tc qdisc add dev p1p1 ingress
$ tc filter add dev p1p1 parent ffff: protocol all \
flower skip_sw action drop
$ tc filter add dev p1p1 parent ffff: protocol ipv4 \
flower skip_sw src_mac 00:02:00:00:00:01/44 action drop

The current flow offload infrastructure used does not support wildcard
matching for ethernet headers, so do not allow the second or third
commands to succeed.  If a user wants to drop traffic on that interface
the protocol and MAC addresses need to be specified explicitly:

$ tc qdisc add dev p1p1 ingress
$ tc filter add dev p1p1 parent ffff: protocol arp \
flower skip_sw action drop
$ tc filter add dev p1p1 parent ffff: protocol ipv4 \
flower skip_sw action drop
...
$ tc filter add dev p1p1 parent ffff: protocol ipv4 \
flower skip_sw src_mac 00:02:00:00:00:01 action drop
$ tc filter add dev p1p1 parent ffff: protocol ipv4 \
flower skip_sw src_mac 00:02:00:00:00:02 action drop
...

There are also checks for VLAN parameters in this patch as other callers
may wildcard those parameters even if tc does not.  Using different
flow infrastructure could allow this to work in the future for L2 flows,
but for now it does not.

Fixes: 2ae7408fedfe ("bnxt_en: bnxt: add TC flower filter offload support")
Signed-off-by: Andy Gospodarek <gospo@broadcom.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c

index 65c2cee357669a7a7b5784b3c7b9a3805095304f..ac193408a418621b8eb33638694ceabe827f83b8 100644 (file)
@@ -377,6 +377,30 @@ static bool is_wildcard(void *mask, int len)
        return true;
 }
 
+static bool is_exactmatch(void *mask, int len)
+{
+       const u8 *p = mask;
+       int i;
+
+       for (i = 0; i < len; i++)
+               if (p[i] != 0xff)
+                       return false;
+
+       return true;
+}
+
+static bool bits_set(void *key, int len)
+{
+       const u8 *p = key;
+       int i;
+
+       for (i = 0; i < len; i++)
+               if (p[i] != 0)
+                       return true;
+
+       return false;
+}
+
 static int bnxt_hwrm_cfa_flow_alloc(struct bnxt *bp, struct bnxt_tc_flow *flow,
                                    __le16 ref_flow_handle,
                                    __le32 tunnel_handle, __le16 *flow_handle)
@@ -764,6 +788,41 @@ static bool bnxt_tc_can_offload(struct bnxt *bp, struct bnxt_tc_flow *flow)
                return false;
        }
 
+       /* Currently source/dest MAC cannot be partial wildcard  */
+       if (bits_set(&flow->l2_key.smac, sizeof(flow->l2_key.smac)) &&
+           !is_exactmatch(flow->l2_mask.smac, sizeof(flow->l2_mask.smac))) {
+               netdev_info(bp->dev, "Wildcard match unsupported for Source MAC\n");
+               return false;
+       }
+       if (bits_set(&flow->l2_key.dmac, sizeof(flow->l2_key.dmac)) &&
+           !is_exactmatch(&flow->l2_mask.dmac, sizeof(flow->l2_mask.dmac))) {
+               netdev_info(bp->dev, "Wildcard match unsupported for Dest MAC\n");
+               return false;
+       }
+
+       /* Currently VLAN fields cannot be partial wildcard */
+       if (bits_set(&flow->l2_key.inner_vlan_tci,
+                    sizeof(flow->l2_key.inner_vlan_tci)) &&
+           !is_exactmatch(&flow->l2_mask.inner_vlan_tci,
+                          sizeof(flow->l2_mask.inner_vlan_tci))) {
+               netdev_info(bp->dev, "Wildcard match unsupported for VLAN TCI\n");
+               return false;
+       }
+       if (bits_set(&flow->l2_key.inner_vlan_tpid,
+                    sizeof(flow->l2_key.inner_vlan_tpid)) &&
+           !is_exactmatch(&flow->l2_mask.inner_vlan_tpid,
+                          sizeof(flow->l2_mask.inner_vlan_tpid))) {
+               netdev_info(bp->dev, "Wildcard match unsupported for VLAN TPID\n");
+               return false;
+       }
+
+       /* Currently Ethertype must be set */
+       if (!is_exactmatch(&flow->l2_mask.ether_type,
+                          sizeof(flow->l2_mask.ether_type))) {
+               netdev_info(bp->dev, "Wildcard match unsupported for Ethertype\n");
+               return false;
+       }
+
        return true;
 }