Skip to content

Commit 7862b40

Browse files
committed
esp: Add gso handlers for esp4 and esp6
This patch extends the xfrm_type by an encap function pointer and implements esp4_gso_encap and esp6_gso_encap. These functions doing the basic esp encapsulation for a GSO packet. In case the GSO packet needs to be segmented in software, we add gso_segment functions. This codepath is going to be used on esp hardware offloads. Signed-off-by: Steffen Klassert <[email protected]>
1 parent 383d035 commit 7862b40

File tree

5 files changed

+203
-4
lines changed

5 files changed

+203
-4
lines changed

net/ipv4/esp4.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,19 @@ static struct ip_esp_hdr *esp_output_set_extra(struct sk_buff *skb,
161161
* encryption.
162162
*/
163163
if ((x->props.flags & XFRM_STATE_ESN)) {
164+
__u32 seqhi;
165+
struct xfrm_offload *xo = xfrm_offload(skb);
166+
167+
if (xo)
168+
seqhi = xo->seq.hi;
169+
else
170+
seqhi = XFRM_SKB_CB(skb)->seq.output.hi;
171+
164172
extra->esphoff = (unsigned char *)esph -
165173
skb_transport_header(skb);
166174
esph = (struct ip_esp_hdr *)((unsigned char *)esph - 4);
167175
extra->seqhi = esph->spi;
168-
esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.hi);
176+
esph->seq_no = htonl(seqhi);
169177
}
170178

171179
esph->spi = x->id.spi;

net/ipv4/esp4_offload.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,97 @@ static struct sk_buff **esp4_gro_receive(struct sk_buff **head,
8484
return NULL;
8585
}
8686

87+
static void esp4_gso_encap(struct xfrm_state *x, struct sk_buff *skb)
88+
{
89+
struct ip_esp_hdr *esph;
90+
struct iphdr *iph = ip_hdr(skb);
91+
struct xfrm_offload *xo = xfrm_offload(skb);
92+
int proto = iph->protocol;
93+
94+
skb_push(skb, -skb_network_offset(skb));
95+
esph = ip_esp_hdr(skb);
96+
*skb_mac_header(skb) = IPPROTO_ESP;
97+
98+
esph->spi = x->id.spi;
99+
esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
100+
101+
xo->proto = proto;
102+
}
103+
104+
static struct sk_buff *esp4_gso_segment(struct sk_buff *skb,
105+
netdev_features_t features)
106+
{
107+
__u32 seq;
108+
int err = 0;
109+
struct sk_buff *skb2;
110+
struct xfrm_state *x;
111+
struct ip_esp_hdr *esph;
112+
struct crypto_aead *aead;
113+
struct sk_buff *segs = ERR_PTR(-EINVAL);
114+
netdev_features_t esp_features = features;
115+
struct xfrm_offload *xo = xfrm_offload(skb);
116+
117+
if (!xo)
118+
goto out;
119+
120+
seq = xo->seq.low;
121+
122+
x = skb->sp->xvec[skb->sp->len - 1];
123+
aead = x->data;
124+
esph = ip_esp_hdr(skb);
125+
126+
if (esph->spi != x->id.spi)
127+
goto out;
128+
129+
if (!pskb_may_pull(skb, sizeof(*esph) + crypto_aead_ivsize(aead)))
130+
goto out;
131+
132+
__skb_pull(skb, sizeof(*esph) + crypto_aead_ivsize(aead));
133+
134+
skb->encap_hdr_csum = 1;
135+
136+
if (!(features & NETIF_F_HW_ESP))
137+
esp_features = features & ~(NETIF_F_SG | NETIF_F_CSUM_MASK);
138+
139+
segs = x->outer_mode->gso_segment(x, skb, esp_features);
140+
if (IS_ERR_OR_NULL(segs))
141+
goto out;
142+
143+
__skb_pull(skb, skb->data - skb_mac_header(skb));
144+
145+
skb2 = segs;
146+
do {
147+
struct sk_buff *nskb = skb2->next;
148+
149+
xo = xfrm_offload(skb2);
150+
xo->flags |= XFRM_GSO_SEGMENT;
151+
xo->seq.low = seq;
152+
xo->seq.hi = xfrm_replay_seqhi(x, seq);
153+
154+
if(!(features & NETIF_F_HW_ESP))
155+
xo->flags |= CRYPTO_FALLBACK;
156+
157+
x->outer_mode->xmit(x, skb2);
158+
159+
err = x->type_offload->xmit(x, skb2, esp_features);
160+
if (err) {
161+
kfree_skb_list(segs);
162+
return ERR_PTR(err);
163+
}
164+
165+
if (!skb_is_gso(skb2))
166+
seq++;
167+
else
168+
seq += skb_shinfo(skb2)->gso_segs;
169+
170+
skb_push(skb2, skb2->mac_len);
171+
skb2 = nskb;
172+
} while (skb2);
173+
174+
out:
175+
return segs;
176+
}
177+
87178
static int esp_input_tail(struct xfrm_state *x, struct sk_buff *skb)
88179
{
89180
struct crypto_aead *aead = x->data;
@@ -173,6 +264,7 @@ static int esp_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features_
173264
static const struct net_offload esp4_offload = {
174265
.callbacks = {
175266
.gro_receive = esp4_gro_receive,
267+
.gso_segment = esp4_gso_segment,
176268
},
177269
};
178270

@@ -182,6 +274,7 @@ static const struct xfrm_type_offload esp_type_offload = {
182274
.proto = IPPROTO_ESP,
183275
.input_tail = esp_input_tail,
184276
.xmit = esp_xmit,
277+
.encap = esp4_gso_encap,
185278
};
186279

187280
static int __init esp4_offload_init(void)

net/ipv6/esp6.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,14 @@ static struct ip_esp_hdr *esp_output_set_esn(struct sk_buff *skb,
179179
* encryption.
180180
*/
181181
if ((x->props.flags & XFRM_STATE_ESN)) {
182+
struct xfrm_offload *xo = xfrm_offload(skb);
183+
182184
esph = (void *)(skb_transport_header(skb) - sizeof(__be32));
183185
*seqhi = esph->spi;
184-
esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.hi);
186+
if (xo)
187+
esph->seq_no = htonl(xo->seq.hi);
188+
else
189+
esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.hi);
185190
}
186191

187192
esph->spi = x->id.spi;
@@ -223,7 +228,6 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info
223228
struct sk_buff *trailer;
224229
int tailen = esp->tailen;
225230

226-
*skb_mac_header(skb) = IPPROTO_ESP;
227231
esph = ip_esp_hdr(skb);
228232

229233
if (!skb_cloned(skb)) {

net/ipv6/esp6_offload.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,97 @@ static struct sk_buff **esp6_gro_receive(struct sk_buff **head,
8686
return NULL;
8787
}
8888

89+
static void esp6_gso_encap(struct xfrm_state *x, struct sk_buff *skb)
90+
{
91+
struct ip_esp_hdr *esph;
92+
struct ipv6hdr *iph = ipv6_hdr(skb);
93+
struct xfrm_offload *xo = xfrm_offload(skb);
94+
int proto = iph->nexthdr;
95+
96+
skb_push(skb, -skb_network_offset(skb));
97+
esph = ip_esp_hdr(skb);
98+
*skb_mac_header(skb) = IPPROTO_ESP;
99+
100+
esph->spi = x->id.spi;
101+
esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
102+
103+
xo->proto = proto;
104+
}
105+
106+
static struct sk_buff *esp6_gso_segment(struct sk_buff *skb,
107+
netdev_features_t features)
108+
{
109+
__u32 seq;
110+
int err = 0;
111+
struct sk_buff *skb2;
112+
struct xfrm_state *x;
113+
struct ip_esp_hdr *esph;
114+
struct crypto_aead *aead;
115+
struct sk_buff *segs = ERR_PTR(-EINVAL);
116+
netdev_features_t esp_features = features;
117+
struct xfrm_offload *xo = xfrm_offload(skb);
118+
119+
if (xo)
120+
goto out;
121+
122+
seq = xo->seq.low;
123+
124+
x = skb->sp->xvec[skb->sp->len - 1];
125+
aead = x->data;
126+
esph = ip_esp_hdr(skb);
127+
128+
if (esph->spi != x->id.spi)
129+
goto out;
130+
131+
if (!pskb_may_pull(skb, sizeof(*esph) + crypto_aead_ivsize(aead)))
132+
goto out;
133+
134+
__skb_pull(skb, sizeof(*esph) + crypto_aead_ivsize(aead));
135+
136+
skb->encap_hdr_csum = 1;
137+
138+
if (!(features & NETIF_F_HW_ESP))
139+
esp_features = features & ~(NETIF_F_SG | NETIF_F_CSUM_MASK);
140+
141+
segs = x->outer_mode->gso_segment(x, skb, esp_features);
142+
if (IS_ERR_OR_NULL(segs))
143+
goto out;
144+
145+
__skb_pull(skb, skb->data - skb_mac_header(skb));
146+
147+
skb2 = segs;
148+
do {
149+
struct sk_buff *nskb = skb2->next;
150+
151+
xo = xfrm_offload(skb2);
152+
xo->flags |= XFRM_GSO_SEGMENT;
153+
xo->seq.low = seq;
154+
xo->seq.hi = xfrm_replay_seqhi(x, seq);
155+
156+
if(!(features & NETIF_F_HW_ESP))
157+
xo->flags |= CRYPTO_FALLBACK;
158+
159+
x->outer_mode->xmit(x, skb2);
160+
161+
err = x->type_offload->xmit(x, skb2, esp_features);
162+
if (err) {
163+
kfree_skb_list(segs);
164+
return ERR_PTR(err);
165+
}
166+
167+
if (!skb_is_gso(skb2))
168+
seq++;
169+
else
170+
seq += skb_shinfo(skb2)->gso_segs;
171+
172+
skb_push(skb2, skb2->mac_len);
173+
skb2 = nskb;
174+
} while (skb2);
175+
176+
out:
177+
return segs;
178+
}
179+
89180
static int esp6_input_tail(struct xfrm_state *x, struct sk_buff *skb)
90181
{
91182
struct crypto_aead *aead = x->data;
@@ -176,6 +267,7 @@ static int esp6_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features
176267
static const struct net_offload esp6_offload = {
177268
.callbacks = {
178269
.gro_receive = esp6_gro_receive,
270+
.gso_segment = esp6_gso_segment,
179271
},
180272
};
181273

@@ -185,6 +277,7 @@ static const struct xfrm_type_offload esp6_type_offload = {
185277
.proto = IPPROTO_ESP,
186278
.input_tail = esp6_input_tail,
187279
.xmit = esp6_xmit,
280+
.encap = esp6_gso_encap,
188281
};
189282

190283
static int __init esp6_offload_init(void)

net/xfrm/xfrm_replay.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq)
4545

4646
return seq_hi;
4747
}
48-
48+
EXPORT_SYMBOL(xfrm_replay_seqhi);
49+
;
4950
static void xfrm_replay_notify(struct xfrm_state *x, int event)
5051
{
5152
struct km_event c;

0 commit comments

Comments
 (0)