Skip to content

Commit b9a1a57

Browse files
lcolittipundiramit
authored andcommitted
BACKPORT: net: xfrm: support setting an output mark.
On systems that use mark-based routing it may be necessary for routing lookups to use marks in order for packets to be routed correctly. An example of such a system is Android, which uses socket marks to route packets via different networks. Currently, routing lookups in tunnel mode always use a mark of zero, making routing incorrect on such systems. This patch adds a new output_mark element to the xfrm state and a corresponding XFRMA_OUTPUT_MARK netlink attribute. The output mark differs from the existing xfrm mark in two ways: 1. The xfrm mark is used to match xfrm policies and states, while the xfrm output mark is used to set the mark (and influence the routing) of the packets emitted by those states. 2. The existing mark is constrained to be a subset of the bits of the originating socket or transformed packet, but the output mark is arbitrary and depends only on the state. The use of a separate mark provides additional flexibility. For example: - A packet subject to two transforms (e.g., transport mode inside tunnel mode) can have two different output marks applied to it, one for the transport mode SA and one for the tunnel mode SA. - On a system where socket marks determine routing, the packets emitted by an IPsec tunnel can be routed based on a mark that is determined by the tunnel, not by the marks of the unencrypted packets. - Support for setting the output marks can be introduced without breaking any existing setups that employ both mark-based routing and xfrm tunnel mode. Simply changing the code to use the xfrm mark for routing output packets could xfrm mark could change behaviour in a way that breaks these setups. If the output mark is unspecified or set to zero, the mark is not set or changed. [backport of upstream 077fbac405bfc6d41419ad6c1725804ad4e9887c] Bug: 63589535 Test: https://android-review.googlesource.com/452776/ passes Tested: make allyesconfig; make -j64 Tested: https://android-review.googlesource.com/452776 Signed-off-by: Lorenzo Colitti <lorenzo@google.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> Change-Id: I76120fba036e21780ced31ad390faf491ea81e52
1 parent 4e634bf commit b9a1a57

7 files changed

Lines changed: 46 additions & 18 deletions

File tree

include/net/xfrm.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ struct xfrm_state {
159159
int header_len;
160160
int trailer_len;
161161
u32 extra_flags;
162+
u32 output_mark;
162163
} props;
163164

164165
struct xfrm_lifetime_cfg lft;
@@ -288,10 +289,12 @@ struct xfrm_policy_afinfo {
288289
struct dst_entry *(*dst_lookup)(struct net *net,
289290
int tos, int oif,
290291
const xfrm_address_t *saddr,
291-
const xfrm_address_t *daddr);
292+
const xfrm_address_t *daddr,
293+
u32 mark);
292294
int (*get_saddr)(struct net *net, int oif,
293295
xfrm_address_t *saddr,
294-
xfrm_address_t *daddr);
296+
xfrm_address_t *daddr,
297+
u32 mark);
295298
void (*decode_session)(struct sk_buff *skb,
296299
struct flowi *fl,
297300
int reverse);

include/uapi/linux/xfrm.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,9 @@ enum xfrm_attr_type_t {
302302
XFRMA_SA_EXTRA_FLAGS, /* __u32 */
303303
XFRMA_PROTO, /* __u8 */
304304
XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */
305+
XFRMA_PAD,
306+
XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */
307+
XFRMA_OUTPUT_MARK, /* __u32 */
305308
__XFRMA_MAX
306309

307310
#define XFRMA_MAX (__XFRMA_MAX - 1)

net/ipv4/xfrm4_policy.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,16 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo;
2222
static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4,
2323
int tos, int oif,
2424
const xfrm_address_t *saddr,
25-
const xfrm_address_t *daddr)
25+
const xfrm_address_t *daddr,
26+
u32 mark)
2627
{
2728
struct rtable *rt;
2829

2930
memset(fl4, 0, sizeof(*fl4));
3031
fl4->daddr = daddr->a4;
3132
fl4->flowi4_tos = tos;
3233
fl4->flowi4_oif = l3mdev_master_ifindex_by_index(net, oif);
34+
fl4->flowi4_mark = mark;
3335
if (saddr)
3436
fl4->saddr = saddr->a4;
3537

@@ -44,20 +46,22 @@ static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4,
4446

4547
static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, int oif,
4648
const xfrm_address_t *saddr,
47-
const xfrm_address_t *daddr)
49+
const xfrm_address_t *daddr,
50+
u32 mark)
4851
{
4952
struct flowi4 fl4;
5053

51-
return __xfrm4_dst_lookup(net, &fl4, tos, oif, saddr, daddr);
54+
return __xfrm4_dst_lookup(net, &fl4, tos, oif, saddr, daddr, mark);
5255
}
5356

5457
static int xfrm4_get_saddr(struct net *net, int oif,
55-
xfrm_address_t *saddr, xfrm_address_t *daddr)
58+
xfrm_address_t *saddr, xfrm_address_t *daddr,
59+
u32 mark)
5660
{
5761
struct dst_entry *dst;
5862
struct flowi4 fl4;
5963

60-
dst = __xfrm4_dst_lookup(net, &fl4, 0, oif, NULL, daddr);
64+
dst = __xfrm4_dst_lookup(net, &fl4, 0, oif, NULL, daddr, mark);
6165
if (IS_ERR(dst))
6266
return -EHOSTUNREACH;
6367

net/ipv6/xfrm6_policy.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo;
2929

3030
static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif,
3131
const xfrm_address_t *saddr,
32-
const xfrm_address_t *daddr)
32+
const xfrm_address_t *daddr,
33+
u32 mark)
3334
{
3435
struct flowi6 fl6;
3536
struct dst_entry *dst;
@@ -38,6 +39,7 @@ static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif,
3839
memset(&fl6, 0, sizeof(fl6));
3940
fl6.flowi6_oif = l3mdev_master_ifindex_by_index(net, oif);
4041
fl6.flowi6_flags = FLOWI_FLAG_SKIP_NH_OIF;
42+
fl6.flowi6_mark = mark;
4143
memcpy(&fl6.daddr, daddr, sizeof(fl6.daddr));
4244
if (saddr)
4345
memcpy(&fl6.saddr, saddr, sizeof(fl6.saddr));
@@ -54,12 +56,13 @@ static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif,
5456
}
5557

5658
static int xfrm6_get_saddr(struct net *net, int oif,
57-
xfrm_address_t *saddr, xfrm_address_t *daddr)
59+
xfrm_address_t *saddr, xfrm_address_t *daddr,
60+
u32 mark)
5861
{
5962
struct dst_entry *dst;
6063
struct net_device *dev;
6164

62-
dst = xfrm6_dst_lookup(net, 0, oif, NULL, daddr);
65+
dst = xfrm6_dst_lookup(net, 0, oif, NULL, daddr, mark);
6366
if (IS_ERR(dst))
6467
return -EHOSTUNREACH;
6568

net/xfrm/xfrm_output.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ static int xfrm_output_one(struct sk_buff *skb, int err)
6666
goto error_nolock;
6767
}
6868

69+
if (x->props.output_mark)
70+
skb->mark = x->props.output_mark;
71+
6972
err = x->outer_mode->output(x, skb);
7073
if (err) {
7174
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR);

net/xfrm/xfrm_policy.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ static inline struct dst_entry *__xfrm_dst_lookup(struct net *net,
119119
int tos, int oif,
120120
const xfrm_address_t *saddr,
121121
const xfrm_address_t *daddr,
122-
int family)
122+
int family, u32 mark)
123123
{
124124
struct xfrm_policy_afinfo *afinfo;
125125
struct dst_entry *dst;
@@ -128,7 +128,7 @@ static inline struct dst_entry *__xfrm_dst_lookup(struct net *net,
128128
if (unlikely(afinfo == NULL))
129129
return ERR_PTR(-EAFNOSUPPORT);
130130

131-
dst = afinfo->dst_lookup(net, tos, oif, saddr, daddr);
131+
dst = afinfo->dst_lookup(net, tos, oif, saddr, daddr, mark);
132132

133133
xfrm_policy_put_afinfo(afinfo);
134134

@@ -139,7 +139,7 @@ static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x,
139139
int tos, int oif,
140140
xfrm_address_t *prev_saddr,
141141
xfrm_address_t *prev_daddr,
142-
int family)
142+
int family, u32 mark)
143143
{
144144
struct net *net = xs_net(x);
145145
xfrm_address_t *saddr = &x->props.saddr;
@@ -155,7 +155,7 @@ static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x,
155155
daddr = x->coaddr;
156156
}
157157

158-
dst = __xfrm_dst_lookup(net, tos, oif, saddr, daddr, family);
158+
dst = __xfrm_dst_lookup(net, tos, oif, saddr, daddr, family, mark);
159159

160160
if (!IS_ERR(dst)) {
161161
if (prev_saddr != saddr)
@@ -1395,14 +1395,14 @@ int __xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk)
13951395

13961396
static int
13971397
xfrm_get_saddr(struct net *net, int oif, xfrm_address_t *local,
1398-
xfrm_address_t *remote, unsigned short family)
1398+
xfrm_address_t *remote, unsigned short family, u32 mark)
13991399
{
14001400
int err;
14011401
struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
14021402

14031403
if (unlikely(afinfo == NULL))
14041404
return -EINVAL;
1405-
err = afinfo->get_saddr(net, oif, local, remote);
1405+
err = afinfo->get_saddr(net, oif, local, remote, mark);
14061406
xfrm_policy_put_afinfo(afinfo);
14071407
return err;
14081408
}
@@ -1433,7 +1433,7 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl,
14331433
if (xfrm_addr_any(local, tmpl->encap_family)) {
14341434
error = xfrm_get_saddr(net, fl->flowi_oif,
14351435
&tmp, remote,
1436-
tmpl->encap_family);
1436+
tmpl->encap_family, 0);
14371437
if (error)
14381438
goto fail;
14391439
local = &tmp;
@@ -1712,7 +1712,8 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
17121712
if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
17131713
family = xfrm[i]->props.family;
17141714
dst = xfrm_dst_lookup(xfrm[i], tos, fl->flowi_oif,
1715-
&saddr, &daddr, family);
1715+
&saddr, &daddr, family,
1716+
xfrm[i]->props.output_mark);
17161717
err = PTR_ERR(dst);
17171718
if (IS_ERR(dst))
17181719
goto put_states;

net/xfrm/xfrm_user.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,9 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
584584

585585
xfrm_mark_get(attrs, &x->mark);
586586

587+
if (attrs[XFRMA_OUTPUT_MARK])
588+
x->props.output_mark = nla_get_u32(attrs[XFRMA_OUTPUT_MARK]);
589+
587590
err = __xfrm_init_state(x, false);
588591
if (err)
589592
goto error;
@@ -867,6 +870,11 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
867870
goto out;
868871
if (x->security)
869872
ret = copy_sec_ctx(x->security, skb);
873+
if (x->props.output_mark) {
874+
ret = nla_put_u32(skb, XFRMA_OUTPUT_MARK, x->props.output_mark);
875+
if (ret)
876+
goto out;
877+
}
870878
out:
871879
return ret;
872880
}
@@ -2419,6 +2427,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
24192427
[XFRMA_SA_EXTRA_FLAGS] = { .type = NLA_U32 },
24202428
[XFRMA_PROTO] = { .type = NLA_U8 },
24212429
[XFRMA_ADDRESS_FILTER] = { .len = sizeof(struct xfrm_address_filter) },
2430+
[XFRMA_OUTPUT_MARK] = { .len = NLA_U32 },
24222431
};
24232432

24242433
static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = {
@@ -2635,6 +2644,8 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x)
26352644
l += nla_total_size(sizeof(*x->coaddr));
26362645
if (x->props.extra_flags)
26372646
l += nla_total_size(sizeof(x->props.extra_flags));
2647+
if (x->props.output_mark)
2648+
l += nla_total_size(sizeof(x->props.output_mark));
26382649

26392650
/* Must count x->lastused as it may become non-zero behind our back. */
26402651
l += nla_total_size(sizeof(u64));

0 commit comments

Comments
 (0)