@@ -373,6 +373,7 @@ cpfl_fxp_parse_action(struct cpfl_itf *itf,
break;
case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
+ case RTE_FLOW_ACTION_TYPE_PROG:
break;
case RTE_FLOW_ACTION_TYPE_VOID:
break;
@@ -425,6 +426,7 @@ cpfl_is_mod_action(const struct rte_flow_action actions[])
switch (action_type) {
case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
+ case RTE_FLOW_ACTION_TYPE_PROG:
return true;
default:
continue;
@@ -35,6 +35,8 @@ cpfl_get_action_type_by_str(const char *type)
return RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP;
else if (strcmp(type, "vxlan_decap") == 0)
return RTE_FLOW_ACTION_TYPE_VXLAN_DECAP;
+ else if (strcmp(type, "prog") == 0)
+ return RTE_FLOW_ACTION_TYPE_PROG;
PMD_DRV_LOG(ERR, "Not support this type: %s.", type);
return RTE_FLOW_ACTION_TYPE_VOID;
@@ -612,6 +614,57 @@ cpfl_flow_js_mr_key(json_t *ob_mr_keys, struct cpfl_flow_js_mr_key *js_mr_key)
}
encap->protocols[j] = proto_type;
}
+ } else if (js_mr_key->actions[i].type == RTE_FLOW_ACTION_TYPE_PROG) {
+ int ret;
+ uint32_t param_size, j;
+ uint16_t value = 0;
+ json_t *ob_param, *subobject;
+ const char *name;
+
+ ret = cpfl_json_t_to_uint32(object, "id", &js_mr_key->actions[i].prog.id);
+ if (ret < 0) {
+ PMD_DRV_LOG(ERR, "Can not parse uint32 'id'.");
+ goto err;
+ }
+ if (json_object_get(object, "name")) {
+ js_mr_key->actions[i].prog.has_name = TRUE;
+ name = cpfl_json_t_to_string(object, "name");
+ if (!name) {
+ PMD_DRV_LOG(ERR, "Can not parse string 'name'.");
+ goto err;
+ }
+ strncpy(js_mr_key->actions[i].prog.name, name, strlen(name));
+ }
+
+ ob_param = json_object_get(object, "parameters");
+ param_size = json_array_size(ob_param);
+ js_mr_key->actions[i].prog.param_size = param_size;
+ for (j = 0; j < param_size; j++) {
+ subobject = json_array_get(ob_param, j);
+ ret = cpfl_json_t_to_uint16(subobject, "index", &value);
+ if (ret < 0) {
+ PMD_DRV_LOG(ERR, "Can not parse 'index'.");
+ goto err;
+ }
+ js_mr_key->actions[i].prog.params[j].index = value;
+ if (json_object_get(subobject, "name")) {
+ js_mr_key->actions[i].prog.params[j].has_name = TRUE;
+ name = cpfl_json_t_to_string(subobject, "name");
+ if (!name) {
+ PMD_DRV_LOG(ERR, "Can not parse string 'name'.");
+ goto err;
+ }
+ strncpy(js_mr_key->actions[i].prog.params[j].name, name,
+ strlen(name));
+ }
+ ret = cpfl_json_t_to_uint16(subobject, "size", &value);
+ if (ret < 0) {
+ PMD_DRV_LOG(ERR, "Can not parse 'size'.");
+ goto err;
+ }
+ js_mr_key->actions[i].prog.params[j].size = value;
+ }
+
} else if (js_mr_key->actions[i].type != RTE_FLOW_ACTION_TYPE_VXLAN_DECAP) {
PMD_DRV_LOG(ERR, "not support this type: %d.", js_mr_key->actions[i].type);
goto err;
@@ -634,11 +687,6 @@ cpfl_flow_js_mr_layout(json_t *ob_layouts, struct cpfl_flow_js_mr_action_mod *js
js_mod->layout_size = len;
if (len == 0)
return 0;
- js_mod->layout = rte_malloc(NULL, sizeof(struct cpfl_flow_js_mr_layout) * len, 0);
- if (!js_mod->layout) {
- PMD_DRV_LOG(ERR, "Failed to alloc memory.");
- return -ENOMEM;
- }
for (i = 0; i < len; i++) {
json_t *object;
@@ -680,6 +728,79 @@ cpfl_flow_js_mr_layout(json_t *ob_layouts, struct cpfl_flow_js_mr_action_mod *js
return -EINVAL;
}
+static int
+cpfl_flow_js_mr_content(json_t *ob_content, struct cpfl_flow_js_mr_action_mod *js_mod)
+{
+ int ret, len, i;
+ json_t *ob_field;
+
+ if (!ob_content)
+ return 0;
+
+ js_mod->is_content = TRUE;
+ ret = cpfl_json_t_to_uint16(ob_content, "size", &js_mod->content.size);
+ if (ret < 0) {
+ PMD_DRV_LOG(ERR, "Can not parse 'size'.");
+ return -EINVAL;
+ }
+
+ ob_field = json_object_get(ob_content, "fields");
+ len = json_array_size(ob_field);
+ js_mod->content.field_size = len;
+ if (len == 0)
+ return 0;
+
+ for (i = 0; i < len; i++) {
+ json_t *object;
+ uint16_t start = 0, width = 0, index = 0;
+ const char *type;
+
+ object = json_array_get(ob_field, i);
+ type = cpfl_json_t_to_string(object, "type");
+ if (!type) {
+ PMD_DRV_LOG(ERR, "Can not parse string 'type'.");
+ goto err;
+ }
+ strncpy(js_mod->content.fields[i].type, type, strlen(type));
+ ret = cpfl_json_t_to_uint16(object, "start", &start);
+ if (ret < 0) {
+ PMD_DRV_LOG(ERR, "Can not parse 'start'.");
+ goto err;
+ }
+ js_mod->content.fields[i].start = start;
+ ret = cpfl_json_t_to_uint16(object, "width", &width);
+ if (ret < 0) {
+ PMD_DRV_LOG(ERR, "Can not parse 'width'.");
+ goto err;
+ }
+ js_mod->content.fields[i].width = width;
+ if (strcmp(type, "parameter") == 0) {
+ ret = cpfl_json_t_to_uint16(object, "index", &index);
+ if (ret < 0) {
+ PMD_DRV_LOG(ERR, "Can not parse 'index'.");
+ goto err;
+ }
+ js_mod->content.fields[i].index = index;
+ } else if (strcmp(type, "constant") == 0) {
+ json_t *ob_value, *subobj;
+ int value_len, j;
+
+ ob_value = json_object_get(object, "value");
+ value_len = json_array_size(ob_value);
+ for (j = 0; j < value_len; j++) {
+ subobj = json_array_get(ob_value, j);
+ js_mod->content.fields[i].value[j] =
+ (uint8_t)json_integer_value(subobj);
+ }
+ }
+ }
+
+ return 0;
+
+err:
+ return -EINVAL;
+}
+
static int
cpfl_flow_js_mr_action(json_t *ob_mr_act, struct cpfl_flow_js_mr_action *js_mr_act)
{
@@ -695,7 +816,7 @@ cpfl_flow_js_mr_action(json_t *ob_mr_act, struct cpfl_flow_js_mr_action *js_mr_a
/* mr->action->data */
ob_data = json_object_get(ob_mr_act, "data");
if (strcmp(type, "mod") == 0) {
- json_t *ob_layouts;
+ json_t *ob_layouts, *ob_content;
uint16_t profile = 0;
int ret;
@@ -712,6 +833,12 @@ cpfl_flow_js_mr_action(json_t *ob_mr_act, struct cpfl_flow_js_mr_action *js_mr_a
PMD_DRV_LOG(ERR, "Can not parse layout.");
return ret;
}
+ ob_content = json_object_get(ob_data, "content");
+ ret = cpfl_flow_js_mr_content(ob_content, &js_mr_act->mod);
+ if (ret < 0) {
+ PMD_DRV_LOG(ERR, "Can not parse 'content'.");
+ return ret;
+ }
} else {
PMD_DRV_LOG(ERR, "not support this type: %s.", type);
return -EINVAL;
@@ -862,7 +989,6 @@ cpfl_parser_destroy(struct cpfl_flow_js_parser *parser)
struct cpfl_flow_js_mr *mr = &parser->modifications[i];
rte_free(mr->key.actions);
- rte_free(mr->action.mod.layout);
}
rte_free(parser->modifications);
rte_free(parser);
@@ -1544,6 +1670,39 @@ cpfl_check_actions_vxlan_encap(struct cpfl_flow_mr_key_action_vxlan_encap *encap
return 0;
}
+static int
+cpfl_parse_check_prog_action(struct cpfl_flow_js_mr_key_action *key_act,
+ struct cpfl_flow_mr_key_action_prog *mr_key_prog,
+ const struct rte_flow_action_prog *prog)
+{
+ uint32_t k;
+ bool check_name;
+
+ check_name = key_act->prog.has_name ? strcmp(prog->name, key_act->prog.name) == 0
+ : atol(prog->name) == key_act->prog.id;
+ if (!check_name) {
+ PMD_DRV_LOG(ERR, "Not support this prog type: %s.", prog->name);
+ return -EINVAL;
+ }
+ if (key_act->prog.param_size != prog->args_num)
+ return -EINVAL;
+ for (k = 0; k < key_act->prog.param_size; k++) {
+ const struct rte_flow_action_prog_argument *arg = &prog->args[k];
+ struct cpfl_flow_js_prog_parameter *param = &key_act->prog.params[k];
+
+ check_name = param->has_name ? strcmp(arg->name, param->name) == 0
+ : atoi(arg->name) == param->index;
+ if (!check_name || arg->size != param->size)
+ return -EINVAL;
+ if (param->has_name) {
+ mr_key_prog->has_name = TRUE;
+ strncpy(mr_key_prog->name[param->index], param->name, strlen(param->name));
+ }
+ }
+
+ return 0;
+}
+
/* check and parse */
static int
cpfl_parse_mr_key_action(struct cpfl_flow_js_mr_key_action *key_acts, int size,
@@ -1575,9 +1734,9 @@ cpfl_parse_mr_key_action(struct cpfl_flow_js_mr_key_action *key_acts, int size,
}
if (j >= actions_length)
return -EINVAL;
- mr_key_action[i].type = RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP;
- mr_key_action[i].encap.action = &actions[j];
- encap = &mr_key_action[i].encap;
+ mr_key_action->mods[i].type = RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP;
+ mr_key_action->mods[i].encap.action = &actions[j];
+ encap = &mr_key_action->mods[i].encap;
proto_size = key_act->encap.proto_size;
encap->proto_size = proto_size;
@@ -1598,8 +1757,22 @@ cpfl_parse_mr_key_action(struct cpfl_flow_js_mr_key_action *key_acts, int size,
}
if (j >= actions_length)
return -EINVAL;
- mr_key_action[i].type = RTE_FLOW_ACTION_TYPE_VXLAN_DECAP;
+ mr_key_action->mods[i].type = RTE_FLOW_ACTION_TYPE_VXLAN_DECAP;
j++;
+ } else if (type == RTE_FLOW_ACTION_TYPE_PROG) {
+ const struct rte_flow_action_prog *prog;
+
+ while (j < actions_length &&
+ actions[j].type != RTE_FLOW_ACTION_TYPE_PROG) {
+ j++;
+ }
+ if (j >= actions_length)
+ return -EINVAL;
+ prog = actions[j].conf;
+ mr_key_action->prog.prog = prog;
+ ret = cpfl_parse_check_prog_action(key_act, &mr_key_action->prog, prog);
+ if (ret < 0)
+ return -EINVAL;
} else {
PMD_DRV_LOG(ERR, "Not support this type: %d.", type);
return -EPERM;
@@ -1612,7 +1785,7 @@ cpfl_parse_mr_key_action(struct cpfl_flow_js_mr_key_action *key_acts, int size,
/* output: uint8_t *buffer, uint16_t *byte_len */
static int
cpfl_parse_layout(struct cpfl_flow_js_mr_layout *layouts, int layout_size,
- struct cpfl_flow_mr_key_action *mr_key_action,
+ struct cpfl_flow_mr_key_mod *mods,
uint8_t *buffer, uint16_t *byte_len)
{
int i;
@@ -1622,7 +1795,7 @@ cpfl_parse_layout(struct cpfl_flow_js_mr_layout *layouts, int layout_size,
int index, size, offset;
const char *hint;
const uint8_t *addr = NULL;
- struct cpfl_flow_mr_key_action *temp;
+ struct cpfl_flow_mr_key_mod *temp;
struct cpfl_flow_js_mr_layout *layout;
layout = &layouts[i];
@@ -1636,7 +1809,7 @@ cpfl_parse_layout(struct cpfl_flow_js_mr_layout *layouts, int layout_size,
continue;
}
hint = layout->hint;
- temp = mr_key_action + index;
+ temp = mods + index;
if (temp->type == RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP) {
const struct rte_flow_action_vxlan_encap *action_vxlan_encap;
struct rte_flow_item *definition;
@@ -1685,6 +1858,51 @@ cpfl_parse_layout(struct cpfl_flow_js_mr_layout *layouts, int layout_size,
return 0;
}
+static int
+cpfl_parse_content(struct cpfl_flow_js_mr_content *content,
+ struct cpfl_flow_mr_key_action_prog *prog, uint8_t *buffer)
+{
+ int i, j;
+
+ for (i = 0; i < content->field_size; i++) {
+ uint16_t start, width, shift_bit;
+
+ start = content->fields[i].start / 8;
+ width = (content->fields[i].width + 7) / 8;
+ shift_bit = (8 - content->fields[i].start % 8 - content->fields[i].width % 8) % 8;
+
+ for (j = 0; j < width; j++) {
+ uint8_t old_value = 0;
+
+ if (strcmp(content->fields[i].type, "parameter") == 0) {
+ uint32_t k;
+ uint16_t index = content->fields[i].index;
+ const struct rte_flow_action_prog *act_prog = prog->prog;
+
+ for (k = 0; k < act_prog->args_num; k++) {
+ const char *name = act_prog->args[k].name;
+
+ if ((prog->has_name &&
+ strcmp(prog->name[index], name) == 0) ||
+ (!prog->has_name && atoi(name) == index)) {
+ old_value = act_prog->args[k].value[j];
+ break;
+ }
+ }
+ if (k == act_prog->args_num)
+ return -EINVAL;
+ } else if (strcmp(content->fields[i].type, "constant") == 0) {
+ old_value = content->fields[i].value[j];
+ } else {
+ return -EINVAL;
+ }
+ memset(buffer + start + j, buffer[start + j] | old_value << shift_bit, 1);
+ }
+ }
+
+ return 0;
+}
+
static int
cpfl_parse_mr_action(struct cpfl_flow_js_mr_action *action,
struct cpfl_flow_mr_key_action *mr_key_action,
@@ -1695,6 +1913,18 @@ cpfl_parse_mr_action(struct cpfl_flow_js_mr_action *action,
/* mr->action->type */
type = action->type;
/* mr->action->data */
+ if (action->mod.is_content) {
+ struct cpfl_flow_js_mr_content *content = &action->mod.content;
+
+ mr_action->type = CPFL_JS_MR_ACTION_TYPE_MOD;
+ mr_action->mod.byte_len = 0;
+ mr_action->mod.prof = action->mod.prof;
+ mr_action->mod.byte_len = content->size;
+ memset(mr_action->mod.data, 0, sizeof(mr_action->mod.data));
+
+ return cpfl_parse_content(content, &mr_key_action->prog, mr_action->mod.data);
+ }
+
if (type == CPFL_JS_MR_ACTION_TYPE_MOD) {
struct cpfl_flow_js_mr_layout *layout;
@@ -1706,7 +1936,7 @@ cpfl_parse_mr_action(struct cpfl_flow_js_mr_action *action,
return 0;
memset(mr_action->mod.data, 0, sizeof(mr_action->mod.data));
- return cpfl_parse_layout(layout, action->mod.layout_size, mr_key_action,
+ return cpfl_parse_layout(layout, action->mod.layout_size, mr_key_action->mods,
mr_action->mod.data, &mr_action->mod.byte_len);
}
PMD_DRV_LOG(ERR, "Not support this type: %d.", type);
@@ -1731,7 +1961,7 @@ cpfl_parse_mod_rules(struct cpfl_flow_js_parser *parser, const struct rte_flow_a
struct cpfl_flow_mr_action *mr_action)
{
int i;
- struct cpfl_flow_mr_key_action mr_key_action[CPFL_MOD_KEY_NUM_MAX] = {0};
+ struct cpfl_flow_mr_key_action mr_key_action = {0};
for (i = 0; i < parser->mr_size; i++) {
int ret;
@@ -1740,11 +1970,11 @@ cpfl_parse_mod_rules(struct cpfl_flow_js_parser *parser, const struct rte_flow_a
mr = &parser->modifications[i];
if (!mr)
return -EINVAL;
- ret = cpfl_check_mod_key(mr, actions, mr_key_action);
+ ret = cpfl_check_mod_key(mr, actions, &mr_key_action);
if (ret < 0)
continue;
/* mr->action */
- return cpfl_parse_mr_action(&mr->action, mr_key_action, mr_action);
+ return cpfl_parse_mr_action(&mr->action, &mr_key_action, mr_action);
}
return -EINVAL;
@@ -13,6 +13,9 @@
#define CPFL_MAX_SEM_FV_KEY_SIZE 64
#define CPFL_FLOW_JS_PROTO_SIZE 16
#define CPFL_MOD_KEY_NUM_MAX 8
+#define CPFL_PROG_CONTENT_FIELD_NUM_MAX 64
+#define CPFL_PROG_CONSTANT_VALUE_NUM_MAX 8
+#define CPFL_PROG_PARAM_NUM_MAX 10
/* Pattern Rules Storage */
enum cpfl_flow_pr_action_type {
@@ -117,11 +120,27 @@ struct cpfl_flow_js_mr_key_action_vxlan_encap {
int proto_size;
};
+struct cpfl_flow_js_prog_parameter {
+ bool has_name;
+ uint16_t index;
+ char name[CPFL_FLOW_JSON_STR_SIZE_MAX];
+ uint16_t size;
+};
+
+struct cpfl_flow_js_mr_key_action_prog {
+ bool has_name;
+ uint32_t id;
+ char name[CPFL_FLOW_JSON_STR_SIZE_MAX];
+ uint32_t param_size;
+ struct cpfl_flow_js_prog_parameter params[CPFL_PROG_PARAM_NUM_MAX];
+};
+
/* A set of modification rte_flow_action_xxx objects can be defined as a type / data pair. */
struct cpfl_flow_js_mr_key_action {
enum rte_flow_action_type type;
union {
struct cpfl_flow_js_mr_key_action_vxlan_encap encap;
+ struct cpfl_flow_js_mr_key_action_prog prog;
};
};
@@ -137,6 +156,22 @@ struct cpfl_flow_js_mr_layout {
uint16_t size; /* bytes of the data to be copied to the memory region */
};
+struct cpfl_flow_js_mr_field {
+ char type[CPFL_FLOW_JSON_STR_SIZE_MAX];
+ uint16_t start;
+ uint16_t width;
+ union {
+ uint16_t index;
+ uint8_t value[CPFL_PROG_CONSTANT_VALUE_NUM_MAX];
+ };
+};
+
+struct cpfl_flow_js_mr_content {
+ uint16_t size;
+ struct cpfl_flow_js_mr_field fields[CPFL_PROG_CONTENT_FIELD_NUM_MAX];
+ int field_size;
+};
+
/** For mod data, besides the profile ID, a layout array defines a set of hints that helps
* driver composing the MOD memory region when the action need to insert/update some packet
* data from user input.
@@ -144,8 +179,14 @@ struct cpfl_flow_js_mr_layout {
struct cpfl_flow_js_mr_action_mod {
uint16_t prof;
uint16_t byte_len;
- struct cpfl_flow_js_mr_layout *layout;
- int layout_size;
+ bool is_content;
+ union {
+ struct {
+ struct cpfl_flow_js_mr_layout layout[CPFL_FLOW_JS_PROTO_SIZE];
+ int layout_size;
+ };
+ struct cpfl_flow_js_mr_content content;
+ };
};
enum cpfl_flow_mr_action_type {
@@ -203,11 +244,20 @@ struct cpfl_flow_mr_key_action_vxlan_encap {
const struct rte_flow_action *action;
};
-struct cpfl_flow_mr_key_action {
+struct cpfl_flow_mr_key_action_prog {
+ const struct rte_flow_action_prog *prog;
+ bool has_name;
+ char name[CPFL_PROG_PARAM_NUM_MAX][CPFL_FLOW_JSON_STR_SIZE_MAX];
+};
+
+struct cpfl_flow_mr_key_mod {
enum rte_flow_action_type type;
- union {
- struct cpfl_flow_mr_key_action_vxlan_encap encap;
- };
+ struct cpfl_flow_mr_key_action_vxlan_encap encap;
+};
+
+struct cpfl_flow_mr_key_action {
+ struct cpfl_flow_mr_key_mod mods[CPFL_MOD_KEY_NUM_MAX];
+ struct cpfl_flow_mr_key_action_prog prog;
};
struct cpfl_flow_mr_action_mod {