diff mbox series

[ovs-dev,OvS,3/4] ovs-tc: offload MPLS push actions to TC datapath

Message ID 1564484717-18648-4-git-send-email-john.hurley@netronome.com
State Accepted
Headers show
Series Offload MPLS actions to TC datapath | expand

Commit Message

John Hurley July 30, 2019, 11:05 a.m. UTC
TC can now be used to push an MPLS header onto a packet. The MPLS label is
the only information that needs to be passed here with the rest reverting
to default values if none are supplied. OvS, however, gives the entire
MPLS header to be pushed along with the MPLS protocol to use. TC can
optionally accept these values so can be made replicate the OvS datapath
rule.

Convert OvS MPLS push datapath rules to TC format and offload to a TC
datapath.

Signed-off-by: John Hurley <john.hurley@netronome.com>
Reviewed-by: Simon Horman <simon.horman@netronome.com>
---
 lib/netdev-offload-tc.c | 25 ++++++++++++++++++++
 lib/packets.h           | 24 +++++++++++++++++++
 lib/tc.c                | 61 +++++++++++++++++++++++++++++++++++++++++++++++++
 lib/tc.h                |  5 ++++
 4 files changed, 115 insertions(+)
diff mbox series

Patch

diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c
index 2e282c9..03610d8 100644
--- a/lib/netdev-offload-tc.c
+++ b/lib/netdev-offload-tc.c
@@ -650,6 +650,21 @@  parse_tc_flower_to_match(struct tc_flower *flower,
                                 action->mpls.proto);
             }
             break;
+            case TC_ACT_MPLS_PUSH: {
+                struct ovs_action_push_mpls *push;
+                ovs_be32 mpls_lse = 0;
+
+                flow_set_mpls_lse_label(&mpls_lse, action->mpls.label);
+                flow_set_mpls_lse_tc(&mpls_lse, action->mpls.tc);
+                flow_set_mpls_lse_ttl(&mpls_lse, action->mpls.ttl);
+                flow_set_mpls_lse_bos(&mpls_lse, action->mpls.bos);
+
+                push = nl_msg_put_unspec_zero(buf, OVS_ACTION_ATTR_PUSH_MPLS,
+                                              sizeof *push);
+                push->mpls_ethertype = action->mpls.proto;
+                push->mpls_lse = mpls_lse;
+            }
+            break;
             case TC_ACT_PEDIT: {
                 parse_flower_rewrite_to_netlink_action(buf, flower);
             }
@@ -1333,6 +1348,16 @@  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_PUSH_MPLS) {
+            const struct ovs_action_push_mpls *mpls_push = nl_attr_get(nla);
+
+            action->mpls.proto = mpls_push->mpls_ethertype;
+            action->mpls.label = mpls_lse_to_label(mpls_push->mpls_lse);
+            action->mpls.tc = mpls_lse_to_tc(mpls_push->mpls_lse);
+            action->mpls.ttl = mpls_lse_to_ttl(mpls_push->mpls_lse);
+            action->mpls.bos = mpls_lse_to_bos(mpls_push->mpls_lse);
+            action->type = TC_ACT_MPLS_PUSH;
+            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;
diff --git a/lib/packets.h b/lib/packets.h
index 4124490..a4bee38 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -574,6 +574,30 @@  mpls_lse_to_ttl(ovs_be32 mpls_lse)
     return (ntohl(mpls_lse) & MPLS_TTL_MASK) >> MPLS_TTL_SHIFT;
 }
 
+/* Set label in mpls lse. */
+static inline void
+flow_set_mpls_lse_label(ovs_be32 *mpls_lse, uint32_t label)
+{
+    *mpls_lse &= ~htonl(MPLS_LABEL_MASK);
+    *mpls_lse |= htonl(label << MPLS_LABEL_SHIFT);
+}
+
+/* Set TC in mpls lse. */
+static inline void
+flow_set_mpls_lse_tc(ovs_be32 *mpls_lse, uint8_t tc)
+{
+    *mpls_lse &= ~htonl(MPLS_TC_MASK);
+    *mpls_lse |= htonl((tc & 0x7) << MPLS_TC_SHIFT);
+}
+
+/* Set BOS in mpls lse. */
+static inline void
+flow_set_mpls_lse_bos(ovs_be32 *mpls_lse, uint8_t bos)
+{
+    *mpls_lse &= ~htonl(MPLS_BOS_MASK);
+    *mpls_lse |= htonl((bos & 0x1) << MPLS_BOS_SHIFT);
+}
+
 /* Set TTL in mpls lse. */
 static inline void
 flow_set_mpls_lse_ttl(ovs_be32 *mpls_lse, uint8_t ttl)
diff --git a/lib/tc.c b/lib/tc.c
index 85aa9a1..71aa55c 100644
--- a/lib/tc.c
+++ b/lib/tc.c
@@ -1243,6 +1243,10 @@  static const struct nl_policy mpls_policy[] = {
                          .min_len = sizeof(struct tc_mpls),
                          .optional = false, },
     [TCA_MPLS_PROTO] = { .type = NL_A_U16, .optional = true, },
+    [TCA_MPLS_LABEL] = { .type = NL_A_U32, .optional = true, },
+    [TCA_MPLS_TC] = { .type = NL_A_U8, .optional = true, },
+    [TCA_MPLS_TTL] = { .type = NL_A_U8, .optional = true, },
+    [TCA_MPLS_BOS] = { .type = NL_A_U8, .optional = true, },
 };
 
 static int
@@ -1251,8 +1255,12 @@  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 nlattr *mpls_label;
     struct tc_action *action;
     const struct tc_mpls *m;
+    struct nlattr *mpls_ttl;
+    struct nlattr *mpls_bos;
+    struct nlattr *mpls_tc;
 
     if (!nl_parse_nested(options, mpls_policy, mpls_attrs,
                          ARRAY_SIZE(mpls_policy))) {
@@ -1272,6 +1280,29 @@  nl_parse_act_mpls(struct nlattr *options, struct tc_flower *flower)
         }
         action->type = TC_ACT_MPLS_POP;
         break;
+    case TCA_MPLS_ACT_PUSH:
+        mpls_proto = mpls_attrs[TCA_MPLS_PROTO];
+        if (mpls_proto) {
+            action->mpls.proto = nl_attr_get_be16(mpls_proto);
+        }
+        mpls_label = mpls_attrs[TCA_MPLS_LABEL];
+        if (mpls_label) {
+            action->mpls.label = nl_attr_get_u32(mpls_label);
+        }
+        mpls_tc = mpls_attrs[TCA_MPLS_TC];
+        if (mpls_tc) {
+            action->mpls.tc = nl_attr_get_u8(mpls_tc);
+        }
+        mpls_ttl = mpls_attrs[TCA_MPLS_TTL];
+        if (mpls_ttl) {
+            action->mpls.ttl = nl_attr_get_u8(mpls_ttl);
+        }
+        mpls_bos = mpls_attrs[TCA_MPLS_BOS];
+        if (mpls_bos) {
+            action->mpls.bos = nl_attr_get_u8(mpls_bos);
+        }
+        action->type = TC_ACT_MPLS_PUSH;
+        break;
     default:
         VLOG_ERR_RL(&error_rl, "unknown mpls action: %d, %d",
                     m->action, m->m_action);
@@ -1712,6 +1743,28 @@  nl_msg_put_act_pop_mpls(struct ofpbuf *request, ovs_be16 proto)
 }
 
 static void
+nl_msg_put_act_push_mpls(struct ofpbuf *request, ovs_be16 proto,
+                         uint32_t label, uint8_t tc, uint8_t ttl, uint8_t bos)
+{
+    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_PUSH };
+
+        nl_msg_put_unspec(request, TCA_MPLS_PARMS, &parm, sizeof parm);
+        nl_msg_put_be16(request, TCA_MPLS_PROTO, proto);
+        nl_msg_put_u32(request, TCA_MPLS_LABEL, label);
+        nl_msg_put_u8(request, TCA_MPLS_TC, tc);
+        nl_msg_put_u8(request, TCA_MPLS_TTL, ttl);
+        nl_msg_put_u8(request, TCA_MPLS_BOS, bos);
+    }
+    nl_msg_end_nested(request, offset);
+}
+
+static void
 nl_msg_put_act_tunnel_key_release(struct ofpbuf *request)
 {
     size_t offset;
@@ -2094,6 +2147,14 @@  nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)
                 nl_msg_end_nested(request, act_offset);
             }
             break;
+            case TC_ACT_MPLS_PUSH: {
+                act_offset = nl_msg_start_nested(request, act_index++);
+                nl_msg_put_act_push_mpls(request, action->mpls.proto,
+                                         action->mpls.label, action->mpls.tc,
+                                         action->mpls.ttl, action->mpls.bos);
+                nl_msg_end_nested(request, act_offset);
+            }
+            break;
             case TC_ACT_OUTPUT: {
                 ingress = action->out.ingress;
                 ifindex = action->out.ifindex_out;
diff --git a/lib/tc.h b/lib/tc.h
index 7805f69..a498a84 100644
--- a/lib/tc.h
+++ b/lib/tc.h
@@ -154,6 +154,7 @@  enum tc_action_type {
     TC_ACT_VLAN_POP,
     TC_ACT_VLAN_PUSH,
     TC_ACT_MPLS_POP,
+    TC_ACT_MPLS_PUSH,
 };
 
 struct tc_action {
@@ -171,6 +172,10 @@  struct tc_action {
 
         struct {
             ovs_be16 proto;
+            uint32_t label;
+            uint8_t tc;
+            uint8_t ttl;
+            uint8_t bos;
         } mpls;
 
         struct {