summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2016-05-04 14:11:32 -0400
committerDavid S. Miller <davem@davemloft.net>2016-05-04 14:11:32 -0400
commitb8223bd1c49423a39a7da7e73cad8bf0e02bb032 (patch)
tree539fdeba92e58818cb10849a19122679357181a1
parent3f7496aa72d3411579f996eb3998d1441906e99d (diff)
parent125372faa4feb15e86f410c1adabbca9186d9c4a (diff)
downloadlinux-b8223bd1c49423a39a7da7e73cad8bf0e02bb032.tar.gz
linux-b8223bd1c49423a39a7da7e73cad8bf0e02bb032.tar.bz2
linux-b8223bd1c49423a39a7da7e73cad8bf0e02bb032.zip
Merge branch 'gre-teb'
Jiri Benc says: ==================== gre: receive also TEB packets for lwtunnels NOTE: this patchset needs net merged to net-next. This allows lwtunnel users to get also packets with ETH_P_TEB protocol specified in GRE header through an ipgre interface. There's really nothing special about these packets in the case of lwtunnels - it's just an inner protocol like any other. The only complications stem from keeping compatibility with other uses of GRE. This will be used by openvswitch to support eth_push and eth_pop actions. I'd also like to see tc support for lwtunnels (this feature included) in the future. The first patch is not directly related and can be submitted standalone if needed. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/ip_tunnels.h1
-rw-r--r--net/ipv4/gre_demux.c5
-rw-r--r--net/ipv4/ip_gre.c48
3 files changed, 37 insertions, 17 deletions
diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
index 6d790910ebdf..d916b4315903 100644
--- a/include/net/ip_tunnels.h
+++ b/include/net/ip_tunnels.h
@@ -160,6 +160,7 @@ struct tnl_ptk_info {
#define PACKET_RCVD 0
#define PACKET_REJECT 1
+#define PACKET_NEXT 2
#define IP_TNL_HASH_BITS 7
#define IP_TNL_HASH_SIZE (1 << IP_TNL_HASH_BITS)
diff --git a/net/ipv4/gre_demux.c b/net/ipv4/gre_demux.c
index a41e73ab1369..d78e2eefc0f7 100644
--- a/net/ipv4/gre_demux.c
+++ b/net/ipv4/gre_demux.c
@@ -114,11 +114,8 @@ int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
*/
if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) {
tpi->proto = htons(ETH_P_IP);
- if ((*(u8 *)options & 0xF0) != 0x40) {
+ if ((*(u8 *)options & 0xF0) != 0x40)
hdr_len += 4;
- if (!pskb_may_pull(skb, hdr_len))
- return -EINVAL;
- }
}
return hdr_len;
}
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 8260a707b9b8..2b267e71ebf5 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -260,24 +260,22 @@ static __be32 tunnel_id_to_key(__be64 x)
#endif
}
-static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi)
+static int __ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
+ struct ip_tunnel_net *itn, int hdr_len, bool raw_proto)
{
- struct net *net = dev_net(skb->dev);
struct metadata_dst *tun_dst = NULL;
- struct ip_tunnel_net *itn;
const struct iphdr *iph;
struct ip_tunnel *tunnel;
- if (tpi->proto == htons(ETH_P_TEB))
- itn = net_generic(net, gre_tap_net_id);
- else
- itn = net_generic(net, ipgre_net_id);
-
iph = ip_hdr(skb);
tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags,
iph->saddr, iph->daddr, tpi->key);
if (tunnel) {
+ if (__iptunnel_pull_header(skb, hdr_len, tpi->proto,
+ raw_proto, false) < 0)
+ goto drop;
+
skb_pop_mac_header(skb);
if (tunnel->collect_md) {
__be16 flags;
@@ -293,7 +291,34 @@ static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi)
ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
return PACKET_RCVD;
}
- return PACKET_REJECT;
+ return PACKET_NEXT;
+
+drop:
+ kfree_skb(skb);
+ return PACKET_RCVD;
+}
+
+static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
+ int hdr_len)
+{
+ struct net *net = dev_net(skb->dev);
+ struct ip_tunnel_net *itn;
+ int res;
+
+ if (tpi->proto == htons(ETH_P_TEB))
+ itn = net_generic(net, gre_tap_net_id);
+ else
+ itn = net_generic(net, ipgre_net_id);
+
+ res = __ipgre_rcv(skb, tpi, itn, hdr_len, false);
+ if (res == PACKET_NEXT && tpi->proto == htons(ETH_P_TEB)) {
+ /* ipgre tunnels in collect metadata mode should receive
+ * also ETH_P_TEB traffic.
+ */
+ itn = net_generic(net, ipgre_net_id);
+ res = __ipgre_rcv(skb, tpi, itn, hdr_len, true);
+ }
+ return res;
}
static int gre_rcv(struct sk_buff *skb)
@@ -314,10 +339,7 @@ static int gre_rcv(struct sk_buff *skb)
if (hdr_len < 0)
goto drop;
- if (iptunnel_pull_header(skb, hdr_len, tpi.proto, false))
- goto drop;
-
- if (ipgre_rcv(skb, &tpi) == PACKET_RCVD)
+ if (ipgre_rcv(skb, &tpi, hdr_len) == PACKET_RCVD)
return 0;
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);