404频道

学习笔记

ipip协议为在ip协议报文的基础上继续封装ip报文,基于tun设备实现,是一种点对点的通讯技术。

install

ipip需要内核模块ipip的支持

1
2
3
4
5
$ modprobe ipip
$ lsmod | grep ipip
ipip 13465 0
tunnel4 13252 1 ipip
ip_tunnel 25163 1 ipip

实战

两台主机:172.16.5.126(host1)和172.16.5.127(host2)

在host1上创建tun1设备,执行如下命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 用来创建tun1设备,并ipip协议的外层ip,目的ip为172.16.5.127, 源ip为172.16.5.126
ip tunnel add tun1 mode ipip remote 172.16.5.127 local 172.16.5.126
# 给tun1设备增加ip地址,并设置tun1设备的对端ip地址为10.10.200.10
ip addr add 10.10.100.10 peer 10.10.200.10 dev tun1
ip link set tun1 up

$ ifconfig tun1
tun1: flags=209<UP,POINTOPOINT,RUNNING,NOARP> mtu 1480
inet 10.10.100.10 netmask 255.255.255.255 destination 10.10.200.10
tunnel txqueuelen 1000 (IPIP Tunnel)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

# 增加一条路由,所有到达10.10.200.10的请求会经过设备tun1
$ route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.16.7.253 0.0.0.0 UG 0 0 0 eth0
10.10.200.10 0.0.0.0 255.255.255.255 UH 0 0 0 tun1
172.16.0.0 0.0.0.0 255.255.248.0 U 0 0 0 eth0

同样在host2上创建tun1设备:

1
2
3
ip tunnel add tun1 mode ipip remote 172.16.5.126 local 172.16.5.127
ip addr add 10.10.200.10 peer 10.10.100.10 dev tun1
ip link set tun1 up

并分别在host1和host2上打开ip_forward功能

1
echo 1 >  /proc/sys/net/ipv4/ip_forward

然后在host1上ping 10.10.200.10,可以ping通。

在host1的tun1上抓包,可以看到正常的ping包。

在host1的eth1上抓包,可以看到已经是ipip的数据包了。

tun1.pcap

清理现场分别在两台主机上执行

1
ip link delete tun0

ref

Linux虚拟网络设备tap/tun

tap/tun常用于隧道通讯,通过一个字符设备来实现用户态和内核态的通讯,字符设备一端连接着用户空间,一端连接着内核空间。

与物理网卡的最大不同是,tap/tun的数据源来自于用户态的程序,而物理网卡的数据源来自于物理链路。

对应的字符设备文件位置:

  • tap: /dev/tap0
  • tun: /dev/net/tun

当应用程序打开字符设备文件时,驱动程序会创建并注册相应的虚拟设备接口,以tunX或tapX命名。应用程序关闭设备文件时,驱动程序会删除tunX和tapX网络虚拟设备,并删除建立起来的路由信息。

两个设备的不同点:

  • tap是一个二层网络设备,只能处理二层的以太网帧,可以与物理网卡做桥接
  • tun是一个点对点的三层网络设备,只能处理处理三层的IP数据包,无法与物理网卡做桥接,可以通过三层交换方式与物理网卡连通。Linux下的隧道协议基于该tun设备实现,如ipip、gre。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
                ┌──────────────┐
│ │
│ APP │
│ │
└───────┬──────┘






┌────────────▼──────────┐
│ │
─ ─ ─ ─ ─ ─│ /dev/net/tun ├ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
│ │
└────────────┬──────────┘





┌───────▼──────┐ ┌──────────────┐
│ │ │ │
│ tunX ├────────────────▶│Network Stack │
│ │ │ │
└──────────────┘ └──────────────┘

tun设备应用举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
          ┌──────────────┐         ┌──────────────┐
│ │ │ │
│ APP A │ │ APP B │◀┐
│ │ │ │ │
└───────┬──────┘ └───────┬──────┘ │
│ │ │
│ │ │
1│ │ │
│ 5│ │
│ │ │
─ ─ ─ ─ ─ ─ ─ ─ ┼ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ┼ ─ ─ ─ ─ ─
│ │ │
│ │ 4│
│ │ │
┌────────────▼────────────────────────▼─────┐ │
│ │ │
│ Network Stack │ │
│ │ │
└────────────┬───────────────────────┬──────┘ │
│ │ │
6│ 3│ │
│ │ │
┌───────▼──────┐ ┌─▼─────────┴──┐
│ │ │ │
10.1.1.11 │ eth0 │ │ tun0 │ 192.168.1.11
│ │ │ │
└───────┬──────┘ └──────────────┘

7│



10.1.1.100 / 192.168.1.100

应用程序A要发送数据到其他物理机192.168.1.100,由于物理网络环境下只有10.1.1.11和10.1.1.100是相互连通的,192.168.1.11和192.168.1.100是不通的,为了192.168.1.11和192.168.1.100能够进行通讯,需要将数据包进行一次封装。

应用程序B是通过打开字符设备文件/dev/net/tun0的方式来打开网络设备

流程如下:

  1. A构造数据包,目的ip为192.168.1.100,并发送给协议栈
  2. 协议栈根据数据包中的ip地址,匹配路由规则,要从tun0出去
  3. 内核协议栈将数据包发送给tun0网络设备
  4. tun0发送应用程序B打开,于是将数据发送给应用程序B
  5. B收到数据包后,在用户态构造一个新的数据包,源IP为eth0的IP 10.1.1.11,目的IP为配置的对端10.1.1.100,并封装原来的数据包
  6. 协议栈根据当前数据包的IP地址选择路由,将数据包发送给eth0

reference

网卡的混杂模式是指网卡将其接收的所有流量都交给cpu。非混杂模式下,网卡仅接收目的mac地址是自己mac地址的单播,以及多播和广播包,可以看出混杂模式是工作在二层的。

通过ifconfig eth0的方式,如果输出中包含了PROMISC字段,说明网卡处于混杂模式。但是如果ifconfig 命令的输出中未包含PROMISC字段,并不能说明网卡处于非混杂模式下。

可以通过查看 cat /sys/class/net/bond0/flags 的输出得知,如果置位了0x100,说明处于混杂模式。

veth pair是一对虚拟的网络设备,两个网络设备彼此连接。常用于两个network namespace之间的连接,如果在同一个命名空间下有很多的限制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
┌──────────────────────────────────────────────────────────────────────────────┐
│ │
│ │
│ network protocol │
│ │
│ │
└────────────────────▲─────────────────────────▲──────────────────────▲────────┘
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
┌─────▼────┐ ┌─────▼────┐ ┌─────▼────┐
│ │ │ │ │ │
│ eth0 │ │ veth0 ◀───────────▶ veth1 │
│ │ │ │ │ │
└─────▲────┘ └──────────┘ └──────────┘







physical network

实战

veth设备的ping测试

1. 只给一个veth设备配置ip的情况测试

给veth0配置ip 192.168.100.10,可以看到主机的路由表中增加了目的地为192.168.100.0的记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
[root@localhost vagrant]# ip link add veth0 type veth peer name veth1
[root@localhost vagrant]# ip addr add 192.168.100.10/24 dev veth0
[root@localhost vagrant]# ip addr add 192.168.100.11/24 dev veth1
## 因为veth创建完后默认不启用,此时还没有路由
[root@localhost vagrant]# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default gateway 0.0.0.0 UG 100 0 0 eth0
10.0.2.0 0.0.0.0 255.255.255.0 U 100 0 0 eth0
192.168.33.0 0.0.0.0 255.255.255.0 U 101 0 0 eth1

## 启用veth0后增加路由
[root@localhost vagrant]# ip link set veth0 up
[root@localhost vagrant]# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default gateway 0.0.0.0 UG 100 0 0 eth0
10.0.2.0 0.0.0.0 255.255.255.0 U 100 0 0 eth0
192.168.33.0 0.0.0.0 255.255.255.0 U 101 0 0 eth1
192.168.100.0 0.0.0.0 255.255.255.0 U 0 0 0 veth0

## 启用veth1后居然又增加了一条路由信息
[root@localhost vagrant]# ip link set veth1 up
[root@localhost vagrant]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 52:54:00:26:10:60 brd ff:ff:ff:ff:ff:ff
inet 10.0.2.15/24 brd 10.0.2.255 scope global noprefixroute dynamic eth0
valid_lft 86214sec preferred_lft 86214sec
inet6 fe80::5054:ff:fe26:1060/64 scope link
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:98:06:20 brd ff:ff:ff:ff:ff:ff
inet 192.168.33.11/24 brd 192.168.33.255 scope global noprefixroute eth1
valid_lft forever preferred_lft forever
inet6 fe80::a00:27ff:fe98:620/64 scope link
valid_lft forever preferred_lft forever
4: veth1@veth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether e2:15:95:0a:1f:da brd ff:ff:ff:ff:ff:ff
inet 192.168.100.11/24 scope global veth1
valid_lft forever preferred_lft forever
inet6 fe80::e015:95ff:fe0a:1fda/64 scope link
valid_lft forever preferred_lft forever
5: veth0@veth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether b2:2c:f6:e4:74:c5 brd ff:ff:ff:ff:ff:ff
inet 192.168.100.10/24 scope global veth0
valid_lft forever preferred_lft forever
inet6 fe80::b02c:f6ff:fee4:74c5/64 scope link
valid_lft forever preferred_lft forever
[root@localhost vagrant]# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default gateway 0.0.0.0 UG 100 0 0 eth0
10.0.2.0 0.0.0.0 255.255.255.0 U 100 0 0 eth0
192.168.33.0 0.0.0.0 255.255.255.0 U 101 0 0 eth1
192.168.100.0 0.0.0.0 255.255.255.0 U 0 0 0 veth0
192.168.100.0 0.0.0.0 255.255.255.0 U 0 0 0 veth1

默认情况下arp表如下:

1
2
3
4
5
6
# arp
Address HWtype HWaddress Flags Mask Iface
localhost.localdomain (incomplete) veth0
192.168.33.1 ether 0a:00:27:00:00:00 C eth1
gateway ether 52:54:00:12:35:02 C eth0
10.0.2.3 ether 52:54:00:12:35:03 C eth0

使用ping命令ping -I veth0 192.168.100.11 -c 2,默认情况下veth1和veth0会接收到arp报文,但并没有arp的响应报文。这是因为默认情况下有些arp内核参数的限制。执行如下命令解决arp的限制。

1
2
3
4
5
echo 1 > /proc/sys/net/ipv4/conf/veth1/accept_local
echo 1 > /proc/sys/net/ipv4/conf/veth0/accept_local
echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/veth0/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/veth1/rp_filter

veth pair设备的删除

1
2
# 删除veth0后会自动删除veth1
$ ip link delete veth0

container与host veth pair的关系

veth pair的其中一个设备位于container中备位于container中,另外一个设备位于host network namespace中,如何知道container中的eth0和host network namesapce中的veth设备的对应关系呢?

原理为veth pair设备都有一个ifindex和iflink值,,容器中的eth0设备的ifindex值跟host network namespace中的对应veth pair设备的iflink值相等,反之亦然。

方法一

获取iflink值:cat /sys/class/net/eth0/iflink

也可用此方法获取ifindex值:cat /sys/class/net/eth0/ifindex

方法二

1
2
3
$ ip link show eth0
3: eth0@if18: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 96:5f:80:a3:a3:01 brd ff:ff:ff:ff:ff:ff

其中的3为eth0的ifindex。18为eth0的iflink,即对应的veth pair的另外一个设备的ifindex。

host network namespace中找到对应ifindex值的veth pair设备

1
2
3
4
5
$ ip addr 
18: veth0e09999e@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br0 state UP group default
link/ether de:b0:74:89:e8:3e brd ff:ff:ff:ff:ff:ff link-netnsid 4
inet6 fe80::dcb0:74ff:fe89:e83e/64 scope link
valid_lft forever preferred_lft forever

其中的18为ifindex,3为对应的veth pair的ifindex。

reference

距离上次的知识分享系列已经过去了半年之久,难以想象。在该系列的开始我就说过该系列是不定期的,果不食言,只是这次的不定期有些久😓。该系列会继续下去,但节奏仍然是不定期的,但应该不会间隔半年之巨了。

题图来自首钢工业遗址公园,首钢于2010年完成了搬迁到唐山市的工作,位于石景山的工厂被废弃。2019年国庆节前夕以公园的形式部分对外开放,跟普通公园不同的地方在于保留了很多之前的工厂建筑及大型生产机械,足够硬核,非常原汁原味。

2022年要举办的冬奥会也非常明智的将场地选择在了该公园,预计将来会有很多的场馆位于该公园内且对外开放。

国内很多的地市都有一些类似的建筑,比如90年代下岗潮之前的一些国企工厂,我知道的济南的机床厂就有很多个,但很多这些倒闭关门的工厂后来的建筑及地皮都给卖掉了,建筑物也直接给拆掉了,殊不知其衍生价值也是有不少的。位于北京酒仙桥的798就是个非常好的改造案例,798园区的建筑稍加改造,给很多艺术工作室提供了非常好的办公场地,也是城市中的一个亮眼的名片。

资源

1.MessagePack

json作为一种常见的数据序列化方案,存在占用空间过多、反序列化过于消耗cpu的问题。MessagePack是一种基于二进制的高效轻量的数据序列化方案,支持数据的压缩,支持丰富的编程语言。在上图中,可以看出原27字节的json数据转换为MessagePack后仅占用了18字节。

另外,据今日头条的压测,要比Thrift的二进制序列化方案更高效一些。

2.GoAst Viewer

https://raw.githubusercontent.com/yuroyoro/goast-viewer/master/goast-viewer.png

Golang中的ast、parser、token包可用来对golang的源码进行语法分析,并构建出AST树。GoAst Viewer支持在线输入Golang源码来构建AST树。

3.KubeEdge

https://github.com/kubeedge/kubeedge/blob/master/docs/images/kubeedge_arch.png

IoT目前正在大力发展,边缘设备的计算能力在逐渐增强,同时处理的数据量的需求正在快速增加,而数据中心的数据处理能力、网络带宽、扩展能力并没有太多的增强,未来势必会将部分计算能力下放到边缘设备,以降低数据中心的成本。

华为开源的KubeEdge为基于Kubernetes的边缘计算平台,支持边缘集群的编排和管理。

4.Mycat

http://mycat.io/index_files/mycat2.jpg

国内开源的关系型数据库中间件,支持MySQL、Oracle等常见的关系型数据库。关系型数据库单表过大导致性能下降后的解决思路往往是分库分表,分库分表后需要增加中间件层来解决多个数据库多张表的数据增删改查问题,而Mycat是一个不错的解决方案。

当然Mycat的功能不仅限于此,比如支持跨库的两张表join、Mycat-eye可以来监控Mycat等,更多功能请参照官方网站。

5.WeChat Format

一款转换markdown格式的文档为微信公众号排版的工具,排版比较精美,推荐一试。

6.GitNote

https://gitnoteapp.com/imgs/gitnote.png

一款基于git的笔记管理软件,可以将笔记存放到Github中,支持多种图床插件,支持多个平台(还没有移动端),支持富文本编辑和Markdown编辑。由于笔记是可以同步Github上的,可以做到永久保存和版本控制,而且笔记的存放目录和格式不受该工具的影响,可以说是完全没有侵入性,脱离了该工具仍然可以通过直接编辑git项目的方式来发布笔记。

7.Vlang开源啦

V语言宣布开源,从V语言的特性上看到了很多Golang的影子,并未看到耳目一新的特性。

8.krew

一款kubectl的plunin管理工具,mac平台下有brew包管理工具,随着kubectl的plugin机制的成熟,plugin管理工具应运而生。

9.cert-manager

运行在k8s上的证书管理工具,可以签发证书,基于CRD实现。

Let’s Encrypt提供了免费的tls证书,但证书有有效期限制,过期后需要手工重新申请证书,cert-manager可以做到从Let’s Encrypt自动申请证书,并过期后重新申请证书。

10.cmatrix

https://github.com/abishekvashok/cmatrix/raw/master/data/img/capture_orig.gif?raw=true

一款黑客帝国效果的命令行工具,除了炫酷也没啥其他用途了。

11.boxes

boxes为一款有趣的命令行工具,可以显示很多神奇效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
          __   _,--="=--,_   __
/ \." .-. "./ \
/ ,/ _ : : _ \/` \
\ `| /o\ :_: /o\ |\__/
`-'| :="~` _ `~"=: |
\` (_) `/
.-"-. \ | / .-"-.
.---{ }--| /,.-'-.,\ |--{ }---.
) (_)_)_) \_/`~-===-~`\_/ (_(_(_) (
( Different all twisty a )
) of in maze are you, (
( passages little. )
) (
'---------------------------------------'

12.rally

一款elasticsearch的压测工具。

13.tekton

https://tekton.dev/img/logos/tekton-horizontal-color.png

Google开源的一款基于Kubernetes的应用发布框架,Google在云原生生态中出品一般质量都比较高,主要用来做CI/CD。

14.kubectl-debug

一款基于kubectl插件的debug工具,基础镜像使用nicolaka/netshoot(内置了大量的网络排查工具),可用于kubernetes集群中快速定位问题。值得一提的是,该工具的初版是作者在参加pingcap面试时的小作业。

15.Monocular

Rancher出品的一款基于管理helm chart的ui工具。

16.gitmoji

github上的开源项目中经常会看到一些git commit message中包含了moji表情,而且有越来越多的趋势,这些moji表情不紧紧是好玩,而且还非常生动形象的表达了commit message的含义,并且非常醒目,但这些moji表情可不应该是滥用的。该网站记录了一些常用的moji表情在git commit中的含义。

精彩文章

1.Monitoring and Tuning the Linux Networking Stack: Receiving Data

本文讲解了一个数据包到达网卡后是怎么一步步从网卡 -> 操作系统 -> 应用程序,并讲解了Linux中的实现方式。

绝大多数的工程师对于这一块的知识是较为模糊的,建议一读。

视频

https://mp.weixin.qq.com/s?__biz=MzU3OTc1Njk4MQ==&mid=2247486851&idx=1&sn=d0322f6d1a59c21e977488d9701d0476&chksm=fd607b59ca17f24fb07f60b8f488e602ac7e75302c999c206938682387e1d3cac44feb67b208&mpshare=1&scene=1&srcid=%23rd

半年多前比较火的视频,但我还是经常会想起来,给大家重温一下。

视频中为杭州一小伙深夜骑车逆行被交警拦下后情绪崩溃,失声痛哭。小伙每晚加班到十一二点,一方面女朋友在催着给送药匙,另一方面公司还在催着赶回公司,再加上被交警拦下,最终来自三方面的催促导致积压在小伙内心长久以来的压力爆发而情绪失控。隔着屏幕都能感受到小伙长期以来的压力,我猜想如果给他一些自由的时间,他一定会选择独自一人到一个安静的地方过上一段时间与世隔绝的生活。

生活本不易,在觉大多数的成年人生活中没有简单二字,祝愿各位生活如意!

Linux内核会存在一些严重的bug,导致内核crash,会在/var/crash目录下产生类似”127.0.0.1-2019-09-30-21:33:38“这种的文件夹,里面包含了vmcore文件,该文件对于debug 内核crash的原因非常有帮助。

本文在CentOS 7下操作。

执行yum install crash来安装crash

另外还需要两个rpm包:kernel-debuginfo-3.10.0-957.el7.x86_64.rpm 和 kernel-debuginfo-common-x86_64-3.10.0-957.el7.x86_64.rpm,需要关注下操作系统的内核版本,这两个rpm包可以通过搜索引擎找到。

下到包后即可执行rpm -ivh *.rpm的方式来安装rpm包。

在机器上执行crash /usr/lib/debug/lib/modules/3.10.0-957.el7.x86_64/vmlinux /var/crash/xx/vmcore进行debug,可以输入bt命令来查看栈信息。

go mod从1.11开始已经成为了go的默认包管理工具,本文记录go mod的一些使用经验。

要想使用go mod,需要将go升级到1.11或者更高版本。

在没有go mod之前,项目源码必须是放在GOPATH目录下的,有了go mod之后项目即可以放在GOPATH目录下,也可以放在非GOPATH的目录下,在GOPATH目录下在执行时需要指定环境变量GO111MODULE=on,具体的写法可以是GO111MODULE=on go mod init

由于众所周知的原因,go的包相对还是比较难下载的,很多情况下还是需要vendor目录存在的,并将vendor目录中的包一并提交到代码库中。可以使用go mod vendor命令来完成,执行该命令后会将本地下载的包copy到vendor目录下。

坑1 提示unknown revision

1
2
3
4
# GO111MODULE=on go get gitlab.aa-inc.com/bb@v2
go: finding gitlab.aa-inc.com/bb v2
go: finding gitlab.aa-inc.com v2
go get gitlab.aa-inc.com/bb@v2: unknown revision v2

在获取单个包的时候提示unknown revision错误,后发现是go get默认是使用的https协议,而不是git协议,而git仓库的https协议不支持导致的,解决办法为:

1
git config --global url."git@gitlab.aa-inc.com:".insteadOf "https://gitlab.aa-inc.com/"

参考文档

Linux虚拟网络设备 - tap/tun

tap/tun常用于隧道通讯,通过一个字符设备来实现用户态和内核态的通讯,字符设备一端连接着用户空间,一端连接着内核空间。

对应的字符设备文件位置:

  • tap: /dev/tap0
  • tun: /dev/net/tun

当应用程序打开字符设备文件时,驱动程序会创建并注册相应的虚拟设备接口,以tunX或tapX命名。应用程序关闭设备文件时,驱动程序会删除tunX和tapX网络虚拟设备,并删除建立起来的路由信息。

两个设备的不同点:

  • tap是一个二层网络设备,只能处理二层的以太网帧
  • tun是一个点对点的三层网络设备,只能处理处理三层的IP数据包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
                ┌──────────────┐
│ │
│ APP │
│ │
└───────┬──────┘






┌────────────▼──────────┐
│ │
─ ─ ─ ─ ─ ─│ /dev/net/tun ├ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
│ │
└────────────┬──────────┘





┌───────▼──────┐ ┌──────────────┐
│ │ │ │
│ tunX ├────────────────▶│Network Stack │
│ │ │ │
└──────────────┘ └──────────────┘

tun设备应用举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
          ┌──────────────┐         ┌──────────────┐
│ │ │ │
│ APP A │ │ APP B │◀┐
│ │ │ │ │
└───────┬──────┘ └───────┬──────┘ │
│ │ │
│ │ │
1│ │ │
│ 5│ │
│ │ │
─ ─ ─ ─ ─ ─ ─ ─ ┼ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ┼ ─ ─ ─ ─ ─
│ │ │
│ │ 4│
│ │ │
┌────────────▼────────────────────────▼─────┐ │
│ │ │
│ Network Stack │ │
│ │ │
└────────────┬───────────────────────┬──────┘ │
│ │ │
6│ 3│ │
│ │ │
┌───────▼──────┐ ┌─▼─────────┴──┐
│ │ │ │
10.1.1.11 │ eth0 │ │ tun0 │ 192.168.1.11
│ │ │ │
└───────┬──────┘ └──────────────┘

7│



10.1.1.100 / 192.168.1.100

应用程序A要发送数据到其他物理机192.168.1.100,由于物理网络环境下只有10.1.1.11和10.1.1.100是相互连通的,192.168.1.11和192.168.1.100是不通的,为了192.168.1.11和192.168.1.100能够进行通讯,需要将数据包进行一次封装。

应用程序B是通过打开字符设备文件/dev/net/tun0的方式来打开网络设备

流程如下:

  1. A构造数据包,目的ip为192.168.1.100,并发送给协议栈
  2. 协议栈根据数据包中的ip地址,匹配路由规则,要从tun0出去
  3. 内核协议栈将数据包发送给tun0网络设备
  4. tun0发送应用程序B打开,于是将数据发送给应用程序B
  5. B收到数据包后,在用户态构造一个新的数据包,源IP为eth0的IP 10.1.1.11,目的IP为配置的对端10.1.1.100,并封装原来的数据包
  6. 协议栈根据当前数据包的IP地址选择路由,将数据包发送给eth0

reference

行程:海南藏族自治州黑马河乡(9:30) -> 茶卡盐湖(11:30 - 15:00)-> 柴达木盆地 -> 可鲁克湖(18:00 - 18:30) -> 大柴旦镇(21:00)

路程:500+公里

日期:2019.4.22

今天是整个行程的第五天,第四天晚上到达了青海湖西端的黑马河乡,今天的主要行程是茶卡盐湖,以及横穿几乎整个柴达木盆地。

黑马河日出

黑马河地处青海湖最西端,往东边看去是平静的湖水,完全没有任何遮挡,加上高原的空气通透性特别好,况且地处干旱地带,以晴天为主,是个看日出的绝佳地点。

从黑马河赶往茶卡镇需要经过橡皮山,橡皮山口的海拔在3800米+,是整个行程中的海拔最高点。此时的橡皮山还完全是一座雪山,是整个行程中的第二次到达雪山。同时也是由于这些山脉的原因,才阻隔了青海湖和茶卡盐湖,使其分别成为了只进不出的咸水湖。

茶卡盐湖

茶卡盐湖几乎是青海旅游的毕竟之地,无论是环青海湖小环线,还是青海甘肃大环线,同时也是网红景点,网络上有太多穿着红色裙子的漂亮的小姐姐的照片和视频。

茶卡盐湖地处柴达木盆地,周边地势较低,在离盐湖十几公里的地方湖泊就清晰可见,天上的白云倒影在湖中,宛如一面镜子,因此素有“天空之境”之称。远处的昆仑山脉和祁连山脉的雪山清晰可见,由于天空太过透彻,使常年生活在华北地区的我很难判断出雪山的距离。

采盐船
(图为采盐船)

茶卡盐湖的开发利用相当充分,一方面是用来开发采盐,并建有盐厂,湖面上可以看到开采盐矿的船只。另一方面,通过旅游来进一步最大化其价值,其实整个柴达木盆地有很多的盐湖,但最为大众所熟知的仅此一家。而且旅游跟采盐是完全分离的,互不相干,毕竟大部分游客都是来拍照的,旅游占用的盐湖面积比重相对较小。

茶卡盐湖的含盐量实在太高,大部分地方湖面的水都较浅,仅有薄薄的一层,下面全是沉积的盐矿,我此行并没有看到有数米深的湖水。很多地方是可以穿着靴子进入到里面的,但要小心盐坑,看似平坦的盐矿其实有很多的暗洞,很容易就陷进去,好在游客能去的地方盐洞都给堵住了,没啥安全问题。上图中黄色的网状结构为防止游客陷入的盖子。

死海的含盐量肯定没有盐湖的含量高的,尚且人体可以漂浮在表面,我想茶卡盐湖如果有较深的地方,人体一定是可以漂浮在表面的,可惜盐湖并未提供该项旅游体验服务,要不还真想一试。

茶卡盐湖的最佳拍照时机是清晨和傍晚,中午烈日当头的时候晒得人很不舒服,紫外线相当强烈,尤其是对于我这种没有墨镜装备的近视眼游客。在烈日下,去拍人像也很难拍的漂亮,眼睛是很难睁开的,手机在拍人像时,由于背景实在太亮,人像总是会偏黑一些。对于我而言,是很难做到早起的,也就赶不上清晨的茶卡盐湖,实际上到达盐湖景区的时候已经是中午了。

(盐湖的路都是用盐结晶铺成的,好不奢侈)

(在湖中的沉淀物捞出来随手一攥都能成为一个大疙瘩)

柴达木盆地

游览完茶卡盐湖已经是下午三点钟了,接下来还有400多公里的路程要走,好在高原的天黑时间要到晚上八点半。离开茶卡镇后,就进入了漫长的柴达木盆地。

http://p3.pstatp.com/large/pgc-image/1528418882025edccd91e79


我原以为柴达木盆地是属于新疆地区的,后来一看地图才发现彻头彻尾的属于青海省,夹在昆仑山、祁连山和阿尔金山三大山脉之间,而今天的行程几乎就是横穿整个柴达木盆地。

刚离开茶卡镇,还能看到一些牧民养的成群的牛羊,地上也长有一些枯草,但后来地上随着枯草的减少,牛羊也就看不到了。到后面几乎就是戈壁,看不到任何的动物,完全的荒原,让我想起了《北方的空地》中描述的羌塘无人区中的画面,我感觉无人区中也不过如此罢了。地理课本上说柴达木盆地是“聚宝盆”,矿产资源异常丰富,抛开这些埋藏在地底下的矿产不说,但就感官而言,是极其的荒凉。好在一路上,总有雪山陪伴,也不至于太孤单。一路上有很多动物出没的指示牌,好想看到一个活物,但都以失望告终。

由于地广人稀,这段高速公路的管理也相对简陋,曾看到了一辆当地的三轮车在高速的快车道上逆行,吓得我一脸懵,估计是要按正常的路线行驶要多走出好多路。

可鲁克湖

可鲁克湖位于高速公路旁的大约两公里处,甚至都不用下高速就可以到达,属于3A级景区。到达可鲁克湖时已经是下午6点钟,对于进入景区本不报太大的希望,经询问景区居然营业到晚上八点钟,高原地区果然天黑的晚。景区主要是一个偌大的可鲁克湖,可供游玩的地方特别少,简单拍照走人。如果在这里拍张照,拿给别人看,说是青海湖拍的,没有人能够看得出破绽。如果时间紧迫,该景区完全可以不去参观。

可鲁克湖景区旁边还有个比其更大的托素湖,托素湖是可鲁克湖的三倍大小,可鲁克湖的湖水最终会流入托素湖中。比较有意思的是,可鲁克湖的湖水属于淡水湖,而托素湖却属于典型的内陆咸水湖。咸水湖的形成离不开封闭的环境,托素湖由于没有排水渠道,只能靠蒸发来消耗水分,水分被蒸发后,水分中的盐分却不会被蒸发,日积月累就会形成咸水湖。而可鲁克湖由于会流向托素湖,湖水是流动的,因此没有形成咸水湖。

托素湖离高速较远,要开车过去需要沿着可鲁克湖的湖边,来回至少还得要一个半小时的时间,时间不太允许,且可玩性较差,就直接忽略了该景区。

托素湖旁边还有个外星人遗址,单看景区的名字是我特别感兴趣的类型,网上一搜,景区居然暂未开放!

当天终点 - 大柴旦

又是在晚上的时候到达了当天的终点站大柴旦县。

1
2
3
4
5
6
7
8
天空之镜湖
白雪皑皑山
漫漫柴达木
渺渺无人烟
盆地全是宝
可惜只见草
戈壁连成片
夜宿大柴旦

未完待续…

第四天

行程:西宁市 -> 海南藏族自治州黑马河镇

路程:250公里

日期:2019.4.21

经过了前三天的长途跋涉,今天开始了正式的旅行。早上在西宁市的华润万家采购了一些食物,因为还不太清楚接下来的大环线旅行中沿途的住宿饮食条件是什么样子的,也不太清楚很多情况下是否有足够的时间来饱餐一顿,毕竟每天都要赶很多的路。

第一站 塔尔寺

塔尔寺通常都是大家青海旅游的第一站,因为距离西宁市区比较近,大概有几十公里的路程,开车一个小时即可到达。

塔尔寺属于典型的藏传佛教圣地,藏传佛教是受印度佛教、青藏高原本土的苯波教和汉传佛教影响的共同产物,因此有很多区别于其他佛教分支的特点。唐朝时期的文成公主是信奉佛教的,远嫁松赞干布后,为汉族的佛教向青藏地区的渗透起到了非常大的作用。

塔尔寺在藏传佛教中的地位应该跟五台山差不多,但同时也吸收了一些中原道教的文化,比如寺内能看到有西王母的塑像。寺内建筑宏伟,院落也较多,比起五台山而言,除了整体面积小点,其它方面并不逊色。

未能领悟佛教的我,草草的参观塔尔寺后,明显发现了藏传佛教的很多特色,也带给了我不少的震撼。

好几个大殿的院内或者周围都有虔诚的佛教徒在做周而复始的朝拜,口中还振振有词,木质结构的地板早已磨的光滑无比。那种虔诚、执着非常值得敬佩,虽然以我现在的阅历还很难理解这种宗教行为。

第二站 日月山

从塔尔寺出来后,已经是下午两点了,接下来就要往青海湖进发了。日月山是此行的必经之路,属于祁连山脉的支脉,也是此行中看到的第一个雪山,沿途海拔在3000米以上。

进入日月山之前,阳光普照,高原的阳光相当强烈,隔着车玻璃都能感觉到。一开进日月山,雪山清晰可见,突然下起了冰雹,紧接着又下起了雨夹雪,原本没有积雪覆盖的山上也披上了一层薄薄的银装。这一切仿佛在预示着什么,仿佛在迎接着远道而来的客人,又仿佛是在告诫我不要打扰到了雪山上的神灵。

因为日月山的风景太美,全然没有了赶路的想法,就想驻足体验一下日月山的神奇。主干道是京藏高速,有条公路可以通往日月山风景区,索性直接开往日月山风景区。到了景区门口,雨夹雪渐小,一下车发现空气凉了好多,原本仅穿了单件衣服,感觉立马要穿羽绒服的节奏,穿了件外套仍冻得直打哆嗦。高原的天气就是这般神奇,有阳光和没有阳光完全就是两个世界。

日月山风景区并没有必要进入参观,因为景观在景区外一览无余。

景区旁边能看到很多高原鼠兔,发出吱吱的响声,这玩意特别爱打洞,鼠兔的旁边可以看到几个洞。

之后的行程中在公路边上看到了一只死去的马匹,马的头颅已不知所踪。我想放到东部地区,这种现象是肯定不会出现的,死去的马儿肯定还有它的利用价值。

第三站 青海湖

从日月山出来沿着G109国道继续前行,中间经过了倒淌河风景区,倒淌河水源自日月山,自东向西注入青海湖,故名倒淌河。倒淌河的水量不大,加上本来也很难分清东南西北,就很难体会到倒淌河的精妙。看评价景点比较坑,并没有进入参观。

过不了多久,青海湖就会出现在了眼前,而且接下来的两个多小时会一直沿着青海湖南沿的公路前进,足足有一百公里的距离,不愧为中国最大的湖泊。青海湖有个游客去的较多的二郎剑景区,并没有进入,据说性价比依旧很低,无非就是看湖,青海湖的美从哪个角度都能感受到。

G109国道跟青海湖稍微有一段距离,最近处差不多有一里路的样子,中间都是草原,被牧民给围成了一块一块,山羊绵羊在悠闲的吃着草。找了一处牧民的区域,开车过去,一人10元的门票,即可到青海湖边拍照。

身为游客一定觉得湖边的牧民是真正的逍遥快活,每天在自己的牧场上骑马放牧,住在青海湖畔,远处有雪山作伴,呼吸着几乎没有污染的空气。可是一旦天天都是这样的生活,又有几个游客可以放下尘世间的所有诱惑来到这近乎纯净的地方呢?牧民们也有自己的烦恼,牧民的孩子上学怎么办,牧民们生病了怎么办,各种生活的不便利。虽呼吸着最新鲜的空气,却也承受着杀伤力很强的紫外线。冬天的高原夜晚想想都会瑟瑟发抖,但牧民们也要忍受。

我天真的以为,青海湖最初是真正的大海,后来由于地壳运动,地壳上升,而青海湖变成了一个内陆湖。哈哈,不过这个来源忽悠人还是蛮不错的。后来经查阅资料,青海湖的最初是一个内陆淡水湖,并且注入黄河。后来由于地壳运动,青海湖流入黄河的入口被切断,从而青海湖没有了任何出水口。再加上天气较为干旱,湖水的蒸发量大于湖水的注入量,导致湖水的盐分浓度逐渐增加,从而变成了一个咸水湖。青海境内的咸水湖成因都是因为蒸发量大于注入量,包括比较出名的茶卡盐湖。青海湖的湖水浓度并没有海水的浓度高,湖水帮大家尝过了,确实挺咸的。

青海湖的湖水非常清澈,虽湖水很宽,但空气透彻,一眼可以望到河对面远处的雪山。远处的云朵看起来非常低,跟湖水连在一起,微风吹过,湖水上一层层的波澜。

湖边的小水坑里已经有了青蛙,晚上的青海湖畔温度还是非常低的,不知道这些青蛙夜晚是怎么度过的。当然这些小水坑的水是纯淡水,亲尝无误。

终点站 黑马河镇

黑马河位于青海湖的西端,因为是去往茶卡盐湖的必经之地,且可以看到青海湖,因此顺其自然靠着旅游而生存。早晨起来看日出的是个不错的地方,可以想象一下朝霞倒映在湖水中的场景,很多游客都会选择在黑马河观日出。

到达黑马河已经是晚上八点多了,温度较低,索性换上羽绒服,一点也不觉得热。住宿条件比较一般,但价格却不便宜,是整个行程住的性价比最低的宾馆了。找了一家餐馆就餐,全都是组团的游客,非常不错的食材却做的难吃的不行,上等的牦牛肉放到餐桌上后却嚼也嚼不烂,看着放弃的牦牛肉甚是可惜。这大概就是国内很多因旅游而起的餐馆的真实写照,反正能坑一个是一个,不要回头客,回回都是新客人。做的烂对自己的生意影响不大,但游客在心中对于当地的评价确实难以磨灭的。

未完待续…

0%