net/ixgbe: enable flex bytes for generic flow API
authorQi Zhang <qi.z.zhang@intel.com>
Thu, 1 Jun 2017 17:36:45 +0000 (13:36 -0400)
committerFerruh Yigit <ferruh.yigit@intel.com>
Mon, 12 Jun 2017 09:41:28 +0000 (10:41 +0100)
Add fdir flex byte support for rte_flow APIs.

Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
Acked-by: Wenzhuo Lu <wenzhuo.lu@intel.com>
drivers/net/ixgbe/ixgbe_ethdev.h
drivers/net/ixgbe/ixgbe_fdir.c
drivers/net/ixgbe/ixgbe_flow.c

index 3ddfc69..e2d0139 100644 (file)
@@ -189,6 +189,7 @@ struct ixgbe_fdir_rule {
        uint32_t fdirflags; /* drop or forward */
        uint32_t soft_id; /* an unique value for this rule */
        uint8_t queue; /* assigned rx queue */
+       uint8_t flex_bytes_offset;
 };
 
 struct ixgbe_hw_fdir_info {
@@ -621,6 +622,8 @@ void ixgbe_filterlist_flush(void);
  */
 int ixgbe_fdir_configure(struct rte_eth_dev *dev);
 int ixgbe_fdir_set_input_mask(struct rte_eth_dev *dev);
+int ixgbe_fdir_set_flexbytes_offset(struct rte_eth_dev *dev,
+                                   uint16_t offset);
 int ixgbe_fdir_filter_program(struct rte_eth_dev *dev,
                              struct ixgbe_fdir_rule *rule,
                              bool del, bool update);
index 7f6c7b5..950f5ba 100644 (file)
@@ -302,7 +302,7 @@ fdir_set_input_mask_82599(struct rte_eth_dev *dev)
         * mask VM pool and DIPv6 since there are currently not supported
         * mask FLEX byte, it will be set in flex_conf
         */
-       uint32_t fdirm = IXGBE_FDIRM_POOL | IXGBE_FDIRM_DIPv6 | IXGBE_FDIRM_FLEX;
+       uint32_t fdirm = IXGBE_FDIRM_POOL | IXGBE_FDIRM_DIPv6;
        uint32_t fdirtcpm;  /* TCP source and destination port masks. */
        uint32_t fdiripv6m; /* IPv6 source and destination masks. */
        volatile uint32_t *reg;
@@ -333,6 +333,10 @@ fdir_set_input_mask_82599(struct rte_eth_dev *dev)
                return -EINVAL;
        }
 
+       /* flex byte mask */
+       if (info->mask.flex_bytes_mask == 0)
+               fdirm |= IXGBE_FDIRM_FLEX;
+
        IXGBE_WRITE_REG(hw, IXGBE_FDIRM, fdirm);
 
        /* store the TCP/UDP port masks, bit reversed from port layout */
@@ -533,6 +537,31 @@ ixgbe_fdir_set_input_mask(struct rte_eth_dev *dev)
        return -ENOTSUP;
 }
 
+int
+ixgbe_fdir_set_flexbytes_offset(struct rte_eth_dev *dev,
+                               uint16_t offset)
+{
+       struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t fdirctrl;
+       int i;
+
+       fdirctrl = IXGBE_READ_REG(hw, IXGBE_FDIRCTRL);
+
+       fdirctrl &= ~IXGBE_FDIRCTRL_FLEX_MASK;
+       fdirctrl |= ((offset >> 1) /* convert to word offset */
+               << IXGBE_FDIRCTRL_FLEX_SHIFT);
+
+       IXGBE_WRITE_REG(hw, IXGBE_FDIRCTRL, fdirctrl);
+       IXGBE_WRITE_FLUSH(hw);
+       for (i = 0; i < IXGBE_FDIR_INIT_DONE_POLL; i++) {
+               if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) &
+                       IXGBE_FDIRCTRL_INIT_DONE)
+                       break;
+               msec_delay(1);
+       }
+       return 0;
+}
+
 static int
 fdir_set_input_mask(struct rte_eth_dev *dev,
                    const struct rte_eth_fdir_masks *input_mask)
index c893ba6..1cb04f1 100644 (file)
@@ -78,6 +78,7 @@
 
 #define IXGBE_MIN_N_TUPLE_PRIO 1
 #define IXGBE_MAX_N_TUPLE_PRIO 7
+#define IXGBE_MAX_FLX_SOURCE_OFF 62
 #define NEXT_ITEM_OF_PATTERN(item, pattern, index)\
        do {            \
                item = pattern + index;\
@@ -1316,7 +1317,8 @@ ixgbe_parse_fdir_act_attr(const struct rte_flow_attr *attr,
  * UDP/TCP/SCTP PATTERN:
  * The first not void item can be ETH or IPV4.
  * The second not void item must be IPV4 if the first one is ETH.
- * The third not void item must be UDP or TCP or SCTP.
+ * The next not void item could be UDP or TCP or SCTP (optional)
+ * The next not void item could be RAW (for flexbyte, optional)
  * The next not void item must be END.
  * MAC VLAN PATTERN:
  * The first not void item must be ETH.
@@ -1334,6 +1336,14 @@ ixgbe_parse_fdir_act_attr(const struct rte_flow_attr *attr,
  *             dst_addr 192.167.3.50   0xFFFFFFFF
  * UDP/TCP/SCTP        src_port        80      0xFFFF
  *             dst_port        80      0xFFFF
+ * FLEX        relative        0       0x1
+ *             search          0       0x1
+ *             reserved        0       0
+ *             offset          12      0xFFFFFFFF
+ *             limit           0       0xFFFF
+ *             length          2       0xFFFF
+ *             pattern[0]      0x86    0xFF
+ *             pattern[1]      0xDD    0xFF
  * END
  * MAC VLAN pattern example:
  * ITEM                Spec                    Mask
@@ -1365,6 +1375,8 @@ ixgbe_parse_fdir_filter_normal(const struct rte_flow_attr *attr,
        const struct rte_flow_item_sctp *sctp_mask;
        const struct rte_flow_item_vlan *vlan_spec;
        const struct rte_flow_item_vlan *vlan_mask;
+       const struct rte_flow_item_raw *raw_mask;
+       const struct rte_flow_item_raw *raw_spec;
 
        uint32_t index, j;
 
@@ -1396,6 +1408,7 @@ ixgbe_parse_fdir_filter_normal(const struct rte_flow_attr *attr,
        memset(rule, 0, sizeof(struct ixgbe_fdir_rule));
        memset(&rule->mask, 0xFF, sizeof(struct ixgbe_hw_fdir_mask));
        rule->mask.vlan_tci_mask = 0;
+       rule->mask.flex_bytes_mask = 0;
 
        /* parse pattern */
        index = 0;
@@ -1621,7 +1634,8 @@ ixgbe_parse_fdir_filter_normal(const struct rte_flow_attr *attr,
                if (item->type != RTE_FLOW_ITEM_TYPE_TCP &&
                    item->type != RTE_FLOW_ITEM_TYPE_UDP &&
                    item->type != RTE_FLOW_ITEM_TYPE_SCTP &&
-                   item->type != RTE_FLOW_ITEM_TYPE_END) {
+                   item->type != RTE_FLOW_ITEM_TYPE_END &&
+                   item->type != RTE_FLOW_ITEM_TYPE_RAW) {
                        memset(rule, 0, sizeof(struct ixgbe_fdir_rule));
                        rte_flow_error_set(error, EINVAL,
                                RTE_FLOW_ERROR_TYPE_ITEM,
@@ -1682,6 +1696,18 @@ ixgbe_parse_fdir_filter_normal(const struct rte_flow_attr *attr,
                        rule->ixgbe_fdir.formatted.dst_port =
                                tcp_spec->hdr.dst_port;
                }
+
+               index++;
+               NEXT_ITEM_OF_PATTERN(item, pattern, index);
+               if (item->type != RTE_FLOW_ITEM_TYPE_RAW &&
+                   item->type != RTE_FLOW_ITEM_TYPE_END) {
+                       memset(rule, 0, sizeof(struct ixgbe_fdir_rule));
+                       rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM,
+                               item, "Not supported by fdir filter");
+                       return -rte_errno;
+               }
+
        }
 
        /* Get the UDP info */
@@ -1731,6 +1757,18 @@ ixgbe_parse_fdir_filter_normal(const struct rte_flow_attr *attr,
                        rule->ixgbe_fdir.formatted.dst_port =
                                udp_spec->hdr.dst_port;
                }
+
+               index++;
+               NEXT_ITEM_OF_PATTERN(item, pattern, index);
+               if (item->type != RTE_FLOW_ITEM_TYPE_RAW &&
+                   item->type != RTE_FLOW_ITEM_TYPE_END) {
+                       memset(rule, 0, sizeof(struct ixgbe_fdir_rule));
+                       rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM,
+                               item, "Not supported by fdir filter");
+                       return -rte_errno;
+               }
+
        }
 
        /* Get the SCTP info */
@@ -1782,6 +1820,88 @@ ixgbe_parse_fdir_filter_normal(const struct rte_flow_attr *attr,
                        rule->ixgbe_fdir.formatted.dst_port =
                                sctp_spec->hdr.dst_port;
                }
+
+               index++;
+               NEXT_ITEM_OF_PATTERN(item, pattern, index);
+               if (item->type != RTE_FLOW_ITEM_TYPE_RAW &&
+                   item->type != RTE_FLOW_ITEM_TYPE_END) {
+                       memset(rule, 0, sizeof(struct ixgbe_fdir_rule));
+                       rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM,
+                               item, "Not supported by fdir filter");
+                       return -rte_errno;
+               }
+       }
+
+       /* Get the flex byte info */
+       if (item->type == RTE_FLOW_ITEM_TYPE_RAW) {
+               /* Not supported last point for range*/
+               if (item->last) {
+                       rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                               item, "Not supported last point for range");
+                       return -rte_errno;
+               }
+               /* mask should not be null */
+               if (!item->mask || !item->spec) {
+                       memset(rule, 0, sizeof(struct ixgbe_fdir_rule));
+                       rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM,
+                               item, "Not supported by fdir filter");
+                       return -rte_errno;
+               }
+
+               raw_mask = (const struct rte_flow_item_raw *)item->mask;
+
+               /* check mask */
+               if (raw_mask->relative != 0x1 ||
+                   raw_mask->search != 0x1 ||
+                   raw_mask->reserved != 0x0 ||
+                   (uint32_t)raw_mask->offset != 0xffffffff ||
+                   raw_mask->limit != 0xffff ||
+                   raw_mask->length != 0xffff) {
+                       memset(rule, 0, sizeof(struct ixgbe_fdir_rule));
+                       rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM,
+                               item, "Not supported by fdir filter");
+                       return -rte_errno;
+               }
+
+               raw_spec = (const struct rte_flow_item_raw *)item->spec;
+
+               /* check spec */
+               if (raw_spec->relative != 0 ||
+                   raw_spec->search != 0 ||
+                   raw_spec->reserved != 0 ||
+                   raw_spec->offset > IXGBE_MAX_FLX_SOURCE_OFF ||
+                   raw_spec->offset % 2 ||
+                   raw_spec->limit != 0 ||
+                   raw_spec->length != 2 ||
+                   /* pattern can't be 0xffff */
+                   (raw_spec->pattern[0] == 0xff &&
+                    raw_spec->pattern[1] == 0xff)) {
+                       memset(rule, 0, sizeof(struct ixgbe_fdir_rule));
+                       rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM,
+                               item, "Not supported by fdir filter");
+                       return -rte_errno;
+               }
+
+               /* check pattern mask */
+               if (raw_mask->pattern[0] != 0xff ||
+                   raw_mask->pattern[1] != 0xff) {
+                       memset(rule, 0, sizeof(struct ixgbe_fdir_rule));
+                       rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_ITEM,
+                               item, "Not supported by fdir filter");
+                       return -rte_errno;
+               }
+
+               rule->mask.flex_bytes_mask = 0xffff;
+               rule->ixgbe_fdir.formatted.flex_bytes =
+                       (((uint16_t)raw_spec->pattern[1]) << 8) |
+                       raw_spec->pattern[0];
+               rule->flex_bytes_offset = raw_spec->offset;
        }
 
        if (item->type != RTE_FLOW_ITEM_TYPE_END) {
@@ -1919,7 +2039,7 @@ ixgbe_parse_fdir_filter_tunnel(const struct rte_flow_attr *attr,
                                item, "Not supported by fdir filter");
                        return -rte_errno;
                }
-               /*Not supported last point for range*/
+               /* Not supported last point for range*/
                if (item->last) {
                        rte_flow_error_set(error, EINVAL,
                                RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
@@ -2497,6 +2617,13 @@ ixgbe_flow_create(struct rte_eth_dev *dev,
                                rte_memcpy(&fdir_info->mask,
                                        &fdir_rule.mask,
                                        sizeof(struct ixgbe_hw_fdir_mask));
+                               fdir_info->flex_bytes_offset =
+                                       fdir_rule.flex_bytes_offset;
+
+                               if (fdir_rule.mask.flex_bytes_mask)
+                                       ixgbe_fdir_set_flexbytes_offset(dev,
+                                               fdir_rule.flex_bytes_offset);
+
                                ret = ixgbe_fdir_set_input_mask(dev);
                                if (ret)
                                        goto out;
@@ -2512,6 +2639,10 @@ ixgbe_flow_create(struct rte_eth_dev *dev,
                                        sizeof(struct ixgbe_hw_fdir_mask));
                                if (ret)
                                        goto out;
+
+                               if (fdir_info->flex_bytes_offset !=
+                                               fdir_rule.flex_bytes_offset)
+                                       goto out;
                        }
                }