1、IPIP环境搭建及验证
Host_A:
ip tunnel add tun1 mode ipip remote 192.168.124.78 local 192.168.124.101
ip addr add 10.100.200.10/24 dev tun1
ip route add 10.100.200.0/24 dev tun1
Host_B:
ip tunnel add tunnel0 mode ipip remote 192.168.124.101 local 192.168.124.78
ip addr add 10.100.200.11/24 dev tunnel0
ip route add 10.100.200.0/24 dev tun1
2、验证
从host_A上去ping 10.100.200.11能ping通;(两台vm在同一个宿主机的场景,需要将/proc/sys/net/bridge/bridge-nf-call-iptables 设置为0,否则经过bridge的报文会走ipv4的iptables规则,然后做snat,将源ip地址
改成bridge的ip:192.168.124.1,这样到了host后,就会找不到tunnel设备)
3、原理分析
3.1、tun设备创建过程
1)、ipip模块初始化
ipip_init_net
ip_tunnel_init_net
itn->rtnl_link_ops = ops;(设置ip_tunnel_net的ops为ipip_link_ops)
2)、ip tunnel add tunnel0 mode ipip remote 192.168.124.101 local 192.168.124.78
ip_tunnel_ioctl
struct ip_tunnel_net *itn = net_generic(net, t->ip_tnl_net_id); (先获取ip_tunnel_net,ip_tunnel_net在ip_tunnel_init_net里有做初始化)
ip_tunnel_create
__ip_tunnel_create
alloc_netdev(分配ip tunnel设备,这里会携带setup函数,setup对应ipip_link_ops的setup)
setup(分配完成后,调用setup)
ipip_tunnel_setup(调用ipip_link_ops的setup函数,设置ip tunnel设备的xmit、init的回调函数)
dev->rtnl_link_ops = ops;(设置tun设备的rtnl_link_ops为ipip_link_ops)
register_netdevice(注册ip tunnel设备)
ip_tunnel_add
ip_bucket
ip_tunnel_hash
hlist_add_head_rcu(&t->hash_node, head); (将tunnel设备添加到对应的hash链表里)
3.2、HOST_A
1)、根据当前的路由规则,会选择10.100.200.0/24 dev tun1 proto kernel scope link src 10.100.200.11这条规则,将报文发送给tun1接口
2)、tunnel设备封装发送
ndo_start_xmit
ipip_tunnel_xmit
skb_set_inner_ipproto
ip_tunnel_xmit
ip_tunnel_init_flow(设置该ipip流的四元组等信息,ip tunnel add时指定的remote、local值)
ip_tunnel_encap(根据ipip配置的四层封装协议封装四层报文头--- 这里的四层包括fou、gre等,在配置ipip 隧道的时候,可以通过
encap 来指定具体的封装协议类型,但不是必须的,如果没有指定,则ipip直接将ip报文作为一个payload,然后继续封装一个外层ip头部,如果有配置封装协议,
则在封装外层ip头部之前会先封装一层外部的四层协议头)
ip_route_output_key(根据ip_tunnel_init_flow里设置的flow信息做路由)
iptunnel_xmit(封装外层ip头部,这里封装的iph->protocol的协议类型为:IPPROTO_IPIP, 然后将报文发送出去)
3.3、HOST_B
1)、ipip走完ip层后,通过ip_local_deliver_finish发送给本机,然后根据外层ip头部的协议(IPPROTO_IPIP),调用对应的handler处理函数tunnel4_rcv,最后进入ipip_rcv;
2)、ipip_rcv里面先通过ip_tunnel_lookup找到对应的tunnel设备(key+iph->saddr),然后进入ip_tunnel_rcv;
3)、将内部的ip报文通过gro_cells_receive继续走一遍协议栈收包过程;
4)、进入ping处理过程;