This patch adds the xfrm interface id as a lookup key
for xfrm states and policies. With this we can assign
states and policies to virtual xfrm interfaces.

Signed-off-by: Steffen Klassert <steffen.klass...@secunet.com>
Acked-by: Shannon Nelson <shannon.nel...@oracle.com>
Acked-by: Benedict Wong <benedictw...@google.com>
Tested-by: Benedict Wong <benedictw...@google.com>
Tested-by: Antony Antony <ant...@phenome.org>
Reviewed-by: Eyal Birger <eyal.bir...@gmail.com>
---
 include/net/xfrm.h        | 21 +++++++++++++-----
 include/uapi/linux/xfrm.h |  1 +
 net/core/pktgen.c         |  2 +-
 net/key/af_key.c          |  6 +++---
 net/xfrm/xfrm_policy.c    | 18 +++++++++++-----
 net/xfrm/xfrm_state.c     | 19 ++++++++++++-----
 net/xfrm/xfrm_user.c      | 54 +++++++++++++++++++++++++++++++++++++++++------
 7 files changed, 96 insertions(+), 25 deletions(-)

diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 3dc83ba26f62..e8bada4d2a45 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -147,6 +147,7 @@ struct xfrm_state {
        struct xfrm_id          id;
        struct xfrm_selector    sel;
        struct xfrm_mark        mark;
+       u32                     if_id;
        u32                     tfcpad;
 
        u32                     genid;
@@ -574,6 +575,7 @@ struct xfrm_policy {
        atomic_t                genid;
        u32                     priority;
        u32                     index;
+       u32                     if_id;
        struct xfrm_mark        mark;
        struct xfrm_selector    selector;
        struct xfrm_lifetime_cfg lft;
@@ -1533,7 +1535,7 @@ struct xfrm_state *xfrm_state_find(const xfrm_address_t 
*daddr,
                                   struct xfrm_tmpl *tmpl,
                                   struct xfrm_policy *pol, int *err,
                                   unsigned short family);
-struct xfrm_state *xfrm_stateonly_find(struct net *net, u32 mark,
+struct xfrm_state *xfrm_stateonly_find(struct net *net, u32 mark, u32 if_id,
                                       xfrm_address_t *daddr,
                                       xfrm_address_t *saddr,
                                       unsigned short family,
@@ -1690,20 +1692,20 @@ int xfrm_policy_walk(struct net *net, struct 
xfrm_policy_walk *walk,
                     void *);
 void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net);
 int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
-struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark,
+struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u32 if_id,
                                          u8 type, int dir,
                                          struct xfrm_selector *sel,
                                          struct xfrm_sec_ctx *ctx, int delete,
                                          int *err);
-struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8, int dir,
-                                    u32 id, int delete, int *err);
+struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u32 if_id, u8,
+                                    int dir, u32 id, int delete, int *err);
 int xfrm_policy_flush(struct net *net, u8 type, bool task_valid);
 void xfrm_policy_hash_rebuild(struct net *net);
 u32 xfrm_get_acqseq(void);
 int verify_spi_info(u8 proto, u32 min, u32 max);
 int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi);
 struct xfrm_state *xfrm_find_acq(struct net *net, const struct xfrm_mark *mark,
-                                u8 mode, u32 reqid, u8 proto,
+                                u8 mode, u32 reqid, u32 if_id, u8 proto,
                                 const xfrm_address_t *daddr,
                                 const xfrm_address_t *saddr, int create,
                                 unsigned short family);
@@ -2019,6 +2021,15 @@ static inline __u32 xfrm_smark_get(__u32 mark, struct 
xfrm_state *x)
        return (m->v & m->m) | (mark & ~m->m);
 }
 
+static inline int xfrm_if_id_put(struct sk_buff *skb, __u32 if_id)
+{
+       int ret = 0;
+
+       if (if_id)
+               ret = nla_put_u32(skb, XFRMA_IF_ID, if_id);
+       return ret;
+}
+
 static inline int xfrm_tunnel_check(struct sk_buff *skb, struct xfrm_state *x,
                                    unsigned int family)
 {
diff --git a/include/uapi/linux/xfrm.h b/include/uapi/linux/xfrm.h
index 5a6ed7ce5a29..5f3b9fec7b5f 100644
--- a/include/uapi/linux/xfrm.h
+++ b/include/uapi/linux/xfrm.h
@@ -307,6 +307,7 @@ enum xfrm_attr_type_t {
        XFRMA_OFFLOAD_DEV,      /* struct xfrm_state_offload */
        XFRMA_SET_MARK,         /* __u32 */
        XFRMA_SET_MARK_MASK,    /* __u32 */
+       XFRMA_IF_ID,            /* __u32 */
        __XFRMA_MAX
 
 #define XFRMA_OUTPUT_MARK XFRMA_SET_MARK       /* Compatibility */
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 49368e21d228..6d37dbf0aa64 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -2255,7 +2255,7 @@ static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int 
flow)
                        x = xfrm_state_lookup_byspi(pn->net, 
htonl(pkt_dev->spi), AF_INET);
                } else {
                        /* slow path: we dont already have xfrm_state */
-                       x = xfrm_stateonly_find(pn->net, DUMMY_MARK,
+                       x = xfrm_stateonly_find(pn->net, DUMMY_MARK, 0,
                                                (xfrm_address_t 
*)&pkt_dev->cur_daddr,
                                                (xfrm_address_t 
*)&pkt_dev->cur_saddr,
                                                AF_INET,
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 8bdc1cbe490a..398ebcd614a0 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -1383,7 +1383,7 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff 
*skb, const struct sadb_
        }
 
        if (!x)
-               x = xfrm_find_acq(net, &dummy_mark, mode, reqid, proto, xdaddr, 
xsaddr, 1, family);
+               x = xfrm_find_acq(net, &dummy_mark, mode, reqid, 0, proto, 
xdaddr, xsaddr, 1, family);
 
        if (x == NULL)
                return -ENOENT;
@@ -2414,7 +2414,7 @@ static int pfkey_spddelete(struct sock *sk, struct 
sk_buff *skb, const struct sa
                        return err;
        }
 
-       xp = xfrm_policy_bysel_ctx(net, DUMMY_MARK, XFRM_POLICY_TYPE_MAIN,
+       xp = xfrm_policy_bysel_ctx(net, DUMMY_MARK, 0, XFRM_POLICY_TYPE_MAIN,
                                   pol->sadb_x_policy_dir - 1, &sel, pol_ctx,
                                   1, &err);
        security_xfrm_policy_free(pol_ctx);
@@ -2663,7 +2663,7 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff 
*skb, const struct sadb_
                return -EINVAL;
 
        delete = (hdr->sadb_msg_type == SADB_X_SPDDELETE2);
-       xp = xfrm_policy_byid(net, DUMMY_MARK, XFRM_POLICY_TYPE_MAIN,
+       xp = xfrm_policy_byid(net, DUMMY_MARK, 0, XFRM_POLICY_TYPE_MAIN,
                              dir, pol->sadb_x_policy_id, delete, &err);
        if (xp == NULL)
                return -ENOENT;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 7637637717ec..fc0c69312b2c 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -747,6 +747,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, 
int excl)
        newpos = NULL;
        hlist_for_each_entry(pol, chain, bydst) {
                if (pol->type == policy->type &&
+                   pol->if_id == policy->if_id &&
                    !selector_cmp(&pol->selector, &policy->selector) &&
                    xfrm_policy_mark_match(policy, pol) &&
                    xfrm_sec_ctx_match(pol->security, policy->security) &&
@@ -798,8 +799,9 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, 
int excl)
 }
 EXPORT_SYMBOL(xfrm_policy_insert);
 
-struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
-                                         int dir, struct xfrm_selector *sel,
+struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u32 if_id,
+                                         u8 type, int dir,
+                                         struct xfrm_selector *sel,
                                          struct xfrm_sec_ctx *ctx, int delete,
                                          int *err)
 {
@@ -812,6 +814,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, 
u32 mark, u8 type,
        ret = NULL;
        hlist_for_each_entry(pol, chain, bydst) {
                if (pol->type == type &&
+                   pol->if_id == if_id &&
                    (mark & pol->mark.m) == pol->mark.v &&
                    !selector_cmp(sel, &pol->selector) &&
                    xfrm_sec_ctx_match(ctx, pol->security)) {
@@ -837,8 +840,9 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, 
u32 mark, u8 type,
 }
 EXPORT_SYMBOL(xfrm_policy_bysel_ctx);
 
-struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
-                                    int dir, u32 id, int delete, int *err)
+struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u32 if_id,
+                                    u8 type, int dir, u32 id, int delete,
+                                    int *err)
 {
        struct xfrm_policy *pol, *ret;
        struct hlist_head *chain;
@@ -853,6 +857,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 
mark, u8 type,
        ret = NULL;
        hlist_for_each_entry(pol, chain, byidx) {
                if (pol->type == type && pol->index == id &&
+                   pol->if_id == if_id &&
                    (mark & pol->mark.m) == pol->mark.v) {
                        xfrm_pol_hold(pol);
                        if (delete) {
@@ -1063,6 +1068,7 @@ static int xfrm_policy_match(const struct xfrm_policy 
*pol,
        bool match;
 
        if (pol->family != family ||
+           pol->if_id != fl->flowi_xfrm.if_id ||
            (fl->flowi_mark & pol->mark.m) != pol->mark.v ||
            pol->type != type)
                return ret;
@@ -1177,7 +1183,8 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(const 
struct sock *sk, int dir,
 
                match = xfrm_selector_match(&pol->selector, fl, family);
                if (match) {
-                       if ((sk->sk_mark & pol->mark.m) != pol->mark.v) {
+                       if ((sk->sk_mark & pol->mark.m) != pol->mark.v ||
+                           pol->if_id != fl->flowi_xfrm.if_id) {
                                pol = NULL;
                                goto out;
                        }
@@ -1305,6 +1312,7 @@ static struct xfrm_policy *clone_policy(const struct 
xfrm_policy *old, int dir)
                newp->lft = old->lft;
                newp->curlft = old->curlft;
                newp->mark = old->mark;
+               newp->if_id = old->if_id;
                newp->action = old->action;
                newp->flags = old->flags;
                newp->xfrm_nr = old->xfrm_nr;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 8308281f3253..3803b6813fc5 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -941,6 +941,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const 
xfrm_address_t *saddr,
        int error = 0;
        struct xfrm_state *best = NULL;
        u32 mark = pol->mark.v & pol->mark.m;
+       u32 if_id = fl->flowi_xfrm.if_id;
        unsigned short encap_family = tmpl->encap_family;
        unsigned int sequence;
        struct km_event c;
@@ -955,6 +956,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const 
xfrm_address_t *saddr,
                if (x->props.family == encap_family &&
                    x->props.reqid == tmpl->reqid &&
                    (mark & x->mark.m) == x->mark.v &&
+                   x->if_id == if_id &&
                    !(x->props.flags & XFRM_STATE_WILDRECV) &&
                    xfrm_state_addr_check(x, daddr, saddr, encap_family) &&
                    tmpl->mode == x->props.mode &&
@@ -971,6 +973,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const 
xfrm_address_t *saddr,
                if (x->props.family == encap_family &&
                    x->props.reqid == tmpl->reqid &&
                    (mark & x->mark.m) == x->mark.v &&
+                   x->if_id == if_id &&
                    !(x->props.flags & XFRM_STATE_WILDRECV) &&
                    xfrm_addr_equal(&x->id.daddr, daddr, encap_family) &&
                    tmpl->mode == x->props.mode &&
@@ -1010,6 +1013,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const 
xfrm_address_t *saddr,
                 * to current session. */
                xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family);
                memcpy(&x->mark, &pol->mark, sizeof(x->mark));
+               x->if_id = if_id;
 
                error = security_xfrm_state_alloc_acquire(x, pol->security, 
fl->flowi_secid);
                if (error) {
@@ -1067,7 +1071,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const 
xfrm_address_t *saddr,
 }
 
 struct xfrm_state *
-xfrm_stateonly_find(struct net *net, u32 mark,
+xfrm_stateonly_find(struct net *net, u32 mark, u32 if_id,
                    xfrm_address_t *daddr, xfrm_address_t *saddr,
                    unsigned short family, u8 mode, u8 proto, u32 reqid)
 {
@@ -1080,6 +1084,7 @@ xfrm_stateonly_find(struct net *net, u32 mark,
                if (x->props.family == family &&
                    x->props.reqid == reqid &&
                    (mark & x->mark.m) == x->mark.v &&
+                   x->if_id == if_id &&
                    !(x->props.flags & XFRM_STATE_WILDRECV) &&
                    xfrm_state_addr_check(x, daddr, saddr, family) &&
                    mode == x->props.mode &&
@@ -1160,11 +1165,13 @@ static void __xfrm_state_bump_genids(struct xfrm_state 
*xnew)
        struct xfrm_state *x;
        unsigned int h;
        u32 mark = xnew->mark.v & xnew->mark.m;
+       u32 if_id = xnew->if_id;
 
        h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, 
family);
        hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
                if (x->props.family     == family &&
                    x->props.reqid      == reqid &&
+                   x->if_id            == if_id &&
                    (mark & x->mark.m) == x->mark.v &&
                    xfrm_addr_equal(&x->id.daddr, &xnew->id.daddr, family) &&
                    xfrm_addr_equal(&x->props.saddr, &xnew->props.saddr, 
family))
@@ -1187,7 +1194,7 @@ EXPORT_SYMBOL(xfrm_state_insert);
 static struct xfrm_state *__find_acq_core(struct net *net,
                                          const struct xfrm_mark *m,
                                          unsigned short family, u8 mode,
-                                         u32 reqid, u8 proto,
+                                         u32 reqid, u32 if_id, u8 proto,
                                          const xfrm_address_t *daddr,
                                          const xfrm_address_t *saddr,
                                          int create)
@@ -1242,6 +1249,7 @@ static struct xfrm_state *__find_acq_core(struct net *net,
                x->props.family = family;
                x->props.mode = mode;
                x->props.reqid = reqid;
+               x->if_id = if_id;
                x->mark.v = m->v;
                x->mark.m = m->m;
                x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
@@ -1296,7 +1304,7 @@ int xfrm_state_add(struct xfrm_state *x)
 
        if (use_spi && !x1)
                x1 = __find_acq_core(net, &x->mark, family, x->props.mode,
-                                    x->props.reqid, x->id.proto,
+                                    x->props.reqid, x->if_id, x->id.proto,
                                     &x->id.daddr, &x->props.saddr, 0);
 
        __xfrm_state_bump_genids(x);
@@ -1395,6 +1403,7 @@ static struct xfrm_state *xfrm_state_clone(struct 
xfrm_state *orig,
        x->props.flags = orig->props.flags;
        x->props.extra_flags = orig->props.extra_flags;
 
+       x->if_id = orig->if_id;
        x->tfcpad = orig->tfcpad;
        x->replay_maxdiff = orig->replay_maxdiff;
        x->replay_maxage = orig->replay_maxage;
@@ -1619,13 +1628,13 @@ EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
 
 struct xfrm_state *
 xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 
reqid,
-             u8 proto, const xfrm_address_t *daddr,
+             u32 if_id, u8 proto, const xfrm_address_t *daddr,
              const xfrm_address_t *saddr, int create, unsigned short family)
 {
        struct xfrm_state *x;
 
        spin_lock_bh(&net->xfrm.xfrm_state_lock);
-       x = __find_acq_core(net, mark, family, mode, reqid, proto, daddr, 
saddr, create);
+       x = __find_acq_core(net, mark, family, mode, reqid, if_id, proto, 
daddr, saddr, create);
        spin_unlock_bh(&net->xfrm.xfrm_state_lock);
 
        return x;
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 9602cc9e05ab..79245e1c3487 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -594,6 +594,9 @@ static struct xfrm_state *xfrm_state_construct(struct net 
*net,
 
        xfrm_smark_init(attrs, &x->props.smark);
 
+       if (attrs[XFRMA_IF_ID])
+               x->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
+
        err = __xfrm_init_state(x, false, attrs[XFRMA_OFFLOAD_DEV]);
        if (err)
                goto error;
@@ -929,7 +932,11 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
                ret = copy_user_offload(&x->xso, skb);
        if (ret)
                goto out;
-
+       if (x->if_id) {
+               ret = nla_put_u32(skb, XFRMA_IF_ID, x->if_id);
+               if (ret)
+                       goto out;
+       }
        if (x->security)
                ret = copy_sec_ctx(x->security, skb);
 out:
@@ -1278,6 +1285,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct 
nlmsghdr *nlh,
        int err;
        u32 mark;
        struct xfrm_mark m;
+       u32 if_id = 0;
 
        p = nlmsg_data(nlh);
        err = verify_spi_info(p->info.id.proto, p->min, p->max);
@@ -1290,6 +1298,10 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, 
struct nlmsghdr *nlh,
        x = NULL;
 
        mark = xfrm_mark_get(attrs, &m);
+
+       if (attrs[XFRMA_IF_ID])
+               if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
+
        if (p->info.seq) {
                x = xfrm_find_acq_byseq(net, mark, p->info.seq);
                if (x && !xfrm_addr_equal(&x->id.daddr, daddr, family)) {
@@ -1300,7 +1312,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct 
nlmsghdr *nlh,
 
        if (!x)
                x = xfrm_find_acq(net, &m, p->info.mode, p->info.reqid,
-                                 p->info.id.proto, daddr,
+                                 if_id, p->info.id.proto, daddr,
                                  &p->info.saddr, 1,
                                  family);
        err = -ENOENT;
@@ -1588,6 +1600,9 @@ static struct xfrm_policy *xfrm_policy_construct(struct 
net *net, struct xfrm_us
 
        xfrm_mark_get(attrs, &xp->mark);
 
+       if (attrs[XFRMA_IF_ID])
+               xp->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
+
        return xp;
  error:
        *errp = err;
@@ -1733,6 +1748,8 @@ static int dump_one_policy(struct xfrm_policy *xp, int 
dir, int count, void *ptr
                err = copy_to_user_policy_type(xp->type, skb);
        if (!err)
                err = xfrm_mark_put(skb, &xp->mark);
+       if (!err)
+               err = xfrm_if_id_put(skb, xp->if_id);
        if (err) {
                nlmsg_cancel(skb, nlh);
                return err;
@@ -1814,6 +1831,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct 
nlmsghdr *nlh,
        int delete;
        struct xfrm_mark m;
        u32 mark = xfrm_mark_get(attrs, &m);
+       u32 if_id = 0;
 
        p = nlmsg_data(nlh);
        delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY;
@@ -1826,8 +1844,11 @@ static int xfrm_get_policy(struct sk_buff *skb, struct 
nlmsghdr *nlh,
        if (err)
                return err;
 
+       if (attrs[XFRMA_IF_ID])
+               if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
+
        if (p->index)
-               xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, 
delete, &err);
+               xp = xfrm_policy_byid(net, mark, if_id, type, p->dir, p->index, 
delete, &err);
        else {
                struct nlattr *rt = attrs[XFRMA_SEC_CTX];
                struct xfrm_sec_ctx *ctx;
@@ -1844,7 +1865,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct 
nlmsghdr *nlh,
                        if (err)
                                return err;
                }
-               xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir, &p->sel,
+               xp = xfrm_policy_bysel_ctx(net, mark, if_id, type, p->dir, 
&p->sel,
                                           ctx, delete, &err);
                security_xfrm_policy_free(ctx);
        }
@@ -1967,6 +1988,10 @@ static int build_aevent(struct sk_buff *skb, struct 
xfrm_state *x, const struct
        if (err)
                goto out_cancel;
 
+       err = xfrm_if_id_put(skb, x->if_id);
+       if (err)
+               goto out_cancel;
+
        nlmsg_end(skb, nlh);
        return 0;
 
@@ -2109,6 +2134,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, 
struct nlmsghdr *nlh,
        int err = -ENOENT;
        struct xfrm_mark m;
        u32 mark = xfrm_mark_get(attrs, &m);
+       u32 if_id = 0;
 
        err = copy_from_user_policy_type(&type, attrs);
        if (err)
@@ -2118,8 +2144,11 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, 
struct nlmsghdr *nlh,
        if (err)
                return err;
 
+       if (attrs[XFRMA_IF_ID])
+               if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
+
        if (p->index)
-               xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, 0, 
&err);
+               xp = xfrm_policy_byid(net, mark, if_id, type, p->dir, p->index, 
0, &err);
        else {
                struct nlattr *rt = attrs[XFRMA_SEC_CTX];
                struct xfrm_sec_ctx *ctx;
@@ -2136,7 +2165,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, 
struct nlmsghdr *nlh,
                        if (err)
                                return err;
                }
-               xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir,
+               xp = xfrm_policy_bysel_ctx(net, mark, if_id, type, p->dir,
                                           &p->sel, ctx, 0, &err);
                security_xfrm_policy_free(ctx);
        }
@@ -2520,6 +2549,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] 
= {
        [XFRMA_OFFLOAD_DEV]     = { .len = sizeof(struct xfrm_user_offload) },
        [XFRMA_SET_MARK]        = { .type = NLA_U32 },
        [XFRMA_SET_MARK_MASK]   = { .type = NLA_U32 },
+       [XFRMA_IF_ID]           = { .type = NLA_U32 },
 };
 
 static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = {
@@ -2651,6 +2681,10 @@ static int build_expire(struct sk_buff *skb, struct 
xfrm_state *x, const struct
        if (err)
                return err;
 
+       err = xfrm_if_id_put(skb, x->if_id);
+       if (err)
+               return err;
+
        nlmsg_end(skb, nlh);
        return 0;
 }
@@ -2749,6 +2783,8 @@ static inline unsigned int xfrm_sa_len(struct xfrm_state 
*x)
                l += nla_total_size(sizeof(x->props.smark.v));
                l += nla_total_size(sizeof(x->props.smark.m));
        }
+       if (x->if_id)
+               l += nla_total_size(sizeof(x->if_id));
 
        /* Must count x->lastused as it may become non-zero behind our back. */
        l += nla_total_size_64bit(sizeof(u64));
@@ -2878,6 +2914,8 @@ static int build_acquire(struct sk_buff *skb, struct 
xfrm_state *x,
                err = copy_to_user_policy_type(xp->type, skb);
        if (!err)
                err = xfrm_mark_put(skb, &xp->mark);
+       if (!err)
+               err = xfrm_if_id_put(skb, xp->if_id);
        if (err) {
                nlmsg_cancel(skb, nlh);
                return err;
@@ -2994,6 +3032,8 @@ static int build_polexpire(struct sk_buff *skb, struct 
xfrm_policy *xp,
                err = copy_to_user_policy_type(xp->type, skb);
        if (!err)
                err = xfrm_mark_put(skb, &xp->mark);
+       if (!err)
+               err = xfrm_if_id_put(skb, xp->if_id);
        if (err) {
                nlmsg_cancel(skb, nlh);
                return err;
@@ -3075,6 +3115,8 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int 
dir, const struct km_e
                err = copy_to_user_policy_type(xp->type, skb);
        if (!err)
                err = xfrm_mark_put(skb, &xp->mark);
+       if (!err)
+               err = xfrm_if_id_put(skb, xp->if_id);
        if (err)
                goto out_free_skb;
 
-- 
2.14.1

Reply via email to