Skip to content

Commit 21e8a49

Browse files
committed
Merge branch 'nfp-Offload-MPLS-actions'
John Hurley says: ==================== nfp: Offload MPLS actions The module act_mpls has recently been added to the kernel. This allows the manipulation of MPLS headers on packets including push, pop and modify. Add these new actions and parameters to the intermediate representation API for hardware offload. Follow this by implementing the offload of these MPLS actions in the NFP driver. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 658688c + e03e47a commit 21e8a49

File tree

5 files changed

+260
-0
lines changed

5 files changed

+260
-0
lines changed

drivers/net/ethernet/netronome/nfp/flower/action.c

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
33

44
#include <linux/bitfield.h>
5+
#include <linux/mpls.h>
56
#include <net/pkt_cls.h>
67
#include <net/tc_act/tc_csum.h>
78
#include <net/tc_act/tc_gact.h>
89
#include <net/tc_act/tc_mirred.h>
10+
#include <net/tc_act/tc_mpls.h>
911
#include <net/tc_act/tc_pedit.h>
1012
#include <net/tc_act/tc_vlan.h>
1113
#include <net/tc_act/tc_tunnel_key.h>
@@ -25,6 +27,80 @@
2527
NFP_FL_TUNNEL_KEY | \
2628
NFP_FL_TUNNEL_GENEVE_OPT)
2729

30+
static int
31+
nfp_fl_push_mpls(struct nfp_fl_push_mpls *push_mpls,
32+
const struct flow_action_entry *act,
33+
struct netlink_ext_ack *extack)
34+
{
35+
size_t act_size = sizeof(struct nfp_fl_push_mpls);
36+
u32 mpls_lse = 0;
37+
38+
push_mpls->head.jump_id = NFP_FL_ACTION_OPCODE_PUSH_MPLS;
39+
push_mpls->head.len_lw = act_size >> NFP_FL_LW_SIZ;
40+
41+
/* BOS is optional in the TC action but required for offload. */
42+
if (act->mpls_push.bos != ACT_MPLS_BOS_NOT_SET) {
43+
mpls_lse |= act->mpls_push.bos << MPLS_LS_S_SHIFT;
44+
} else {
45+
NL_SET_ERR_MSG_MOD(extack, "unsupported offload: BOS field must explicitly be set for MPLS push");
46+
return -EOPNOTSUPP;
47+
}
48+
49+
/* Leave MPLS TC as a default value of 0 if not explicitly set. */
50+
if (act->mpls_push.tc != ACT_MPLS_TC_NOT_SET)
51+
mpls_lse |= act->mpls_push.tc << MPLS_LS_TC_SHIFT;
52+
53+
/* Proto, label and TTL are enforced and verified for MPLS push. */
54+
mpls_lse |= act->mpls_push.label << MPLS_LS_LABEL_SHIFT;
55+
mpls_lse |= act->mpls_push.ttl << MPLS_LS_TTL_SHIFT;
56+
push_mpls->ethtype = act->mpls_push.proto;
57+
push_mpls->lse = cpu_to_be32(mpls_lse);
58+
59+
return 0;
60+
}
61+
62+
static void
63+
nfp_fl_pop_mpls(struct nfp_fl_pop_mpls *pop_mpls,
64+
const struct flow_action_entry *act)
65+
{
66+
size_t act_size = sizeof(struct nfp_fl_pop_mpls);
67+
68+
pop_mpls->head.jump_id = NFP_FL_ACTION_OPCODE_POP_MPLS;
69+
pop_mpls->head.len_lw = act_size >> NFP_FL_LW_SIZ;
70+
pop_mpls->ethtype = act->mpls_pop.proto;
71+
}
72+
73+
static void
74+
nfp_fl_set_mpls(struct nfp_fl_set_mpls *set_mpls,
75+
const struct flow_action_entry *act)
76+
{
77+
size_t act_size = sizeof(struct nfp_fl_set_mpls);
78+
u32 mpls_lse = 0, mpls_mask = 0;
79+
80+
set_mpls->head.jump_id = NFP_FL_ACTION_OPCODE_SET_MPLS;
81+
set_mpls->head.len_lw = act_size >> NFP_FL_LW_SIZ;
82+
83+
if (act->mpls_mangle.label != ACT_MPLS_LABEL_NOT_SET) {
84+
mpls_lse |= act->mpls_mangle.label << MPLS_LS_LABEL_SHIFT;
85+
mpls_mask |= MPLS_LS_LABEL_MASK;
86+
}
87+
if (act->mpls_mangle.tc != ACT_MPLS_TC_NOT_SET) {
88+
mpls_lse |= act->mpls_mangle.tc << MPLS_LS_TC_SHIFT;
89+
mpls_mask |= MPLS_LS_TC_MASK;
90+
}
91+
if (act->mpls_mangle.bos != ACT_MPLS_BOS_NOT_SET) {
92+
mpls_lse |= act->mpls_mangle.bos << MPLS_LS_S_SHIFT;
93+
mpls_mask |= MPLS_LS_S_MASK;
94+
}
95+
if (act->mpls_mangle.ttl) {
96+
mpls_lse |= act->mpls_mangle.ttl << MPLS_LS_TTL_SHIFT;
97+
mpls_mask |= MPLS_LS_TTL_MASK;
98+
}
99+
100+
set_mpls->lse = cpu_to_be32(mpls_lse);
101+
set_mpls->lse_mask = cpu_to_be32(mpls_mask);
102+
}
103+
28104
static void nfp_fl_pop_vlan(struct nfp_fl_pop_vlan *pop_vlan)
29105
{
30106
size_t act_size = sizeof(struct nfp_fl_pop_vlan);
@@ -869,7 +945,10 @@ nfp_flower_loop_action(struct nfp_app *app, const struct flow_action_entry *act,
869945
struct nfp_fl_set_ipv4_tun *set_tun;
870946
struct nfp_fl_pre_tunnel *pre_tun;
871947
struct nfp_fl_push_vlan *psh_v;
948+
struct nfp_fl_push_mpls *psh_m;
872949
struct nfp_fl_pop_vlan *pop_v;
950+
struct nfp_fl_pop_mpls *pop_m;
951+
struct nfp_fl_set_mpls *set_m;
873952
int err;
874953

875954
switch (act->id) {
@@ -975,6 +1054,47 @@ nfp_flower_loop_action(struct nfp_app *app, const struct flow_action_entry *act,
9751054
*/
9761055
*csum_updated &= ~act->csum_flags;
9771056
break;
1057+
case FLOW_ACTION_MPLS_PUSH:
1058+
if (*a_len +
1059+
sizeof(struct nfp_fl_push_mpls) > NFP_FL_MAX_A_SIZ) {
1060+
NL_SET_ERR_MSG_MOD(extack, "unsupported offload: maximum allowed action list size exceeded at push MPLS");
1061+
return -EOPNOTSUPP;
1062+
}
1063+
1064+
psh_m = (struct nfp_fl_push_mpls *)&nfp_fl->action_data[*a_len];
1065+
nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL);
1066+
1067+
err = nfp_fl_push_mpls(psh_m, act, extack);
1068+
if (err)
1069+
return err;
1070+
*a_len += sizeof(struct nfp_fl_push_mpls);
1071+
break;
1072+
case FLOW_ACTION_MPLS_POP:
1073+
if (*a_len +
1074+
sizeof(struct nfp_fl_pop_mpls) > NFP_FL_MAX_A_SIZ) {
1075+
NL_SET_ERR_MSG_MOD(extack, "unsupported offload: maximum allowed action list size exceeded at pop MPLS");
1076+
return -EOPNOTSUPP;
1077+
}
1078+
1079+
pop_m = (struct nfp_fl_pop_mpls *)&nfp_fl->action_data[*a_len];
1080+
nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL);
1081+
1082+
nfp_fl_pop_mpls(pop_m, act);
1083+
*a_len += sizeof(struct nfp_fl_pop_mpls);
1084+
break;
1085+
case FLOW_ACTION_MPLS_MANGLE:
1086+
if (*a_len +
1087+
sizeof(struct nfp_fl_set_mpls) > NFP_FL_MAX_A_SIZ) {
1088+
NL_SET_ERR_MSG_MOD(extack, "unsupported offload: maximum allowed action list size exceeded at set MPLS");
1089+
return -EOPNOTSUPP;
1090+
}
1091+
1092+
set_m = (struct nfp_fl_set_mpls *)&nfp_fl->action_data[*a_len];
1093+
nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL);
1094+
1095+
nfp_fl_set_mpls(set_m, act);
1096+
*a_len += sizeof(struct nfp_fl_set_mpls);
1097+
break;
9781098
default:
9791099
/* Currently we do not handle any other actions. */
9801100
NL_SET_ERR_MSG_MOD(extack, "unsupported offload: unsupported action in action list");

drivers/net/ethernet/netronome/nfp/flower/cmsg.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,11 @@
6868
#define NFP_FL_ACTION_OPCODE_OUTPUT 0
6969
#define NFP_FL_ACTION_OPCODE_PUSH_VLAN 1
7070
#define NFP_FL_ACTION_OPCODE_POP_VLAN 2
71+
#define NFP_FL_ACTION_OPCODE_PUSH_MPLS 3
72+
#define NFP_FL_ACTION_OPCODE_POP_MPLS 4
7173
#define NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL 6
7274
#define NFP_FL_ACTION_OPCODE_SET_ETHERNET 7
75+
#define NFP_FL_ACTION_OPCODE_SET_MPLS 8
7376
#define NFP_FL_ACTION_OPCODE_SET_IPV4_ADDRS 9
7477
#define NFP_FL_ACTION_OPCODE_SET_IPV4_TTL_TOS 10
7578
#define NFP_FL_ACTION_OPCODE_SET_IPV6_SRC 11
@@ -232,6 +235,24 @@ struct nfp_fl_push_geneve {
232235
u8 opt_data[];
233236
};
234237

238+
struct nfp_fl_push_mpls {
239+
struct nfp_fl_act_head head;
240+
__be16 ethtype;
241+
__be32 lse;
242+
};
243+
244+
struct nfp_fl_pop_mpls {
245+
struct nfp_fl_act_head head;
246+
__be16 ethtype;
247+
};
248+
249+
struct nfp_fl_set_mpls {
250+
struct nfp_fl_act_head head;
251+
__be16 reserved;
252+
__be32 lse_mask;
253+
__be32 lse;
254+
};
255+
235256
/* Metadata with L2 (1W/4B)
236257
* ----------------------------------------------------------------
237258
* 3 2 1

include/net/flow_offload.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ enum flow_action_id {
131131
FLOW_ACTION_SAMPLE,
132132
FLOW_ACTION_POLICE,
133133
FLOW_ACTION_CT,
134+
FLOW_ACTION_MPLS_PUSH,
135+
FLOW_ACTION_MPLS_POP,
136+
FLOW_ACTION_MPLS_MANGLE,
134137
};
135138

136139
/* This is mirroring enum pedit_header_type definition for easy mapping between
@@ -184,6 +187,22 @@ struct flow_action_entry {
184187
int action;
185188
u16 zone;
186189
} ct;
190+
struct { /* FLOW_ACTION_MPLS_PUSH */
191+
u32 label;
192+
__be16 proto;
193+
u8 tc;
194+
u8 bos;
195+
u8 ttl;
196+
} mpls_push;
197+
struct { /* FLOW_ACTION_MPLS_POP */
198+
__be16 proto;
199+
} mpls_pop;
200+
struct { /* FLOW_ACTION_MPLS_MANGLE */
201+
u32 label;
202+
u8 tc;
203+
u8 bos;
204+
u8 ttl;
205+
} mpls_mangle;
187206
};
188207
};
189208

include/net/tc_act/tc_mpls.h

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,79 @@ struct tcf_mpls {
2727
};
2828
#define to_mpls(a) ((struct tcf_mpls *)a)
2929

30+
static inline bool is_tcf_mpls(const struct tc_action *a)
31+
{
32+
#ifdef CONFIG_NET_CLS_ACT
33+
if (a->ops && a->ops->id == TCA_ID_MPLS)
34+
return true;
35+
#endif
36+
return false;
37+
}
38+
39+
static inline u32 tcf_mpls_action(const struct tc_action *a)
40+
{
41+
u32 tcfm_action;
42+
43+
rcu_read_lock();
44+
tcfm_action = rcu_dereference(to_mpls(a)->mpls_p)->tcfm_action;
45+
rcu_read_unlock();
46+
47+
return tcfm_action;
48+
}
49+
50+
static inline __be16 tcf_mpls_proto(const struct tc_action *a)
51+
{
52+
__be16 tcfm_proto;
53+
54+
rcu_read_lock();
55+
tcfm_proto = rcu_dereference(to_mpls(a)->mpls_p)->tcfm_proto;
56+
rcu_read_unlock();
57+
58+
return tcfm_proto;
59+
}
60+
61+
static inline u32 tcf_mpls_label(const struct tc_action *a)
62+
{
63+
u32 tcfm_label;
64+
65+
rcu_read_lock();
66+
tcfm_label = rcu_dereference(to_mpls(a)->mpls_p)->tcfm_label;
67+
rcu_read_unlock();
68+
69+
return tcfm_label;
70+
}
71+
72+
static inline u8 tcf_mpls_tc(const struct tc_action *a)
73+
{
74+
u8 tcfm_tc;
75+
76+
rcu_read_lock();
77+
tcfm_tc = rcu_dereference(to_mpls(a)->mpls_p)->tcfm_tc;
78+
rcu_read_unlock();
79+
80+
return tcfm_tc;
81+
}
82+
83+
static inline u8 tcf_mpls_bos(const struct tc_action *a)
84+
{
85+
u8 tcfm_bos;
86+
87+
rcu_read_lock();
88+
tcfm_bos = rcu_dereference(to_mpls(a)->mpls_p)->tcfm_bos;
89+
rcu_read_unlock();
90+
91+
return tcfm_bos;
92+
}
93+
94+
static inline u8 tcf_mpls_ttl(const struct tc_action *a)
95+
{
96+
u8 tcfm_ttl;
97+
98+
rcu_read_lock();
99+
tcfm_ttl = rcu_dereference(to_mpls(a)->mpls_p)->tcfm_ttl;
100+
rcu_read_unlock();
101+
102+
return tcfm_ttl;
103+
}
104+
30105
#endif /* __NET_TC_MPLS_H */

net/sched/cls_api.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <net/tc_act/tc_sample.h>
3737
#include <net/tc_act/tc_skbedit.h>
3838
#include <net/tc_act/tc_ct.h>
39+
#include <net/tc_act/tc_mpls.h>
3940

4041
extern const struct nla_policy rtm_tca_policy[TCA_MAX + 1];
4142

@@ -3269,6 +3270,30 @@ int tc_setup_flow_action(struct flow_action *flow_action,
32693270
entry->id = FLOW_ACTION_CT;
32703271
entry->ct.action = tcf_ct_action(act);
32713272
entry->ct.zone = tcf_ct_zone(act);
3273+
} else if (is_tcf_mpls(act)) {
3274+
switch (tcf_mpls_action(act)) {
3275+
case TCA_MPLS_ACT_PUSH:
3276+
entry->id = FLOW_ACTION_MPLS_PUSH;
3277+
entry->mpls_push.proto = tcf_mpls_proto(act);
3278+
entry->mpls_push.label = tcf_mpls_label(act);
3279+
entry->mpls_push.tc = tcf_mpls_tc(act);
3280+
entry->mpls_push.bos = tcf_mpls_bos(act);
3281+
entry->mpls_push.ttl = tcf_mpls_ttl(act);
3282+
break;
3283+
case TCA_MPLS_ACT_POP:
3284+
entry->id = FLOW_ACTION_MPLS_POP;
3285+
entry->mpls_pop.proto = tcf_mpls_proto(act);
3286+
break;
3287+
case TCA_MPLS_ACT_MODIFY:
3288+
entry->id = FLOW_ACTION_MPLS_MANGLE;
3289+
entry->mpls_mangle.label = tcf_mpls_label(act);
3290+
entry->mpls_mangle.tc = tcf_mpls_tc(act);
3291+
entry->mpls_mangle.bos = tcf_mpls_bos(act);
3292+
entry->mpls_mangle.ttl = tcf_mpls_ttl(act);
3293+
break;
3294+
default:
3295+
goto err_out;
3296+
}
32723297
} else {
32733298
goto err_out;
32743299
}

0 commit comments

Comments
 (0)