@@ -645,6 +645,11 @@ parse_tc_flower_to_match(struct tc_flower *flower,
| VLAN_CFI);
}
break;
+ case TC_ACT_MPLS_POP: {
+ nl_msg_put_be16(buf, OVS_ACTION_ATTR_POP_MPLS,
+ action->mpls.proto);
+ }
+ break;
case TC_ACT_PEDIT: {
parse_flower_rewrite_to_netlink_action(buf, flower);
}
@@ -1328,6 +1333,10 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
} else if (nl_attr_type(nla) == OVS_ACTION_ATTR_POP_VLAN) {
action->type = TC_ACT_VLAN_POP;
flower.action_count++;
+ } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_POP_MPLS) {
+ action->mpls.proto = nl_attr_get_be16(nla);
+ action->type = TC_ACT_MPLS_POP;
+ flower.action_count++;
} else if (nl_attr_type(nla) == OVS_ACTION_ATTR_SET) {
const struct nlattr *set = nl_attr_get(nla);
const size_t set_len = nl_attr_get_size(nla);
@@ -25,6 +25,7 @@
#include <linux/tc_act/tc_csum.h>
#include <linux/tc_act/tc_gact.h>
#include <linux/tc_act/tc_mirred.h>
+#include <linux/tc_act/tc_mpls.h>
#include <linux/tc_act/tc_pedit.h>
#include <linux/tc_act/tc_skbedit.h>
#include <linux/tc_act/tc_tunnel_key.h>
@@ -1237,6 +1238,49 @@ nl_parse_act_vlan(struct nlattr *options, struct tc_flower *flower)
return 0;
}
+static const struct nl_policy mpls_policy[] = {
+ [TCA_MPLS_PARMS] = { .type = NL_A_UNSPEC,
+ .min_len = sizeof(struct tc_mpls),
+ .optional = false, },
+ [TCA_MPLS_PROTO] = { .type = NL_A_U16, .optional = true, },
+};
+
+static int
+nl_parse_act_mpls(struct nlattr *options, struct tc_flower *flower)
+{
+ struct nlattr *mpls_attrs[ARRAY_SIZE(mpls_policy)];
+ const struct nlattr *mpls_parms;
+ struct nlattr *mpls_proto;
+ struct tc_action *action;
+ const struct tc_mpls *m;
+
+ if (!nl_parse_nested(options, mpls_policy, mpls_attrs,
+ ARRAY_SIZE(mpls_policy))) {
+ VLOG_ERR_RL(&error_rl, "failed to parse mpls action options");
+ return EPROTO;
+ }
+
+ action = &flower->actions[flower->action_count++];
+ mpls_parms = mpls_attrs[TCA_MPLS_PARMS];
+ m = nl_attr_get_unspec(mpls_parms, sizeof *m);
+
+ switch (m->m_action) {
+ case TCA_MPLS_ACT_POP:
+ mpls_proto = mpls_attrs[TCA_MPLS_PROTO];
+ if (mpls_proto) {
+ action->mpls.proto = nl_attr_get_be16(mpls_proto);
+ }
+ action->type = TC_ACT_MPLS_POP;
+ break;
+ default:
+ VLOG_ERR_RL(&error_rl, "unknown mpls action: %d, %d",
+ m->action, m->m_action);
+ return EINVAL;
+ }
+
+ return 0;
+}
+
static const struct nl_policy csum_policy[] = {
[TCA_CSUM_PARMS] = { .type = NL_A_UNSPEC,
.min_len = sizeof(struct tc_csum),
@@ -1319,6 +1363,8 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower)
err = nl_parse_act_mirred(act_options, flower);
} else if (!strcmp(act_kind, "vlan")) {
err = nl_parse_act_vlan(act_options, flower);
+ } else if (!strcmp(act_kind, "mpls")) {
+ err = nl_parse_act_mpls(act_options, flower);
} else if (!strcmp(act_kind, "tunnel_key")) {
err = nl_parse_act_tunnel_key(act_options, flower);
} else if (!strcmp(act_kind, "pedit")) {
@@ -1649,6 +1695,23 @@ nl_msg_put_act_pop_vlan(struct ofpbuf *request)
}
static void
+nl_msg_put_act_pop_mpls(struct ofpbuf *request, ovs_be16 proto)
+{
+ size_t offset;
+
+ nl_msg_put_string(request, TCA_ACT_KIND, "mpls");
+ offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS | NLA_F_NESTED);
+ {
+ struct tc_mpls parm = { .action = TC_ACT_PIPE,
+ .m_action = TCA_MPLS_ACT_POP };
+
+ nl_msg_put_unspec(request, TCA_MPLS_PARMS, &parm, sizeof parm);
+ nl_msg_put_be16(request, TCA_MPLS_PROTO, proto);
+ }
+ nl_msg_end_nested(request, offset);
+}
+
+static void
nl_msg_put_act_tunnel_key_release(struct ofpbuf *request)
{
size_t offset;
@@ -2025,6 +2088,12 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)
nl_msg_end_nested(request, act_offset);
}
break;
+ case TC_ACT_MPLS_POP: {
+ act_offset = nl_msg_start_nested(request, act_index++);
+ nl_msg_put_act_pop_mpls(request, action->mpls.proto);
+ nl_msg_end_nested(request, act_offset);
+ }
+ break;
case TC_ACT_OUTPUT: {
ingress = action->out.ingress;
ifindex = action->out.ifindex_out;
@@ -153,6 +153,7 @@ enum tc_action_type {
TC_ACT_PEDIT,
TC_ACT_VLAN_POP,
TC_ACT_VLAN_PUSH,
+ TC_ACT_MPLS_POP,
};
struct tc_action {
@@ -169,6 +170,10 @@ struct tc_action {
} vlan;
struct {
+ ovs_be16 proto;
+ } mpls;
+
+ struct {
bool id_present;
ovs_be64 id;
ovs_be16 tp_src;