Skip to content

Commit c35fe41

Browse files
committed
xfrm: Add mode handlers for IPsec on layer 2
This patch adds a gso_segment and xmit callback for the xfrm_mode and implement these functions for tunnel and transport mode. Signed-off-by: Steffen Klassert <[email protected]>
1 parent 21f42cc commit c35fe41

File tree

5 files changed

+124
-0
lines changed

5 files changed

+124
-0
lines changed

include/net/xfrm.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,16 @@ struct xfrm_mode {
444444
*/
445445
int (*output)(struct xfrm_state *x, struct sk_buff *skb);
446446

447+
/*
448+
* Adjust pointers into the packet and do GSO segmentation.
449+
*/
450+
struct sk_buff *(*gso_segment)(struct xfrm_state *x, struct sk_buff *skb, netdev_features_t features);
451+
452+
/*
453+
* Adjust pointers into the packet when IPsec is done at layer2.
454+
*/
455+
void (*xmit)(struct xfrm_state *x, struct sk_buff *skb);
456+
447457
struct xfrm_state_afinfo *afinfo;
448458
struct module *owner;
449459
unsigned int encap;

net/ipv4/xfrm4_mode_transport.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <net/dst.h>
1313
#include <net/ip.h>
1414
#include <net/xfrm.h>
15+
#include <net/protocol.h>
1516

1617
/* Add encapsulation header.
1718
*
@@ -56,9 +57,40 @@ static int xfrm4_transport_input(struct xfrm_state *x, struct sk_buff *skb)
5657
return 0;
5758
}
5859

60+
static struct sk_buff *xfrm4_transport_gso_segment(struct xfrm_state *x,
61+
struct sk_buff *skb,
62+
netdev_features_t features)
63+
{
64+
const struct net_offload *ops;
65+
struct sk_buff *segs = ERR_PTR(-EINVAL);
66+
struct xfrm_offload *xo = xfrm_offload(skb);
67+
68+
skb->transport_header += x->props.header_len;
69+
ops = rcu_dereference(inet_offloads[xo->proto]);
70+
if (likely(ops && ops->callbacks.gso_segment))
71+
segs = ops->callbacks.gso_segment(skb, features);
72+
73+
return segs;
74+
}
75+
76+
static void xfrm4_transport_xmit(struct xfrm_state *x, struct sk_buff *skb)
77+
{
78+
struct xfrm_offload *xo = xfrm_offload(skb);
79+
80+
skb_reset_mac_len(skb);
81+
pskb_pull(skb, skb->mac_len + sizeof(struct iphdr) + x->props.header_len);
82+
83+
if (xo->flags & XFRM_GSO_SEGMENT) {
84+
skb_reset_transport_header(skb);
85+
skb->transport_header -= x->props.header_len;
86+
}
87+
}
88+
5989
static struct xfrm_mode xfrm4_transport_mode = {
6090
.input = xfrm4_transport_input,
6191
.output = xfrm4_transport_output,
92+
.gso_segment = xfrm4_transport_gso_segment,
93+
.xmit = xfrm4_transport_xmit,
6294
.owner = THIS_MODULE,
6395
.encap = XFRM_MODE_TRANSPORT,
6496
};

net/ipv4/xfrm4_mode_tunnel.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,36 @@ static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
9696
return err;
9797
}
9898

99+
static struct sk_buff *xfrm4_mode_tunnel_gso_segment(struct xfrm_state *x,
100+
struct sk_buff *skb,
101+
netdev_features_t features)
102+
{
103+
__skb_push(skb, skb->mac_len);
104+
return skb_mac_gso_segment(skb, features);
105+
106+
}
107+
108+
static void xfrm4_mode_tunnel_xmit(struct xfrm_state *x, struct sk_buff *skb)
109+
{
110+
struct xfrm_offload *xo = xfrm_offload(skb);
111+
112+
if (xo->flags & XFRM_GSO_SEGMENT) {
113+
skb->network_header = skb->network_header - x->props.header_len;
114+
skb->transport_header = skb->network_header +
115+
sizeof(struct iphdr);
116+
}
117+
118+
skb_reset_mac_len(skb);
119+
pskb_pull(skb, skb->mac_len + x->props.header_len);
120+
}
121+
99122
static struct xfrm_mode xfrm4_tunnel_mode = {
100123
.input2 = xfrm4_mode_tunnel_input,
101124
.input = xfrm_prepare_input,
102125
.output2 = xfrm4_mode_tunnel_output,
103126
.output = xfrm4_prepare_output,
127+
.gso_segment = xfrm4_mode_tunnel_gso_segment,
128+
.xmit = xfrm4_mode_tunnel_xmit,
104129
.owner = THIS_MODULE,
105130
.encap = XFRM_MODE_TUNNEL,
106131
.flags = XFRM_MODE_FLAG_TUNNEL,

net/ipv6/xfrm6_mode_transport.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <net/dst.h>
1414
#include <net/ipv6.h>
1515
#include <net/xfrm.h>
16+
#include <net/protocol.h>
1617

1718
/* Add encapsulation header.
1819
*
@@ -61,9 +62,41 @@ static int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb)
6162
return 0;
6263
}
6364

65+
static struct sk_buff *xfrm4_transport_gso_segment(struct xfrm_state *x,
66+
struct sk_buff *skb,
67+
netdev_features_t features)
68+
{
69+
const struct net_offload *ops;
70+
struct sk_buff *segs = ERR_PTR(-EINVAL);
71+
struct xfrm_offload *xo = xfrm_offload(skb);
72+
73+
skb->transport_header += x->props.header_len;
74+
ops = rcu_dereference(inet6_offloads[xo->proto]);
75+
if (likely(ops && ops->callbacks.gso_segment))
76+
segs = ops->callbacks.gso_segment(skb, features);
77+
78+
return segs;
79+
}
80+
81+
static void xfrm6_transport_xmit(struct xfrm_state *x, struct sk_buff *skb)
82+
{
83+
struct xfrm_offload *xo = xfrm_offload(skb);
84+
85+
skb_reset_mac_len(skb);
86+
pskb_pull(skb, skb->mac_len + sizeof(struct ipv6hdr) + x->props.header_len);
87+
88+
if (xo->flags & XFRM_GSO_SEGMENT) {
89+
skb_reset_transport_header(skb);
90+
skb->transport_header -= x->props.header_len;
91+
}
92+
}
93+
94+
6495
static struct xfrm_mode xfrm6_transport_mode = {
6596
.input = xfrm6_transport_input,
6697
.output = xfrm6_transport_output,
98+
.gso_segment = xfrm4_transport_gso_segment,
99+
.xmit = xfrm6_transport_xmit,
67100
.owner = THIS_MODULE,
68101
.encap = XFRM_MODE_TRANSPORT,
69102
};

net/ipv6/xfrm6_mode_tunnel.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,35 @@ static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
9696
return err;
9797
}
9898

99+
static struct sk_buff *xfrm6_mode_tunnel_gso_segment(struct xfrm_state *x,
100+
struct sk_buff *skb,
101+
netdev_features_t features)
102+
{
103+
__skb_push(skb, skb->mac_len);
104+
return skb_mac_gso_segment(skb, features);
105+
106+
}
107+
108+
static void xfrm6_mode_tunnel_xmit(struct xfrm_state *x, struct sk_buff *skb)
109+
{
110+
struct xfrm_offload *xo = xfrm_offload(skb);
111+
112+
if (xo->flags & XFRM_GSO_SEGMENT) {
113+
skb->network_header = skb->network_header - x->props.header_len;
114+
skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
115+
}
116+
117+
skb_reset_mac_len(skb);
118+
pskb_pull(skb, skb->mac_len + x->props.header_len);
119+
}
120+
99121
static struct xfrm_mode xfrm6_tunnel_mode = {
100122
.input2 = xfrm6_mode_tunnel_input,
101123
.input = xfrm_prepare_input,
102124
.output2 = xfrm6_mode_tunnel_output,
103125
.output = xfrm6_prepare_output,
126+
.gso_segment = xfrm6_mode_tunnel_gso_segment,
127+
.xmit = xfrm6_mode_tunnel_xmit,
104128
.owner = THIS_MODULE,
105129
.encap = XFRM_MODE_TUNNEL,
106130
.flags = XFRM_MODE_FLAG_TUNNEL,

0 commit comments

Comments
 (0)