Skip to content

Commit 573e8fc

Browse files
Tom Herbertdavem330
authored andcommitted
net: skb_gro_checksum_* functions
Add skb_gro_checksum_validate, skb_gro_checksum_validate_zero_check, and skb_gro_checksum_simple_validate, and __skb_gro_checksum_complete. These are the cognates of the normal checksum functions but are used in the gro_receive path and operate on GRO related fields in sk_buffs. Signed-off-by: Tom Herbert <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 8fc54f6 commit 573e8fc

File tree

2 files changed

+107
-3
lines changed

2 files changed

+107
-3
lines changed

include/linux/netdevice.h

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1883,7 +1883,13 @@ struct napi_gro_cb {
18831883
u16 proto;
18841884

18851885
/* Used in udp_gro_receive */
1886-
u16 udp_mark;
1886+
u8 udp_mark:1;
1887+
1888+
/* GRO checksum is valid */
1889+
u8 csum_valid:1;
1890+
1891+
/* Number encapsulation layers crossed */
1892+
u8 encapsulation;
18871893

18881894
/* used to support CHECKSUM_COMPLETE for tunneling protocols */
18891895
__wsum csum;
@@ -2154,11 +2160,77 @@ static inline void *skb_gro_network_header(struct sk_buff *skb)
21542160
static inline void skb_gro_postpull_rcsum(struct sk_buff *skb,
21552161
const void *start, unsigned int len)
21562162
{
2157-
if (skb->ip_summed == CHECKSUM_COMPLETE)
2163+
if (NAPI_GRO_CB(skb)->csum_valid)
21582164
NAPI_GRO_CB(skb)->csum = csum_sub(NAPI_GRO_CB(skb)->csum,
21592165
csum_partial(start, len, 0));
21602166
}
21612167

2168+
/* GRO checksum functions. These are logical equivalents of the normal
2169+
* checksum functions (in skbuff.h) except that they operate on the GRO
2170+
* offsets and fields in sk_buff.
2171+
*/
2172+
2173+
__sum16 __skb_gro_checksum_complete(struct sk_buff *skb);
2174+
2175+
static inline bool __skb_gro_checksum_validate_needed(struct sk_buff *skb,
2176+
bool zero_okay,
2177+
__sum16 check)
2178+
{
2179+
return (skb->ip_summed != CHECKSUM_PARTIAL &&
2180+
(skb->ip_summed != CHECKSUM_UNNECESSARY ||
2181+
(NAPI_GRO_CB(skb)->encapsulation > skb->encapsulation)) &&
2182+
(!zero_okay || check));
2183+
}
2184+
2185+
static inline __sum16 __skb_gro_checksum_validate_complete(struct sk_buff *skb,
2186+
__wsum psum)
2187+
{
2188+
if (NAPI_GRO_CB(skb)->csum_valid &&
2189+
!csum_fold(csum_add(psum, NAPI_GRO_CB(skb)->csum)))
2190+
return 0;
2191+
2192+
NAPI_GRO_CB(skb)->csum = psum;
2193+
2194+
return __skb_gro_checksum_complete(skb);
2195+
}
2196+
2197+
/* Update skb for CHECKSUM_UNNECESSARY when we verified a top level
2198+
* checksum or an encapsulated one during GRO. This saves work
2199+
* if we fallback to normal path with the packet.
2200+
*/
2201+
static inline void skb_gro_incr_csum_unnecessary(struct sk_buff *skb)
2202+
{
2203+
if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
2204+
if (NAPI_GRO_CB(skb)->encapsulation)
2205+
skb->encapsulation = 1;
2206+
} else if (skb->ip_summed != CHECKSUM_PARTIAL) {
2207+
skb->ip_summed = CHECKSUM_UNNECESSARY;
2208+
skb->encapsulation = 0;
2209+
}
2210+
}
2211+
2212+
#define __skb_gro_checksum_validate(skb, proto, zero_okay, check, \
2213+
compute_pseudo) \
2214+
({ \
2215+
__sum16 __ret = 0; \
2216+
if (__skb_gro_checksum_validate_needed(skb, zero_okay, check)) \
2217+
__ret = __skb_gro_checksum_validate_complete(skb, \
2218+
compute_pseudo(skb, proto)); \
2219+
if (!__ret) \
2220+
skb_gro_incr_csum_unnecessary(skb); \
2221+
__ret; \
2222+
})
2223+
2224+
#define skb_gro_checksum_validate(skb, proto, compute_pseudo) \
2225+
__skb_gro_checksum_validate(skb, proto, false, 0, compute_pseudo)
2226+
2227+
#define skb_gro_checksum_validate_zero_check(skb, proto, check, \
2228+
compute_pseudo) \
2229+
__skb_gro_checksum_validate(skb, proto, true, check, compute_pseudo)
2230+
2231+
#define skb_gro_checksum_simple_validate(skb) \
2232+
__skb_gro_checksum_validate(skb, 0, false, 0, null_compute_pseudo)
2233+
21622234
static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev,
21632235
unsigned short type,
21642236
const void *daddr, const void *saddr,

net/core/dev.c

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3962,7 +3962,13 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
39623962
goto normal;
39633963

39643964
gro_list_prepare(napi, skb);
3965-
NAPI_GRO_CB(skb)->csum = skb->csum; /* Needed for CHECKSUM_COMPLETE */
3965+
3966+
if (skb->ip_summed == CHECKSUM_COMPLETE) {
3967+
NAPI_GRO_CB(skb)->csum = skb->csum;
3968+
NAPI_GRO_CB(skb)->csum_valid = 1;
3969+
} else {
3970+
NAPI_GRO_CB(skb)->csum_valid = 0;
3971+
}
39663972

39673973
rcu_read_lock();
39683974
list_for_each_entry_rcu(ptype, head, list) {
@@ -3975,6 +3981,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
39753981
NAPI_GRO_CB(skb)->flush = 0;
39763982
NAPI_GRO_CB(skb)->free = 0;
39773983
NAPI_GRO_CB(skb)->udp_mark = 0;
3984+
NAPI_GRO_CB(skb)->encapsulation = 0;
39783985

39793986
pp = ptype->callbacks.gro_receive(&napi->gro_list, skb);
39803987
break;
@@ -4205,6 +4212,31 @@ gro_result_t napi_gro_frags(struct napi_struct *napi)
42054212
}
42064213
EXPORT_SYMBOL(napi_gro_frags);
42074214

4215+
/* Compute the checksum from gro_offset and return the folded value
4216+
* after adding in any pseudo checksum.
4217+
*/
4218+
__sum16 __skb_gro_checksum_complete(struct sk_buff *skb)
4219+
{
4220+
__wsum wsum;
4221+
__sum16 sum;
4222+
4223+
wsum = skb_checksum(skb, skb_gro_offset(skb), skb_gro_len(skb), 0);
4224+
4225+
/* NAPI_GRO_CB(skb)->csum holds pseudo checksum */
4226+
sum = csum_fold(csum_add(NAPI_GRO_CB(skb)->csum, wsum));
4227+
if (likely(!sum)) {
4228+
if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) &&
4229+
!skb->csum_complete_sw)
4230+
netdev_rx_csum_fault(skb->dev);
4231+
}
4232+
4233+
NAPI_GRO_CB(skb)->csum = wsum;
4234+
NAPI_GRO_CB(skb)->csum_valid = 1;
4235+
4236+
return sum;
4237+
}
4238+
EXPORT_SYMBOL(__skb_gro_checksum_complete);
4239+
42084240
/*
42094241
* net_rps_action_and_irq_enable sends any pending IPI's for rps.
42104242
* Note: called with local irq disabled, but exits with local irq enabled.

0 commit comments

Comments
 (0)