[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20200523095548.GB20405@pc-3.home>
Date: Sat, 23 May 2020 11:55:48 +0200
From: Guillaume Nault <gnault@...hat.com>
To: David Miller <davem@...emloft.net>,
Jakub Kicinski <kuba@...nel.org>
Cc: John Hurley <john.hurley@...ronome.com>, netdev@...r.kernel.org,
Jamal Hadi Salim <jhs@...atatu.com>,
Cong Wang <xiyou.wangcong@...il.com>,
Jiri Pirko <jiri@...lanox.com>,
Tom Herbert <tom@...bertland.com>,
Pablo Neira Ayuso <pablo@...filter.org>,
Liel Shoshan <liels@...lanox.com>,
Rony Efraim <ronye@...lanox.com>
Subject: Re: [PATCH net-next v2 1/2] flow_dissector: Parse multiple MPLS
Label Stack Entries
[Cc: John Hurley <john.hurley@...ronome.com> for NFP driver review,
as Pieter Jansen van Vuuren and Benjamin LaHaise emails bounce]
On Thu, May 21, 2020 at 07:47:17PM +0200, Guillaume Nault wrote:
> The current MPLS dissector only parses the first MPLS Label Stack
> Entry (second LSE can be parsed too, but only to set a key_id).
>
> This patch adds the possibility to parse several LSEs by making
> __skb_flow_dissect_mpls() return FLOW_DISSECT_RET_PROTO_AGAIN as long
> as the Bottom Of Stack bit hasn't been seen, up to a maximum of
> FLOW_DIS_MPLS_MAX entries.
>
> FLOW_DIS_MPLS_MAX is arbitrarily set to 7. This should be enough for
> many practical purposes, without wasting too much space.
>
> To record the parsed values, flow_dissector_key_mpls is modified to
> store an array of stack entries, instead of just the values of the
> first one. A bit field, "used_lses", is also added to keep track of
> the LSEs that have been set. The objective is to avoid defining a
> new FLOW_DISSECTOR_KEY_MPLS_XX for each level of the MPLS stack.
>
> TC flower is adapted for the new struct flow_dissector_key_mpls layout.
> Matching on several MPLS Label Stack Entries will be added in the next
> patch.
>
> The NFP driver is also adapted: nfp_flower_compile_mac() now verifies
> that the rule only uses the first LSE and fails if it doesn't.
>
> Finally, the behaviour of the FLOW_DISSECTOR_KEY_MPLS_ENTROPY key is
> slightly modified. Instead of recording the first Entropy Label, it
> now records the last one. This shouldn't have any consequences since
> there doesn't seem to have any user of FLOW_DISSECTOR_KEY_MPLS_ENTROPY
> in the tree. We'd probably better do a hash of all parsed MPLS labels
> instead (excluding reserved labels) anyway. That'd give better entropy
> and would probably also simplify the code. But that's not the purpose
> of this patch, so I'm keeping that as a future possible improvement.
>
> Signed-off-by: Guillaume Nault <gnault@...hat.com>
> ---
> .../net/ethernet/netronome/nfp/flower/match.c | 42 +++++++++++----
> include/net/flow_dissector.h | 14 ++++-
> net/core/flow_dissector.c | 49 +++++++++++------
> net/sched/cls_flower.c | 52 +++++++++++++------
> 4 files changed, 113 insertions(+), 44 deletions(-)
>
> Note: the NFP driver update was only compile-tested. Review from
> Netronome highly encouraged.
>
> diff --git a/drivers/net/ethernet/netronome/nfp/flower/match.c b/drivers/net/ethernet/netronome/nfp/flower/match.c
> index 546bc01d507d..f7f01e2e3dce 100644
> --- a/drivers/net/ethernet/netronome/nfp/flower/match.c
> +++ b/drivers/net/ethernet/netronome/nfp/flower/match.c
> @@ -74,9 +74,10 @@ nfp_flower_compile_port(struct nfp_flower_in_port *frame, u32 cmsg_port,
> return 0;
> }
>
> -static void
> +static int
> 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(msk, 0, sizeof(struct nfp_flower_mac_mpls));
> @@ -97,14 +98,28 @@ nfp_flower_compile_mac(struct nfp_flower_mac_mpls *ext,
> u32 t_mpls;
>
> 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) |
> - FIELD_PREP(NFP_FLOWER_MASK_MPLS_BOS, match.key->mpls_bos) |
> +
> + /* Only support matching the first LSE */
> + 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;
> ext->mpls_lse = cpu_to_be32(t_mpls);
> - t_mpls = FIELD_PREP(NFP_FLOWER_MASK_MPLS_LB, match.mask->mpls_label) |
> - FIELD_PREP(NFP_FLOWER_MASK_MPLS_TC, match.mask->mpls_tc) |
> - FIELD_PREP(NFP_FLOWER_MASK_MPLS_BOS, match.mask->mpls_bos) |
> + t_mpls = FIELD_PREP(NFP_FLOWER_MASK_MPLS_LB,
> + match.mask->ls[0].mpls_label) |
> + 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;
> msk->mpls_lse = cpu_to_be32(t_mpls);
> } 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,
> msk->mpls_lse = cpu_to_be32(NFP_FLOWER_MASK_MPLS_Q);
> }
> }
> +
> + return 0;
> }
>
> static void
> @@ -461,9 +478,12 @@ int nfp_flower_compile_flow_match(struct nfp_app *app,
> msk += sizeof(struct nfp_flower_in_port);
>
> if (NFP_FLOWER_LAYER_MAC & key_ls->key_layer) {
> - nfp_flower_compile_mac((struct nfp_flower_mac_mpls *)ext,
> - (struct nfp_flower_mac_mpls *)msk,
> - rule);
> + err = nfp_flower_compile_mac((struct nfp_flower_mac_mpls *)ext,
> + (struct nfp_flower_mac_mpls *)msk,
> + rule, extack);
> + if (err)
> + return err;
> +
> ext += sizeof(struct nfp_flower_mac_mpls);
> msk += sizeof(struct nfp_flower_mac_mpls);
> }
> diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h
> index 628383915827..4fb1a69c6ecf 100644
> --- a/include/net/flow_dissector.h
> +++ b/include/net/flow_dissector.h
> @@ -59,13 +59,25 @@ struct flow_dissector_key_vlan {
> __be16 vlan_tpid;
> };
>
> -struct flow_dissector_key_mpls {
> +struct flow_dissector_mpls_lse {
> u32 mpls_ttl:8,
> mpls_bos:1,
> mpls_tc:3,
> 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
> /**
> * struct flow_dissector_key_enc_opts:
> diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
> index 3eff84824c8b..e26b6ed22f6b 100644
> --- a/net/core/flow_dissector.c
> +++ b/net/core/flow_dissector.c
> @@ -464,47 +464,59 @@ EXPORT_SYMBOL(skb_flow_dissect_tunnel_info);
> static enum flow_dissect_ret
> __skb_flow_dissect_mpls(const struct sk_buff *skb,
> 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[2];
> - u32 entry, label;
> + struct mpls_label *hdr, _hdr;
> + u32 entry, label, bos;
>
> if (!dissector_uses_key(flow_dissector,
> FLOW_DISSECTOR_KEY_MPLS_ENTROPY) &&
> !dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_MPLS))
> 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,
> hlen, &_hdr);
> if (!hdr)
> 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;
> + bos = (entry & MPLS_LS_S_MASK) >> MPLS_LS_S_SHIFT;
>
> if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_MPLS)) {
> struct flow_dissector_key_mpls *key_mpls;
> + struct flow_dissector_mpls_lse *lse;
>
> key_mpls = skb_flow_dissector_target(flow_dissector,
> FLOW_DISSECTOR_KEY_MPLS,
> target_container);
> - key_mpls->mpls_label = label;
> - key_mpls->mpls_ttl = (entry & MPLS_LS_TTL_MASK)
> - >> MPLS_LS_TTL_SHIFT;
> - key_mpls->mpls_tc = (entry & MPLS_LS_TC_MASK)
> - >> MPLS_LS_TC_SHIFT;
> - key_mpls->mpls_bos = (entry & MPLS_LS_S_MASK)
> - >> MPLS_LS_S_SHIFT;
> + lse = &key_mpls->ls[lse_index];
> +
> + lse->mpls_ttl = (entry & MPLS_LS_TTL_MASK) >> MPLS_LS_TTL_SHIFT;
> + lse->mpls_bos = bos;
> + lse->mpls_tc = (entry & MPLS_LS_TC_MASK) >> MPLS_LS_TC_SHIFT;
> + lse->mpls_label = label;
> + 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,
> FLOW_DISSECTOR_KEY_MPLS_ENTROPY,
> 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
> @@ -963,6 +975,8 @@ bool __skb_flow_dissect(const struct net *net,
> struct bpf_prog *attached = NULL;
> enum flow_dissect_ret fdret;
> enum flow_dissector_key_id dissector_vlan = FLOW_DISSECTOR_KEY_MAX;
> + bool mpls_el = false;
> + int mpls_lse = 0;
> int num_hdrs = 0;
> u8 ip_proto = 0;
> bool ret;
> @@ -1262,7 +1276,10 @@ bool __skb_flow_dissect(const struct net *net,
> case htons(ETH_P_MPLS_MC):
> fdret = __skb_flow_dissect_mpls(skb, flow_dissector,
> target_container, data,
> - nhoff, hlen);
> + nhoff, hlen, mpls_lse,
> + &mpls_el);
> + nhoff += sizeof(struct mpls_label);
> + mpls_lse++;
> break;
> case htons(ETH_P_FCOE):
> if ((hlen - nhoff) < FCOE_HEADER_LEN) {
> diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
> index 0c574700da75..f524afe0b7f5 100644
> --- a/net/sched/cls_flower.c
> +++ b/net/sched/cls_flower.c
> @@ -781,9 +781,17 @@ static int fl_set_key_mpls(struct nlattr **tb,
> struct flow_dissector_key_mpls *key_mask,
> struct netlink_ext_ack *extack)
> {
> + struct flow_dissector_mpls_lse *lse_mask;
> + struct flow_dissector_mpls_lse *lse_val;
> +
> + lse_val = &key_val->ls[0];
> + lse_mask = &key_mask->ls[0];
> +
> if (tb[TCA_FLOWER_KEY_MPLS_TTL]) {
> - key_val->mpls_ttl = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TTL]);
> - key_mask->mpls_ttl = MPLS_TTL_MASK;
> + lse_val->mpls_ttl = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TTL]);
> + lse_mask->mpls_ttl = MPLS_TTL_MASK;
> + dissector_set_mpls_lse(key_val, 0);
> + dissector_set_mpls_lse(key_mask, 0);
> }
> if (tb[TCA_FLOWER_KEY_MPLS_BOS]) {
> u8 bos = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_BOS]);
> @@ -794,8 +802,10 @@ static int fl_set_key_mpls(struct nlattr **tb,
> "Bottom Of Stack (BOS) must be 0 or 1");
> return -EINVAL;
> }
> - key_val->mpls_bos = bos;
> - key_mask->mpls_bos = MPLS_BOS_MASK;
> + lse_val->mpls_bos = bos;
> + lse_mask->mpls_bos = MPLS_BOS_MASK;
> + dissector_set_mpls_lse(key_val, 0);
> + dissector_set_mpls_lse(key_mask, 0);
> }
> if (tb[TCA_FLOWER_KEY_MPLS_TC]) {
> u8 tc = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TC]);
> @@ -806,8 +816,10 @@ static int fl_set_key_mpls(struct nlattr **tb,
> "Traffic Class (TC) must be between 0 and 7");
> return -EINVAL;
> }
> - key_val->mpls_tc = tc;
> - key_mask->mpls_tc = MPLS_TC_MASK;
> + lse_val->mpls_tc = tc;
> + lse_mask->mpls_tc = MPLS_TC_MASK;
> + dissector_set_mpls_lse(key_val, 0);
> + dissector_set_mpls_lse(key_mask, 0);
> }
> if (tb[TCA_FLOWER_KEY_MPLS_LABEL]) {
> u32 label = nla_get_u32(tb[TCA_FLOWER_KEY_MPLS_LABEL]);
> @@ -818,8 +830,10 @@ static int fl_set_key_mpls(struct nlattr **tb,
> "Label must be between 0 and 1048575");
> return -EINVAL;
> }
> - key_val->mpls_label = label;
> - key_mask->mpls_label = MPLS_LABEL_MASK;
> + lse_val->mpls_label = label;
> + lse_mask->mpls_label = MPLS_LABEL_MASK;
> + dissector_set_mpls_lse(key_val, 0);
> + dissector_set_mpls_lse(key_mask, 0);
> }
> return 0;
> }
> @@ -2222,31 +2236,37 @@ static int fl_dump_key_mpls(struct sk_buff *skb,
> struct flow_dissector_key_mpls *mpls_key,
> struct flow_dissector_key_mpls *mpls_mask)
> {
> + struct flow_dissector_mpls_lse *lse_mask;
> + struct flow_dissector_mpls_lse *lse_key;
> int err;
>
> if (!memchr_inv(mpls_mask, 0, sizeof(*mpls_mask)))
> return 0;
> - if (mpls_mask->mpls_ttl) {
> +
> + lse_mask = &mpls_mask->ls[0];
> + lse_key = &mpls_key->ls[0];
> +
> + if (lse_mask->mpls_ttl) {
> err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TTL,
> - mpls_key->mpls_ttl);
> + lse_key->mpls_ttl);
> if (err)
> return err;
> }
> - if (mpls_mask->mpls_tc) {
> + if (lse_mask->mpls_tc) {
> err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TC,
> - mpls_key->mpls_tc);
> + lse_key->mpls_tc);
> if (err)
> return err;
> }
> - if (mpls_mask->mpls_label) {
> + if (lse_mask->mpls_label) {
> err = nla_put_u32(skb, TCA_FLOWER_KEY_MPLS_LABEL,
> - mpls_key->mpls_label);
> + lse_key->mpls_label);
> if (err)
> return err;
> }
> - if (mpls_mask->mpls_bos) {
> + if (lse_mask->mpls_bos) {
> err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_BOS,
> - mpls_key->mpls_bos);
> + lse_key->mpls_bos);
> if (err)
> return err;
> }
> --
> 2.21.1
>
Powered by blists - more mailing lists