Linux has built-in support for two types of tunnels: ipip and gre. In the form in which the tunnels are traditionally used in the system, no matter which one to use: they both give exactly the same overhead to the packets sent to the IPv4-in-IPv4 tunnel (specifically tested), are equally protected by IPsec and occupy same processor time to process. However, these are different types of tunnels, and the possibilities of gre are much broader.
Unfortunately, nowhere on the Internet a very convenient and remarkable feature of gre-tunnels is described, and most (if not all) Linux administrators are not aware of such an option as mGRE-tunnels. Fortunately, we intend to fill this shortcoming :-)
So, we have three machines, all three have running version 2.6 of Linux (I'm not sure, maybe, and 2.4 also supports). We also need the iproute2 package - this is the standard for modern Linux systems (by the way, it’s already time to forget about obsolete utilities ifconfig, route, and others). External ip-addresses of systems: 1.1.1.1, 2.2.2.2 and 3.3.3.3; there is a routing between them.
')
For the time being, we can do without encryption and authentication of packets - this is all easy to add to our example, “just” setting up IPsec between our hosts in transport mode. This is a topic beyond the subject;)
1. Create a GRE tunnel:
(on all three) ip tunnel add mgre0 mode gre key 0xfffffffe ttl 255
Notice, we did not specify a peer address here. This means that in principle it can be located at any address. key in this case identifies a specific mGRE network - it is a 32-bit number, the same for all nodes.
2. Assign him the address:
(1.1.1.1) ip addr add 10.0.0.1/24 dev mgre0
(2.2.2.2) ip addr add 10.0.0.2/24 dev mgre0
(on 3.3.3.3) ip addr add 10.0.0.3/24 dev mgre0
For Ethernet interfaces this would be enough. Ethernet has the Adress Resolution Protocol (ARP), which allows systems to independently find the MAC address knowing the destination IP address. Ethernet is a Broadcast Multiple Access environment, and the ARP protocol is to create a request to all stations on the network (at the MAC address FF: FF: FF: FF: FF: FF): “Hey, who among you has the IP address
xxxx ?”. If there is a station with such an IP address, it already privately reports that "
xxxx is located at
yy: yy: yy: yy: yy: yy ".
In our network (Internet) there is no such tool as ARP, and the role of “second-level” addresses, which in the case of Ethernet are MAC addresses, is performed here ... external IP addresses of systems. We work with the Non-Broadcast Multiple Access (NBMA) environment, we cannot shout to the entire Internet, as ARP would do: “Hey, who in the 0xfffffffe GRE network has the address 10.0.0.2?”.
The Next Hop Resolution Protocol (NHRP, an analogue of ARP for NBMA environments) is designed to resolve this address problem, but we will do the work for it for the first time - at the same time we will figure out how the Linux network works :)
3. So, let us manually tell each station where to look for neighbors. To do this, run the following commands:
(1.1.1.1) ip neigh add 10.0.0.2 lladdr 2.2.2.2 dev mgre0
ip neigh add 10.0.0.3 lladdr 3.3.3.3 dev mgre0
(2.2.2.2) ip neigh add 10.0.0.1 lladdr 1.1.1.1 dev mgre0
ip neigh add 10.0.0.3 lladdr 3.3.3.3 dev mgre0
(on 3.3.3.3) ip neigh add 10.0.0.1 lladdr 1.1.1.1 dev mgre0
ip neigh add 10.0.0.2 lladdr 2.2.2.2 dev mgre0
Here, each command says: “the neighboring station with the network address IP
xxxx has a physical address (link layer address, lladdr)
yyyy , which is accessible through device
M ”. If we configured a static Ethernet (without ARP), instead of
yyyy there would be the MAC address of the corresponding station. (By the way, if you look at ip neigh show dev ethN on a working Ethernet network, we will see the results of ARP operation - dynamically obtained neighbor addresses).
Everything. On this, our tunnel will work: each of the stations will be able to ping any other. If the kernel is built with the support of GRE multicast, then we generally get a full-featured “LAN” - dynamic routing protocols such as RIP and OSPF will work in our virtual network in full force!
This is how it looks from the second station (2.2.2.2):
linux2 # ping 10.0.0.1
PING 10.0.0.1 (10.0.0.1) 56 (84) bytes of data.
64 bytes from 10.0.0.1: icmp_seq = 1 ttl = 64 time = 4.41 ms
64 bytes from 10.0.0.1: icmp_seq = 2 ttl = 64 time = 0.429 ms
^ C
--- 10.0.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1013ms
rtt min / avg / max / mdev = 0.429 / 2.419 / 4.410 / 1.991 ms
linux2 # ping 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56 (84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq = 1 ttl = 64 time = 0.027 ms
64 bytes from 10.0.0.2: icmp_seq = 2 ttl = 64 time = 0.020 ms
^ C
--- 10.0.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min / avg / max / mdev = 0.020 / 0.023 / 0.027 / 0.006 ms
linux2 # ping 10.0.0.3
PING 10.0.0.3 (10.0.0.3) 56 (84) bytes of data.
64 bytes from 10.0.0.3: icmp_seq = 1 ttl = 64 time = 8.47 ms
64 bytes from 10.0.0.3: icmp_seq = 2 ttl = 64 time = 0.164 ms
^ C
--- 10.0.0.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1018ms
rtt min / avg / max / mdev = 0.164 / 4.318 / 8.472 / 4.154 ms
linux2 # ip addr show dev mgre0
5: mgre0 @ NONE: <UP, LOWER_UP> mtu 1472 qdisc noqueue
link / gre 0.0.0.0 brd 0.0.0.0
inet 10.0.0.2/24 brd 10.0.0.255 scope global mgre0
linux2 # ip neigh show dev mgre0
10.0.0.1 lladdr 1.1.1.1 PERMANENT
10.0.0.3 lladdr 3.3.3.3 PERMANENT
Of course, if there are a lot of stations, this approach is not good - do not register all neighbors at each station! But it is quite clear how to solve this problem. But more about that later.