eal: expose internal config elements
[dpdk.git] / drivers / net / e1000 / igb_flow.c
index 2fefa7d..76c0c52 100644 (file)
@@ -77,6 +77,8 @@
                }                                               \
        } while (0)
 
+#define        IGB_FLEX_RAW_NUM        12
+
 /**
  * Please aware there's an asumption for all the parsers.
  * rte_flow_item is using big endian, rte_flow_attr and
@@ -692,7 +694,8 @@ igb_parse_ethertype_filter(struct rte_eth_dev *dev,
 
        if (hw->mac.type == e1000_82576) {
                if (filter->queue >= IGB_MAX_RX_QUEUE_NUM_82576) {
-                       memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
+                       memset(filter, 0, sizeof(
+                                       struct rte_eth_ethertype_filter));
                        rte_flow_error_set(error, EINVAL,
                                RTE_FLOW_ERROR_TYPE_ITEM,
                                NULL, "queue number not supported "
@@ -701,7 +704,8 @@ igb_parse_ethertype_filter(struct rte_eth_dev *dev,
                }
        } else {
                if (filter->queue >= IGB_MAX_RX_QUEUE_NUM) {
-                       memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
+                       memset(filter, 0, sizeof(
+                                       struct rte_eth_ethertype_filter));
                        rte_flow_error_set(error, EINVAL,
                                RTE_FLOW_ERROR_TYPE_ITEM,
                                NULL, "queue number not supported "
@@ -1043,8 +1047,11 @@ cons_parse_flex_filter(const struct rte_flow_attr *attr,
        const struct rte_flow_item_raw *raw_spec;
        const struct rte_flow_item_raw *raw_mask;
        const struct rte_flow_action_queue *act_q;
-       uint32_t index, i, offset, total_offset = 0;
-       int32_t shift;
+       uint32_t index, i, offset, total_offset;
+       uint32_t max_offset = 0;
+       int32_t shift, j, raw_index = 0;
+       int32_t relative[IGB_FLEX_RAW_NUM] = {0};
+       int32_t raw_offset[IGB_FLEX_RAW_NUM] = {0};
 
        if (!pattern) {
                rte_flow_error_set(error, EINVAL,
@@ -1105,8 +1112,8 @@ item_loop:
        else
                offset = 0;
 
-       for (index = 0; index < raw_spec->length; index++) {
-               if (raw_mask->pattern[index] != 0xFF) {
+       for (j = 0; j < raw_spec->length; j++) {
+               if (raw_mask->pattern[j] != 0xFF) {
                        memset(filter, 0, sizeof(struct rte_eth_flex_filter));
                        rte_flow_error_set(error, EINVAL,
                                        RTE_FLOW_ERROR_TYPE_ITEM,
@@ -1115,6 +1122,21 @@ item_loop:
                }
        }
 
+       total_offset = 0;
+
+       if (raw_spec->relative) {
+               for (j = raw_index; j > 0; j--) {
+                       total_offset += raw_offset[j - 1];
+                       if (!relative[j - 1])
+                               break;
+               }
+               if (total_offset + raw_spec->length + offset > max_offset)
+                       max_offset = total_offset + raw_spec->length + offset;
+       } else {
+               if (raw_spec->length + offset > max_offset)
+                       max_offset = raw_spec->length + offset;
+       }
+
        if ((raw_spec->length + offset + total_offset) >
                        RTE_FLEX_FILTER_MAXLEN) {
                memset(filter, 0, sizeof(struct rte_eth_flex_filter));
@@ -1125,30 +1147,35 @@ item_loop:
        }
 
        if (raw_spec->relative == 0) {
-               for (index = 0; index < raw_spec->length; index++)
-                       filter->bytes[index] = raw_spec->pattern[index];
-               index = offset / CHAR_BIT;
+               for (j = 0; j < raw_spec->length; j++)
+                       filter->bytes[offset + j] =
+                       raw_spec->pattern[j];
+               j = offset / CHAR_BIT;
+               shift = offset % CHAR_BIT;
        } else {
-               for (index = 0; index < raw_spec->length; index++)
-                       filter->bytes[total_offset + index] =
-                               raw_spec->pattern[index];
-               index = (total_offset + offset) / CHAR_BIT;
+               for (j = 0; j < raw_spec->length; j++)
+                       filter->bytes[total_offset + offset + j] =
+                               raw_spec->pattern[j];
+               j = (total_offset + offset) / CHAR_BIT;
+               shift = (total_offset + offset) % CHAR_BIT;
        }
 
        i = 0;
 
-       for (shift = offset % CHAR_BIT; shift < CHAR_BIT; shift++) {
-               filter->mask[index] |= (0x80 >> shift);
+       for ( ; shift < CHAR_BIT; shift++) {
+               filter->mask[j] |= (0x80 >> shift);
                i++;
                if (i == raw_spec->length)
                        break;
                if (shift == (CHAR_BIT - 1)) {
-                       index++;
+                       j++;
                        shift = -1;
                }
        }
 
-       total_offset += offset + raw_spec->length;
+       relative[raw_index] = raw_spec->relative;
+       raw_offset[raw_index] = offset + raw_spec->length;
+       raw_index++;
 
        /* check if the next not void item is RAW */
        index++;
@@ -1167,7 +1194,7 @@ item_loop:
                goto item_loop;
        }
 
-       filter->len = RTE_ALIGN(total_offset, 8);
+       filter->len = RTE_ALIGN(max_offset, 8);
 
        /* parse action */
        index = 0;
@@ -1319,7 +1346,7 @@ igb_flow_create(struct rte_eth_dev *dev,
                if (!ret) {
                        ntuple_filter_ptr = rte_zmalloc("igb_ntuple_filter",
                                sizeof(struct igb_ntuple_filter_ele), 0);
-                       (void)rte_memcpy(&ntuple_filter_ptr->filter_info,
+                       rte_memcpy(&ntuple_filter_ptr->filter_info,
                                &ntuple_filter,
                                sizeof(struct rte_eth_ntuple_filter));
                        TAILQ_INSERT_TAIL(&igb_filter_ntuple_list,
@@ -1341,7 +1368,7 @@ igb_flow_create(struct rte_eth_dev *dev,
                        ethertype_filter_ptr = rte_zmalloc(
                                "igb_ethertype_filter",
                                sizeof(struct igb_ethertype_filter_ele), 0);
-                       (void)rte_memcpy(&ethertype_filter_ptr->filter_info,
+                       rte_memcpy(&ethertype_filter_ptr->filter_info,
                                &ethertype_filter,
                                sizeof(struct rte_eth_ethertype_filter));
                        TAILQ_INSERT_TAIL(&igb_filter_ethertype_list,
@@ -1361,7 +1388,7 @@ igb_flow_create(struct rte_eth_dev *dev,
                if (!ret) {
                        syn_filter_ptr = rte_zmalloc("igb_syn_filter",
                                sizeof(struct igb_eth_syn_filter_ele), 0);
-                       (void)rte_memcpy(&syn_filter_ptr->filter_info,
+                       rte_memcpy(&syn_filter_ptr->filter_info,
                                &syn_filter,
                                sizeof(struct rte_eth_syn_filter));
                        TAILQ_INSERT_TAIL(&igb_filter_syn_list,
@@ -1382,7 +1409,7 @@ igb_flow_create(struct rte_eth_dev *dev,
                if (!ret) {
                        flex_filter_ptr = rte_zmalloc("igb_flex_filter",
                                sizeof(struct igb_flex_filter_ele), 0);
-                       (void)rte_memcpy(&flex_filter_ptr->filter_info,
+                       rte_memcpy(&flex_filter_ptr->filter_info,
                                &flex_filter,
                                sizeof(struct rte_eth_flex_filter));
                        TAILQ_INSERT_TAIL(&igb_filter_flex_list,
@@ -1447,10 +1474,234 @@ igb_flow_validate(__rte_unused struct rte_eth_dev *dev,
        return ret;
 }
 
+/* Destroy a flow rule on igb. */
+static int
+igb_flow_destroy(struct rte_eth_dev *dev,
+               struct rte_flow *flow,
+               struct rte_flow_error *error)
+{
+       int ret;
+       struct rte_flow *pmd_flow = flow;
+       enum rte_filter_type filter_type = pmd_flow->filter_type;
+       struct igb_ntuple_filter_ele *ntuple_filter_ptr;
+       struct igb_ethertype_filter_ele *ethertype_filter_ptr;
+       struct igb_eth_syn_filter_ele *syn_filter_ptr;
+       struct igb_flex_filter_ele *flex_filter_ptr;
+       struct igb_flow_mem *igb_flow_mem_ptr;
+
+       switch (filter_type) {
+       case RTE_ETH_FILTER_NTUPLE:
+               ntuple_filter_ptr = (struct igb_ntuple_filter_ele *)
+                                       pmd_flow->rule;
+               ret = igb_add_del_ntuple_filter(dev,
+                               &ntuple_filter_ptr->filter_info, FALSE);
+               if (!ret) {
+                       TAILQ_REMOVE(&igb_filter_ntuple_list,
+                       ntuple_filter_ptr, entries);
+                       rte_free(ntuple_filter_ptr);
+               }
+               break;
+       case RTE_ETH_FILTER_ETHERTYPE:
+               ethertype_filter_ptr = (struct igb_ethertype_filter_ele *)
+                                       pmd_flow->rule;
+               ret = igb_add_del_ethertype_filter(dev,
+                               &ethertype_filter_ptr->filter_info, FALSE);
+               if (!ret) {
+                       TAILQ_REMOVE(&igb_filter_ethertype_list,
+                               ethertype_filter_ptr, entries);
+                       rte_free(ethertype_filter_ptr);
+               }
+               break;
+       case RTE_ETH_FILTER_SYN:
+               syn_filter_ptr = (struct igb_eth_syn_filter_ele *)
+                               pmd_flow->rule;
+               ret = eth_igb_syn_filter_set(dev,
+                               &syn_filter_ptr->filter_info, FALSE);
+               if (!ret) {
+                       TAILQ_REMOVE(&igb_filter_syn_list,
+                               syn_filter_ptr, entries);
+                       rte_free(syn_filter_ptr);
+               }
+               break;
+       case RTE_ETH_FILTER_FLEXIBLE:
+               flex_filter_ptr = (struct igb_flex_filter_ele *)
+                               pmd_flow->rule;
+               ret = eth_igb_add_del_flex_filter(dev,
+                               &flex_filter_ptr->filter_info, FALSE);
+               if (!ret) {
+                       TAILQ_REMOVE(&igb_filter_flex_list,
+                               flex_filter_ptr, entries);
+                       rte_free(flex_filter_ptr);
+               }
+               break;
+       default:
+               PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
+                           filter_type);
+               ret = -EINVAL;
+               break;
+       }
+
+       if (ret) {
+               rte_flow_error_set(error, EINVAL,
+                               RTE_FLOW_ERROR_TYPE_HANDLE,
+                               NULL, "Failed to destroy flow");
+               return ret;
+       }
+
+       TAILQ_FOREACH(igb_flow_mem_ptr, &igb_flow_list, entries) {
+               if (igb_flow_mem_ptr->flow == pmd_flow) {
+                       TAILQ_REMOVE(&igb_flow_list,
+                               igb_flow_mem_ptr, entries);
+                       rte_free(igb_flow_mem_ptr);
+               }
+       }
+       rte_free(flow);
+
+       return ret;
+}
+
+/* remove all the n-tuple filters */
+static void
+igb_clear_all_ntuple_filter(struct rte_eth_dev *dev)
+{
+       struct e1000_filter_info *filter_info =
+               E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
+       struct e1000_5tuple_filter *p_5tuple;
+       struct e1000_2tuple_filter *p_2tuple;
+
+       while ((p_5tuple = TAILQ_FIRST(&filter_info->fivetuple_list)))
+               igb_delete_5tuple_filter_82576(dev, p_5tuple);
+
+       while ((p_2tuple = TAILQ_FIRST(&filter_info->twotuple_list)))
+               igb_delete_2tuple_filter(dev, p_2tuple);
+}
+
+/* remove all the ether type filters */
+static void
+igb_clear_all_ethertype_filter(struct rte_eth_dev *dev)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct e1000_filter_info *filter_info =
+               E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
+       int i;
+
+       for (i = 0; i < E1000_MAX_ETQF_FILTERS; i++) {
+               if (filter_info->ethertype_mask & (1 << i)) {
+                       (void)igb_ethertype_filter_remove(filter_info,
+                                                           (uint8_t)i);
+                       E1000_WRITE_REG(hw, E1000_ETQF(i), 0);
+                       E1000_WRITE_FLUSH(hw);
+               }
+       }
+}
+
+/* remove the SYN filter */
+static void
+igb_clear_syn_filter(struct rte_eth_dev *dev)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct e1000_filter_info *filter_info =
+               E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
+
+       if (filter_info->syn_info & E1000_SYN_FILTER_ENABLE) {
+               filter_info->syn_info = 0;
+               E1000_WRITE_REG(hw, E1000_SYNQF(0), 0);
+               E1000_WRITE_FLUSH(hw);
+       }
+}
+
+/* remove all the flex filters */
+static void
+igb_clear_all_flex_filter(struct rte_eth_dev *dev)
+{
+       struct e1000_filter_info *filter_info =
+               E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
+       struct e1000_flex_filter *flex_filter;
+
+       while ((flex_filter = TAILQ_FIRST(&filter_info->flex_list)))
+               igb_remove_flex_filter(dev, flex_filter);
+}
+
+void
+igb_filterlist_flush(struct rte_eth_dev *dev)
+{
+       struct igb_ntuple_filter_ele *ntuple_filter_ptr;
+       struct igb_ethertype_filter_ele *ethertype_filter_ptr;
+       struct igb_eth_syn_filter_ele *syn_filter_ptr;
+       struct igb_flex_filter_ele *flex_filter_ptr;
+       struct igb_flow_mem *igb_flow_mem_ptr;
+       enum rte_filter_type filter_type;
+       struct rte_flow *pmd_flow;
+
+       TAILQ_FOREACH(igb_flow_mem_ptr, &igb_flow_list, entries) {
+               if (igb_flow_mem_ptr->dev == dev) {
+                       pmd_flow = igb_flow_mem_ptr->flow;
+                       filter_type = pmd_flow->filter_type;
+
+                       switch (filter_type) {
+                       case RTE_ETH_FILTER_NTUPLE:
+                               ntuple_filter_ptr =
+                               (struct igb_ntuple_filter_ele *)
+                                       pmd_flow->rule;
+                               TAILQ_REMOVE(&igb_filter_ntuple_list,
+                                               ntuple_filter_ptr, entries);
+                               rte_free(ntuple_filter_ptr);
+                               break;
+                       case RTE_ETH_FILTER_ETHERTYPE:
+                               ethertype_filter_ptr =
+                               (struct igb_ethertype_filter_ele *)
+                                       pmd_flow->rule;
+                               TAILQ_REMOVE(&igb_filter_ethertype_list,
+                                               ethertype_filter_ptr, entries);
+                               rte_free(ethertype_filter_ptr);
+                               break;
+                       case RTE_ETH_FILTER_SYN:
+                               syn_filter_ptr =
+                                       (struct igb_eth_syn_filter_ele *)
+                                               pmd_flow->rule;
+                               TAILQ_REMOVE(&igb_filter_syn_list,
+                                               syn_filter_ptr, entries);
+                               rte_free(syn_filter_ptr);
+                               break;
+                       case RTE_ETH_FILTER_FLEXIBLE:
+                               flex_filter_ptr =
+                                       (struct igb_flex_filter_ele *)
+                                               pmd_flow->rule;
+                               TAILQ_REMOVE(&igb_filter_flex_list,
+                                               flex_filter_ptr, entries);
+                               rte_free(flex_filter_ptr);
+                               break;
+                       default:
+                               PMD_DRV_LOG(WARNING, "Filter type"
+                                       "(%d) not supported", filter_type);
+                               break;
+                       }
+                       TAILQ_REMOVE(&igb_flow_list,
+                                igb_flow_mem_ptr,
+                                entries);
+                       rte_free(igb_flow_mem_ptr->flow);
+                       rte_free(igb_flow_mem_ptr);
+               }
+       }
+}
+
+/*  Destroy all flow rules associated with a port on igb. */
+static int
+igb_flow_flush(struct rte_eth_dev *dev,
+               __rte_unused struct rte_flow_error *error)
+{
+       igb_clear_all_ntuple_filter(dev);
+       igb_clear_all_ethertype_filter(dev);
+       igb_clear_syn_filter(dev);
+       igb_clear_all_flex_filter(dev);
+       igb_filterlist_flush(dev);
+
+       return 0;
+}
+
 const struct rte_flow_ops igb_flow_ops = {
-       igb_flow_validate,
-       igb_flow_create,
-       NULL,
-       NULL,
-       NULL,
+       .validate = igb_flow_validate,
+       .create = igb_flow_create,
+       .destroy = igb_flow_destroy,
+       .flush = igb_flow_flush,
 };