[RAMEN9610-20741]UPSTREAM: xfrm: Extend the output_mark to support input direction...
authorSteffen Klassert <steffen.klassert@secunet.com>
Tue, 12 Jun 2018 10:44:26 +0000 (12:44 +0200)
committerrobot <robot@samsung.com>
Sun, 27 Oct 2019 17:53:34 +0000 (02:53 +0900)
We already support setting an output mark at the xfrm_state,
unfortunately this does not support the input direction and
masking the marks that will be applied to the skb. This change
adds support applying a masked value in both directions.

The existing XFRMA_OUTPUT_MARK number is reused for this purpose
and as it is now bi-directional, it is renamed to XFRMA_SET_MARK.

An additional XFRMA_SET_MARK_MASK attribute is added for setting the
mask. If the attribute mask not provided, it is set to 0xffffffff,
keeping the XFRMA_OUTPUT_MARK existing 'full mask' semantics.

Co-developed-by: Tobias Brunner <tobias@strongswan.org>
Co-developed-by: Eyal Birger <eyal.birger@gmail.com>
Co-developed-by: Lorenzo Colitti <lorenzo@google.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: Tobias Brunner <tobias@strongswan.org>
Signed-off-by: Eyal Birger <eyal.birger@gmail.com>
Signed-off-by: Lorenzo Colitti <lorenzo@google.com>
(cherry picked from commit 9b42c1f179a614e11893ae4619f0304a38f481ae)
Signed-off-by: Benedict Wong <benedictwong@google.com>
Bug: 113046120
Change-Id: I582f0b460dc58f01e0c30afb6167725aa337d054

include/net/xfrm.h
include/uapi/linux/xfrm.h
net/xfrm/xfrm_device.c
net/xfrm/xfrm_input.c
net/xfrm/xfrm_output.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_user.c

index db99efb2d1d0e0a64eeef13a2f712c619724fb38..404769f001200dd0dc1a9355b354bc5628794338 100644 (file)
@@ -166,7 +166,7 @@ struct xfrm_state {
                int             header_len;
                int             trailer_len;
                u32             extra_flags;
-               u32             output_mark;
+               struct xfrm_mark        smark;
        } props;
 
        struct xfrm_lifetime_cfg lft;
@@ -1948,6 +1948,13 @@ static inline int xfrm_mark_put(struct sk_buff *skb, const struct xfrm_mark *m)
        return ret;
 }
 
+static inline __u32 xfrm_smark_get(__u32 mark, struct xfrm_state *x)
+{
+       struct xfrm_mark *m = &x->props.smark;
+
+       return (m->v & m->m) | (mark & ~m->m);
+}
+
 static inline int xfrm_tunnel_check(struct sk_buff *skb, struct xfrm_state *x,
                                    unsigned int family)
 {
index e3af2859188bb1e52d6f0c49be7a9edb1a91dda7..5a6ed7ce5a295712c298482c87564ab88f788d69 100644 (file)
@@ -305,9 +305,11 @@ enum xfrm_attr_type_t {
        XFRMA_ADDRESS_FILTER,   /* struct xfrm_address_filter */
        XFRMA_PAD,
        XFRMA_OFFLOAD_DEV,      /* struct xfrm_state_offload */
-       XFRMA_OUTPUT_MARK,      /* __u32 */
+       XFRMA_SET_MARK,         /* __u32 */
+       XFRMA_SET_MARK_MASK,    /* __u32 */
        __XFRMA_MAX
 
+#define XFRMA_OUTPUT_MARK XFRMA_SET_MARK       /* Compatibility */
 #define XFRMA_MAX (__XFRMA_MAX - 1)
 };
 
index 30e5746085b8fcfc5aa8abc7a8a23753c510a630..4a6859e6d0fc0261897af9faf22180dfb1accff9 100644 (file)
@@ -80,7 +80,8 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
                }
 
                dst = __xfrm_dst_lookup(net, 0, 0, saddr, daddr,
-                                       x->props.family, x->props.output_mark);
+                                       x->props.family,
+                                       xfrm_smark_get(0, x));
                if (IS_ERR(dst))
                        return 0;
 
index 06dec32503bd66b18478e19c75255e348daaea58..949fe7aea4383a2e598f92475c21fc4a1a5f65d6 100644 (file)
@@ -339,6 +339,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
                        goto drop;
                }
 
+               skb->mark = xfrm_smark_get(skb->mark, x);
+
                skb->sp->xvec[skb->sp->len++] = x;
 
                skb_dst_force(skb);
index b226b230e8bf76bed2de0948353684b94ad237c3..97b191c3ede0770b4bad1d98edaa6272701cdff0 100644 (file)
@@ -66,8 +66,7 @@ static int xfrm_output_one(struct sk_buff *skb, int err)
                        goto error_nolock;
                }
 
-               if (x->props.output_mark)
-                       skb->mark = x->props.output_mark;
+               skb->mark = xfrm_smark_get(skb->mark, x);
 
                err = x->outer_mode->output(x, skb);
                if (err) {
index 70ec57b887f6371e0097290794418d977aa9f536..5604591dfda2b6319bbddfa3f69568d23b702b8c 100644 (file)
@@ -1605,10 +1605,11 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
                dst_copy_metrics(dst1, dst);
 
                if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
+                       __u32 mark = xfrm_smark_get(fl->flowi_mark, xfrm[i]);
+
                        family = xfrm[i]->props.family;
                        dst = xfrm_dst_lookup(xfrm[i], tos, fl->flowi_oif,
-                                             &saddr, &daddr, family,
-                                             xfrm[i]->props.output_mark);
+                                             &saddr, &daddr, family, mark);
                        err = PTR_ERR(dst);
                        if (IS_ERR(dst))
                                goto put_states;
index 46f8bba65f9bf8d6fcd5550a10707ef8e7cb8da2..cf28ee59a43a2d0aca4dcbb034ceb1c22c544eee 100644 (file)
@@ -533,6 +533,19 @@ static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs,
                x->replay_maxdiff = nla_get_u32(rt);
 }
 
+static void xfrm_smark_init(struct nlattr **attrs, struct xfrm_mark *m)
+{
+       if (attrs[XFRMA_SET_MARK]) {
+               m->v = nla_get_u32(attrs[XFRMA_SET_MARK]);
+               if (attrs[XFRMA_SET_MARK_MASK])
+                       m->m = nla_get_u32(attrs[XFRMA_SET_MARK_MASK]);
+               else
+                       m->m = 0xffffffff;
+       } else {
+               m->v = m->m = 0;
+       }
+}
+
 static struct xfrm_state *xfrm_state_construct(struct net *net,
                                               struct xfrm_usersa_info *p,
                                               struct nlattr **attrs,
@@ -585,8 +598,7 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
 
        xfrm_mark_get(attrs, &x->mark);
 
-       if (attrs[XFRMA_OUTPUT_MARK])
-               x->props.output_mark = nla_get_u32(attrs[XFRMA_OUTPUT_MARK]);
+       xfrm_smark_init(attrs, &x->props.smark);
 
        err = __xfrm_init_state(x, false, attrs[XFRMA_OFFLOAD_DEV]);
        if (err)
@@ -826,6 +838,18 @@ static int copy_to_user_auth(struct xfrm_algo_auth *auth, struct sk_buff *skb)
        return 0;
 }
 
+static int xfrm_smark_put(struct sk_buff *skb, struct xfrm_mark *m)
+{
+       int ret = 0;
+
+       if (m->v | m->m) {
+               ret = nla_put_u32(skb, XFRMA_SET_MARK, m->v);
+               if (!ret)
+                       ret = nla_put_u32(skb, XFRMA_SET_MARK_MASK, m->m);
+       }
+       return ret;
+}
+
 /* Don't change this without updating xfrm_sa_len! */
 static int copy_to_user_state_extra(struct xfrm_state *x,
                                    struct xfrm_usersa_info *p,
@@ -889,6 +913,11 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
        ret = xfrm_mark_put(skb, &x->mark);
        if (ret)
                goto out;
+
+       ret = xfrm_smark_put(skb, &x->props.smark);
+       if (ret)
+               goto out;
+
        if (x->replay_esn)
                ret = nla_put(skb, XFRMA_REPLAY_ESN_VAL,
                              xfrm_replay_state_esn_len(x->replay_esn),
@@ -902,11 +931,7 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
                ret = copy_user_offload(&x->xso, skb);
        if (ret)
                goto out;
-       if (x->props.output_mark) {
-               ret = nla_put_u32(skb, XFRMA_OUTPUT_MARK, x->props.output_mark);
-               if (ret)
-                       goto out;
-       }
+
        if (x->security)
                ret = copy_sec_ctx(x->security, skb);
 out:
@@ -2509,7 +2534,8 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
        [XFRMA_PROTO]           = { .type = NLA_U8 },
        [XFRMA_ADDRESS_FILTER]  = { .len = sizeof(struct xfrm_address_filter) },
        [XFRMA_OFFLOAD_DEV]     = { .len = sizeof(struct xfrm_user_offload) },
-       [XFRMA_OUTPUT_MARK]     = { .type = NLA_U32 },
+       [XFRMA_SET_MARK]        = { .type = NLA_U32 },
+       [XFRMA_SET_MARK_MASK]   = { .type = NLA_U32 },
 };
 
 static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = {
@@ -2736,8 +2762,10 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x)
                l += nla_total_size(sizeof(x->props.extra_flags));
        if (x->xso.dev)
                 l += nla_total_size(sizeof(x->xso));
-       if (x->props.output_mark)
-               l += nla_total_size(sizeof(x->props.output_mark));
+       if (x->props.smark.v | x->props.smark.m) {
+               l += nla_total_size(sizeof(x->props.smark.v));
+               l += nla_total_size(sizeof(x->props.smark.m));
+       }
 
        /* Must count x->lastused as it may become non-zero behind our back. */
        l += nla_total_size_64bit(sizeof(u64));