summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteffen Klassert <steffen.klassert@secunet.com>2018-06-12 08:07:07 -0400
committerSteffen Klassert <steffen.klassert@secunet.com>2018-06-23 10:07:15 -0400
commit7e6526404adedf079279aa7aa11722deaca8fe2e (patch)
tree64a7db3916d2f5bf24dfd17f495f27eb9cc1beca
parentd159ce7957eec306eacda672e5909e26675ca8ef (diff)
xfrm: Add a new lookup key to match xfrm interfaces.
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.klassert@secunet.com> Acked-by: Shannon Nelson <shannon.nelson@oracle.com> Acked-by: Benedict Wong <benedictwong@google.com> Tested-by: Benedict Wong <benedictwong@google.com> Tested-by: Antony Antony <antony@phenome.org> Reviewed-by: Eyal Birger <eyal.birger@gmail.com>
-rw-r--r--include/net/xfrm.h21
-rw-r--r--include/uapi/linux/xfrm.h1
-rw-r--r--net/core/pktgen.c2
-rw-r--r--net/key/af_key.c6
-rw-r--r--net/xfrm/xfrm_policy.c18
-rw-r--r--net/xfrm/xfrm_state.c19
-rw-r--r--net/xfrm/xfrm_user.c54
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 {
147 struct xfrm_id id; 147 struct xfrm_id id;
148 struct xfrm_selector sel; 148 struct xfrm_selector sel;
149 struct xfrm_mark mark; 149 struct xfrm_mark mark;
150 u32 if_id;
150 u32 tfcpad; 151 u32 tfcpad;
151 152
152 u32 genid; 153 u32 genid;
@@ -574,6 +575,7 @@ struct xfrm_policy {
574 atomic_t genid; 575 atomic_t genid;
575 u32 priority; 576 u32 priority;
576 u32 index; 577 u32 index;
578 u32 if_id;
577 struct xfrm_mark mark; 579 struct xfrm_mark mark;
578 struct xfrm_selector selector; 580 struct xfrm_selector selector;
579 struct xfrm_lifetime_cfg lft; 581 struct xfrm_lifetime_cfg lft;
@@ -1533,7 +1535,7 @@ struct xfrm_state *xfrm_state_find(const xfrm_address_t *daddr,
1533 struct xfrm_tmpl *tmpl, 1535 struct xfrm_tmpl *tmpl,
1534 struct xfrm_policy *pol, int *err, 1536 struct xfrm_policy *pol, int *err,
1535 unsigned short family); 1537 unsigned short family);
1536struct xfrm_state *xfrm_stateonly_find(struct net *net, u32 mark, 1538struct xfrm_state *xfrm_stateonly_find(struct net *net, u32 mark, u32 if_id,
1537 xfrm_address_t *daddr, 1539 xfrm_address_t *daddr,
1538 xfrm_address_t *saddr, 1540 xfrm_address_t *saddr,
1539 unsigned short family, 1541 unsigned short family,
@@ -1690,20 +1692,20 @@ int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
1690 void *); 1692 void *);
1691void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net); 1693void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net);
1692int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); 1694int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
1693struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, 1695struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u32 if_id,
1694 u8 type, int dir, 1696 u8 type, int dir,
1695 struct xfrm_selector *sel, 1697 struct xfrm_selector *sel,
1696 struct xfrm_sec_ctx *ctx, int delete, 1698 struct xfrm_sec_ctx *ctx, int delete,
1697 int *err); 1699 int *err);
1698struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8, int dir, 1700struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u32 if_id, u8,
1699 u32 id, int delete, int *err); 1701 int dir, u32 id, int delete, int *err);
1700int xfrm_policy_flush(struct net *net, u8 type, bool task_valid); 1702int xfrm_policy_flush(struct net *net, u8 type, bool task_valid);
1701void xfrm_policy_hash_rebuild(struct net *net); 1703void xfrm_policy_hash_rebuild(struct net *net);
1702u32 xfrm_get_acqseq(void); 1704u32 xfrm_get_acqseq(void);
1703int verify_spi_info(u8 proto, u32 min, u32 max); 1705int verify_spi_info(u8 proto, u32 min, u32 max);
1704int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi); 1706int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi);
1705struct xfrm_state *xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, 1707struct xfrm_state *xfrm_find_acq(struct net *net, const struct xfrm_mark *mark,
1706 u8 mode, u32 reqid, u8 proto, 1708 u8 mode, u32 reqid, u32 if_id, u8 proto,
1707 const xfrm_address_t *daddr, 1709 const xfrm_address_t *daddr,
1708 const xfrm_address_t *saddr, int create, 1710 const xfrm_address_t *saddr, int create,
1709 unsigned short family); 1711 unsigned short family);
@@ -2019,6 +2021,15 @@ static inline __u32 xfrm_smark_get(__u32 mark, struct xfrm_state *x)
2019 return (m->v & m->m) | (mark & ~m->m); 2021 return (m->v & m->m) | (mark & ~m->m);
2020} 2022}
2021 2023
2024static inline int xfrm_if_id_put(struct sk_buff *skb, __u32 if_id)
2025{
2026 int ret = 0;
2027
2028 if (if_id)
2029 ret = nla_put_u32(skb, XFRMA_IF_ID, if_id);
2030 return ret;
2031}
2032
2022static inline int xfrm_tunnel_check(struct sk_buff *skb, struct xfrm_state *x, 2033static inline int xfrm_tunnel_check(struct sk_buff *skb, struct xfrm_state *x,
2023 unsigned int family) 2034 unsigned int family)
2024{ 2035{
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 {
307 XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */ 307 XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */
308 XFRMA_SET_MARK, /* __u32 */ 308 XFRMA_SET_MARK, /* __u32 */
309 XFRMA_SET_MARK_MASK, /* __u32 */ 309 XFRMA_SET_MARK_MASK, /* __u32 */
310 XFRMA_IF_ID, /* __u32 */
310 __XFRMA_MAX 311 __XFRMA_MAX
311 312
312#define XFRMA_OUTPUT_MARK XFRMA_SET_MARK /* Compatibility */ 313#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)
2255 x = xfrm_state_lookup_byspi(pn->net, htonl(pkt_dev->spi), AF_INET); 2255 x = xfrm_state_lookup_byspi(pn->net, htonl(pkt_dev->spi), AF_INET);
2256 } else { 2256 } else {
2257 /* slow path: we dont already have xfrm_state */ 2257 /* slow path: we dont already have xfrm_state */
2258 x = xfrm_stateonly_find(pn->net, DUMMY_MARK, 2258 x = xfrm_stateonly_find(pn->net, DUMMY_MARK, 0,
2259 (xfrm_address_t *)&pkt_dev->cur_daddr, 2259 (xfrm_address_t *)&pkt_dev->cur_daddr,
2260 (xfrm_address_t *)&pkt_dev->cur_saddr, 2260 (xfrm_address_t *)&pkt_dev->cur_saddr,
2261 AF_INET, 2261 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_
1383 } 1383 }
1384 1384
1385 if (!x) 1385 if (!x)
1386 x = xfrm_find_acq(net, &dummy_mark, mode, reqid, proto, xdaddr, xsaddr, 1, family); 1386 x = xfrm_find_acq(net, &dummy_mark, mode, reqid, 0, proto, xdaddr, xsaddr, 1, family);
1387 1387
1388 if (x == NULL) 1388 if (x == NULL)
1389 return -ENOENT; 1389 return -ENOENT;
@@ -2414,7 +2414,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, const struct sa
2414 return err; 2414 return err;
2415 } 2415 }
2416 2416
2417 xp = xfrm_policy_bysel_ctx(net, DUMMY_MARK, XFRM_POLICY_TYPE_MAIN, 2417 xp = xfrm_policy_bysel_ctx(net, DUMMY_MARK, 0, XFRM_POLICY_TYPE_MAIN,
2418 pol->sadb_x_policy_dir - 1, &sel, pol_ctx, 2418 pol->sadb_x_policy_dir - 1, &sel, pol_ctx,
2419 1, &err); 2419 1, &err);
2420 security_xfrm_policy_free(pol_ctx); 2420 security_xfrm_policy_free(pol_ctx);
@@ -2663,7 +2663,7 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, const struct sadb_
2663 return -EINVAL; 2663 return -EINVAL;
2664 2664
2665 delete = (hdr->sadb_msg_type == SADB_X_SPDDELETE2); 2665 delete = (hdr->sadb_msg_type == SADB_X_SPDDELETE2);
2666 xp = xfrm_policy_byid(net, DUMMY_MARK, XFRM_POLICY_TYPE_MAIN, 2666 xp = xfrm_policy_byid(net, DUMMY_MARK, 0, XFRM_POLICY_TYPE_MAIN,
2667 dir, pol->sadb_x_policy_id, delete, &err); 2667 dir, pol->sadb_x_policy_id, delete, &err);
2668 if (xp == NULL) 2668 if (xp == NULL)
2669 return -ENOENT; 2669 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)
747 newpos = NULL; 747 newpos = NULL;
748 hlist_for_each_entry(pol, chain, bydst) { 748 hlist_for_each_entry(pol, chain, bydst) {
749 if (pol->type == policy->type && 749 if (pol->type == policy->type &&
750 pol->if_id == policy->if_id &&
750 !selector_cmp(&pol->selector, &policy->selector) && 751 !selector_cmp(&pol->selector, &policy->selector) &&
751 xfrm_policy_mark_match(policy, pol) && 752 xfrm_policy_mark_match(policy, pol) &&
752 xfrm_sec_ctx_match(pol->security, policy->security) && 753 xfrm_sec_ctx_match(pol->security, policy->security) &&
@@ -798,8 +799,9 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
798} 799}
799EXPORT_SYMBOL(xfrm_policy_insert); 800EXPORT_SYMBOL(xfrm_policy_insert);
800 801
801struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, 802struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u32 if_id,
802 int dir, struct xfrm_selector *sel, 803 u8 type, int dir,
804 struct xfrm_selector *sel,
803 struct xfrm_sec_ctx *ctx, int delete, 805 struct xfrm_sec_ctx *ctx, int delete,
804 int *err) 806 int *err)
805{ 807{
@@ -812,6 +814,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
812 ret = NULL; 814 ret = NULL;
813 hlist_for_each_entry(pol, chain, bydst) { 815 hlist_for_each_entry(pol, chain, bydst) {
814 if (pol->type == type && 816 if (pol->type == type &&
817 pol->if_id == if_id &&
815 (mark & pol->mark.m) == pol->mark.v && 818 (mark & pol->mark.m) == pol->mark.v &&
816 !selector_cmp(sel, &pol->selector) && 819 !selector_cmp(sel, &pol->selector) &&
817 xfrm_sec_ctx_match(ctx, pol->security)) { 820 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,
837} 840}
838EXPORT_SYMBOL(xfrm_policy_bysel_ctx); 841EXPORT_SYMBOL(xfrm_policy_bysel_ctx);
839 842
840struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type, 843struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u32 if_id,
841 int dir, u32 id, int delete, int *err) 844 u8 type, int dir, u32 id, int delete,
845 int *err)
842{ 846{
843 struct xfrm_policy *pol, *ret; 847 struct xfrm_policy *pol, *ret;
844 struct hlist_head *chain; 848 struct hlist_head *chain;
@@ -853,6 +857,7 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
853 ret = NULL; 857 ret = NULL;
854 hlist_for_each_entry(pol, chain, byidx) { 858 hlist_for_each_entry(pol, chain, byidx) {
855 if (pol->type == type && pol->index == id && 859 if (pol->type == type && pol->index == id &&
860 pol->if_id == if_id &&
856 (mark & pol->mark.m) == pol->mark.v) { 861 (mark & pol->mark.m) == pol->mark.v) {
857 xfrm_pol_hold(pol); 862 xfrm_pol_hold(pol);
858 if (delete) { 863 if (delete) {
@@ -1063,6 +1068,7 @@ static int xfrm_policy_match(const struct xfrm_policy *pol,
1063 bool match; 1068 bool match;
1064 1069
1065 if (pol->family != family || 1070 if (pol->family != family ||
1071 pol->if_id != fl->flowi_xfrm.if_id ||
1066 (fl->flowi_mark & pol->mark.m) != pol->mark.v || 1072 (fl->flowi_mark & pol->mark.m) != pol->mark.v ||
1067 pol->type != type) 1073 pol->type != type)
1068 return ret; 1074 return ret;
@@ -1177,7 +1183,8 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir,
1177 1183
1178 match = xfrm_selector_match(&pol->selector, fl, family); 1184 match = xfrm_selector_match(&pol->selector, fl, family);
1179 if (match) { 1185 if (match) {
1180 if ((sk->sk_mark & pol->mark.m) != pol->mark.v) { 1186 if ((sk->sk_mark & pol->mark.m) != pol->mark.v ||
1187 pol->if_id != fl->flowi_xfrm.if_id) {
1181 pol = NULL; 1188 pol = NULL;
1182 goto out; 1189 goto out;
1183 } 1190 }
@@ -1305,6 +1312,7 @@ static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir)
1305 newp->lft = old->lft; 1312 newp->lft = old->lft;
1306 newp->curlft = old->curlft; 1313 newp->curlft = old->curlft;
1307 newp->mark = old->mark; 1314 newp->mark = old->mark;
1315 newp->if_id = old->if_id;
1308 newp->action = old->action; 1316 newp->action = old->action;
1309 newp->flags = old->flags; 1317 newp->flags = old->flags;
1310 newp->xfrm_nr = old->xfrm_nr; 1318 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,
941 int error = 0; 941 int error = 0;
942 struct xfrm_state *best = NULL; 942 struct xfrm_state *best = NULL;
943 u32 mark = pol->mark.v & pol->mark.m; 943 u32 mark = pol->mark.v & pol->mark.m;
944 u32 if_id = fl->flowi_xfrm.if_id;
944 unsigned short encap_family = tmpl->encap_family; 945 unsigned short encap_family = tmpl->encap_family;
945 unsigned int sequence; 946 unsigned int sequence;
946 struct km_event c; 947 struct km_event c;
@@ -955,6 +956,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
955 if (x->props.family == encap_family && 956 if (x->props.family == encap_family &&
956 x->props.reqid == tmpl->reqid && 957 x->props.reqid == tmpl->reqid &&
957 (mark & x->mark.m) == x->mark.v && 958 (mark & x->mark.m) == x->mark.v &&
959 x->if_id == if_id &&
958 !(x->props.flags & XFRM_STATE_WILDRECV) && 960 !(x->props.flags & XFRM_STATE_WILDRECV) &&
959 xfrm_state_addr_check(x, daddr, saddr, encap_family) && 961 xfrm_state_addr_check(x, daddr, saddr, encap_family) &&
960 tmpl->mode == x->props.mode && 962 tmpl->mode == x->props.mode &&
@@ -971,6 +973,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
971 if (x->props.family == encap_family && 973 if (x->props.family == encap_family &&
972 x->props.reqid == tmpl->reqid && 974 x->props.reqid == tmpl->reqid &&
973 (mark & x->mark.m) == x->mark.v && 975 (mark & x->mark.m) == x->mark.v &&
976 x->if_id == if_id &&
974 !(x->props.flags & XFRM_STATE_WILDRECV) && 977 !(x->props.flags & XFRM_STATE_WILDRECV) &&
975 xfrm_addr_equal(&x->id.daddr, daddr, encap_family) && 978 xfrm_addr_equal(&x->id.daddr, daddr, encap_family) &&
976 tmpl->mode == x->props.mode && 979 tmpl->mode == x->props.mode &&
@@ -1010,6 +1013,7 @@ found:
1010 * to current session. */ 1013 * to current session. */
1011 xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family); 1014 xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family);
1012 memcpy(&x->mark, &pol->mark, sizeof(x->mark)); 1015 memcpy(&x->mark, &pol->mark, sizeof(x->mark));
1016 x->if_id = if_id;
1013 1017
1014 error = security_xfrm_state_alloc_acquire(x, pol->security, fl->flowi_secid); 1018 error = security_xfrm_state_alloc_acquire(x, pol->security, fl->flowi_secid);
1015 if (error) { 1019 if (error) {
@@ -1067,7 +1071,7 @@ out:
1067} 1071}
1068 1072
1069struct xfrm_state * 1073struct xfrm_state *
1070xfrm_stateonly_find(struct net *net, u32 mark, 1074xfrm_stateonly_find(struct net *net, u32 mark, u32 if_id,
1071 xfrm_address_t *daddr, xfrm_address_t *saddr, 1075 xfrm_address_t *daddr, xfrm_address_t *saddr,
1072 unsigned short family, u8 mode, u8 proto, u32 reqid) 1076 unsigned short family, u8 mode, u8 proto, u32 reqid)
1073{ 1077{
@@ -1080,6 +1084,7 @@ xfrm_stateonly_find(struct net *net, u32 mark,
1080 if (x->props.family == family && 1084 if (x->props.family == family &&
1081 x->props.reqid == reqid && 1085 x->props.reqid == reqid &&
1082 (mark & x->mark.m) == x->mark.v && 1086 (mark & x->mark.m) == x->mark.v &&
1087 x->if_id == if_id &&
1083 !(x->props.flags & XFRM_STATE_WILDRECV) && 1088 !(x->props.flags & XFRM_STATE_WILDRECV) &&
1084 xfrm_state_addr_check(x, daddr, saddr, family) && 1089 xfrm_state_addr_check(x, daddr, saddr, family) &&
1085 mode == x->props.mode && 1090 mode == x->props.mode &&
@@ -1160,11 +1165,13 @@ static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
1160 struct xfrm_state *x; 1165 struct xfrm_state *x;
1161 unsigned int h; 1166 unsigned int h;
1162 u32 mark = xnew->mark.v & xnew->mark.m; 1167 u32 mark = xnew->mark.v & xnew->mark.m;
1168 u32 if_id = xnew->if_id;
1163 1169
1164 h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family); 1170 h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family);
1165 hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 1171 hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
1166 if (x->props.family == family && 1172 if (x->props.family == family &&
1167 x->props.reqid == reqid && 1173 x->props.reqid == reqid &&
1174 x->if_id == if_id &&
1168 (mark & x->mark.m) == x->mark.v && 1175 (mark & x->mark.m) == x->mark.v &&
1169 xfrm_addr_equal(&x->id.daddr, &xnew->id.daddr, family) && 1176 xfrm_addr_equal(&x->id.daddr, &xnew->id.daddr, family) &&
1170 xfrm_addr_equal(&x->props.saddr, &xnew->props.saddr, family)) 1177 xfrm_addr_equal(&x->props.saddr, &xnew->props.saddr, family))
@@ -1187,7 +1194,7 @@ EXPORT_SYMBOL(xfrm_state_insert);
1187static struct xfrm_state *__find_acq_core(struct net *net, 1194static struct xfrm_state *__find_acq_core(struct net *net,
1188 const struct xfrm_mark *m, 1195 const struct xfrm_mark *m,
1189 unsigned short family, u8 mode, 1196 unsigned short family, u8 mode,
1190 u32 reqid, u8 proto, 1197 u32 reqid, u32 if_id, u8 proto,
1191 const xfrm_address_t *daddr, 1198 const xfrm_address_t *daddr,
1192 const xfrm_address_t *saddr, 1199 const xfrm_address_t *saddr,
1193 int create) 1200 int create)
@@ -1242,6 +1249,7 @@ static struct xfrm_state *__find_acq_core(struct net *net,
1242 x->props.family = family; 1249 x->props.family = family;
1243 x->props.mode = mode; 1250 x->props.mode = mode;
1244 x->props.reqid = reqid; 1251 x->props.reqid = reqid;
1252 x->if_id = if_id;
1245 x->mark.v = m->v; 1253 x->mark.v = m->v;
1246 x->mark.m = m->m; 1254 x->mark.m = m->m;
1247 x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; 1255 x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
@@ -1296,7 +1304,7 @@ int xfrm_state_add(struct xfrm_state *x)
1296 1304
1297 if (use_spi && !x1) 1305 if (use_spi && !x1)
1298 x1 = __find_acq_core(net, &x->mark, family, x->props.mode, 1306 x1 = __find_acq_core(net, &x->mark, family, x->props.mode,
1299 x->props.reqid, x->id.proto, 1307 x->props.reqid, x->if_id, x->id.proto,
1300 &x->id.daddr, &x->props.saddr, 0); 1308 &x->id.daddr, &x->props.saddr, 0);
1301 1309
1302 __xfrm_state_bump_genids(x); 1310 __xfrm_state_bump_genids(x);
@@ -1395,6 +1403,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
1395 x->props.flags = orig->props.flags; 1403 x->props.flags = orig->props.flags;
1396 x->props.extra_flags = orig->props.extra_flags; 1404 x->props.extra_flags = orig->props.extra_flags;
1397 1405
1406 x->if_id = orig->if_id;
1398 x->tfcpad = orig->tfcpad; 1407 x->tfcpad = orig->tfcpad;
1399 x->replay_maxdiff = orig->replay_maxdiff; 1408 x->replay_maxdiff = orig->replay_maxdiff;
1400 x->replay_maxage = orig->replay_maxage; 1409 x->replay_maxage = orig->replay_maxage;
@@ -1619,13 +1628,13 @@ EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
1619 1628
1620struct xfrm_state * 1629struct xfrm_state *
1621xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid, 1630xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid,
1622 u8 proto, const xfrm_address_t *daddr, 1631 u32 if_id, u8 proto, const xfrm_address_t *daddr,
1623 const xfrm_address_t *saddr, int create, unsigned short family) 1632 const xfrm_address_t *saddr, int create, unsigned short family)
1624{ 1633{
1625 struct xfrm_state *x; 1634 struct xfrm_state *x;
1626 1635
1627 spin_lock_bh(&net->xfrm.xfrm_state_lock); 1636 spin_lock_bh(&net->xfrm.xfrm_state_lock);
1628 x = __find_acq_core(net, mark, family, mode, reqid, proto, daddr, saddr, create); 1637 x = __find_acq_core(net, mark, family, mode, reqid, if_id, proto, daddr, saddr, create);
1629 spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1638 spin_unlock_bh(&net->xfrm.xfrm_state_lock);
1630 1639
1631 return x; 1640 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,
594 594
595 xfrm_smark_init(attrs, &x->props.smark); 595 xfrm_smark_init(attrs, &x->props.smark);
596 596
597 if (attrs[XFRMA_IF_ID])
598 x->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
599
597 err = __xfrm_init_state(x, false, attrs[XFRMA_OFFLOAD_DEV]); 600 err = __xfrm_init_state(x, false, attrs[XFRMA_OFFLOAD_DEV]);
598 if (err) 601 if (err)
599 goto error; 602 goto error;
@@ -929,7 +932,11 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
929 ret = copy_user_offload(&x->xso, skb); 932 ret = copy_user_offload(&x->xso, skb);
930 if (ret) 933 if (ret)
931 goto out; 934 goto out;
932 935 if (x->if_id) {
936 ret = nla_put_u32(skb, XFRMA_IF_ID, x->if_id);
937 if (ret)
938 goto out;
939 }
933 if (x->security) 940 if (x->security)
934 ret = copy_sec_ctx(x->security, skb); 941 ret = copy_sec_ctx(x->security, skb);
935out: 942out:
@@ -1278,6 +1285,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
1278 int err; 1285 int err;
1279 u32 mark; 1286 u32 mark;
1280 struct xfrm_mark m; 1287 struct xfrm_mark m;
1288 u32 if_id = 0;
1281 1289
1282 p = nlmsg_data(nlh); 1290 p = nlmsg_data(nlh);
1283 err = verify_spi_info(p->info.id.proto, p->min, p->max); 1291 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,
1290 x = NULL; 1298 x = NULL;
1291 1299
1292 mark = xfrm_mark_get(attrs, &m); 1300 mark = xfrm_mark_get(attrs, &m);
1301
1302 if (attrs[XFRMA_IF_ID])
1303 if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
1304
1293 if (p->info.seq) { 1305 if (p->info.seq) {
1294 x = xfrm_find_acq_byseq(net, mark, p->info.seq); 1306 x = xfrm_find_acq_byseq(net, mark, p->info.seq);
1295 if (x && !xfrm_addr_equal(&x->id.daddr, daddr, family)) { 1307 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,
1300 1312
1301 if (!x) 1313 if (!x)
1302 x = xfrm_find_acq(net, &m, p->info.mode, p->info.reqid, 1314 x = xfrm_find_acq(net, &m, p->info.mode, p->info.reqid,
1303 p->info.id.proto, daddr, 1315 if_id, p->info.id.proto, daddr,
1304 &p->info.saddr, 1, 1316 &p->info.saddr, 1,
1305 family); 1317 family);
1306 err = -ENOENT; 1318 err = -ENOENT;
@@ -1588,6 +1600,9 @@ static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_us
1588 1600
1589 xfrm_mark_get(attrs, &xp->mark); 1601 xfrm_mark_get(attrs, &xp->mark);
1590 1602
1603 if (attrs[XFRMA_IF_ID])
1604 xp->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
1605
1591 return xp; 1606 return xp;
1592 error: 1607 error:
1593 *errp = err; 1608 *errp = err;
@@ -1733,6 +1748,8 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr
1733 err = copy_to_user_policy_type(xp->type, skb); 1748 err = copy_to_user_policy_type(xp->type, skb);
1734 if (!err) 1749 if (!err)
1735 err = xfrm_mark_put(skb, &xp->mark); 1750 err = xfrm_mark_put(skb, &xp->mark);
1751 if (!err)
1752 err = xfrm_if_id_put(skb, xp->if_id);
1736 if (err) { 1753 if (err) {
1737 nlmsg_cancel(skb, nlh); 1754 nlmsg_cancel(skb, nlh);
1738 return err; 1755 return err;
@@ -1814,6 +1831,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
1814 int delete; 1831 int delete;
1815 struct xfrm_mark m; 1832 struct xfrm_mark m;
1816 u32 mark = xfrm_mark_get(attrs, &m); 1833 u32 mark = xfrm_mark_get(attrs, &m);
1834 u32 if_id = 0;
1817 1835
1818 p = nlmsg_data(nlh); 1836 p = nlmsg_data(nlh);
1819 delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; 1837 delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY;
@@ -1826,8 +1844,11 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
1826 if (err) 1844 if (err)
1827 return err; 1845 return err;
1828 1846
1847 if (attrs[XFRMA_IF_ID])
1848 if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
1849
1829 if (p->index) 1850 if (p->index)
1830 xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, delete, &err); 1851 xp = xfrm_policy_byid(net, mark, if_id, type, p->dir, p->index, delete, &err);
1831 else { 1852 else {
1832 struct nlattr *rt = attrs[XFRMA_SEC_CTX]; 1853 struct nlattr *rt = attrs[XFRMA_SEC_CTX];
1833 struct xfrm_sec_ctx *ctx; 1854 struct xfrm_sec_ctx *ctx;
@@ -1844,7 +1865,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
1844 if (err) 1865 if (err)
1845 return err; 1866 return err;
1846 } 1867 }
1847 xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir, &p->sel, 1868 xp = xfrm_policy_bysel_ctx(net, mark, if_id, type, p->dir, &p->sel,
1848 ctx, delete, &err); 1869 ctx, delete, &err);
1849 security_xfrm_policy_free(ctx); 1870 security_xfrm_policy_free(ctx);
1850 } 1871 }
@@ -1967,6 +1988,10 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, const struct
1967 if (err) 1988 if (err)
1968 goto out_cancel; 1989 goto out_cancel;
1969 1990
1991 err = xfrm_if_id_put(skb, x->if_id);
1992 if (err)
1993 goto out_cancel;
1994
1970 nlmsg_end(skb, nlh); 1995 nlmsg_end(skb, nlh);
1971 return 0; 1996 return 0;
1972 1997
@@ -2109,6 +2134,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
2109 int err = -ENOENT; 2134 int err = -ENOENT;
2110 struct xfrm_mark m; 2135 struct xfrm_mark m;
2111 u32 mark = xfrm_mark_get(attrs, &m); 2136 u32 mark = xfrm_mark_get(attrs, &m);
2137 u32 if_id = 0;
2112 2138
2113 err = copy_from_user_policy_type(&type, attrs); 2139 err = copy_from_user_policy_type(&type, attrs);
2114 if (err) 2140 if (err)
@@ -2118,8 +2144,11 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
2118 if (err) 2144 if (err)
2119 return err; 2145 return err;
2120 2146
2147 if (attrs[XFRMA_IF_ID])
2148 if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
2149
2121 if (p->index) 2150 if (p->index)
2122 xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, 0, &err); 2151 xp = xfrm_policy_byid(net, mark, if_id, type, p->dir, p->index, 0, &err);
2123 else { 2152 else {
2124 struct nlattr *rt = attrs[XFRMA_SEC_CTX]; 2153 struct nlattr *rt = attrs[XFRMA_SEC_CTX];
2125 struct xfrm_sec_ctx *ctx; 2154 struct xfrm_sec_ctx *ctx;
@@ -2136,7 +2165,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
2136 if (err) 2165 if (err)
2137 return err; 2166 return err;
2138 } 2167 }
2139 xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir, 2168 xp = xfrm_policy_bysel_ctx(net, mark, if_id, type, p->dir,
2140 &p->sel, ctx, 0, &err); 2169 &p->sel, ctx, 0, &err);
2141 security_xfrm_policy_free(ctx); 2170 security_xfrm_policy_free(ctx);
2142 } 2171 }
@@ -2520,6 +2549,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
2520 [XFRMA_OFFLOAD_DEV] = { .len = sizeof(struct xfrm_user_offload) }, 2549 [XFRMA_OFFLOAD_DEV] = { .len = sizeof(struct xfrm_user_offload) },
2521 [XFRMA_SET_MARK] = { .type = NLA_U32 }, 2550 [XFRMA_SET_MARK] = { .type = NLA_U32 },
2522 [XFRMA_SET_MARK_MASK] = { .type = NLA_U32 }, 2551 [XFRMA_SET_MARK_MASK] = { .type = NLA_U32 },
2552 [XFRMA_IF_ID] = { .type = NLA_U32 },
2523}; 2553};
2524 2554
2525static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = { 2555static 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
2651 if (err) 2681 if (err)
2652 return err; 2682 return err;
2653 2683
2684 err = xfrm_if_id_put(skb, x->if_id);
2685 if (err)
2686 return err;
2687
2654 nlmsg_end(skb, nlh); 2688 nlmsg_end(skb, nlh);
2655 return 0; 2689 return 0;
2656} 2690}
@@ -2749,6 +2783,8 @@ static inline unsigned int xfrm_sa_len(struct xfrm_state *x)
2749 l += nla_total_size(sizeof(x->props.smark.v)); 2783 l += nla_total_size(sizeof(x->props.smark.v));
2750 l += nla_total_size(sizeof(x->props.smark.m)); 2784 l += nla_total_size(sizeof(x->props.smark.m));
2751 } 2785 }
2786 if (x->if_id)
2787 l += nla_total_size(sizeof(x->if_id));
2752 2788
2753 /* Must count x->lastused as it may become non-zero behind our back. */ 2789 /* Must count x->lastused as it may become non-zero behind our back. */
2754 l += nla_total_size_64bit(sizeof(u64)); 2790 l += nla_total_size_64bit(sizeof(u64));
@@ -2878,6 +2914,8 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
2878 err = copy_to_user_policy_type(xp->type, skb); 2914 err = copy_to_user_policy_type(xp->type, skb);
2879 if (!err) 2915 if (!err)
2880 err = xfrm_mark_put(skb, &xp->mark); 2916 err = xfrm_mark_put(skb, &xp->mark);
2917 if (!err)
2918 err = xfrm_if_id_put(skb, xp->if_id);
2881 if (err) { 2919 if (err) {
2882 nlmsg_cancel(skb, nlh); 2920 nlmsg_cancel(skb, nlh);
2883 return err; 2921 return err;
@@ -2994,6 +3032,8 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp,
2994 err = copy_to_user_policy_type(xp->type, skb); 3032 err = copy_to_user_policy_type(xp->type, skb);
2995 if (!err) 3033 if (!err)
2996 err = xfrm_mark_put(skb, &xp->mark); 3034 err = xfrm_mark_put(skb, &xp->mark);
3035 if (!err)
3036 err = xfrm_if_id_put(skb, xp->if_id);
2997 if (err) { 3037 if (err) {
2998 nlmsg_cancel(skb, nlh); 3038 nlmsg_cancel(skb, nlh);
2999 return err; 3039 return err;
@@ -3075,6 +3115,8 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, const struct km_e
3075 err = copy_to_user_policy_type(xp->type, skb); 3115 err = copy_to_user_policy_type(xp->type, skb);
3076 if (!err) 3116 if (!err)
3077 err = xfrm_mark_put(skb, &xp->mark); 3117 err = xfrm_mark_put(skb, &xp->mark);
3118 if (!err)
3119 err = xfrm_if_id_put(skb, xp->if_id);
3078 if (err) 3120 if (err)
3079 goto out_free_skb; 3121 goto out_free_skb;
3080 3122