gre: Check whether IPv6 is compiled into the kernel.
[openvswitch] / datapath / vport-gre.c
index dbfc1001cd296b59fb64a04d1c71a6ce094540c2..237835ba9d443ae3a0d0bf4cebf2c91e644cd915 100644 (file)
@@ -22,7 +22,9 @@
 #include <net/icmp.h>
 #include <net/inet_ecn.h>
 #include <net/ip.h>
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 #include <net/ipv6.h>
+#endif
 #include <net/protocol.h>
 #include <net/route.h>
 #include <net/xfrm.h>
@@ -377,6 +379,7 @@ ipv4_build_icmp(struct sk_buff *skb, struct sk_buff *nskb,
        icmph->checksum = csum_fold(nskb->csum);
 }
 
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 static bool
 ipv6_should_icmp(struct sk_buff *skb)
 {
@@ -452,13 +455,14 @@ ipv6_build_icmp(struct sk_buff *skb, struct sk_buff *nskb, unsigned int mtu,
                                                + payload_length,
                                                ipv6h->nexthdr, nskb->csum);
 }
+#endif /* IPv6 */
 
 static bool
 send_frag_needed(struct vport *vport, const struct mutable_config *mutable,
                 struct sk_buff *skb, unsigned int mtu, __be32 flow_key)
 {
        unsigned int eth_hdr_len = ETH_HLEN;
-       unsigned int total_length, header_length, payload_length;
+       unsigned int total_length = 0, header_length = 0, payload_length;
        struct ethhdr *eh, *old_eh = eth_hdr(skb);
        struct sk_buff *nskb;
 
@@ -469,7 +473,9 @@ send_frag_needed(struct vport *vport, const struct mutable_config *mutable,
 
                if (!ipv4_should_icmp(skb))
                        return true;
-       } else {
+       }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       else if (skb->protocol == htons(ETH_P_IPV6)) {
                if (mtu < IPV6_MIN_MTU)
                        return false;
 
@@ -481,6 +487,9 @@ send_frag_needed(struct vport *vport, const struct mutable_config *mutable,
                if (!ipv6_should_icmp(skb))
                        return true;
        }
+#endif
+       else
+               return false;
 
        /* Allocate */
        if (old_eh->h_proto == htons(ETH_P_8021Q))
@@ -491,12 +500,16 @@ send_frag_needed(struct vport *vport, const struct mutable_config *mutable,
                header_length = sizeof(struct iphdr) + sizeof(struct icmphdr);
                total_length = min_t(unsigned int, header_length +
                                                   payload_length, 576);
-       } else {
+       }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       else {
                header_length = sizeof(struct ipv6hdr) +
                                sizeof(struct icmp6hdr);
                total_length = min_t(unsigned int, header_length +
                                                  payload_length, IPV6_MIN_MTU);
        }
+#endif
+
        total_length = min(total_length, mutable->mtu);
        payload_length = total_length - header_length;
 
@@ -523,8 +536,10 @@ send_frag_needed(struct vport *vport, const struct mutable_config *mutable,
        /* Protocol */
        if (skb->protocol == htons(ETH_P_IP))
                ipv4_build_icmp(skb, nskb, mtu, payload_length);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
        else
                ipv6_build_icmp(skb, nskb, mtu, payload_length);
+#endif
 
        /* Assume that flow based keys are symmetric with respect to input
         * and output and use the key that we were going to put on the
@@ -672,8 +687,10 @@ ecn_encapsulate(u8 tos, struct sk_buff *skb)
 
        if (skb->protocol == htons(ETH_P_IP))
                inner = ((struct iphdr *)skb_network_header(skb))->tos;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
        else if (skb->protocol == htons(ETH_P_IPV6))
                inner = ipv6_get_dsfield((struct ipv6hdr *)skb_network_header(skb));
+#endif
        else
                inner = 0;
 
@@ -701,7 +718,9 @@ ecn_decapsulate(u8 tos, struct sk_buff *skb)
                                return;
 
                        IP_ECN_set_ce((struct iphdr *)(nw_header + skb->data));
-               } else if (protocol == htons(ETH_P_IPV6)) {
+               }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+               else if (protocol == htons(ETH_P_IPV6)) {
                        if (unlikely(!pskb_may_pull(skb, nw_header
                            + sizeof(struct ipv6hdr))))
                                return;
@@ -709,6 +728,7 @@ ecn_decapsulate(u8 tos, struct sk_buff *skb)
                        IP6_ECN_set_ce((struct ipv6hdr *)(nw_header
                                                          + skb->data));
                }
+#endif
        }
 }
 
@@ -809,8 +829,10 @@ gre_err(struct sk_buff *skb, u32 info)
 
        if (skb->protocol == htons(ETH_P_IP))
                tot_hdr_len += sizeof(struct iphdr);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
        else if (skb->protocol == htons(ETH_P_IPV6))
                tot_hdr_len += sizeof(struct ipv6hdr);
+#endif
        else
                goto out;
 
@@ -825,7 +847,9 @@ gre_err(struct sk_buff *skb, u32 info)
                                goto out;
                }
 
-       } else if (skb->protocol == htons(ETH_P_IPV6)) {
+       }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       else if (skb->protocol == htons(ETH_P_IPV6)) {
                if (mtu < IPV6_MIN_MTU) {
                        unsigned int packet_length = sizeof(struct ipv6hdr) +
                                              ntohs(ipv6_hdr(skb)->payload_len);
@@ -837,6 +861,7 @@ gre_err(struct sk_buff *skb, u32 info)
                                goto out;
                }
        }
+#endif
 
        __pskb_pull(skb, tunnel_hdr_len);
        send_frag_needed(vport, mutable, skb, mtu, key);
@@ -942,7 +967,9 @@ build_packet(struct vport *vport, const struct mutable_config *mutable,
                                goto error_free;
                }
 
-       } else if (skb->protocol == htons(ETH_P_IPV6)) {
+       }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       else if (skb->protocol == htons(ETH_P_IPV6)) {
                unsigned int packet_length = skb->len - ETH_HLEN
                        - (eth_hdr(skb)->h_proto == htons(ETH_P_8021Q) ? VLAN_HLEN : 0);
 
@@ -955,6 +982,7 @@ build_packet(struct vport *vport, const struct mutable_config *mutable,
                                goto error_free;
                }
        }
+#endif
 
        skb_reset_transport_header(skb);
        new_iph = (struct iphdr *)skb_push(skb, mutable->tunnel_hlen);
@@ -996,7 +1024,6 @@ gre_send(struct vport *vport, struct sk_buff *skb)
        const struct mutable_config *mutable = rcu_dereference(gre_vport->mutable);
 
        struct iphdr *old_iph;
-       struct ipv6hdr *old_ipv6h;
        int orig_len;
        struct iphdr iph;
        struct rtable *rt;
@@ -1016,21 +1043,24 @@ gre_send(struct vport *vport, struct sk_buff *skb)
                if (unlikely(!pskb_may_pull(skb, skb_network_header(skb)
                    + sizeof(struct iphdr) - skb->data)))
                        skb->protocol = 0;
-       } else if (skb->protocol == htons(ETH_P_IPV6)) {
+       }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       else if (skb->protocol == htons(ETH_P_IPV6)) {
                if (unlikely(!pskb_may_pull(skb, skb_network_header(skb)
                    + sizeof(struct ipv6hdr) - skb->data)))
                        skb->protocol = 0;
        }
-
+#endif
        old_iph = ip_hdr(skb);
-       old_ipv6h = ipv6_hdr(skb);
 
        iph.tos = mutable->port_config.tos;
        if (mutable->port_config.flags & GRE_F_TOS_INHERIT) {
                if (skb->protocol == htons(ETH_P_IP))
                        iph.tos = old_iph->tos;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
                else if (skb->protocol == htons(ETH_P_IPV6))
                        iph.tos = ipv6_get_dsfield(ipv6_hdr(skb));
+#endif
        }
        iph.tos = ecn_encapsulate(iph.tos, skb);
 
@@ -1049,8 +1079,10 @@ gre_send(struct vport *vport, struct sk_buff *skb)
        if (mutable->port_config.flags & GRE_F_TTL_INHERIT) {
                if (skb->protocol == htons(ETH_P_IP))
                        iph.ttl = old_iph->ttl;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
                else if (skb->protocol == htons(ETH_P_IPV6))
-                       iph.ttl = old_ipv6h->hop_limit;
+                       iph.ttl = ipv6_hdr(skb)->hop_limit;
+#endif
        }
        if (!iph.ttl)
                iph.ttl = dst_metric(&rt->u.dst, RTAX_HOPLIMIT);
@@ -1067,9 +1099,11 @@ gre_send(struct vport *vport, struct sk_buff *skb)
        if (skb->protocol == htons(ETH_P_IP)) {
                iph.frag_off |= old_iph->frag_off & htons(IP_DF);
                mtu = max(mtu, IP_MIN_MTU);
-
-       } else if (skb->protocol == htons(ETH_P_IPV6))
+       }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       else if (skb->protocol == htons(ETH_P_IPV6))
                mtu = max(mtu, IPV6_MIN_MTU);
+#endif
 
        iph.version = 4;
        iph.ihl = sizeof(struct iphdr) >> 2;