diff options
-rw-r--r-- | include/linux/skbuff.h | 16 | ||||
-rw-r--r-- | net/core/skbuff.c | 63 | ||||
-rw-r--r-- | net/sched/sch_tbf.c | 10 |
3 files changed, 66 insertions, 23 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index ac89a93b7c83..5ebc0f869720 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -3287,6 +3287,7 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen); | |||
3287 | void skb_scrub_packet(struct sk_buff *skb, bool xnet); | 3287 | void skb_scrub_packet(struct sk_buff *skb, bool xnet); |
3288 | unsigned int skb_gso_transport_seglen(const struct sk_buff *skb); | 3288 | unsigned int skb_gso_transport_seglen(const struct sk_buff *skb); |
3289 | bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu); | 3289 | 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); | ||
3290 | struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features); | 3291 | struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features); |
3291 | struct sk_buff *skb_vlan_untag(struct sk_buff *skb); | 3292 | struct sk_buff *skb_vlan_untag(struct sk_buff *skb); |
3292 | int skb_ensure_writable(struct sk_buff *skb, int write_len); | 3293 | 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) | |||
4120 | return hdr_len + skb_gso_transport_seglen(skb); | 4121 | return hdr_len + skb_gso_transport_seglen(skb); |
4121 | } | 4122 | } |
4122 | 4123 | ||
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 | |||
4123 | /* Local Checksum Offload. | 4139 | /* Local Checksum Offload. |
4124 | * Compute outer checksum based on the assumption that the | 4140 | * Compute outer checksum based on the assumption that the |
4125 | * inner checksum will be offloaded later. | 4141 | * inner checksum will be offloaded later. |
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 01e8285aea73..8c61c27c1b28 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -4914,37 +4914,74 @@ unsigned int skb_gso_transport_seglen(const struct sk_buff *skb) | |||
4914 | EXPORT_SYMBOL_GPL(skb_gso_transport_seglen); | 4914 | EXPORT_SYMBOL_GPL(skb_gso_transport_seglen); |
4915 | 4915 | ||
4916 | /** | 4916 | /** |
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 |
4918 | * | 4918 | * |
4919 | * @skb: GSO skb | 4919 | * There are a couple of instances where we have a GSO skb, and we |
4920 | * @mtu: MTU to validate against | 4920 | * want to determine what size it would be after it is segmented. |
4921 | * | 4921 | * |
4922 | * skb_gso_validate_mtu validates if a given skb will fit a wanted MTU | 4922 | * We might want to check: |
4923 | * once split. | 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. | ||
4924 | */ | 4934 | */ |
4925 | bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu) | 4935 | static inline bool skb_gso_size_check(const struct sk_buff *skb, |
4926 | { | 4936 | unsigned int seg_len, |
4937 | unsigned int max_len) { | ||
4927 | const struct skb_shared_info *shinfo = skb_shinfo(skb); | 4938 | const struct skb_shared_info *shinfo = skb_shinfo(skb); |
4928 | const struct sk_buff *iter; | 4939 | const struct sk_buff *iter; |
4929 | unsigned int hlen; | ||
4930 | |||
4931 | hlen = skb_gso_network_seglen(skb); | ||
4932 | 4940 | ||
4933 | if (shinfo->gso_size != GSO_BY_FRAGS) | 4941 | if (shinfo->gso_size != GSO_BY_FRAGS) |
4934 | return hlen <= mtu; | 4942 | return seg_len <= max_len; |
4935 | 4943 | ||
4936 | /* Undo this so we can re-use header sizes */ | 4944 | /* Undo this so we can re-use header sizes */ |
4937 | hlen -= GSO_BY_FRAGS; | 4945 | seg_len -= GSO_BY_FRAGS; |
4938 | 4946 | ||
4939 | skb_walk_frags(skb, iter) { | 4947 | skb_walk_frags(skb, iter) { |
4940 | if (hlen + skb_headlen(iter) > mtu) | 4948 | if (seg_len + skb_headlen(iter) > max_len) |
4941 | return false; | 4949 | return false; |
4942 | } | 4950 | } |
4943 | 4951 | ||
4944 | return true; | 4952 | return true; |
4945 | } | 4953 | } |
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 | } | ||
4946 | EXPORT_SYMBOL_GPL(skb_gso_validate_mtu); | 4968 | EXPORT_SYMBOL_GPL(skb_gso_validate_mtu); |
4947 | 4969 | ||
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 | |||
4948 | static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb) | 4985 | static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb) |
4949 | { | 4986 | { |
4950 | if (skb_cow(skb, skb_headroom(skb)) < 0) { | 4987 | if (skb_cow(skb, skb_headroom(skb)) < 0) { |
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 83e76d046993..229172d509cc 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c | |||
@@ -142,16 +142,6 @@ static u64 psched_ns_t2l(const struct psched_ratecfg *r, | |||
142 | return len; | 142 | return len; |
143 | } | 143 | } |
144 | 144 | ||
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 | |||
155 | /* GSO packet is too big, segment it so that tbf can transmit | 145 | /* GSO packet is too big, segment it so that tbf can transmit |
156 | * each segment in time | 146 | * each segment in time |
157 | */ | 147 | */ |