【计算机网络】Linux虚拟网络设备之veth(arp incomplete)_linux arp incomplete-程序员宅基地

技术标签: 网络  linux  【计算机组成原理&操作系统】  docker  


相关文章:

《Linux 虚拟网络设备 veth-pair》 linux基础
《Linux虚拟网络设备之veth(arp incomplete)》
【Linux 】查看veth-pair对的映射关系

Docker网络(veth、网桥、host、container、none) docker上网络概述

Docker的网络配置 1 初识 docker 精讲
Docker的网络配置 2 配置 DNS和主机名
Docker的网络配置 3 user-defined网络
Docker的网络配置 4 内嵌的DNS server
Docker的网络配置 5 将容器与外部世界连接
Docker的网络配置 6 docker-proxy

【云原生】网络之桥接(网卡对) openshift下的网络桥接模式

1. veth设备的特点

veth是虚拟以太端口,总是成对出现

  • veth和其它的网络设备都一样,一端连接的是内核协议栈。
  • veth设备是成对出现的,另一端两个设备彼此相连
    创建veth时,必须提供2个成对的目标
  • 一个设备收到协议栈的数据发送请求后,会将数据发送到另一个设备上去。

下面这张关系图很清楚的说明了veth设备的特点:

+----------------------------------------------------------------+
|                                                                |
|       +------------------------------------------------+       |
|       |             Newwork Protocol Stack             |       |
|       +------------------------------------------------+       |
|              ↑               ↑               ↑                 |
|..............|...............|...............|.................|
|              ↓               ↓               ↓                 |
|        +----------+    +-----------+   +-----------+           |
|        |   eth0   |    |   veth100   |   |   veth199   |           |
|        +----------+    +-----------+   +-----------+           |
|192.168.1.11  ↑               ↑               ↑                 |
|              |               +---------------+                 |
|              |         192.168.2.11     192.168.2.1            |
+--------------|-------------------------------------------------+
               ↓
         Physical Network

上图中,我们给物理网卡eth0配置的IP为192.168.1.11, 而veth100和veth1的IP分别是192.168.2.11和192.168.2.1。

1.1 创建 veth

标准语法 :
ip link add veth0 type veth peer name veth1

34: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 1a:f5:90:11:07:13 brd ff:ff:ff:ff:ff:ff
35: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether ce:5d:7f:77:f1:ef brd ff:ff:ff:ff:ff:ff

注意: 当你不添加 peer name veth1 时,会自动添加 peer name vethxxx,其中 vethxxx 是数字自动累加的,保证成对出现

ip link add veth0 type veth 

查看,仍然会生成一对:

37: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
38: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000

甚至,你可以直接 不指定任何veth的名称,仍然可以生成一对,其名称是 vethxxx自动累加的:
ip link add type veth // 不指定任何veth的名称

2. 示例

我们通过示例的方式来一步一步的看看veth设备的特点。

2.1 只给一个veth设备配置IP

先通过ip link命令添加veth100和veth1,然后配置veth100的IP,并将两个设备都启动起来

dev@debian:~$ sudo ip link add veth100 type veth peer name veth199   '创建一个veth类型的网卡'

此时通过 ip a进行查看,发现多了2个网卡:

[root@paas-controller-3:R50s:/proc/24415]$  ip a|grep veth100
162: veth199@veth100: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
163: veth100@veth199: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000

注意:这里面veth100 veth199 在同一个空间,因此 可以直接看到veth199@veth100 这种配对的关系,但是当你移到其它空间时,就不那么直观了,可能是类似这样 的 veth100@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000,具体 怎么映射的,可以参见 【Linux 】查看veth-pair对的映射关系

给其中的一个虚拟网卡设置ip:

dev@debian:~$ sudo ip addr add 192.168.2.11/24 dev veth100
dev@debian:~$ sudo ip link set veth100 up
dev@debian:~$ sudo ip link set veth199 up

这里不给veth1设备配置IP的原因就是想看看在veth1没有IP的情况下,veth100收到协议栈的数据后会不会转发给veth1。

ping一下192.168.2.1,由于veth1还没配置IP,所以肯定不通:

dev@debian:~$ ping -c 4 192.168.2.1
PING 192.168.2.1 (192.168.2.1) 56(84) bytes of data.
From 192.168.2.11 icmp_seq=1 Destination Host Unreachable
From 192.168.2.11 icmp_seq=2 Destination Host Unreachable
From 192.168.2.11 icmp_seq=3 Destination Host Unreachable
From 192.168.2.11 icmp_seq=4 Destination Host Unreachable

--- 192.168.2.1 ping statistics ---
4 packets transmitted, 0 received, +4 errors, 100% packet loss, time 3015ms
pipe 3

但为什么ping不通呢?是到哪一步失败的呢?

先看看抓包的情况,从下面的输出可以看出,veth100和veth1收到了同样的ARP请求包,但没有看到ARP应答包:

dev@debian:~$ sudo tcpdump -n -i veth100
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth100, link-type EN10MB (Ethernet), capture size 262144 bytes
20:20:18.285230 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28     'ARP请求包'
20:20:19.282018 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28
20:20:20.282038 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28
20:20:21.300320 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28
20:20:22.298783 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28
20:20:23.298923 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28

dev@debian:~$ sudo tcpdump -n -i veth199
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth199, link-type EN10MB (Ethernet), capture size 262144 bytes
20:20:48.570459 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28     'ARP请求包'
20:20:49.570012 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28
20:20:50.570023 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28
20:20:51.570023 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28
20:20:52.569988 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28
20:20:53.570833 ARP, Request who-has 192.168.2.1 tell 192.168.2.11, length 28

为什么会这样呢?了解ping背后发生的事情后就明白了:

1.ping进程构造ICMP echo请求包,并通过socket发给协议栈,
2.协议栈根据目的IP地址和系统路由表,知道去192.168.2.1的数据包应该要由192.168.2.11口出去
3.由于是第一次访问192.168.2.1,且目的IP和本地IP在同一个网段,所以协议栈会先发送ARP出去,询问192.168.2.1的mac地址
4.协议栈将ARP包交给veth100,让它发出去
5.由于veth100的另一端连的是veth1,所以ARP请求包就转发给了veth1
6.veth1收到ARP包后,查看协议栈
7.协议栈一看自己的设备列表,发现本地没有192.168.2.1这个IP,于是就丢弃了该ARP请求包,这就是为什么只能看到ARP请求包,看不到应答包的原因

2.2 给两个veth设备都配置IP

给veth1也配置上IP

dev@debian:~$ sudo ip addr add 192.168.2.1/24 dev veth199

再ping 192.168.2.1成功(由于192.168.2.1是本地IP,所以默认会走lo设备,为了避免这种情况,这里使用ping命令带上了-I参数,指定数据包走指定设备),假设此时的ping次数即为Pn

dev@debian:~$ ping -c 4 192.168.2.1 -I veth100
PING 192.168.2.1 (192.168.2.1) from 192.168.2.11 veth100: 56(84) bytes of data.
64 bytes from 192.168.2.1: icmp_seq=1 ttl=64 time=0.032 ms
64 bytes from 192.168.2.1: icmp_seq=2 ttl=64 time=0.048 ms
64 bytes from 192.168.2.1: icmp_seq=3 ttl=64 time=0.055 ms
64 bytes from 192.168.2.1: icmp_seq=4 ttl=64 time=0.050 ms

--- 192.168.2.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3002ms
rtt min/avg/max/mdev = 0.032/0.046/0.055/0.009 ms

注意:对于非debian系统,这里有可能ping不通,主要是因为内核中的一些ARP相关配置导致veth1不返回ARP应答包,如ubuntu上就会出现这种情况,解决办法如下:

如果不设置,会导致192.168.2.1在arp缓存中状态为 arp incomplete。
或者 把其中veth199加入到一个其他的命名空间。然后再ping ,参见 章节3

root@ubuntu:~# echo 1 > /proc/sys/net/ipv4/conf/veth199/accept_local
root@ubuntu:~# echo 1 > /proc/sys/net/ipv4/conf/veth100/accept_local
root@ubuntu:~# echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
root@ubuntu:~# echo 0 > /proc/sys/net/ipv4/conf/veth100/rp_filter
root@ubuntu:~# echo 0 > /proc/sys/net/ipv4/conf/veth199/rp_filter

再来看看抓包情况(假设此时的ping次数即为Pn+1),我们在veth100和veth1上都看到了ICMP echo的请求包,但为什么没有应答包呢?上面不是显示ping进程已经成功收到了应答包吗?

由于Pn次 操作让ARP缓存产生一条新的记录,此时再抓包,就看不到ARP消息了

dev@debian:~$ sudo tcpdump -n -i veth100
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth100, link-type EN10MB (Ethernet), capture size 262144 bytes
20:23:43.113062 IP 192.168.2.11 > 192.168.2.1: ICMP echo request, id 24169, seq 1, length 64
20:23:44.112078 IP 192.168.2.11 
> 192.168.2.1: ICMP echo request, id 24169, seq 2, length 64
20:23:45.111091 IP 192.168.2.11 > 192.168.2.1: ICMP echo request, id 24169, seq 3, length 64
20:23:46.110082 IP 192.168.2.11 > 192.168.2.1: ICMP echo request, id 24169, seq 4, length 64


dev@debian:~$ sudo tcpdump -n -i veth199
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth199, link-type EN10MB (Ethernet), capture size 262144 bytes
20:24:12.221372 IP 192.168.2.11 > 192.168.2.1: ICMP echo request, id 24174, seq 1, length 64
20:24:13.222089 IP 192.168.2.11 > 192.168.2.1: ICMP echo request, id 24174, seq 2, length 64
20:24:14.224836 IP 192.168.2.11 > 192.168.2.1: ICMP echo request, id 24174, seq 3, length 64
20:24:15.223826 IP 192.168.2.11 > 192.168.2.1: ICMP echo request, id 24174, seq 4, length 64

看看数据包的流程就明白了:

  • 1ping进程构造ICMP echo请求包,并通过socket发给协议栈,

  • 2由于ping程序指定了走veth100,并且本地ARP缓存里面已经有了相关记录,所以不用再发送ARP出去,协议栈就直接将该数据包交给了veth100

  • 3由于veth100的另一端连的是veth1,所以ICMP echo请求包就转发给了veth1

  • 4veth1收到ICMP echo请求包后,转交给另一端的协议栈

  • 5协议栈一看自己的设备列表,发现本地有192.168.2.1这个IP,于是构造ICMP echo应答包,准备返回

    为啥协议栈发送reply消息不是原路返回的?是因为同主机优先从lo走吗,并且没有-i veth1指定原路返回?
    为啥是协议栈 发送reply消息,而不是veth1发送reply消息?

  • 6协议栈查看自己的路由表,发现回给192.168.2.11的数据包应该走lo口,于是将应答包交给lo设备

  • 7lo接到协议栈的应答包后,啥都没干,转手又把数据包还给了协议栈(相当于协议栈通过发送流程把数据包给lo,然后lo再将数据包交给协议栈的接收流程)

  • 8协议栈收到应答包后,发现有socket需要该包,于是交给了相应的socket

  • 9这个socket正好是ping进程创建的socket,于是ping进程收到了应答包

抓一下lo设备上的数据,发现应答包确实是从lo口回来的:

dev@debian:~$ sudo tcpdump -n -i lo
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
20:25:49.590273 IP 192.168.2.1 > 192.168.2.11: ICMP echo reply, id 24177, seq 1, length 64
20:25:50.590018 IP 192.168.2.1 > 192.168.2.11: ICMP echo reply, id 24177, seq 2, length 64
20:25:51.590027 IP 192.168.2.1 > 192.168.2.11: ICMP echo reply, id 24177, seq 3, length 64
20:25:52.590030 IP 192.168.2.1 > 192.168.2.11: ICMP echo reply, id 24177, seq 4, length 64

2.3 试着ping下其它的IP

ping 192.168.2.0/24网段的其它IP失败,ping一个公网的IP也失败:

dev@debian:~$ ping -c 1 -I veth100 192.168.2.2
PING 192.168.2.2 (192.168.2.2) from 192.168.2.11 veth100: 56(84) bytes of data.
From 192.168.2.11 icmp_seq=1 Destination Host Unreachable

--- 192.168.2.2 ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms

dev@debian:~$ ping -c 1 -I veth100 baidu.com
PING baidu.com (111.13.101.208) from 192.168.2.11 veth100: 56(84) bytes of data.
From 192.168.2.11 icmp_seq=1 Destination Host Unreachable

--- baidu.com ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms

从抓包来看,和上面第一种veth1没有配置IP的情况是一样的,ARP请求没人处理:

dev@debian:~$ sudo tcpdump -i veth199
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth199, link-type EN10MB (Ethernet), capture size 262144 bytes
02:25:23.223947 ARP, Request who-has 192.168.2.2 tell 192.168.2.11, length 28
02:25:24.224352 ARP, Request who-has 192.168.2.2 tell 192.168.2.11, length 28
02:25:25.223471 ARP, Request who-has 192.168.2.2 tell 192.168.2.11, length 28
02:25:27.946539 ARP, Request who-has 123.125.114.144 tell 192.168.2.11, length 28
02:25:28.946633 ARP, Request who-has 123.125.114.144 tell 192.168.2.11, length 28
02:25:29.948055 ARP, Request who-has 123.125.114.144 tell 192.168.2.11, length 28

3. 不同命名空间的示例

$ sudo ip link add veth100 type veth peer name veth199 ‘创建一个veth类型的网卡’
$ sudo ip addr add 192.168.2.11/24 dev veth100
$ sudo ip link set veth100 up

ip netns add netns199 //新建一个命名空间
ip link set veth199 netns netns199 //把veth199 加入到这个新建的空间
ip netns exec netns199 ip link set dev veth199 up //启动这个网卡
ip netns exec netns199 ip a a 192.168.2.12/24 dev veth199 //添加地址
ip netns exec netns199 ip a //查看网卡

在主机默认空间上 # ping 192.168.2.12

4. 结束语

从上面的介绍中可以看出,从veth100设备出去的数据包,会转发到veth1上,如果目的地址是veth1的IP的话,就能被协议栈处理,否则连ARP那关都过不了,IP forward啥的都用不上,所以不借助其它虚拟设备的话,这样的数据包只能在本地协议栈里面打转转,没法走到eth0上去,即没法发送到外面的网络中去。

下一篇将介绍Linux下的网桥,到时候veth设备就有用武之地了。

参考

Linux虚拟网络设备之veth

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_45406092/article/details/118497011

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签