Generic Routing Encapsulation
1. 实验
$ ip tunnel add Tunnel-1 mode gre remote 192.168.0.107 local 192.168.0.106
$ ip addr add 10.10.10.1/24 dev Tunnel-1
$ ip link set Tunnel-1 up
$ route add -net 10.10.20.0/24 gw 10.10.10.1
$ ip tunnel add Tunnel-1 mode gre remote 192.168.0.106 local 192.168.0.107
$ ip addr add 10.10.20.1/24 dev Tunnel-2
$ ip link set Tunnel-2 up
$ route add -net 10.10.10.0/24 gw 10.10.20.1
$ ping 10.10.20.1
2. 源码走读
static const struct net_protocol net_gre_protocol = {
.handler = gre_rcv,
.err_handler = gre_err,
};
static int __init gre_init(void)
{
pr_info("GRE over IPv4 demultiplexor driver\n");
if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) {
pr_err("can't add protocol\n");
return -EAGAIN;
}
return 0;
}
static const struct gre_protocol ipgre_protocol = {
.handler = gre_rcv,
.err_handler = gre_err,
};
static int __init ipgre_init(void)
{
int err;
pr_info("GRE over IPv4 tunneling driver\n");
...
err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
...
}
void ip_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int protocol)
{
const struct net_protocol *ipprot;
ipprot = rcu_dereference(inet_protos[protocol]);
if (ipprot) {
ret = INDIRECT_CALL_2(ipprot->handler, tcp_v4_rcv, udp_rcv, skb);
}
}
static int gre_rcv(struct sk_buff *skb)
{
const struct gre_protocol *proto;
ver = skb->data[1]&0x7f;
...
proto = rcu_dereference(gre_proto[ver]);
ret = proto->handler(skb);
...
}
static int gre_rcv(struct sk_buff *skb)
{
hdr_len = gre_parse_header(skb, &tpi, &csum_err, htons(ETH_P_IP), 0);
if (unlikely(tpi.proto == htons(ETH_P_ERSPAN) ||
tpi.proto == htons(ETH_P_ERSPAN2))) {
if (erspan_rcv(skb, &tpi, hdr_len) == PACKET_RCVD)
return 0;
goto out;
}
if (ipgre_rcv(skb, &tpi, hdr_len) == PACKET_RCVD)
return 0;
...
}
ipgre_rcv
__ipgre_rcv
ip_tunnel_lookup
ip_tunnel_rcv
skb->dev = tunnel->dev;
gro_cells_receive