Skip to content

Commit 0d3c703

Browse files
tomratbertdavem330
authored andcommitted
ipv6: Cleanup IPv6 tunnel receive path
Some basic changes to make IPv6 tunnel receive path look more like IPv4 path: - Make ip6_tnl_rcv non-static so that GREv6 and others can call it - Make ip6_tnl_rcv look like ip_tunnel_rcv - Switch to gro_cells_receive - Make ip6_tnl_rcv non-static and export it Signed-off-by: Tom Herbert <tom@herbertland.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 570d632 commit 0d3c703

File tree

2 files changed

+146
-70
lines changed

2 files changed

+146
-70
lines changed

include/net/ip6_tunnel.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ struct ip6_tnl {
4242
struct __ip6_tnl_parm parms; /* tunnel configuration parameters */
4343
struct flowi fl; /* flowi template for xmit */
4444
struct dst_cache dst_cache; /* cached dst */
45+
struct gro_cells gro_cells;
4546

4647
int err_count;
4748
unsigned long err_time;
@@ -63,6 +64,9 @@ struct ipv6_tlv_tnl_enc_lim {
6364

6465
int ip6_tnl_rcv_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
6566
const struct in6_addr *raddr);
67+
int ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
68+
const struct tnl_ptk_info *tpi, struct metadata_dst *tun_dst,
69+
bool log_ecn_error);
6670
int ip6_tnl_xmit_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
6771
const struct in6_addr *raddr);
6872
__u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw);

net/ipv6/ip6_tunnel.c

Lines changed: 142 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ static void ip6_dev_free(struct net_device *dev)
238238
{
239239
struct ip6_tnl *t = netdev_priv(dev);
240240

241+
gro_cells_destroy(&t->gro_cells);
241242
dst_cache_destroy(&t->dst_cache);
242243
free_percpu(dev->tstats);
243244
free_netdev(dev);
@@ -753,97 +754,157 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
753754
}
754755
EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl);
755756

756-
/**
757-
* ip6_tnl_rcv - decapsulate IPv6 packet and retransmit it locally
758-
* @skb: received socket buffer
759-
* @protocol: ethernet protocol ID
760-
* @dscp_ecn_decapsulate: the function to decapsulate DSCP code and ECN
761-
*
762-
* Return: 0
763-
**/
764-
765-
static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
766-
__u8 ipproto,
767-
int (*dscp_ecn_decapsulate)(const struct ip6_tnl *t,
768-
const struct ipv6hdr *ipv6h,
769-
struct sk_buff *skb))
757+
static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
758+
const struct tnl_ptk_info *tpi,
759+
struct metadata_dst *tun_dst,
760+
int (*dscp_ecn_decapsulate)(const struct ip6_tnl *t,
761+
const struct ipv6hdr *ipv6h,
762+
struct sk_buff *skb),
763+
bool log_ecn_err)
770764
{
771-
struct ip6_tnl *t;
765+
struct pcpu_sw_netstats *tstats;
772766
const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
773-
u8 tproto;
774767
int err;
775768

776-
rcu_read_lock();
777-
t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, &ipv6h->daddr);
778-
if (t) {
779-
struct pcpu_sw_netstats *tstats;
769+
if ((!(tpi->flags & TUNNEL_CSUM) &&
770+
(tunnel->parms.i_flags & TUNNEL_CSUM)) ||
771+
((tpi->flags & TUNNEL_CSUM) &&
772+
!(tunnel->parms.i_flags & TUNNEL_CSUM))) {
773+
tunnel->dev->stats.rx_crc_errors++;
774+
tunnel->dev->stats.rx_errors++;
775+
goto drop;
776+
}
780777

781-
tproto = ACCESS_ONCE(t->parms.proto);
782-
if (tproto != ipproto && tproto != 0) {
783-
rcu_read_unlock();
784-
goto discard;
778+
if (tunnel->parms.i_flags & TUNNEL_SEQ) {
779+
if (!(tpi->flags & TUNNEL_SEQ) ||
780+
(tunnel->i_seqno &&
781+
(s32)(ntohl(tpi->seq) - tunnel->i_seqno) < 0)) {
782+
tunnel->dev->stats.rx_fifo_errors++;
783+
tunnel->dev->stats.rx_errors++;
784+
goto drop;
785785
}
786+
tunnel->i_seqno = ntohl(tpi->seq) + 1;
787+
}
786788

787-
if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
788-
rcu_read_unlock();
789-
goto discard;
790-
}
789+
skb->protocol = tpi->proto;
791790

792-
if (!ip6_tnl_rcv_ctl(t, &ipv6h->daddr, &ipv6h->saddr)) {
793-
t->dev->stats.rx_dropped++;
794-
rcu_read_unlock();
795-
goto discard;
791+
/* Warning: All skb pointers will be invalidated! */
792+
if (tunnel->dev->type == ARPHRD_ETHER) {
793+
if (!pskb_may_pull(skb, ETH_HLEN)) {
794+
tunnel->dev->stats.rx_length_errors++;
795+
tunnel->dev->stats.rx_errors++;
796+
goto drop;
796797
}
797-
skb->mac_header = skb->network_header;
798-
skb_reset_network_header(skb);
799-
skb->protocol = htons(protocol);
800-
memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
801-
802-
__skb_tunnel_rx(skb, t->dev, t->net);
803-
804-
err = dscp_ecn_decapsulate(t, ipv6h, skb);
805-
if (unlikely(err)) {
806-
if (log_ecn_error)
807-
net_info_ratelimited("non-ECT from %pI6 with dsfield=%#x\n",
808-
&ipv6h->saddr,
809-
ipv6_get_dsfield(ipv6h));
810-
if (err > 1) {
811-
++t->dev->stats.rx_frame_errors;
812-
++t->dev->stats.rx_errors;
813-
rcu_read_unlock();
814-
goto discard;
815-
}
798+
799+
ipv6h = ipv6_hdr(skb);
800+
skb->protocol = eth_type_trans(skb, tunnel->dev);
801+
skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
802+
} else {
803+
skb->dev = tunnel->dev;
804+
}
805+
806+
skb_reset_network_header(skb);
807+
memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
808+
809+
__skb_tunnel_rx(skb, tunnel->dev, tunnel->net);
810+
811+
err = dscp_ecn_decapsulate(tunnel, ipv6h, skb);
812+
if (unlikely(err)) {
813+
if (log_ecn_err)
814+
net_info_ratelimited("non-ECT from %pI6 with DS=%#x\n",
815+
&ipv6h->saddr,
816+
ipv6_get_dsfield(ipv6h));
817+
if (err > 1) {
818+
++tunnel->dev->stats.rx_frame_errors;
819+
++tunnel->dev->stats.rx_errors;
820+
goto drop;
816821
}
822+
}
817823

818-
tstats = this_cpu_ptr(t->dev->tstats);
819-
u64_stats_update_begin(&tstats->syncp);
820-
tstats->rx_packets++;
821-
tstats->rx_bytes += skb->len;
822-
u64_stats_update_end(&tstats->syncp);
824+
tstats = this_cpu_ptr(tunnel->dev->tstats);
825+
u64_stats_update_begin(&tstats->syncp);
826+
tstats->rx_packets++;
827+
tstats->rx_bytes += skb->len;
828+
u64_stats_update_end(&tstats->syncp);
823829

824-
netif_rx(skb);
830+
skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(tunnel->dev)));
825831

826-
rcu_read_unlock();
827-
return 0;
832+
gro_cells_receive(&tunnel->gro_cells, skb);
833+
return 0;
834+
835+
drop:
836+
kfree_skb(skb);
837+
return 0;
838+
}
839+
840+
int ip6_tnl_rcv(struct ip6_tnl *t, struct sk_buff *skb,
841+
const struct tnl_ptk_info *tpi,
842+
struct metadata_dst *tun_dst,
843+
bool log_ecn_err)
844+
{
845+
return __ip6_tnl_rcv(t, skb, tpi, NULL, ip6ip6_dscp_ecn_decapsulate,
846+
log_ecn_err);
847+
}
848+
EXPORT_SYMBOL(ip6_tnl_rcv);
849+
850+
static const struct tnl_ptk_info tpi_v6 = {
851+
/* no tunnel info required for ipxip6. */
852+
.proto = htons(ETH_P_IPV6),
853+
};
854+
855+
static const struct tnl_ptk_info tpi_v4 = {
856+
/* no tunnel info required for ipxip6. */
857+
.proto = htons(ETH_P_IP),
858+
};
859+
860+
static int ipxip6_rcv(struct sk_buff *skb, u8 ipproto,
861+
const struct tnl_ptk_info *tpi,
862+
int (*dscp_ecn_decapsulate)(const struct ip6_tnl *t,
863+
const struct ipv6hdr *ipv6h,
864+
struct sk_buff *skb))
865+
{
866+
struct ip6_tnl *t;
867+
const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
868+
int ret = -1;
869+
870+
rcu_read_lock();
871+
t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, &ipv6h->daddr);
872+
873+
if (t) {
874+
u8 tproto = ACCESS_ONCE(t->parms.proto);
875+
876+
if (tproto != ipproto && tproto != 0)
877+
goto drop;
878+
if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
879+
goto drop;
880+
if (!ip6_tnl_rcv_ctl(t, &ipv6h->daddr, &ipv6h->saddr))
881+
goto drop;
882+
if (iptunnel_pull_header(skb, 0, tpi->proto, false))
883+
goto drop;
884+
ret = __ip6_tnl_rcv(t, skb, tpi, NULL, dscp_ecn_decapsulate,
885+
log_ecn_error);
828886
}
887+
829888
rcu_read_unlock();
830-
return 1;
831889

832-
discard:
890+
return ret;
891+
892+
drop:
893+
rcu_read_unlock();
833894
kfree_skb(skb);
834895
return 0;
835896
}
836897

837898
static int ip4ip6_rcv(struct sk_buff *skb)
838899
{
839-
return ip6_tnl_rcv(skb, ETH_P_IP, IPPROTO_IPIP,
840-
ip4ip6_dscp_ecn_decapsulate);
900+
return ipxip6_rcv(skb, IPPROTO_IP, &tpi_v4,
901+
ip4ip6_dscp_ecn_decapsulate);
841902
}
842903

843904
static int ip6ip6_rcv(struct sk_buff *skb)
844905
{
845-
return ip6_tnl_rcv(skb, ETH_P_IPV6, IPPROTO_IPV6,
846-
ip6ip6_dscp_ecn_decapsulate);
906+
return ipxip6_rcv(skb, IPPROTO_IPV6, &tpi_v6,
907+
ip6ip6_dscp_ecn_decapsulate);
847908
}
848909

849910
struct ipv6_tel_txoption {
@@ -1370,6 +1431,8 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
13701431
struct net *net = t->net;
13711432
struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
13721433

1434+
memset(&p1, 0, sizeof(p1));
1435+
13731436
switch (cmd) {
13741437
case SIOCGETTUNNEL:
13751438
if (dev == ip6n->fb_tnl_dev) {
@@ -1549,13 +1612,22 @@ ip6_tnl_dev_init_gen(struct net_device *dev)
15491612
return -ENOMEM;
15501613

15511614
ret = dst_cache_init(&t->dst_cache, GFP_KERNEL);
1552-
if (ret) {
1553-
free_percpu(dev->tstats);
1554-
dev->tstats = NULL;
1555-
return ret;
1556-
}
1615+
if (ret)
1616+
goto free_stats;
1617+
1618+
ret = gro_cells_init(&t->gro_cells, dev);
1619+
if (ret)
1620+
goto destroy_dst;
15571621

15581622
return 0;
1623+
1624+
destroy_dst:
1625+
dst_cache_destroy(&t->dst_cache);
1626+
free_stats:
1627+
free_percpu(dev->tstats);
1628+
dev->tstats = NULL;
1629+
1630+
return ret;
15591631
}
15601632

15611633
/**

0 commit comments

Comments
 (0)