aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorReece R. Pollack2015-02-02 15:06:03 -0600
committerReece R. Pollack2015-02-04 17:36:03 -0600
commit8931ad85747fb375811f4ad43c32b879e54202b7 (patch)
tree2de0f5b7e69d446e5b75c43a9ebc154123bcff21
parent579f5a90edb6a600de31d1edfe59a7c3bac8f548 (diff)
downloadlinux-8931ad85747fb375811f4ad43c32b879e54202b7.tar.gz
linux-8931ad85747fb375811f4ad43c32b879e54202b7.tar.xz
linux-8931ad85747fb375811f4ad43c32b879e54202b7.zip
net: Add IPv4 ICMP support to GSO
This patch adds support for IPv4 ICMP to Generic Segementation Offload. This permits inner fragmentation of ICMP packets sent over certain IPsec tunnels, rather than requiring fragmentation of the over-sized IPsec packets. Signed-off-by: Reece R. Pollack <x0183204@ti.com>
-rw-r--r--include/net/icmp.h4
-rw-r--r--net/ipv4/af_inet.c12
-rw-r--r--net/ipv4/icmp.c28
3 files changed, 43 insertions, 1 deletions
diff --git a/include/net/icmp.h b/include/net/icmp.h
index 081439fd070..76d8d6f4424 100644
--- a/include/net/icmp.h
+++ b/include/net/icmp.h
@@ -45,4 +45,8 @@ extern void icmp_err(struct sk_buff *, u32 info);
45extern int icmp_init(void); 45extern int icmp_init(void);
46extern void icmp_out_count(struct net *net, unsigned char type); 46extern void icmp_out_count(struct net *net, unsigned char type);
47 47
48int icmp4_ifo_send_check(struct sk_buff *skb);
49struct sk_buff *icmp4_ifo_fragment(struct sk_buff *skb,
50 netdev_features_t features);
51
48#endif /* _ICMP_H */ 52#endif /* _ICMP_H */
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index c4adc319cc2..db094b764ef 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1328,7 +1328,8 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
1328 skb = segs; 1328 skb = segs;
1329 do { 1329 do {
1330 iph = ip_hdr(skb); 1330 iph = ip_hdr(skb);
1331 if (!tunnel && proto == IPPROTO_UDP) { 1331 if (!tunnel && ((proto == IPPROTO_UDP) ||
1332 (proto == IPPROTO_ICMP))) {
1332 iph->id = htons(id); 1333 iph->id = htons(id);
1333 iph->frag_off = htons(offset >> 3); 1334 iph->frag_off = htons(offset >> 3);
1334 if (skb->next != NULL) 1335 if (skb->next != NULL)
@@ -1585,6 +1586,13 @@ static const struct net_protocol icmp_protocol = {
1585 .netns_ok = 1, 1586 .netns_ok = 1,
1586}; 1587};
1587 1588
1589static const struct net_offload icmp_offload = {
1590 .callbacks = {
1591 .gso_send_check = icmp4_ifo_send_check,
1592 .gso_segment = icmp4_ifo_fragment,
1593 },
1594};
1595
1588static __net_init int ipv4_mib_init_net(struct net *net) 1596static __net_init int ipv4_mib_init_net(struct net *net)
1589{ 1597{
1590 if (snmp_mib_init((void __percpu **)net->mib.tcp_statistics, 1598 if (snmp_mib_init((void __percpu **)net->mib.tcp_statistics,
@@ -1681,6 +1689,8 @@ static int __init ipv4_offload_init(void)
1681 pr_crit("%s: Cannot add UDP protocol offload\n", __func__); 1689 pr_crit("%s: Cannot add UDP protocol offload\n", __func__);
1682 if (inet_add_offload(&tcp_offload, IPPROTO_TCP) < 0) 1690 if (inet_add_offload(&tcp_offload, IPPROTO_TCP) < 0)
1683 pr_crit("%s: Cannot add TCP protocol offlaod\n", __func__); 1691 pr_crit("%s: Cannot add TCP protocol offlaod\n", __func__);
1692 if (inet_add_offload(&icmp_offload, IPPROTO_ICMP) < 0)
1693 pr_crit("%s: Cannot add ICMP protocol offload\n", __func__);
1684 1694
1685 dev_add_offload(&ip_packet_offload); 1695 dev_add_offload(&ip_packet_offload);
1686 return 0; 1696 return 0;
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index ea78ef5ac35..6e456f97d23 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -1031,6 +1031,34 @@ static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = {
1031 }, 1031 },
1032}; 1032};
1033 1033
1034int icmp4_ifo_send_check(struct sk_buff *skb)
1035{
1036 return 0;
1037}
1038
1039struct sk_buff *icmp4_ifo_fragment(struct sk_buff *skb,
1040 netdev_features_t features)
1041{
1042 struct icmphdr *icmph;
1043 struct sk_buff *segs = ERR_PTR(-EINVAL);
1044 unsigned int mss;
1045
1046 mss = skb_shinfo(skb)->gso_size;
1047 if (unlikely(skb->len <= mss))
1048 goto out;
1049
1050 /* Fragment the skb. IP headers of the fragments are updated in
1051 * inet_gso_segment()
1052 */
1053 icmph = icmp_hdr(skb);
1054 skb->ip_summed = CHECKSUM_NONE;
1055
1056 segs = skb_segment(skb, features);
1057
1058out:
1059 return segs;
1060}
1061
1034static void __net_exit icmp_sk_exit(struct net *net) 1062static void __net_exit icmp_sk_exit(struct net *net)
1035{ 1063{
1036 int i; 1064 int i;