Skip to content

Commit 2b16f04

Browse files
daxtensdavem330
authored andcommitted
net: create skb_gso_validate_mac_len()
If you take a GSO skb, and split it into packets, will the MAC length (L2 + L3 + L4 headers + payload) of those packets be small enough to fit within a given length? Move skb_gso_mac_seglen() to skbuff.h with other related functions like skb_gso_network_seglen() so we can use it, and then create skb_gso_validate_mac_len to do the full calculation. Signed-off-by: Daniel Axtens <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 255442c commit 2b16f04

File tree

3 files changed

+66
-23
lines changed

3 files changed

+66
-23
lines changed

include/linux/skbuff.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3287,6 +3287,7 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen);
32873287
void skb_scrub_packet(struct sk_buff *skb, bool xnet);
32883288
unsigned int skb_gso_transport_seglen(const struct sk_buff *skb);
32893289
bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu);
3290+
bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len);
32903291
struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features);
32913292
struct sk_buff *skb_vlan_untag(struct sk_buff *skb);
32923293
int skb_ensure_writable(struct sk_buff *skb, int write_len);
@@ -4120,6 +4121,21 @@ static inline unsigned int skb_gso_network_seglen(const struct sk_buff *skb)
41204121
return hdr_len + skb_gso_transport_seglen(skb);
41214122
}
41224123

4124+
/**
4125+
* skb_gso_mac_seglen - Return length of individual segments of a gso packet
4126+
*
4127+
* @skb: GSO skb
4128+
*
4129+
* skb_gso_mac_seglen is used to determine the real size of the
4130+
* individual segments, including MAC/L2, Layer3 (IP, IPv6) and L4
4131+
* headers (TCP/UDP).
4132+
*/
4133+
static inline unsigned int skb_gso_mac_seglen(const struct sk_buff *skb)
4134+
{
4135+
unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
4136+
return hdr_len + skb_gso_transport_seglen(skb);
4137+
}
4138+
41234139
/* Local Checksum Offload.
41244140
* Compute outer checksum based on the assumption that the
41254141
* inner checksum will be offloaded later.

net/core/skbuff.c

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4914,37 +4914,74 @@ unsigned int skb_gso_transport_seglen(const struct sk_buff *skb)
49144914
EXPORT_SYMBOL_GPL(skb_gso_transport_seglen);
49154915

49164916
/**
4917-
* skb_gso_validate_mtu - Return in case such skb fits a given MTU
4917+
* skb_gso_size_check - check the skb size, considering GSO_BY_FRAGS
49184918
*
4919-
* @skb: GSO skb
4920-
* @mtu: MTU to validate against
4919+
* There are a couple of instances where we have a GSO skb, and we
4920+
* want to determine what size it would be after it is segmented.
49214921
*
4922-
* skb_gso_validate_mtu validates if a given skb will fit a wanted MTU
4923-
* once split.
4922+
* We might want to check:
4923+
* - L3+L4+payload size (e.g. IP forwarding)
4924+
* - L2+L3+L4+payload size (e.g. sanity check before passing to driver)
4925+
*
4926+
* This is a helper to do that correctly considering GSO_BY_FRAGS.
4927+
*
4928+
* @seg_len: The segmented length (from skb_gso_*_seglen). In the
4929+
* GSO_BY_FRAGS case this will be [header sizes + GSO_BY_FRAGS].
4930+
*
4931+
* @max_len: The maximum permissible length.
4932+
*
4933+
* Returns true if the segmented length <= max length.
49244934
*/
4925-
bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu)
4926-
{
4935+
static inline bool skb_gso_size_check(const struct sk_buff *skb,
4936+
unsigned int seg_len,
4937+
unsigned int max_len) {
49274938
const struct skb_shared_info *shinfo = skb_shinfo(skb);
49284939
const struct sk_buff *iter;
4929-
unsigned int hlen;
4930-
4931-
hlen = skb_gso_network_seglen(skb);
49324940

49334941
if (shinfo->gso_size != GSO_BY_FRAGS)
4934-
return hlen <= mtu;
4942+
return seg_len <= max_len;
49354943

49364944
/* Undo this so we can re-use header sizes */
4937-
hlen -= GSO_BY_FRAGS;
4945+
seg_len -= GSO_BY_FRAGS;
49384946

49394947
skb_walk_frags(skb, iter) {
4940-
if (hlen + skb_headlen(iter) > mtu)
4948+
if (seg_len + skb_headlen(iter) > max_len)
49414949
return false;
49424950
}
49434951

49444952
return true;
49454953
}
4954+
4955+
/**
4956+
* skb_gso_validate_mtu - Return in case such skb fits a given MTU
4957+
*
4958+
* @skb: GSO skb
4959+
* @mtu: MTU to validate against
4960+
*
4961+
* skb_gso_validate_mtu validates if a given skb will fit a wanted MTU
4962+
* once split.
4963+
*/
4964+
bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu)
4965+
{
4966+
return skb_gso_size_check(skb, skb_gso_network_seglen(skb), mtu);
4967+
}
49464968
EXPORT_SYMBOL_GPL(skb_gso_validate_mtu);
49474969

4970+
/**
4971+
* skb_gso_validate_mac_len - Will a split GSO skb fit in a given length?
4972+
*
4973+
* @skb: GSO skb
4974+
* @len: length to validate against
4975+
*
4976+
* skb_gso_validate_mac_len validates if a given skb will fit a wanted
4977+
* length once split, including L2, L3 and L4 headers and the payload.
4978+
*/
4979+
bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len)
4980+
{
4981+
return skb_gso_size_check(skb, skb_gso_mac_seglen(skb), len);
4982+
}
4983+
EXPORT_SYMBOL_GPL(skb_gso_validate_mac_len);
4984+
49484985
static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb)
49494986
{
49504987
if (skb_cow(skb, skb_headroom(skb)) < 0) {

net/sched/sch_tbf.c

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -142,16 +142,6 @@ static u64 psched_ns_t2l(const struct psched_ratecfg *r,
142142
return len;
143143
}
144144

145-
/*
146-
* Return length of individual segments of a gso packet,
147-
* including all headers (MAC, IP, TCP/UDP)
148-
*/
149-
static unsigned int skb_gso_mac_seglen(const struct sk_buff *skb)
150-
{
151-
unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
152-
return hdr_len + skb_gso_transport_seglen(skb);
153-
}
154-
155145
/* GSO packet is too big, segment it so that tbf can transmit
156146
* each segment in time
157147
*/

0 commit comments

Comments
 (0)