Commit 8928e19a authored by David S. Miller's avatar David S. Miller

Merge branch 'flow-mpls'

Guillaume Nault says:

====================
flow_dissector, cls_flower: Add support for multiple MPLS Label Stack Entries

Currently, the flow dissector and the Flower classifier can only handle
the first entry of an MPLS label stack. This patch series generalises
the code to allow parsing and matching the Label Stack Entries that
follow.

Patch 1 extends the flow dissector to parse MPLS LSEs until the Bottom
Of Stack bit is reached. The number of parsed LSEs is capped at
FLOW_DIS_MPLS_MAX (arbitrarily set to 7). Flower and the NFP driver
are updated to take into account the new layout of struct
flow_dissector_key_mpls.

Patch 2 extends Flower. It defines new netlink attributes, which are
independent from the previous MPLS ones. Mixing the old and the new
attributes in a same filter is not allowed. For backward compatibility,
the old attributes are used when dumping filters that don't require the
new ones.

Changes since v2:
  * Fix compilation with the new MLX5 bareudp tunnel code.

Changes since v1:
  * Fix compilation of NFP driver (kbuild test robot).
  * Fix sparse warning with entropy label (kbuild test robot).
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents fb8ddaa9 61aec25a
...@@ -101,25 +101,36 @@ static int parse_tunnel(struct mlx5e_priv *priv, ...@@ -101,25 +101,36 @@ static int parse_tunnel(struct mlx5e_priv *priv,
flow_rule_match_mpls(rule, &match); flow_rule_match_mpls(rule, &match);
/* Only support matching the first LSE */
if (match.mask->used_lses != 1)
return -EOPNOTSUPP;
MLX5_SET(fte_match_set_misc2, misc2_c, MLX5_SET(fte_match_set_misc2, misc2_c,
outer_first_mpls_over_udp.mpls_label, match.mask->mpls_label); outer_first_mpls_over_udp.mpls_label,
match.mask->ls[0].mpls_label);
MLX5_SET(fte_match_set_misc2, misc2_v, MLX5_SET(fte_match_set_misc2, misc2_v,
outer_first_mpls_over_udp.mpls_label, match.key->mpls_label); outer_first_mpls_over_udp.mpls_label,
match.key->ls[0].mpls_label);
MLX5_SET(fte_match_set_misc2, misc2_c, MLX5_SET(fte_match_set_misc2, misc2_c,
outer_first_mpls_over_udp.mpls_exp, match.mask->mpls_tc); outer_first_mpls_over_udp.mpls_exp,
match.mask->ls[0].mpls_tc);
MLX5_SET(fte_match_set_misc2, misc2_v, MLX5_SET(fte_match_set_misc2, misc2_v,
outer_first_mpls_over_udp.mpls_exp, match.key->mpls_tc); outer_first_mpls_over_udp.mpls_exp, match.key->ls[0].mpls_tc);
MLX5_SET(fte_match_set_misc2, misc2_c, MLX5_SET(fte_match_set_misc2, misc2_c,
outer_first_mpls_over_udp.mpls_s_bos, match.mask->mpls_bos); outer_first_mpls_over_udp.mpls_s_bos,
match.mask->ls[0].mpls_bos);
MLX5_SET(fte_match_set_misc2, misc2_v, MLX5_SET(fte_match_set_misc2, misc2_v,
outer_first_mpls_over_udp.mpls_s_bos, match.key->mpls_bos); outer_first_mpls_over_udp.mpls_s_bos,
match.key->ls[0].mpls_bos);
MLX5_SET(fte_match_set_misc2, misc2_c, MLX5_SET(fte_match_set_misc2, misc2_c,
outer_first_mpls_over_udp.mpls_ttl, match.mask->mpls_ttl); outer_first_mpls_over_udp.mpls_ttl,
match.mask->ls[0].mpls_ttl);
MLX5_SET(fte_match_set_misc2, misc2_v, MLX5_SET(fte_match_set_misc2, misc2_v,
outer_first_mpls_over_udp.mpls_ttl, match.key->mpls_ttl); outer_first_mpls_over_udp.mpls_ttl,
match.key->ls[0].mpls_ttl);
spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2; spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
return 0; return 0;
......
...@@ -74,9 +74,10 @@ nfp_flower_compile_port(struct nfp_flower_in_port *frame, u32 cmsg_port, ...@@ -74,9 +74,10 @@ nfp_flower_compile_port(struct nfp_flower_in_port *frame, u32 cmsg_port,
return 0; return 0;
} }
static void static int
nfp_flower_compile_mac(struct nfp_flower_mac_mpls *ext, nfp_flower_compile_mac(struct nfp_flower_mac_mpls *ext,
struct nfp_flower_mac_mpls *msk, struct flow_rule *rule) struct nfp_flower_mac_mpls *msk, struct flow_rule *rule,
struct netlink_ext_ack *extack)
{ {
memset(ext, 0, sizeof(struct nfp_flower_mac_mpls)); memset(ext, 0, sizeof(struct nfp_flower_mac_mpls));
memset(msk, 0, sizeof(struct nfp_flower_mac_mpls)); memset(msk, 0, sizeof(struct nfp_flower_mac_mpls));
...@@ -97,14 +98,28 @@ nfp_flower_compile_mac(struct nfp_flower_mac_mpls *ext, ...@@ -97,14 +98,28 @@ nfp_flower_compile_mac(struct nfp_flower_mac_mpls *ext,
u32 t_mpls; u32 t_mpls;
flow_rule_match_mpls(rule, &match); flow_rule_match_mpls(rule, &match);
t_mpls = FIELD_PREP(NFP_FLOWER_MASK_MPLS_LB, match.key->mpls_label) |
FIELD_PREP(NFP_FLOWER_MASK_MPLS_TC, match.key->mpls_tc) | /* Only support matching the first LSE */
FIELD_PREP(NFP_FLOWER_MASK_MPLS_BOS, match.key->mpls_bos) | if (match.mask->used_lses != 1) {
NL_SET_ERR_MSG_MOD(extack,
"unsupported offload: invalid LSE depth for MPLS match offload");
return -EOPNOTSUPP;
}
t_mpls = FIELD_PREP(NFP_FLOWER_MASK_MPLS_LB,
match.key->ls[0].mpls_label) |
FIELD_PREP(NFP_FLOWER_MASK_MPLS_TC,
match.key->ls[0].mpls_tc) |
FIELD_PREP(NFP_FLOWER_MASK_MPLS_BOS,
match.key->ls[0].mpls_bos) |
NFP_FLOWER_MASK_MPLS_Q; NFP_FLOWER_MASK_MPLS_Q;
ext->mpls_lse = cpu_to_be32(t_mpls); ext->mpls_lse = cpu_to_be32(t_mpls);
t_mpls = FIELD_PREP(NFP_FLOWER_MASK_MPLS_LB, match.mask->mpls_label) | t_mpls = FIELD_PREP(NFP_FLOWER_MASK_MPLS_LB,
FIELD_PREP(NFP_FLOWER_MASK_MPLS_TC, match.mask->mpls_tc) | match.mask->ls[0].mpls_label) |
FIELD_PREP(NFP_FLOWER_MASK_MPLS_BOS, match.mask->mpls_bos) | FIELD_PREP(NFP_FLOWER_MASK_MPLS_TC,
match.mask->ls[0].mpls_tc) |
FIELD_PREP(NFP_FLOWER_MASK_MPLS_BOS,
match.mask->ls[0].mpls_bos) |
NFP_FLOWER_MASK_MPLS_Q; NFP_FLOWER_MASK_MPLS_Q;
msk->mpls_lse = cpu_to_be32(t_mpls); msk->mpls_lse = cpu_to_be32(t_mpls);
} else if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) { } else if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
...@@ -121,6 +136,8 @@ nfp_flower_compile_mac(struct nfp_flower_mac_mpls *ext, ...@@ -121,6 +136,8 @@ nfp_flower_compile_mac(struct nfp_flower_mac_mpls *ext,
msk->mpls_lse = cpu_to_be32(NFP_FLOWER_MASK_MPLS_Q); msk->mpls_lse = cpu_to_be32(NFP_FLOWER_MASK_MPLS_Q);
} }
} }
return 0;
} }
static void static void
...@@ -461,9 +478,12 @@ int nfp_flower_compile_flow_match(struct nfp_app *app, ...@@ -461,9 +478,12 @@ int nfp_flower_compile_flow_match(struct nfp_app *app,
msk += sizeof(struct nfp_flower_in_port); msk += sizeof(struct nfp_flower_in_port);
if (NFP_FLOWER_LAYER_MAC & key_ls->key_layer) { if (NFP_FLOWER_LAYER_MAC & key_ls->key_layer) {
nfp_flower_compile_mac((struct nfp_flower_mac_mpls *)ext, err = nfp_flower_compile_mac((struct nfp_flower_mac_mpls *)ext,
(struct nfp_flower_mac_mpls *)msk, (struct nfp_flower_mac_mpls *)msk,
rule); rule, extack);
if (err)
return err;
ext += sizeof(struct nfp_flower_mac_mpls); ext += sizeof(struct nfp_flower_mac_mpls);
msk += sizeof(struct nfp_flower_mac_mpls); msk += sizeof(struct nfp_flower_mac_mpls);
} }
......
...@@ -59,13 +59,25 @@ struct flow_dissector_key_vlan { ...@@ -59,13 +59,25 @@ struct flow_dissector_key_vlan {
__be16 vlan_tpid; __be16 vlan_tpid;
}; };
struct flow_dissector_key_mpls { struct flow_dissector_mpls_lse {
u32 mpls_ttl:8, u32 mpls_ttl:8,
mpls_bos:1, mpls_bos:1,
mpls_tc:3, mpls_tc:3,
mpls_label:20; mpls_label:20;
}; };
#define FLOW_DIS_MPLS_MAX 7
struct flow_dissector_key_mpls {
struct flow_dissector_mpls_lse ls[FLOW_DIS_MPLS_MAX]; /* Label Stack */
u8 used_lses; /* One bit set for each Label Stack Entry in use */
};
static inline void dissector_set_mpls_lse(struct flow_dissector_key_mpls *mpls,
int lse_index)
{
mpls->used_lses |= 1 << lse_index;
}
#define FLOW_DIS_TUN_OPTS_MAX 255 #define FLOW_DIS_TUN_OPTS_MAX 255
/** /**
* struct flow_dissector_key_enc_opts: * struct flow_dissector_key_enc_opts:
......
...@@ -576,6 +576,8 @@ enum { ...@@ -576,6 +576,8 @@ enum {
TCA_FLOWER_KEY_CT_LABELS, /* u128 */ TCA_FLOWER_KEY_CT_LABELS, /* u128 */
TCA_FLOWER_KEY_CT_LABELS_MASK, /* u128 */ TCA_FLOWER_KEY_CT_LABELS_MASK, /* u128 */
TCA_FLOWER_KEY_MPLS_OPTS,
__TCA_FLOWER_MAX, __TCA_FLOWER_MAX,
}; };
...@@ -640,6 +642,27 @@ enum { ...@@ -640,6 +642,27 @@ enum {
#define TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX \ #define TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX \
(__TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX - 1) (__TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX - 1)
enum {
TCA_FLOWER_KEY_MPLS_OPTS_UNSPEC,
TCA_FLOWER_KEY_MPLS_OPTS_LSE,
__TCA_FLOWER_KEY_MPLS_OPTS_MAX,
};
#define TCA_FLOWER_KEY_MPLS_OPTS_MAX (__TCA_FLOWER_KEY_MPLS_OPTS_MAX - 1)
enum {
TCA_FLOWER_KEY_MPLS_OPT_LSE_UNSPEC,
TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH,
TCA_FLOWER_KEY_MPLS_OPT_LSE_TTL,
TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS,
TCA_FLOWER_KEY_MPLS_OPT_LSE_TC,
TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL,
__TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX,
};
#define TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX \
(__TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX - 1)
enum { enum {
TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT = (1 << 0), TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT = (1 << 0),
TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST = (1 << 1), TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST = (1 << 1),
......
...@@ -480,47 +480,59 @@ EXPORT_SYMBOL(skb_flow_dissect_tunnel_info); ...@@ -480,47 +480,59 @@ EXPORT_SYMBOL(skb_flow_dissect_tunnel_info);
static enum flow_dissect_ret static enum flow_dissect_ret
__skb_flow_dissect_mpls(const struct sk_buff *skb, __skb_flow_dissect_mpls(const struct sk_buff *skb,
struct flow_dissector *flow_dissector, struct flow_dissector *flow_dissector,
void *target_container, void *data, int nhoff, int hlen) void *target_container, void *data, int nhoff, int hlen,
int lse_index, bool *entropy_label)
{ {
struct flow_dissector_key_keyid *key_keyid; struct mpls_label *hdr, _hdr;
struct mpls_label *hdr, _hdr[2]; u32 entry, label, bos;
u32 entry, label;
if (!dissector_uses_key(flow_dissector, if (!dissector_uses_key(flow_dissector,
FLOW_DISSECTOR_KEY_MPLS_ENTROPY) && FLOW_DISSECTOR_KEY_MPLS_ENTROPY) &&
!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_MPLS)) !dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_MPLS))
return FLOW_DISSECT_RET_OUT_GOOD; return FLOW_DISSECT_RET_OUT_GOOD;
if (lse_index >= FLOW_DIS_MPLS_MAX)
return FLOW_DISSECT_RET_OUT_GOOD;
hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data,
hlen, &_hdr); hlen, &_hdr);
if (!hdr) if (!hdr)
return FLOW_DISSECT_RET_OUT_BAD; return FLOW_DISSECT_RET_OUT_BAD;
entry = ntohl(hdr[0].entry); entry = ntohl(hdr->entry);
label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT; label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT;
bos = (entry & MPLS_LS_S_MASK) >> MPLS_LS_S_SHIFT;
if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_MPLS)) { if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_MPLS)) {
struct flow_dissector_key_mpls *key_mpls; struct flow_dissector_key_mpls *key_mpls;
struct flow_dissector_mpls_lse *lse;
key_mpls = skb_flow_dissector_target(flow_dissector, key_mpls = skb_flow_dissector_target(flow_dissector,
FLOW_DISSECTOR_KEY_MPLS, FLOW_DISSECTOR_KEY_MPLS,
target_container); target_container);
key_mpls->mpls_label = label; lse = &key_mpls->ls[lse_index];
key_mpls->mpls_ttl = (entry & MPLS_LS_TTL_MASK)
>> MPLS_LS_TTL_SHIFT; lse->mpls_ttl = (entry & MPLS_LS_TTL_MASK) >> MPLS_LS_TTL_SHIFT;
key_mpls->mpls_tc = (entry & MPLS_LS_TC_MASK) lse->mpls_bos = bos;
>> MPLS_LS_TC_SHIFT; lse->mpls_tc = (entry & MPLS_LS_TC_MASK) >> MPLS_LS_TC_SHIFT;
key_mpls->mpls_bos = (entry & MPLS_LS_S_MASK) lse->mpls_label = label;
>> MPLS_LS_S_SHIFT; dissector_set_mpls_lse(key_mpls, lse_index);
} }
if (label == MPLS_LABEL_ENTROPY) { if (*entropy_label &&
dissector_uses_key(flow_dissector,
FLOW_DISSECTOR_KEY_MPLS_ENTROPY)) {
struct flow_dissector_key_keyid *key_keyid;
key_keyid = skb_flow_dissector_target(flow_dissector, key_keyid = skb_flow_dissector_target(flow_dissector,
FLOW_DISSECTOR_KEY_MPLS_ENTROPY, FLOW_DISSECTOR_KEY_MPLS_ENTROPY,
target_container); target_container);
key_keyid->keyid = hdr[1].entry & htonl(MPLS_LS_LABEL_MASK); key_keyid->keyid = cpu_to_be32(label);
} }
return FLOW_DISSECT_RET_OUT_GOOD;
*entropy_label = label == MPLS_LABEL_ENTROPY;
return bos ? FLOW_DISSECT_RET_OUT_GOOD : FLOW_DISSECT_RET_PROTO_AGAIN;
} }
static enum flow_dissect_ret static enum flow_dissect_ret
...@@ -979,6 +991,8 @@ bool __skb_flow_dissect(const struct net *net, ...@@ -979,6 +991,8 @@ bool __skb_flow_dissect(const struct net *net,
struct bpf_prog *attached = NULL; struct bpf_prog *attached = NULL;
enum flow_dissect_ret fdret; enum flow_dissect_ret fdret;
enum flow_dissector_key_id dissector_vlan = FLOW_DISSECTOR_KEY_MAX; enum flow_dissector_key_id dissector_vlan = FLOW_DISSECTOR_KEY_MAX;
bool mpls_el = false;
int mpls_lse = 0;
int num_hdrs = 0; int num_hdrs = 0;
u8 ip_proto = 0; u8 ip_proto = 0;
bool ret; bool ret;
...@@ -1278,7 +1292,10 @@ bool __skb_flow_dissect(const struct net *net, ...@@ -1278,7 +1292,10 @@ bool __skb_flow_dissect(const struct net *net,
case htons(ETH_P_MPLS_MC): case htons(ETH_P_MPLS_MC):
fdret = __skb_flow_dissect_mpls(skb, flow_dissector, fdret = __skb_flow_dissect_mpls(skb, flow_dissector,
target_container, data, target_container, data,
nhoff, hlen); nhoff, hlen, mpls_lse,
&mpls_el);
nhoff += sizeof(struct mpls_label);
mpls_lse++;
break; break;
case htons(ETH_P_FCOE): case htons(ETH_P_FCOE):
if ((hlen - nhoff) < FCOE_HEADER_LEN) { if ((hlen - nhoff) < FCOE_HEADER_LEN) {
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment