nfp: flower: offload MPLS push action
authorJohn Hurley <john.hurley@netronome.com>
Tue, 23 Jul 2019 14:34:00 +0000 (15:34 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 23 Jul 2019 20:52:50 +0000 (13:52 -0700)
Recent additions to the kernel include a TC action module to manipulate
MPLS headers on packets. Such actions are available to offload via the
flow_offload intermediate representation API.

Modify the NFP driver to allow the offload of MPLS push actions to
firmware.

Signed-off-by: John Hurley <john.hurley@netronome.com>
Reviewed-by: Simon Horman <simon.horman@netronome.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/netronome/nfp/flower/action.c
drivers/net/ethernet/netronome/nfp/flower/cmsg.h

index 5a54fe8..9e18bec 100644 (file)
@@ -2,10 +2,12 @@
 /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
 
 #include <linux/bitfield.h>
+#include <linux/mpls.h>
 #include <net/pkt_cls.h>
 #include <net/tc_act/tc_csum.h>
 #include <net/tc_act/tc_gact.h>
 #include <net/tc_act/tc_mirred.h>
+#include <net/tc_act/tc_mpls.h>
 #include <net/tc_act/tc_pedit.h>
 #include <net/tc_act/tc_vlan.h>
 #include <net/tc_act/tc_tunnel_key.h>
                                                 NFP_FL_TUNNEL_KEY | \
                                                 NFP_FL_TUNNEL_GENEVE_OPT)
 
+static int
+nfp_fl_push_mpls(struct nfp_fl_push_mpls *push_mpls,
+                const struct flow_action_entry *act,
+                struct netlink_ext_ack *extack)
+{
+       size_t act_size = sizeof(struct nfp_fl_push_mpls);
+       u32 mpls_lse = 0;
+
+       push_mpls->head.jump_id = NFP_FL_ACTION_OPCODE_PUSH_MPLS;
+       push_mpls->head.len_lw = act_size >> NFP_FL_LW_SIZ;
+
+       /* BOS is optional in the TC action but required for offload. */
+       if (act->mpls_push.bos != ACT_MPLS_BOS_NOT_SET) {
+               mpls_lse |= act->mpls_push.bos << MPLS_LS_S_SHIFT;
+       } else {
+               NL_SET_ERR_MSG_MOD(extack, "unsupported offload: BOS field must explicitly be set for MPLS push");
+               return -EOPNOTSUPP;
+       }
+
+       /* Leave MPLS TC as a default value of 0 if not explicitly set. */
+       if (act->mpls_push.tc != ACT_MPLS_TC_NOT_SET)
+               mpls_lse |= act->mpls_push.tc << MPLS_LS_TC_SHIFT;
+
+       /* Proto, label and TTL are enforced and verified for MPLS push. */
+       mpls_lse |= act->mpls_push.label << MPLS_LS_LABEL_SHIFT;
+       mpls_lse |= act->mpls_push.ttl << MPLS_LS_TTL_SHIFT;
+       push_mpls->ethtype = act->mpls_push.proto;
+       push_mpls->lse = cpu_to_be32(mpls_lse);
+
+       return 0;
+}
+
 static void nfp_fl_pop_vlan(struct nfp_fl_pop_vlan *pop_vlan)
 {
        size_t act_size = sizeof(struct nfp_fl_pop_vlan);
@@ -869,6 +903,7 @@ nfp_flower_loop_action(struct nfp_app *app, const struct flow_action_entry *act,
        struct nfp_fl_set_ipv4_tun *set_tun;
        struct nfp_fl_pre_tunnel *pre_tun;
        struct nfp_fl_push_vlan *psh_v;
+       struct nfp_fl_push_mpls *psh_m;
        struct nfp_fl_pop_vlan *pop_v;
        int err;
 
@@ -975,6 +1010,21 @@ nfp_flower_loop_action(struct nfp_app *app, const struct flow_action_entry *act,
                 */
                *csum_updated &= ~act->csum_flags;
                break;
+       case FLOW_ACTION_MPLS_PUSH:
+               if (*a_len +
+                   sizeof(struct nfp_fl_push_mpls) > NFP_FL_MAX_A_SIZ) {
+                       NL_SET_ERR_MSG_MOD(extack, "unsupported offload: maximum allowed action list size exceeded at push MPLS");
+                       return -EOPNOTSUPP;
+               }
+
+               psh_m = (struct nfp_fl_push_mpls *)&nfp_fl->action_data[*a_len];
+               nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL);
+
+               err = nfp_fl_push_mpls(psh_m, act, extack);
+               if (err)
+                       return err;
+               *a_len += sizeof(struct nfp_fl_push_mpls);
+               break;
        default:
                /* Currently we do not handle any other actions. */
                NL_SET_ERR_MSG_MOD(extack, "unsupported offload: unsupported action in action list");
index 0f1706a..91af0fa 100644 (file)
@@ -68,6 +68,7 @@
 #define NFP_FL_ACTION_OPCODE_OUTPUT            0
 #define NFP_FL_ACTION_OPCODE_PUSH_VLAN         1
 #define NFP_FL_ACTION_OPCODE_POP_VLAN          2
+#define NFP_FL_ACTION_OPCODE_PUSH_MPLS         3
 #define NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL   6
 #define NFP_FL_ACTION_OPCODE_SET_ETHERNET      7
 #define NFP_FL_ACTION_OPCODE_SET_IPV4_ADDRS    9
@@ -232,6 +233,12 @@ struct nfp_fl_push_geneve {
        u8 opt_data[];
 };
 
+struct nfp_fl_push_mpls {
+       struct nfp_fl_act_head head;
+       __be16 ethtype;
+       __be32 lse;
+};
+
 /* Metadata with L2 (1W/4B)
  * ----------------------------------------------------------------
  *    3                   2                   1