+ if (mplsogre_encap_conf.select_ipv4) {
+ memcpy(header, &ipv4, sizeof(ipv4));
+ header += sizeof(ipv4);
+ } else {
+ memcpy(&ipv6.hdr.src_addr,
+ &mplsogre_encap_conf.ipv6_src,
+ sizeof(mplsogre_encap_conf.ipv6_src));
+ memcpy(&ipv6.hdr.dst_addr,
+ &mplsogre_encap_conf.ipv6_dst,
+ sizeof(mplsogre_encap_conf.ipv6_dst));
+ memcpy(header, &ipv6, sizeof(ipv6));
+ header += sizeof(ipv6);
+ }
+ memcpy(header, &gre, sizeof(gre));
+ header += sizeof(gre);
+ memcpy(mpls.label_tc_s, mplsogre_encap_conf.label,
+ RTE_DIM(mplsogre_encap_conf.label));
+ mpls.label_tc_s[2] |= 0x1;
+ memcpy(header, &mpls, sizeof(mpls));
+ header += sizeof(mpls);
+ action_encap_data->conf.size = header -
+ action_encap_data->data;
+ action->conf = &action_encap_data->conf;
+ return ret;
+}
+
+/** Parse MPLSOGRE decap action. */
+static int
+parse_vc_action_mplsogre_decap(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+ struct rte_flow_action *action;
+ struct action_raw_decap_data *action_decap_data;
+ struct rte_flow_item_eth eth = { .type = 0, };
+ struct rte_flow_item_vlan vlan = {.tci = 0};
+ struct rte_flow_item_ipv4 ipv4 = {
+ .hdr = {
+ .next_proto_id = IPPROTO_GRE,
+ },
+ };
+ struct rte_flow_item_ipv6 ipv6 = {
+ .hdr = {
+ .proto = IPPROTO_GRE,
+ },
+ };
+ struct rte_flow_item_gre gre = {
+ .protocol = rte_cpu_to_be_16(ETHER_TYPE_MPLS_UNICAST),
+ };
+ struct rte_flow_item_mpls mpls;
+ uint8_t *header;
+ int ret;
+
+ ret = parse_vc(ctx, token, str, len, buf, size);
+ if (ret < 0)
+ return ret;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return ret;
+ if (!out->args.vc.actions_n)
+ return -1;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ /* Point to selected object. */
+ ctx->object = out->args.vc.data;
+ ctx->objmask = NULL;
+ /* Copy the headers to the buffer. */
+ action_decap_data = ctx->object;
+ *action_decap_data = (struct action_raw_decap_data) {
+ .conf = (struct rte_flow_action_raw_decap){
+ .data = action_decap_data->data,
+ },
+ .data = {},
+ };
+ header = action_decap_data->data;
+ if (mplsogre_decap_conf.select_vlan)
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
+ else if (mplsogre_encap_conf.select_ipv4)
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ else
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ memcpy(eth.dst.addr_bytes,
+ mplsogre_encap_conf.eth_dst, RTE_ETHER_ADDR_LEN);
+ memcpy(eth.src.addr_bytes,
+ mplsogre_encap_conf.eth_src, RTE_ETHER_ADDR_LEN);
+ memcpy(header, ð, sizeof(eth));
+ header += sizeof(eth);
+ if (mplsogre_encap_conf.select_vlan) {
+ if (mplsogre_encap_conf.select_ipv4)
+ vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ else
+ vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ memcpy(header, &vlan, sizeof(vlan));
+ header += sizeof(vlan);
+ }
+ if (mplsogre_encap_conf.select_ipv4) {
+ memcpy(header, &ipv4, sizeof(ipv4));
+ header += sizeof(ipv4);
+ } else {
+ memcpy(header, &ipv6, sizeof(ipv6));
+ header += sizeof(ipv6);
+ }
+ memcpy(header, &gre, sizeof(gre));
+ header += sizeof(gre);
+ memset(&mpls, 0, sizeof(mpls));
+ memcpy(header, &mpls, sizeof(mpls));
+ header += sizeof(mpls);
+ action_decap_data->conf.size = header -
+ action_decap_data->data;
+ action->conf = &action_decap_data->conf;
+ return ret;
+}
+
+/** Parse MPLSOUDP encap action. */
+static int
+parse_vc_action_mplsoudp_encap(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+ struct rte_flow_action *action;
+ struct action_raw_encap_data *action_encap_data;
+ struct rte_flow_item_eth eth = { .type = 0, };
+ struct rte_flow_item_vlan vlan = {
+ .tci = mplsoudp_encap_conf.vlan_tci,
+ .inner_type = 0,
+ };
+ struct rte_flow_item_ipv4 ipv4 = {
+ .hdr = {
+ .src_addr = mplsoudp_encap_conf.ipv4_src,
+ .dst_addr = mplsoudp_encap_conf.ipv4_dst,
+ .next_proto_id = IPPROTO_UDP,
+ .version_ihl = RTE_IPV4_VHL_DEF,
+ .time_to_live = IPDEFTTL,
+ },
+ };
+ struct rte_flow_item_ipv6 ipv6 = {
+ .hdr = {
+ .proto = IPPROTO_UDP,
+ .hop_limits = IPDEFTTL,
+ },
+ };
+ struct rte_flow_item_udp udp = {
+ .hdr = {
+ .src_port = mplsoudp_encap_conf.udp_src,
+ .dst_port = mplsoudp_encap_conf.udp_dst,
+ },
+ };
+ struct rte_flow_item_mpls mpls;
+ uint8_t *header;
+ int ret;
+
+ ret = parse_vc(ctx, token, str, len, buf, size);
+ if (ret < 0)
+ return ret;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return ret;
+ if (!out->args.vc.actions_n)
+ return -1;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ /* Point to selected object. */
+ ctx->object = out->args.vc.data;
+ ctx->objmask = NULL;
+ /* Copy the headers to the buffer. */
+ action_encap_data = ctx->object;
+ *action_encap_data = (struct action_raw_encap_data) {
+ .conf = (struct rte_flow_action_raw_encap){
+ .data = action_encap_data->data,
+ },
+ .data = {},
+ .preserve = {},
+ };
+ header = action_encap_data->data;
+ if (mplsoudp_encap_conf.select_vlan)
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
+ else if (mplsoudp_encap_conf.select_ipv4)
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ else
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ memcpy(eth.dst.addr_bytes,
+ mplsoudp_encap_conf.eth_dst, RTE_ETHER_ADDR_LEN);
+ memcpy(eth.src.addr_bytes,
+ mplsoudp_encap_conf.eth_src, RTE_ETHER_ADDR_LEN);
+ memcpy(header, ð, sizeof(eth));
+ header += sizeof(eth);
+ if (mplsoudp_encap_conf.select_vlan) {
+ if (mplsoudp_encap_conf.select_ipv4)
+ vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ else
+ vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ memcpy(header, &vlan, sizeof(vlan));
+ header += sizeof(vlan);
+ }
+ if (mplsoudp_encap_conf.select_ipv4) {
+ memcpy(header, &ipv4, sizeof(ipv4));
+ header += sizeof(ipv4);
+ } else {
+ memcpy(&ipv6.hdr.src_addr,
+ &mplsoudp_encap_conf.ipv6_src,
+ sizeof(mplsoudp_encap_conf.ipv6_src));
+ memcpy(&ipv6.hdr.dst_addr,
+ &mplsoudp_encap_conf.ipv6_dst,
+ sizeof(mplsoudp_encap_conf.ipv6_dst));
+ memcpy(header, &ipv6, sizeof(ipv6));
+ header += sizeof(ipv6);
+ }
+ memcpy(header, &udp, sizeof(udp));
+ header += sizeof(udp);
+ memcpy(mpls.label_tc_s, mplsoudp_encap_conf.label,
+ RTE_DIM(mplsoudp_encap_conf.label));
+ mpls.label_tc_s[2] |= 0x1;
+ memcpy(header, &mpls, sizeof(mpls));
+ header += sizeof(mpls);
+ action_encap_data->conf.size = header -
+ action_encap_data->data;
+ action->conf = &action_encap_data->conf;
+ return ret;
+}
+
+/** Parse MPLSOUDP decap action. */
+static int
+parse_vc_action_mplsoudp_decap(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+ struct rte_flow_action *action;
+ struct action_raw_decap_data *action_decap_data;
+ struct rte_flow_item_eth eth = { .type = 0, };
+ struct rte_flow_item_vlan vlan = {.tci = 0};
+ struct rte_flow_item_ipv4 ipv4 = {
+ .hdr = {
+ .next_proto_id = IPPROTO_UDP,
+ },
+ };
+ struct rte_flow_item_ipv6 ipv6 = {
+ .hdr = {
+ .proto = IPPROTO_UDP,
+ },
+ };
+ struct rte_flow_item_udp udp = {
+ .hdr = {
+ .dst_port = rte_cpu_to_be_16(6635),
+ },
+ };
+ struct rte_flow_item_mpls mpls;
+ uint8_t *header;
+ int ret;
+
+ ret = parse_vc(ctx, token, str, len, buf, size);
+ if (ret < 0)
+ return ret;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return ret;
+ if (!out->args.vc.actions_n)
+ return -1;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ /* Point to selected object. */
+ ctx->object = out->args.vc.data;
+ ctx->objmask = NULL;
+ /* Copy the headers to the buffer. */
+ action_decap_data = ctx->object;
+ *action_decap_data = (struct action_raw_decap_data) {
+ .conf = (struct rte_flow_action_raw_decap){
+ .data = action_decap_data->data,
+ },
+ .data = {},
+ };
+ header = action_decap_data->data;
+ if (mplsoudp_decap_conf.select_vlan)
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
+ else if (mplsoudp_encap_conf.select_ipv4)
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ else
+ eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ memcpy(eth.dst.addr_bytes,
+ mplsoudp_encap_conf.eth_dst, RTE_ETHER_ADDR_LEN);
+ memcpy(eth.src.addr_bytes,
+ mplsoudp_encap_conf.eth_src, RTE_ETHER_ADDR_LEN);
+ memcpy(header, ð, sizeof(eth));
+ header += sizeof(eth);
+ if (mplsoudp_encap_conf.select_vlan) {
+ if (mplsoudp_encap_conf.select_ipv4)
+ vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ else
+ vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ memcpy(header, &vlan, sizeof(vlan));
+ header += sizeof(vlan);
+ }
+ if (mplsoudp_encap_conf.select_ipv4) {
+ memcpy(header, &ipv4, sizeof(ipv4));
+ header += sizeof(ipv4);
+ } else {
+ memcpy(header, &ipv6, sizeof(ipv6));
+ header += sizeof(ipv6);
+ }
+ memcpy(header, &udp, sizeof(udp));
+ header += sizeof(udp);
+ memset(&mpls, 0, sizeof(mpls));
+ memcpy(header, &mpls, sizeof(mpls));
+ header += sizeof(mpls);
+ action_decap_data->conf.size = header -
+ action_decap_data->data;
+ action->conf = &action_decap_data->conf;
+ return ret;
+}
+
+static int
+parse_vc_action_raw_decap_index(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len, void *buf,
+ unsigned int size)
+{
+ struct action_raw_decap_data *action_raw_decap_data;
+ struct rte_flow_action *action;
+ const struct arg *arg;
+ struct buffer *out = buf;
+ int ret;
+ uint16_t idx;
+
+ RTE_SET_USED(token);
+ RTE_SET_USED(buf);
+ RTE_SET_USED(size);
+ arg = ARGS_ENTRY_ARB_BOUNDED
+ (offsetof(struct action_raw_decap_data, idx),
+ sizeof(((struct action_raw_decap_data *)0)->idx),
+ 0, RAW_ENCAP_CONFS_MAX_NUM - 1);
+ if (push_args(ctx, arg))
+ return -1;
+ ret = parse_int(ctx, token, str, len, NULL, 0);
+ if (ret < 0) {
+ pop_args(ctx);
+ return -1;
+ }
+ if (!ctx->object)
+ return len;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ action_raw_decap_data = ctx->object;
+ idx = action_raw_decap_data->idx;
+ action_raw_decap_data->conf.data = raw_decap_confs[idx].data;
+ action_raw_decap_data->conf.size = raw_decap_confs[idx].size;
+ action->conf = &action_raw_decap_data->conf;
+ return len;
+}
+
+
+static int
+parse_vc_action_raw_encap_index(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len, void *buf,
+ unsigned int size)
+{
+ struct action_raw_encap_data *action_raw_encap_data;
+ struct rte_flow_action *action;
+ const struct arg *arg;
+ struct buffer *out = buf;
+ int ret;
+ uint16_t idx;
+
+ RTE_SET_USED(token);
+ RTE_SET_USED(buf);
+ RTE_SET_USED(size);
+ if (ctx->curr != ACTION_RAW_ENCAP_INDEX_VALUE)
+ return -1;
+ arg = ARGS_ENTRY_ARB_BOUNDED
+ (offsetof(struct action_raw_encap_data, idx),
+ sizeof(((struct action_raw_encap_data *)0)->idx),
+ 0, RAW_ENCAP_CONFS_MAX_NUM - 1);
+ if (push_args(ctx, arg))
+ return -1;
+ ret = parse_int(ctx, token, str, len, NULL, 0);
+ if (ret < 0) {
+ pop_args(ctx);
+ return -1;
+ }
+ if (!ctx->object)
+ return len;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ action_raw_encap_data = ctx->object;
+ idx = action_raw_encap_data->idx;
+ action_raw_encap_data->conf.data = raw_encap_confs[idx].data;
+ action_raw_encap_data->conf.size = raw_encap_confs[idx].size;
+ action_raw_encap_data->conf.preserve = NULL;
+ action->conf = &action_raw_encap_data->conf;
+ return len;
+}
+
+static int
+parse_vc_action_raw_encap(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len, void *buf,
+ unsigned int size)
+{
+ struct buffer *out = buf;
+ struct rte_flow_action *action;
+ struct action_raw_encap_data *action_raw_encap_data = NULL;
+ int ret;
+
+ ret = parse_vc(ctx, token, str, len, buf, size);
+ if (ret < 0)
+ return ret;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return ret;
+ if (!out->args.vc.actions_n)
+ return -1;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ /* Point to selected object. */
+ ctx->object = out->args.vc.data;
+ ctx->objmask = NULL;
+ /* Copy the headers to the buffer. */
+ action_raw_encap_data = ctx->object;
+ action_raw_encap_data->conf.data = raw_encap_confs[0].data;
+ action_raw_encap_data->conf.preserve = NULL;
+ action_raw_encap_data->conf.size = raw_encap_confs[0].size;
+ action->conf = &action_raw_encap_data->conf;
+ return ret;
+}
+
+static int
+parse_vc_action_raw_decap(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len, void *buf,
+ unsigned int size)
+{
+ struct buffer *out = buf;
+ struct rte_flow_action *action;
+ struct action_raw_decap_data *action_raw_decap_data = NULL;
+ int ret;
+
+ ret = parse_vc(ctx, token, str, len, buf, size);
+ if (ret < 0)
+ return ret;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return ret;
+ if (!out->args.vc.actions_n)
+ return -1;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ /* Point to selected object. */
+ ctx->object = out->args.vc.data;
+ ctx->objmask = NULL;
+ /* Copy the headers to the buffer. */
+ action_raw_decap_data = ctx->object;
+ action_raw_decap_data->conf.data = raw_decap_confs[0].data;
+ action_raw_decap_data->conf.size = raw_decap_confs[0].size;
+ action->conf = &action_raw_decap_data->conf;
+ return ret;
+}
+
+static int
+parse_vc_action_set_meta(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len, void *buf,
+ unsigned int size)
+{
+ int ret;
+
+ ret = parse_vc(ctx, token, str, len, buf, size);
+ if (ret < 0)
+ return ret;
+ ret = rte_flow_dynf_metadata_register();
+ if (ret < 0)
+ return -1;
+ return len;
+}
+
+/** Parse tokens for destroy command. */
+static int
+parse_destroy(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+
+ /* Token name must match. */
+ if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+ return -1;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return len;
+ if (!out->command) {
+ if (ctx->curr != DESTROY)
+ return -1;
+ if (sizeof(*out) > size)
+ return -1;
+ out->command = ctx->curr;
+ ctx->objdata = 0;
+ ctx->object = out;
+ ctx->objmask = NULL;
+ out->args.destroy.rule =
+ (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
+ sizeof(double));
+ return len;
+ }
+ if (((uint8_t *)(out->args.destroy.rule + out->args.destroy.rule_n) +
+ sizeof(*out->args.destroy.rule)) > (uint8_t *)out + size)
+ return -1;
+ ctx->objdata = 0;
+ ctx->object = out->args.destroy.rule + out->args.destroy.rule_n++;
+ ctx->objmask = NULL;
+ return len;
+}
+
+/** Parse tokens for flush command. */
+static int
+parse_flush(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+
+ /* Token name must match. */
+ if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+ return -1;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return len;
+ if (!out->command) {
+ if (ctx->curr != FLUSH)
+ return -1;
+ if (sizeof(*out) > size)
+ return -1;
+ out->command = ctx->curr;
+ ctx->objdata = 0;
+ ctx->object = out;
+ ctx->objmask = NULL;
+ }
+ return len;
+}
+
+/** Parse tokens for dump command. */
+static int
+parse_dump(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+
+ /* Token name must match. */
+ if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+ return -1;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return len;
+ if (!out->command) {
+ if (ctx->curr != DUMP)
+ return -1;
+ if (sizeof(*out) > size)
+ return -1;
+ out->command = ctx->curr;
+ ctx->objdata = 0;
+ ctx->object = out;
+ ctx->objmask = NULL;
+ }
+ return len;
+}
+
+/** Parse tokens for query command. */
+static int
+parse_query(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+
+ /* Token name must match. */
+ if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+ return -1;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return len;
+ if (!out->command) {
+ if (ctx->curr != QUERY)
+ return -1;
+ if (sizeof(*out) > size)
+ return -1;
+ out->command = ctx->curr;
+ ctx->objdata = 0;
+ ctx->object = out;
+ ctx->objmask = NULL;
+ }
+ return len;