Skip to content

Commit b05229f

Browse files
tomratbertdavem330
authored andcommitted
gre6: Cleanup GREv6 transmit path, call common GRE functions
Changes in GREv6 transmit path: - Call gre_checksum, remove gre6_checksum - Rename ip6gre_xmit2 to __gre6_xmit - Call gre_build_header utility function - Call ip6_tnl_xmit common function - Call ip6_tnl_change_mtu, eliminate ip6gre_tunnel_change_mtu Signed-off-by: Tom Herbert <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 79ecb90 commit b05229f

File tree

1 file changed

+50
-202
lines changed

1 file changed

+50
-202
lines changed

net/ipv6/ip6_gre.c

Lines changed: 50 additions & 202 deletions
Original file line numberDiff line numberDiff line change
@@ -488,199 +488,40 @@ struct ipv6_tel_txoption {
488488
__u8 dst_opt[8];
489489
};
490490

491-
static void init_tel_txopt(struct ipv6_tel_txoption *opt, __u8 encap_limit)
491+
static int gre_handle_offloads(struct sk_buff *skb, bool csum)
492492
{
493-
memset(opt, 0, sizeof(struct ipv6_tel_txoption));
494-
495-
opt->dst_opt[2] = IPV6_TLV_TNL_ENCAP_LIMIT;
496-
opt->dst_opt[3] = 1;
497-
opt->dst_opt[4] = encap_limit;
498-
opt->dst_opt[5] = IPV6_TLV_PADN;
499-
opt->dst_opt[6] = 1;
500-
501-
opt->ops.dst0opt = (struct ipv6_opt_hdr *) opt->dst_opt;
502-
opt->ops.opt_nflen = 8;
493+
return iptunnel_handle_offloads(skb,
494+
csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
503495
}
504496

505-
static __sum16 gre6_checksum(struct sk_buff *skb)
506-
{
507-
__wsum csum;
508-
509-
if (skb->ip_summed == CHECKSUM_PARTIAL)
510-
csum = lco_csum(skb);
511-
else
512-
csum = skb_checksum(skb, sizeof(struct ipv6hdr),
513-
skb->len - sizeof(struct ipv6hdr), 0);
514-
return csum_fold(csum);
515-
}
516-
517-
static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
518-
struct net_device *dev,
519-
__u8 dsfield,
520-
struct flowi6 *fl6,
521-
int encap_limit,
522-
__u32 *pmtu)
497+
static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
498+
struct net_device *dev, __u8 dsfield,
499+
struct flowi6 *fl6, int encap_limit,
500+
__u32 *pmtu, __be16 proto)
523501
{
524502
struct ip6_tnl *tunnel = netdev_priv(dev);
525-
struct net *net = tunnel->net;
526-
struct net_device *tdev; /* Device to other host */
527-
struct ipv6hdr *ipv6h; /* Our new IP header */
528-
unsigned int min_headroom = 0; /* The extra header space needed */
529-
int gre_hlen;
530-
struct ipv6_tel_txoption opt;
531-
int mtu;
532-
struct dst_entry *dst = NULL, *ndst = NULL;
533-
struct net_device_stats *stats = &tunnel->dev->stats;
534-
int err = -1;
535-
u8 proto;
536-
__be16 protocol;
503+
__be16 protocol = (dev->type == ARPHRD_ETHER) ?
504+
htons(ETH_P_TEB) : proto;
537505

538506
if (dev->type == ARPHRD_ETHER)
539507
IPCB(skb)->flags = 0;
540508

541-
if (dev->header_ops && dev->type == ARPHRD_IP6GRE) {
542-
gre_hlen = 0;
543-
ipv6h = (struct ipv6hdr *)skb->data;
544-
fl6->daddr = ipv6h->daddr;
545-
} else {
546-
gre_hlen = tunnel->hlen;
509+
if (dev->header_ops && dev->type == ARPHRD_IP6GRE)
510+
fl6->daddr = ((struct ipv6hdr *)skb->data)->daddr;
511+
else
547512
fl6->daddr = tunnel->parms.raddr;
548-
}
549-
550-
if (!fl6->flowi6_mark)
551-
dst = dst_cache_get(&tunnel->dst_cache);
552-
553-
if (!dst) {
554-
dst = ip6_route_output(net, NULL, fl6);
555-
556-
if (dst->error)
557-
goto tx_err_link_failure;
558-
dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), NULL, 0);
559-
if (IS_ERR(dst)) {
560-
err = PTR_ERR(dst);
561-
dst = NULL;
562-
goto tx_err_link_failure;
563-
}
564-
ndst = dst;
565-
}
566-
567-
tdev = dst->dev;
568-
569-
if (tdev == dev) {
570-
stats->collisions++;
571-
net_warn_ratelimited("%s: Local routing loop detected!\n",
572-
tunnel->parms.name);
573-
goto tx_err_dst_release;
574-
}
575513

576-
mtu = dst_mtu(dst) - sizeof(*ipv6h);
577-
if (encap_limit >= 0) {
578-
min_headroom += 8;
579-
mtu -= 8;
580-
}
581-
if (mtu < IPV6_MIN_MTU)
582-
mtu = IPV6_MIN_MTU;
583-
if (skb_dst(skb))
584-
skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
585-
if (skb->len > mtu && !skb_is_gso(skb)) {
586-
*pmtu = mtu;
587-
err = -EMSGSIZE;
588-
goto tx_err_dst_release;
589-
}
514+
if (tunnel->parms.o_flags & TUNNEL_SEQ)
515+
tunnel->o_seqno++;
590516

591-
if (tunnel->err_count > 0) {
592-
if (time_before(jiffies,
593-
tunnel->err_time + IP6TUNNEL_ERR_TIMEO)) {
594-
tunnel->err_count--;
517+
/* Push GRE header. */
518+
gre_build_header(skb, tunnel->tun_hlen, tunnel->parms.o_flags,
519+
protocol, tunnel->parms.o_key, htonl(tunnel->o_seqno));
595520

596-
dst_link_failure(skb);
597-
} else
598-
tunnel->err_count = 0;
599-
}
521+
skb_set_inner_protocol(skb, proto);
600522

601-
skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(dev)));
602-
603-
min_headroom += LL_RESERVED_SPACE(tdev) + gre_hlen + dst->header_len;
604-
605-
if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) {
606-
int head_delta = SKB_DATA_ALIGN(min_headroom -
607-
skb_headroom(skb) +
608-
16);
609-
610-
err = pskb_expand_head(skb, max_t(int, head_delta, 0),
611-
0, GFP_ATOMIC);
612-
if (min_headroom > dev->needed_headroom)
613-
dev->needed_headroom = min_headroom;
614-
if (unlikely(err))
615-
goto tx_err_dst_release;
616-
}
617-
618-
if (!fl6->flowi6_mark && ndst)
619-
dst_cache_set_ip6(&tunnel->dst_cache, ndst, &fl6->saddr);
620-
skb_dst_set(skb, dst);
621-
622-
proto = NEXTHDR_GRE;
623-
if (encap_limit >= 0) {
624-
init_tel_txopt(&opt, encap_limit);
625-
ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL);
626-
}
627-
628-
err = iptunnel_handle_offloads(skb,
629-
(tunnel->parms.o_flags & GRE_CSUM) ?
630-
SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
631-
if (err)
632-
goto tx_err_dst_release;
633-
634-
skb_push(skb, gre_hlen);
635-
skb_reset_network_header(skb);
636-
skb_set_transport_header(skb, sizeof(*ipv6h));
637-
638-
/*
639-
* Push down and install the IP header.
640-
*/
641-
ipv6h = ipv6_hdr(skb);
642-
ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield),
643-
ip6_make_flowlabel(net, skb, fl6->flowlabel, true, fl6));
644-
ipv6h->hop_limit = tunnel->parms.hop_limit;
645-
ipv6h->nexthdr = proto;
646-
ipv6h->saddr = fl6->saddr;
647-
ipv6h->daddr = fl6->daddr;
648-
649-
((__be16 *)(ipv6h + 1))[0] = tunnel->parms.o_flags;
650-
protocol = (dev->type == ARPHRD_ETHER) ?
651-
htons(ETH_P_TEB) : skb->protocol;
652-
((__be16 *)(ipv6h + 1))[1] = protocol;
653-
654-
if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) {
655-
__be32 *ptr = (__be32 *)(((u8 *)ipv6h) + tunnel->hlen - 4);
656-
657-
if (tunnel->parms.o_flags&GRE_SEQ) {
658-
++tunnel->o_seqno;
659-
*ptr = htonl(tunnel->o_seqno);
660-
ptr--;
661-
}
662-
if (tunnel->parms.o_flags&GRE_KEY) {
663-
*ptr = tunnel->parms.o_key;
664-
ptr--;
665-
}
666-
if ((tunnel->parms.o_flags & GRE_CSUM) &&
667-
!(skb_shinfo(skb)->gso_type &
668-
(SKB_GSO_GRE | SKB_GSO_GRE_CSUM))) {
669-
*ptr = 0;
670-
*(__sum16 *)ptr = gre6_checksum(skb);
671-
}
672-
}
673-
674-
skb_set_inner_protocol(skb, protocol);
675-
676-
ip6tunnel_xmit(NULL, skb, dev);
677-
return 0;
678-
tx_err_link_failure:
679-
stats->tx_carrier_errors++;
680-
dst_link_failure(skb);
681-
tx_err_dst_release:
682-
dst_release(dst);
683-
return err;
523+
return ip6_tnl_xmit(skb, dev, dsfield, fl6, encap_limit, pmtu,
524+
NEXTHDR_GRE);
684525
}
685526

686527
static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)
@@ -699,7 +540,6 @@ static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)
699540
encap_limit = t->parms.encap_limit;
700541

701542
memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
702-
fl6.flowi6_proto = IPPROTO_GRE;
703543

704544
dsfield = ipv4_get_dsfield(iph);
705545

@@ -709,7 +549,12 @@ static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)
709549
if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
710550
fl6.flowi6_mark = skb->mark;
711551

712-
err = ip6gre_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu);
552+
err = gre_handle_offloads(skb, !!(t->parms.o_flags & TUNNEL_CSUM));
553+
if (err)
554+
return -1;
555+
556+
err = __gre6_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
557+
skb->protocol);
713558
if (err != 0) {
714559
/* XXX: send ICMP error even if DF is not set. */
715560
if (err == -EMSGSIZE)
@@ -749,7 +594,6 @@ static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev)
749594
encap_limit = t->parms.encap_limit;
750595

751596
memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
752-
fl6.flowi6_proto = IPPROTO_GRE;
753597

754598
dsfield = ipv6_get_dsfield(ipv6h);
755599
if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
@@ -759,7 +603,11 @@ static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev)
759603
if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
760604
fl6.flowi6_mark = skb->mark;
761605

762-
err = ip6gre_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu);
606+
if (gre_handle_offloads(skb, !!(t->parms.o_flags & TUNNEL_CSUM)))
607+
return -1;
608+
609+
err = __gre6_xmit(skb, dev, dsfield, &fl6, encap_limit,
610+
&mtu, skb->protocol);
763611
if (err != 0) {
764612
if (err == -EMSGSIZE)
765613
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
@@ -803,7 +651,11 @@ static int ip6gre_xmit_other(struct sk_buff *skb, struct net_device *dev)
803651
memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
804652
fl6.flowi6_proto = skb->protocol;
805653

806-
err = ip6gre_xmit2(skb, dev, 0, &fl6, encap_limit, &mtu);
654+
err = gre_handle_offloads(skb, !!(t->parms.o_flags & TUNNEL_CSUM));
655+
if (err)
656+
return err;
657+
658+
err = __gre6_xmit(skb, dev, 0, &fl6, encap_limit, &mtu, skb->protocol);
807659

808660
return err;
809661
}
@@ -1080,15 +932,6 @@ static int ip6gre_tunnel_ioctl(struct net_device *dev,
1080932
return err;
1081933
}
1082934

1083-
static int ip6gre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
1084-
{
1085-
if (new_mtu < 68 ||
1086-
new_mtu > 0xFFF8 - dev->hard_header_len)
1087-
return -EINVAL;
1088-
dev->mtu = new_mtu;
1089-
return 0;
1090-
}
1091-
1092935
static int ip6gre_header(struct sk_buff *skb, struct net_device *dev,
1093936
unsigned short type,
1094937
const void *daddr, const void *saddr, unsigned int len)
@@ -1132,7 +975,7 @@ static const struct net_device_ops ip6gre_netdev_ops = {
1132975
.ndo_uninit = ip6gre_tunnel_uninit,
1133976
.ndo_start_xmit = ip6gre_tunnel_xmit,
1134977
.ndo_do_ioctl = ip6gre_tunnel_ioctl,
1135-
.ndo_change_mtu = ip6gre_tunnel_change_mtu,
978+
.ndo_change_mtu = ip6_tnl_change_mtu,
1136979
.ndo_get_stats64 = ip_tunnel_get_stats64,
1137980
.ndo_get_iflink = ip6_tnl_get_iflink,
1138981
};
@@ -1148,17 +991,11 @@ static void ip6gre_dev_free(struct net_device *dev)
1148991

1149992
static void ip6gre_tunnel_setup(struct net_device *dev)
1150993
{
1151-
struct ip6_tnl *t;
1152-
1153994
dev->netdev_ops = &ip6gre_netdev_ops;
1154995
dev->destructor = ip6gre_dev_free;
1155996

1156997
dev->type = ARPHRD_IP6GRE;
1157-
dev->hard_header_len = LL_MAX_HEADER + sizeof(struct ipv6hdr) + 4;
1158-
dev->mtu = ETH_DATA_LEN - sizeof(struct ipv6hdr) - 4;
1159-
t = netdev_priv(dev);
1160-
if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
1161-
dev->mtu -= 8;
998+
1162999
dev->flags |= IFF_NOARP;
11631000
dev->addr_len = sizeof(struct in6_addr);
11641001
netif_keep_dst(dev);
@@ -1168,6 +1005,7 @@ static int ip6gre_tunnel_init_common(struct net_device *dev)
11681005
{
11691006
struct ip6_tnl *tunnel;
11701007
int ret;
1008+
int t_hlen;
11711009

11721010
tunnel = netdev_priv(dev);
11731011

@@ -1186,6 +1024,16 @@ static int ip6gre_tunnel_init_common(struct net_device *dev)
11861024
return ret;
11871025
}
11881026

1027+
tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags);
1028+
1029+
t_hlen = tunnel->hlen + sizeof(struct ipv6hdr);
1030+
1031+
dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4;
1032+
dev->mtu = ETH_DATA_LEN - t_hlen - 4;
1033+
1034+
if (!(tunnel->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
1035+
dev->mtu -= 8;
1036+
11891037
return 0;
11901038
}
11911039

@@ -1420,7 +1268,7 @@ static const struct net_device_ops ip6gre_tap_netdev_ops = {
14201268
.ndo_start_xmit = ip6gre_tunnel_xmit,
14211269
.ndo_set_mac_address = eth_mac_addr,
14221270
.ndo_validate_addr = eth_validate_addr,
1423-
.ndo_change_mtu = ip6gre_tunnel_change_mtu,
1271+
.ndo_change_mtu = ip6_tnl_change_mtu,
14241272
.ndo_get_stats64 = ip_tunnel_get_stats64,
14251273
.ndo_get_iflink = ip6_tnl_get_iflink,
14261274
};

0 commit comments

Comments
 (0)