Skip to contentSkip to conversation

ip_gre: sendto/recvfrom NBMA address

PATCH RESEND Superseded Timo Teräs 4 participants 13 messages Oct 23, 2007 – Dec 20, 2007

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH RESEND 1/1 ip_gre: sendto/recvfrom NBMA address

When GRE tunnel is in NBMA mode, this patch allows an application to use a PF_PACKET socket to:
- send a packet to specific NBMA address with sendto()
- use recvfrom() to receive packet and check which NBMA address it came from

---

This is useful for implementing NHRP (and other low level protocols) over NBMA GRE tunnels.

Posted about a week ago, but got no reply. Could someone comment on this? Or commit it? Thanks.

net/ipv4/ip_gre.c | 12 +++++++++++-

1 files changed, 11 insertions(+), 1 deletions(-)
net/ipv4/ip_gre.c +0 -0
index f151900..b1e3816 100644
@@ -1033,7 +1033,6 @@ static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
	return 0;
}

-#ifdef CONFIG_NET_IPGRE_BROADCAST
/* Nice toy. Unfortunately, useless in real life :-)
It allows to construct virtual multiprotocol broadcast "LAN"
over the Internet, provided multicast routing is tuned.
@@ -1092,10 +1091,19 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev,

	return -t->hlen;
}

+static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr) +{
+ struct iphdr *iph = (struct iphdr *) skb_mac_header(skb);
+ memcpy(haddr, &iph->saddr, 4);
+ return 4;
+}
+
static const struct header_ops ipgre_header_ops = {
.create = ipgre_header,
+ .parse = ipgre_header_parse,
};

+#ifdef CONFIG_NET_IPGRE_BROADCAST
static int ipgre_open(struct net_device *dev)

{
	struct ip_tunnel *t = netdev_priv(dev);
@@ -1197,6 +1205,8 @@ static int ipgre_tunnel_init(struct net_device *dev)
			dev->stop = ipgre_close;
		}
#endif
+	} else {
+		dev->header_ops = &ipgre_header_ops;
	}

	if (!tdev && tunnel->parms.link)
#1 lore raw
Quoted 8 lines · Timo Teräs

When GRE tunnel is in NBMA mode, this patch allows an application to use a PF_PACKET socket to:
- send a packet to specific NBMA address with sendto()
- use recvfrom() to receive packet and check which NBMA address it came from

Quoted 7 lines

---

This is useful for implementing NHRP (and other low level protocols) over NBMA GRE tunnels.

Posted about a week ago, but got no reply. Could someone comment on this? Or commit it? Thanks.

Your mailer mangled tabs, it won't apply like this. Try sending to yourself for testing, then repost when it works properly.

#2 lore raw

PATCH RESEND 1/1 ip_gre: sendto/recvfrom NBMA address

When GRE tunnel is in NBMA mode, this patch allows an application to use a PF_PACKET socket to:
- send a packet to specific NBMA address with sendto()
- use recvfrom() to receive packet and check which NBMA address it came from

This is required to implement properly NHRP over GRE tunnel.

---

Quoted 2 lines

Your mailer mangled tabs, it won't apply like this. Try sending to yourself for testing, then repost when it works properly.

Sorry. Tabs were ok, but the initial white space on context lines was somehow removed. Apparently a bug in my editor where I cut/pasted from.

net/ipv4/ip_gre.c | 12 +++++++++++-

1 files changed, 11 insertions(+), 1 deletions(-)
net/ipv4/ip_gre.c +0 -0
index f151900..b1e3816 100644
@@ -1033,7 +1033,6 @@ static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
	return 0;
}

-#ifdef CONFIG_NET_IPGRE_BROADCAST
/* Nice toy. Unfortunately, useless in real life :-)
It allows to construct virtual multiprotocol broadcast "LAN"
over the Internet, provided multicast routing is tuned.
@@ -1092,10 +1091,19 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev,

	return -t->hlen;
}

+static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr) +{
+ struct iphdr *iph = (struct iphdr*) skb_mac_header(skb);
+ memcpy(haddr, &iph->saddr, 4);
+ return 4;
+}
+
static const struct header_ops ipgre_header_ops = {
.create = ipgre_header,
+ .parse = ipgre_header_parse,
};

+#ifdef CONFIG_NET_IPGRE_BROADCAST
static int ipgre_open(struct net_device *dev)

{
	struct ip_tunnel *t = netdev_priv(dev);
@@ -1197,6 +1205,8 @@ static int ipgre_tunnel_init(struct net_device *dev)
			dev->stop = ipgre_close;
		}
#endif
+	} else {
+		dev->header_ops = &ipgre_header_ops;
	}

	if (!tdev && tunnel->parms.link)
#3 lore raw

PATCH RESEND 1/1 ip_gre: sendto/recvfrom NBMA address

In reply to Patrick McHardy

When GRE tunnel is in NBMA mode, this patch allows an application to use a PF_PACKET socket to:
- send a packet to specific NBMA address with sendto()
- use recvfrom() to receive packet and check which NBMA address it came from

This is required to implement properly NHRP over GRE tunnel.

---

Quoted 2 lines · Patrick McHardy

Your mailer mangled tabs, it won't apply like this. Try sending to yourself for testing, then repost when it works properly.

Tabs were ok, I think. But somehow it seems that cut'n'paste from my default editor loses the space from context lines. It should be good now.

net/ipv4/ip_gre.c | 12 +++++++++++-

1 files changed, 11 insertions(+), 1 deletions(-)
net/ipv4/ip_gre.c +0 -0
index f151900..b1e3816 100644
@@ -1033,7 +1033,6 @@ static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
	return 0;
}

-#ifdef CONFIG_NET_IPGRE_BROADCAST
/* Nice toy. Unfortunately, useless in real life :-)
It allows to construct virtual multiprotocol broadcast "LAN"
over the Internet, provided multicast routing is tuned.
@@ -1092,10 +1091,19 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev,

	return -t->hlen;
}

+static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr) +{
+ struct iphdr *iph = (struct iphdr*) skb_mac_header(skb);
+ memcpy(haddr, &iph->saddr, 4);
+ return 4;
+}
+
static const struct header_ops ipgre_header_ops = {
.create = ipgre_header,
+ .parse = ipgre_header_parse,
};

+#ifdef CONFIG_NET_IPGRE_BROADCAST
static int ipgre_open(struct net_device *dev)

{
	struct ip_tunnel *t = netdev_priv(dev);
@@ -1197,6 +1205,8 @@ static int ipgre_tunnel_init(struct net_device *dev)
			dev->stop = ipgre_close;
		}
#endif
+	} else {
+		dev->header_ops = &ipgre_header_ops;
	}

	if (!tdev && tunnel->parms.link)
#4 lore raw
Quoted 10 lines · Timo Teräs

When GRE tunnel is in NBMA mode, this patch allows an application to use a PF_PACKET socket to:
- send a packet to specific NBMA address with sendto()
- use recvfrom() to receive packet and check which NBMA address it came from

This is required to implement properly NHRP over GRE tunnel.

Quoted 7 lines

---

Quoted 2 lines · Patrick McHardy

Your mailer mangled tabs, it won't apply like this. Try sending to yourself for testing, then repost when it works properly.

Tabs were ok, I think. But somehow it seems that cut'n'paste from my default editor loses the space from context lines. It should be good now.

Might have been a problem on my side, I just updated my mailer and it still displays tabs broken, but the actual patch seems fine. Sorry for the noise ...

#5 lore raw
In reply to Timo Teräs

Hello!

Quoted 6 lines

When GRE tunnel is in NBMA mode, this patch allows an application to use a PF_PACKET socket to:
- send a packet to specific NBMA address with sendto()
- use recvfrom() to receive packet and check which NBMA address it came from

This is required to implement properly NHRP over GRE tunnel.

Ack. This is good idea.

Frankly, I was sure ip_gre worked in this way all these years. I do not remember any reasons why it was crippled.

The only dubious case is when next hop is set using routing tables. But code in ipgre_tunnel_xmit() is ready to accept this situation, it checks for zero destination address and fixes it when it is able to.

Alexey

maintainer
#6 lore raw

From: Alexey Kuznetsov <[email protected]>
Date: Tue, 23 Oct 2007 23:03:24 +0400

Quoted 10 lines

Hello!

Quoted 6 lines

When GRE tunnel is in NBMA mode, this patch allows an application to use a PF_PACKET socket to:
- send a packet to specific NBMA address with sendto()
- use recvfrom() to receive packet and check which NBMA address it came from

This is required to implement properly NHRP over GRE tunnel.

Ack. This is good idea.

Patch applied, thanks everyone!

#7 lore raw
In reply to Timo Teräs

Hello!

Quoted 8 lines · Me

Ack. This is good idea.

Frankly, I was sure ip_gre worked in this way all these years. I do not remember any reasons why it was crippled.

The only dubious case is when next hop is set using routing tables. But code in ipgre_tunnel_xmit() is ready to accept this situation, it checks for zero destination address and fixes it when it is able to.

Nevertheless, it does not work.

The reason is that NOARP arp entries on device with initialized hard_header are initialized not to all zeros, but to dev->dev_addr. So that, netxthop from routing tables is ignored and all gre packets are lost in loopback. Not good.

The problem can be ignored. I am even not sure that someone uses this feature. Actually, it was not recommended in documentation.

Alternatively, arp.c can be changed to generate 0 addresses instead of dev->dev_addr. Normally it is equally good, but I am not sure about possible side effects.

Another thoughts?

Alexey

#8 lore raw

Hi,

Quoted 7 lines · Alexey Kuznetsov
Quoted 3 lines

The only dubious case is when next hop is set using routing tables. But code in ipgre_tunnel_xmit() is ready to accept this situation, it checks for zero destination address and fixes it when it is able to.

Nevertheless, it does not work.

Another thoughts?

Could you explain this a little more?

I was able to set a nbma gre tunnel, add routes to it and it worked perfectly ok.

Link-level next hop worked:
ip route add <route> via <link-level-address> dev <tunnel-dev> onlink

Also normal route with static neighbor worked:
ip neigh add <router-tunnel-ip> lladdr <link-level-address> nud permanent dev <tunnel-dev> ip route add <route> via <router-tunnel-ip>

In both cases packets were routed as expected to hosts accessible using the added route. And sendto() sent a packet correctly with destination link-level-address set. Did I miss/misunderstand something?

Cheers,
Timo

#9 lore raw

Hello!

Quoted 5 lines

I was able to set a nbma gre tunnel, add routes to it and it worked perfectly ok.

Link-level next hop worked:
ip route add <route> via <link-level-address> dev <tunnel-dev> onlink

This can work if you use gre0. By plain luck it has all-zero dev_addr.

It will break on nbma devices set with:

ip tunnel add XXX mode gre local a.b.c.d [key whatever] ...

Alexey

#10 lore raw

RFC PATCH 1/1 ip_gre: use skb->{mac,network}_header consistently

From: Timo Teras <[email protected]>

Make both send and receive paths use consistently skb->*_header:
mac_header = outer IPv4 header
network_header = encapsulated packet (e.g. inner IPv4 header)

---
Currently in send path:
network_header = outer IPv4 header
transport_header = encapsulated packet
And receive path:
network_header = encapsulated packet
mac_header = GRE header

mac_header used to be the outer IPv4 header on receive path, but it was broken/changed when skb_reset_mac_header() was introduced.

This also makes ipgre_header_parse() work correctly as it assumes that mac_header points to the outer IPv4 header always. Though, it returns zeros for outgoing packets that are tcpdumped from gre tunnel without explicit local address, since the routing is done in ipgre_tunnel_xmit().

 net/ipv4/ip_gre.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)
net/ipv4/ip_gre.c +4 -4
index 02b02a8..eba1ade 100644
@@ -613,7 +613,7 @@ static int ipgre_rcv(struct sk_buff *skb)
 				offset += 4;
 		}
 
-		skb_reset_mac_header(skb);
+		skb->mac_header = skb->network_header;
 		__pskb_pull(skb, offset);
 		skb_reset_network_header(skb);
 		skb_postpull_rcsum(skb, skb_transport_header(skb), offset);
@@ -826,9 +826,8 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 		old_iph = ip_hdr(skb);
 	}
 
-	skb->transport_header = skb->network_header;
 	skb_push(skb, gre_hlen);
-	skb_reset_network_header(skb);
+	skb_reset_mac_header(skb);
 	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
 	IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
 			      IPSKB_REROUTED);
@@ -839,7 +838,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 	 *	Push down and install the IPIP header.
 	 */
 
-	iph 			=	ip_hdr(skb);
+	iph 			=	(struct iphdr *) skb_mac_header(skb);
 	iph->version		=	4;
 	iph->ihl		=	sizeof(struct iphdr) >> 2;
 	iph->frag_off		=	df;
@@ -1070,6 +1069,7 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
 	struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen);
 	__be16 *p = (__be16*)(iph+1);
 
+	skb_reset_mac_header(skb);
 	memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
 	p[0]		= t->parms.o_flags;
 	p[1]		= htons(type);
Signature · 1 line
1.5.2.5
#11 lore raw

PATCH 1/1 ip_gre: set mac_header correctly in receive path

From: Timo Teras <[email protected]>

mac_header update in ipgre_recv() was incorrectly changed to skb_reset_mac_header() when it was introduced.

---
This replaces my earlier patch titled "ip_gre: use skb->{mac, network}_header consistently". Apparently I hadn't done my homework how to use *_header correctly. And I should have done a bit more testing to figure out the previous patch does not work.

But the main problem was the receive path in the first place, and this patch fixes it.

The bug was introduced in commit 459a98ed881802dee55897441bc7f77af614368e. There might be other similar incorrect replaces.

 net/ipv4/ip_gre.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
net/ipv4/ip_gre.c +1 -1
index 02b02a8..4b93f32 100644
@@ -613,7 +613,7 @@ static int ipgre_rcv(struct sk_buff *skb)
 				offset += 4;
 		}
 
-		skb_reset_mac_header(skb);
+		skb->mac_header = skb->network_header;
 		__pskb_pull(skb, offset);
 		skb_reset_network_header(skb);
 		skb_postpull_rcsum(skb, skb_transport_header(skb), offset);
Signature · 1 line
1.5.2.5
maintainer
#12 lore raw

Re: [PATCH][IPV4] ip_gre: set mac_header correctly in receive path

From: Timo_Teräs <[email protected]>
Date: Wed, 19 Dec 2007 20:10:41 +0200

Quoted 6 lines

From: Timo Teras <[email protected]>

mac_header update in ipgre_recv() was incorrectly changed to skb_reset_mac_header() when it was introduced.

Patch applied, thanks.

Quoted 11 lines

---
This replaces my earlier patch titled "ip_gre: use skb->{mac, network}_header consistently". Apparently I hadn't done my homework how to use *_header correctly. And I should have done a bit more testing to figure out the previous patch does not work.

But the main problem was the receive path in the first place, and this patch fixes it.

The bug was introduced in commit 459a98ed881802dee55897441bc7f77af614368e. There might be other similar incorrect replaces.

That commit has two other identical bad conversions, I'll fix them up.