net/igb: fix flex type filter
authorWei Zhao <wei.zhao1@intel.com>
Fri, 16 Jun 2017 05:04:23 +0000 (13:04 +0800)
committerFerruh Yigit <ferruh.yigit@intel.com>
Thu, 6 Jul 2017 13:00:56 +0000 (15:00 +0200)
There is a bug in flex type filter parsing because of wrong local
variable index usage.

Bug cause filter to fail and wrong mask calculation.

Fixes: 7cd77faf7129 ("net/igb: parse flow API flex filter")

Signed-off-by: Wei Zhao <wei.zhao1@intel.com>
drivers/net/e1000/igb_flow.c

index 8d59cd0..db73b18 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
@@ -1043,8 +1045,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 +1110,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 +1120,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 +1145,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 +1192,7 @@ item_loop:
                goto item_loop;
        }
 
-       filter->len = RTE_ALIGN(total_offset, 8);
+       filter->len = RTE_ALIGN(max_offset, 8);
 
        /* parse action */
        index = 0;