Skip to content

Commit 2817a33

Browse files
Daniel Borkmanndavem330
authored andcommitted
net: skb_checksum: allow custom update/combine for walking skb
Currently, skb_checksum walks over 1) linearized, 2) frags[], and 3) frag_list data and calculats the one's complement, a 32 bit result suitable for feeding into itself or csum_tcpudp_magic(), but unsuitable for SCTP as we're calculating CRC32c there. Hence, in order to not re-implement the very same function in SCTP (and maybe other protocols) over and over again, use an update() + combine() callback internally to allow for walking over the skb with different algorithms. Signed-off-by: Daniel Borkmann <dborkman@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent efba721 commit 2817a33

File tree

3 files changed

+37
-13
lines changed

3 files changed

+37
-13
lines changed

include/linux/skbuff.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2360,8 +2360,6 @@ int skb_copy_datagram_const_iovec(const struct sk_buff *from, int offset,
23602360
void skb_free_datagram(struct sock *sk, struct sk_buff *skb);
23612361
void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb);
23622362
int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags);
2363-
__wsum skb_checksum(const struct sk_buff *skb, int offset, int len,
2364-
__wsum csum);
23652363
int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len);
23662364
int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len);
23672365
__wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to,
@@ -2373,9 +2371,18 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to);
23732371
void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len);
23742372
int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen);
23752373
void skb_scrub_packet(struct sk_buff *skb, bool xnet);
2376-
23772374
struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features);
23782375

2376+
struct skb_checksum_ops {
2377+
__wsum (*update)(const void *mem, int len, __wsum wsum);
2378+
__wsum (*combine)(__wsum csum, __wsum csum2, int offset, int len);
2379+
};
2380+
2381+
__wsum __skb_checksum(const struct sk_buff *skb, int offset, int len,
2382+
__wsum csum, const struct skb_checksum_ops *ops);
2383+
__wsum skb_checksum(const struct sk_buff *skb, int offset, int len,
2384+
__wsum csum);
2385+
23792386
static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
23802387
int len, void *buffer)
23812388
{

include/net/checksum.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ csum_block_add(__wsum csum, __wsum csum2, int offset)
7878
return csum_add(csum, (__force __wsum)sum);
7979
}
8080

81+
static inline __wsum
82+
csum_block_add_ext(__wsum csum, __wsum csum2, int offset, int len)
83+
{
84+
return csum_block_add(csum, csum2, offset);
85+
}
86+
8187
static inline __wsum
8288
csum_block_sub(__wsum csum, __wsum csum2, int offset)
8389
{

net/core/skbuff.c

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1928,9 +1928,8 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)
19281928
EXPORT_SYMBOL(skb_store_bits);
19291929

19301930
/* Checksum skb data. */
1931-
1932-
__wsum skb_checksum(const struct sk_buff *skb, int offset,
1933-
int len, __wsum csum)
1931+
__wsum __skb_checksum(const struct sk_buff *skb, int offset, int len,
1932+
__wsum csum, const struct skb_checksum_ops *ops)
19341933
{
19351934
int start = skb_headlen(skb);
19361935
int i, copy = start - offset;
@@ -1941,7 +1940,7 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
19411940
if (copy > 0) {
19421941
if (copy > len)
19431942
copy = len;
1944-
csum = csum_partial(skb->data + offset, copy, csum);
1943+
csum = ops->update(skb->data + offset, copy, csum);
19451944
if ((len -= copy) == 0)
19461945
return csum;
19471946
offset += copy;
@@ -1962,10 +1961,10 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
19621961
if (copy > len)
19631962
copy = len;
19641963
vaddr = kmap_atomic(skb_frag_page(frag));
1965-
csum2 = csum_partial(vaddr + frag->page_offset +
1966-
offset - start, copy, 0);
1964+
csum2 = ops->update(vaddr + frag->page_offset +
1965+
offset - start, copy, 0);
19671966
kunmap_atomic(vaddr);
1968-
csum = csum_block_add(csum, csum2, pos);
1967+
csum = ops->combine(csum, csum2, pos, copy);
19691968
if (!(len -= copy))
19701969
return csum;
19711970
offset += copy;
@@ -1984,9 +1983,9 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
19841983
__wsum csum2;
19851984
if (copy > len)
19861985
copy = len;
1987-
csum2 = skb_checksum(frag_iter, offset - start,
1988-
copy, 0);
1989-
csum = csum_block_add(csum, csum2, pos);
1986+
csum2 = __skb_checksum(frag_iter, offset - start,
1987+
copy, 0, ops);
1988+
csum = ops->combine(csum, csum2, pos, copy);
19901989
if ((len -= copy) == 0)
19911990
return csum;
19921991
offset += copy;
@@ -1998,6 +1997,18 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
19981997

19991998
return csum;
20001999
}
2000+
EXPORT_SYMBOL(__skb_checksum);
2001+
2002+
__wsum skb_checksum(const struct sk_buff *skb, int offset,
2003+
int len, __wsum csum)
2004+
{
2005+
const struct skb_checksum_ops ops = {
2006+
.update = csum_partial,
2007+
.combine = csum_block_add_ext,
2008+
};
2009+
2010+
return __skb_checksum(skb, offset, len, csum, &ops);
2011+
}
20012012
EXPORT_SYMBOL(skb_checksum);
20022013

20032014
/* Both of above in one bottle. */

0 commit comments

Comments
 (0)