X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Fip_gre.c;h=0f9b3a31997be8af4360f55ec77fa99f7da3f69f;hb=16c70f8c1b54b61c3b951b6fb220df250fe09b32;hp=4a227f51b2c120983e0d8a7bef0e5fd6b7ea4833;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 4a227f51b..0f9b3a319 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -10,7 +10,7 @@ * */ -#include +#include #include #include #include @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -36,6 +37,7 @@ #include #include #include +#include #include #include @@ -151,7 +153,7 @@ static struct ip_tunnel *tunnels[4][HASH_SIZE]; #define tunnels_l (tunnels[1]) #define tunnels_wc (tunnels[0]) -static rwlock_t ipgre_lock = RW_LOCK_UNLOCKED; +static DEFINE_RWLOCK(ipgre_lock); /* Given src, dst and key, find appropriate for input tunnel. */ @@ -186,7 +188,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(u32 remote, u32 local, u32 key) } if (ipgre_fb_tunnel_dev->flags&IFF_UP) - return ipgre_fb_tunnel_dev->priv; + return netdev_priv(ipgre_fb_tunnel_dev); return NULL; } @@ -276,7 +278,7 @@ static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int return NULL; dev->init = ipgre_tunnel_init; - nt = dev->priv; + nt = netdev_priv(dev); nt->parms = *parms; if (register_netdevice(dev) < 0) { @@ -284,12 +286,8 @@ static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int goto failed; } - nt = dev->priv; - nt->parms = *parms; - dev_hold(dev); ipgre_tunnel_link(nt); - /* Do not decrement MOD_USE_COUNT here. */ return nt; failed: @@ -298,12 +296,12 @@ failed: static void ipgre_tunnel_uninit(struct net_device *dev) { - ipgre_tunnel_unlink((struct ip_tunnel*)dev->priv); + ipgre_tunnel_unlink(netdev_priv(dev)); dev_put(dev); } -void ipgre_err(struct sk_buff *skb, u32 info) +static void ipgre_err(struct sk_buff *skb, u32 info) { #ifndef I_WISH_WORLD_WERE_PERFECT @@ -510,14 +508,14 @@ out: /* change mtu on this route */ if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { - if (rel_info > dst_pmtu(skb2->dst)) { + if (rel_info > dst_mtu(skb2->dst)) { kfree_skb(skb2); return; } skb2->dst->ops->update_pmtu(skb2->dst, rel_info); rel_info = htonl(rel_info); } else if (type == ICMP_TIME_EXCEEDED) { - struct ip_tunnel *t = (struct ip_tunnel*)skb2->dev->priv; + struct ip_tunnel *t = netdev_priv(skb2->dev); if (t->parms.iph.ttl) { rel_type = ICMP_DEST_UNREACH; rel_code = ICMP_HOST_UNREACH; @@ -533,11 +531,9 @@ static inline void ipgre_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb) { if (INET_ECN_is_ce(iph->tos)) { if (skb->protocol == htons(ETH_P_IP)) { - if (INET_ECN_is_not_ce(skb->nh.iph->tos)) - IP_ECN_set_ce(skb->nh.iph); + IP_ECN_set_ce(skb->nh.iph); } else if (skb->protocol == htons(ETH_P_IPV6)) { - if (INET_ECN_is_not_ce(ip6_get_dsfield(skb->nh.ipv6h))) - IP6_ECN_set_ce(skb->nh.ipv6h); + IP6_ECN_set_ce(skb->nh.ipv6h); } } } @@ -549,11 +545,11 @@ ipgre_ecn_encapsulate(u8 tos, struct iphdr *old_iph, struct sk_buff *skb) if (skb->protocol == htons(ETH_P_IP)) inner = old_iph->tos; else if (skb->protocol == htons(ETH_P_IPV6)) - inner = ip6_get_dsfield((struct ipv6hdr*)old_iph); + inner = ipv6_get_dsfield((struct ipv6hdr *)old_iph); return INET_ECN_encapsulate(tos, inner); } -int ipgre_rcv(struct sk_buff *skb) +static int ipgre_rcv(struct sk_buff *skb) { struct iphdr *iph; u8 *h; @@ -579,15 +575,16 @@ int ipgre_rcv(struct sk_buff *skb) goto drop_nolock; if (flags&GRE_CSUM) { - if (skb->ip_summed == CHECKSUM_HW) { + switch (skb->ip_summed) { + case CHECKSUM_HW: csum = (u16)csum_fold(skb->csum); - if (csum) - skb->ip_summed = CHECKSUM_NONE; - } - if (skb->ip_summed == CHECKSUM_NONE) { - skb->csum = skb_checksum(skb, 0, skb->len, 0); + if (!csum) + break; + /* fall through */ + case CHECKSUM_NONE: + skb->csum = 0; + csum = __skb_checksum_complete(skb); skb->ip_summed = CHECKSUM_HW; - csum = (u16)csum_fold(skb->csum); } offset += 4; } @@ -605,13 +602,21 @@ int ipgre_rcv(struct sk_buff *skb) if ((tunnel = ipgre_tunnel_lookup(iph->saddr, iph->daddr, key)) != NULL) { secpath_reset(skb); + skb->protocol = *(u16*)(h + 2); + /* WCCP version 1 and 2 protocol decoding. + * - Change protocol to IP + * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header + */ + if (flags == 0 && + skb->protocol == __constant_htons(ETH_P_WCCP)) { + skb->protocol = __constant_htons(ETH_P_IP); + if ((*(h + offset) & 0xF0) != 0x40) + offset += 4; + } + skb->mac.raw = skb->nh.raw; skb->nh.raw = __pskb_pull(skb, offset); - memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); - if (skb->ip_summed == CHECKSUM_HW) - skb->csum = csum_sub(skb->csum, - csum_partial(skb->mac.raw, skb->nh.raw-skb->mac.raw, 0)); - skb->protocol = *(u16*)(h + 2); + skb_postpull_rcsum(skb, skb->h.raw, offset); skb->pkt_type = PACKET_HOST; #ifdef CONFIG_NET_IPGRE_BROADCAST if (MULTICAST(iph->daddr)) { @@ -643,19 +648,13 @@ int ipgre_rcv(struct sk_buff *skb) skb->dev = tunnel->dev; dst_release(skb->dst); skb->dst = NULL; -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif -#endif + nf_reset(skb); ipgre_ecn_decapsulate(iph, skb); netif_rx(skb); read_unlock(&ipgre_lock); return(0); } - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0); + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); drop: read_unlock(&ipgre_lock); @@ -666,7 +665,7 @@ drop_nolock: static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ip_tunnel *tunnel = (struct ip_tunnel*)dev->priv; + struct ip_tunnel *tunnel = netdev_priv(dev); struct net_device_stats *stats = &tunnel->stat; struct iphdr *old_iph = skb->nh.iph; struct iphdr *tiph; @@ -762,9 +761,9 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) df = tiph->frag_off; if (df) - mtu = dst_pmtu(&rt->u.dst) - tunnel->hlen; + mtu = dst_mtu(&rt->u.dst) - tunnel->hlen; else - mtu = skb->dst ? dst_pmtu(skb->dst) : dev->mtu; + mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu; if (skb->dst) skb->dst->ops->update_pmtu(skb->dst, mtu); @@ -783,7 +782,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) else if (skb->protocol == htons(ETH_P_IPV6)) { struct rt6_info *rt6 = (struct rt6_info*)skb->dst; - if (rt6 && mtu < dst_pmtu(skb->dst) && mtu >= IPV6_MIN_MTU) { + if (rt6 && mtu < dst_mtu(skb->dst) && mtu >= IPV6_MIN_MTU) { if ((tunnel->parms.iph.daddr && !MULTICAST(tunnel->parms.iph.daddr)) || rt6->rt6i_dst.plen == 128) { rt6->rt6i_flags |= RTF_MODIFIED; @@ -829,6 +828,8 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) skb->h.raw = skb->nh.raw; skb->nh.raw = skb_push(skb, gre_hlen); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); + IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | + IPSKB_REROUTED); dst_release(skb->dst); skb->dst = &rt->u.dst; @@ -877,13 +878,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) } } -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif -#endif + nf_reset(skb); IPTUNNEL_XMIT(); tunnel->recursion--; @@ -917,7 +912,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) t = ipgre_tunnel_locate(&p, 0); } if (t == NULL) - t = (struct ip_tunnel*)dev->priv; + t = netdev_priv(dev); memcpy(&p, &t->parms, sizeof(p)); if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) err = -EFAULT; @@ -957,7 +952,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) } else { unsigned nflags=0; - t = (struct ip_tunnel*)dev->priv; + t = netdev_priv(dev); if (MULTICAST(p.iph.daddr)) nflags = IFF_BROADCAST; @@ -1006,7 +1001,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) if ((t = ipgre_tunnel_locate(&p, 0)) == NULL) goto done; err = -EPERM; - if (t == ipgre_fb_tunnel_dev->priv) + if (t == netdev_priv(ipgre_fb_tunnel_dev)) goto done; dev = t->dev; } @@ -1023,12 +1018,12 @@ done: static struct net_device_stats *ipgre_tunnel_get_stats(struct net_device *dev) { - return &(((struct ip_tunnel*)dev->priv)->stat); + return &(((struct ip_tunnel*)netdev_priv(dev))->stat); } static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu) { - struct ip_tunnel *tunnel = (struct ip_tunnel*)dev->priv; + struct ip_tunnel *tunnel = netdev_priv(dev); if (new_mtu < 68 || new_mtu > 0xFFF8 - tunnel->hlen) return -EINVAL; dev->mtu = new_mtu; @@ -1068,7 +1063,7 @@ static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu) static int ipgre_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len) { - struct ip_tunnel *t = (struct ip_tunnel*)dev->priv; + struct ip_tunnel *t = netdev_priv(dev); struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen); u16 *p = (u16*)(iph+1); @@ -1095,7 +1090,7 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev, unsigned sh static int ipgre_open(struct net_device *dev) { - struct ip_tunnel *t = (struct ip_tunnel*)dev->priv; + struct ip_tunnel *t = netdev_priv(dev); if (MULTICAST(t->parms.iph.daddr)) { struct flowi fl = { .oif = t->parms.link, @@ -1109,17 +1104,17 @@ static int ipgre_open(struct net_device *dev) return -EADDRNOTAVAIL; dev = rt->u.dst.dev; ip_rt_put(rt); - if (__in_dev_get(dev) == NULL) + if (__in_dev_get_rtnl(dev) == NULL) return -EADDRNOTAVAIL; t->mlink = dev->ifindex; - ip_mc_inc_group(__in_dev_get(dev), t->parms.iph.daddr); + ip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr); } return 0; } static int ipgre_close(struct net_device *dev) { - struct ip_tunnel *t = (struct ip_tunnel*)dev->priv; + struct ip_tunnel *t = netdev_priv(dev); if (MULTICAST(t->parms.iph.daddr) && t->mlink) { struct in_device *in_dev = inetdev_by_index(t->mlink); if (in_dev) { @@ -1144,7 +1139,7 @@ static void ipgre_tunnel_setup(struct net_device *dev) dev->type = ARPHRD_IPGRE; dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr) + 4; - dev->mtu = 1500 - sizeof(struct iphdr) - 4; + dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 4; dev->flags = IFF_NOARP; dev->iflink = 0; dev->addr_len = 4; @@ -1156,10 +1151,10 @@ static int ipgre_tunnel_init(struct net_device *dev) struct ip_tunnel *tunnel; struct iphdr *iph; int hlen = LL_MAX_HEADER; - int mtu = 1500; + int mtu = ETH_DATA_LEN; int addend = sizeof(struct iphdr) + 4; - tunnel = (struct ip_tunnel*)dev->priv; + tunnel = netdev_priv(dev); iph = &tunnel->parms.iph; tunnel->dev = dev; @@ -1221,9 +1216,9 @@ static int ipgre_tunnel_init(struct net_device *dev) return 0; } -int __init ipgre_fb_tunnel_init(struct net_device *dev) +static int __init ipgre_fb_tunnel_init(struct net_device *dev) { - struct ip_tunnel *tunnel = (struct ip_tunnel*)dev->priv; + struct ip_tunnel *tunnel = netdev_priv(dev); struct iphdr *iph = &tunnel->parms.iph; tunnel->dev = dev; @@ -1240,7 +1235,7 @@ int __init ipgre_fb_tunnel_init(struct net_device *dev) } -static struct inet_protocol ipgre_protocol = { +static struct net_protocol ipgre_protocol = { .handler = ipgre_rcv, .err_handler = ipgre_err, }; @@ -1252,7 +1247,7 @@ static struct inet_protocol ipgre_protocol = { static int __init ipgre_init(void) { - int err = -EINVAL; + int err; printk(KERN_INFO "GRE over IPv4 tunneling driver\n"); @@ -1265,27 +1260,44 @@ static int __init ipgre_init(void) ipgre_tunnel_setup); if (!ipgre_fb_tunnel_dev) { err = -ENOMEM; - goto fail; + goto err1; } ipgre_fb_tunnel_dev->init = ipgre_fb_tunnel_init; if ((err = register_netdev(ipgre_fb_tunnel_dev))) - goto fail; + goto err2; out: return err; -fail: - inet_del_protocol(&ipgre_protocol, IPPROTO_GRE); +err2: free_netdev(ipgre_fb_tunnel_dev); +err1: + inet_del_protocol(&ipgre_protocol, IPPROTO_GRE); goto out; } -void ipgre_fini(void) +static void __exit ipgre_destroy_tunnels(void) +{ + int prio; + + for (prio = 0; prio < 4; prio++) { + int h; + for (h = 0; h < HASH_SIZE; h++) { + struct ip_tunnel *t; + while ((t = tunnels[prio][h]) != NULL) + unregister_netdevice(t->dev); + } + } +} + +static void __exit ipgre_fini(void) { if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0) printk(KERN_INFO "ipgre close: can't remove protocol\n"); - unregister_netdev(ipgre_fb_tunnel_dev); + rtnl_lock(); + ipgre_destroy_tunnels(); + rtnl_unlock(); } module_init(ipgre_init);