Keep learning, keep living...

0%

Docker默认的网络模式是bridge模式, 在宿主机上创建一个Linux bridge:docker0,并分配一个网段给该网桥使用。该模式下启动的容器,会分配一个该网段的IP, 并通过veth-pair接入网桥。为了能够从宿主机外部访问容器,需要在创建容器时指定-p参数,在宿主机上将某个宿主机的端口映射到容器的端口。
如:

1
docker run --rm  -itd -p 80:80 nginx

本文来简要分析一下从宿主机外访问bridge网络模式下docker容器的数据包路径。

整体的网络架构如图所示:

阅读全文 »

之前的两篇文章<<nf_ct_deliver_cached_events崩溃分析>><<nf_ct_deliver_cached_events崩溃修复或规避方案>>介绍了nf_conntrack模块中的一个BUG的原因和规避方案。触发BUG的原因在于NFQUEUE操作位于ipv4_conntrack_inipv4_confirm两个函数之间,于是本可以无中断执行完成的两个函数之间出现了CPU调度,导致大量conntrack entry冲突。各HOOK函数执行顺序如图:

阅读全文 »

最近遇到一个CentOS8环境上的内核崩溃问题,内核版本号为4.18.0-305.3.1.el8.x86_64,崩溃堆栈为:

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
crash> bt
PID: 2310003 TASK: ffff99f4ee683e80 CPU: 1 COMMAND: "Verdict2"
#0 [ffffb71241e375e8] machine_kexec at ffffffffbc66156e
#1 [ffffb71241e37640] __crash_kexec at ffffffffbc78f99d
#2 [ffffb71241e37708] crash_kexec at ffffffffbc79088d
#3 [ffffb71241e37720] oops_end at ffffffffbc62434d
#4 [ffffb71241e37740] no_context at ffffffffbc67262f
#5 [ffffb71241e37798] __bad_area_nosemaphore at ffffffffbc67298c
#6 [ffffb71241e377e0] do_page_fault at ffffffffbc673267
#7 [ffffb71241e37810] page_fault at ffffffffbd0010fe
[exception RIP: __pv_queued_spin_lock_slowpath+410]
RIP: ffffffffbc73cbda RSP: ffffb71241e378c0 RFLAGS: 00010282
RAX: 0000000000003ffe RBX: ffff99f4a6ffc624 RCX: 0000000000000001
RDX: 0000000000003fff RSI: 0000000000000000 RDI: 0000000000000000
RBP: ffff99f576e6ac00 R8: 0000000000000000 R9: ffff99f56428e200
R10: 0000000032950000 R11: 0000000000000002 R12: ffffffffbcaaa6d0
R13: ffff99f576e6ac14 R14: 0000000000000001 R15: 0000000000080000
ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018
#8 [ffffb71241e378f8] queued_write_lock_slowpath at ffffffffbc73df3c
#9 [ffffb71241e37910] bpf_sk_reuseport_detach at ffffffffbc842ff9
#10 [ffffb71241e37928] reuseport_detach_sock at ffffffffbcdc2c25
#11 [ffffb71241e37940] sk_destruct at ffffffffbcd7ac33
#12 [ffffb71241e37950] nf_queue_entry_release_refs at ffffffffbce1c1e4
#13 [ffffb71241e37960] nf_reinject at ffffffffbce1c52e
#14 [ffffb71241e37998] nfqnl_recv_verdict at ffffffffc095a81f [nfnetlink_queue]
#15 [ffffb71241e37a10] nfnetlink_rcv_msg at ffffffffc09552be [nfnetlink]
#16 [ffffb71241e37b88] netlink_rcv_skb at ffffffffbce07a3c
#17 [ffffb71241e37bd8] nfnetlink_rcv at ffffffffc0955d08 [nfnetlink]
#18 [ffffb71241e37c18] netlink_unicast at ffffffffbce0725e
#19 [ffffb71241e37c58] netlink_sendmsg at ffffffffbce07524
#20 [ffffb71241e37cc8] sock_sendmsg at ffffffffbcd751fc
#21 [ffffb71241e37ce0] ____sys_sendmsg at ffffffffbcd7551b
#22 [ffffb71241e37d58] ___sys_sendmsg at ffffffffbcd76b9c
#23 [ffffb71241e37eb0] __sys_sendmsg at ffffffffbcd76c67
#24 [ffffb71241e37f38] do_syscall_64 at ffffffffbc60420b
#25 [ffffb71241e37f50] entry_SYSCALL_64_after_hwframe at ffffffffbd0000ad
阅读全文 »

之前的文章<<nf_ct_deliver_cached_events崩溃分析>>分析了nf_conntrack内核模块中存在的一个BUG。由于CentOS7一直没有修复该问题,甚至到当前最新的CentOS8 streamkernel-4.18.0-383.el8版本,这个问题依旧没有修复,这样就无法通过升级官方内核的方法来解决该问题了,只能我们自己来想办法进行修复或规避。

最直观的思路是修改代码后重新编译相关的内核模块进行替换。但在我们无法直接控制的环境中替换模块不是太理想,理想的方案还是能在我们的内核模块中进行修复或者规避。

类似于LivePatch的思路,可以直接HOOK存在BUG的函数:nf_conntrack_confirm, 重新实现正确的逻辑。但该函数是inline函数, 在内核中没有符号:

1
2
3
4
5
6
7
8
9
[root@k8smaster ~]# cat /proc/kallsyms |grep nf_conntrack_confirm
ffffffffc0664050 r __ksymtab___nf_conntrack_confirm [nf_conntrack]
ffffffffc0667b59 r __kstrtab___nf_conntrack_confirm [nf_conntrack]
ffffffffc06647b0 r __kcrctab___nf_conntrack_confirm [nf_conntrack]
ffffffffc06570e0 t __nf_conntrack_confirm [nf_conntrack]

[root@k8smaster ~]# cat /proc/kallsyms |grep ipv4_confirm
ffffffffb5e9b470 t ipv4_confirm_neigh
ffffffffc061c280 t ipv4_confirm [nf_conntrack_ipv4]
阅读全文 »

udev机制是Linux kernel的设备管理机制. 当内核检测到设备插拔后, 会发送事件给用户态的udevd进程. 用户态udevd进程根据事件信息匹配不同规则从而进行不同的处理逻辑.

CentOS7中使用的是systemd中实现的udevd进程. udev规则文件的扩展名为.rules, 主要位于两个目录:

  • /etc/udev/rules.d/: 自定义规则
  • /usr/lib/udev/rules.d/: 系统自带规则

udev规则是以规则文件名按字母顺序进行匹配处理的, 一般文件名中会带有数字前缀, 如:50-udev-default.rules. 处理顺序与规则放在哪个目录下无关, 但如果不同目录下规则文件同名, /etc/udev/rules.d下的文件会覆盖/usr/lib/udev/rules.d/下的文件.

阅读全文 »

之前的文章<<NSX-T路由逻辑介绍>>主介绍了NSX-T的路由逻辑, 举例介绍的是南北向网络路径, 介绍从逻辑交换机/分段Tire1逻辑路由器, 再到Tire0逻辑路由器的过程.

本文来简要介绍一下两个逻辑交换机之间通过Tire1逻辑路由器通信的东西向路径.

实验拓扑如图:

阅读全文 »

最近遇到一个so库符号冲突的问题, 可以总结为:

  • 动态库so1中静态编译了某基础库
  • 动态库so2中动态链接了该基础库的另一版本
  • 可执行程序动态链接了这两个so
  • 程序执行到so2中函数时, 调用了so1中的基础库的符号, 而恰好该基础库两个版本的同名函数不兼容, 因而出现了崩溃.

下面通过demo代码来说明如何解决这个问题.

阅读全文 »

VMware vSphere的很多高级特性都依赖于共享存储, 如vMotion, HA: High Availability, DRS: Distributed Resource Schedule等, 它们要生效都需要虚拟机的存储位于共享存储中. vSphere支持的共享存储除了自家的vSAN, 还包括: NFS, iSCSI, 光纤通道: Fibre Channel等.

iSCSI是一个标准协议, 全称为:Internet Small Computer System Interface, 它在以太网上基于TCP/IP协议来传输SCSI协议. SCSI协议是计算机上的I/O传输协议, SCSI控制器通过SCSI总线与硬盘等设备以块为单位传输数据. iSCSI服务器称为target, 客户端称为initiator. iSCSI initiator能够以纯软件实现运行在标准网络适配器上, 也可以以硬件形式实现为专用的HBA卡:(Host Bus Adaptor), 也有带有iSCSCI offload硬件支持的网卡可以来加速iSCSI协议处理.

iSCSI协议层次如图(来自: https://www.snia.org/education/what-is-iscsi):

阅读全文 »

VMware NSX-T网络构建中,有两个地方需要配置VLAN, 分别是:

  • 逻辑交换机/分段中的VLAN, 如图:

  • Uplink Profile中的传输VLAN(Transport VLAN), 如图:

逻辑交换机VLAN决定了逻辑交换机上的端口类型,表示access或者trunk类型的端口。逻辑交换机又分为基于VLAN类型和Overlay类型两种。
对于VLAN类型的逻辑交换机, 如果配置的VLAN为单一VLAN时,表示端口为access类型。这时逻辑交换机与所连接的虚拟接口间的数据是不携带VLAN tag的,但发送到ESXi主机外部的物理网络的报文会携带有所配置的VLAN tagVLAN 0则比较特殊,在NSX-T以及vSphere体系里都表示不携带VLAN tag。而如果配置多个VLAN后,表示端口为trunk类型。这种情况下,发送到逻辑交换机的报文则必须携带有配置范围内的VLAN tag。而该tag也会透传到外部物理网络。因而使用VLAN类型的逻辑交换机需要底层物理网络做相应的配置允许相应的VLAN通行。
而对于Overlay类型的逻辑交换机, 可以不配置VLAN, 这种情况下,逻辑交换机的端口为access类型。当设置VLAN时,即使设置的是单一VLAN,也会自动修改为trunk类型。这种情况下,逻辑交换机与虚拟接口间的报文则必须携带配置范围内的VLAN tag

整体逻辑可以梳理为:

阅读全文 »

首先介绍NSX-T的基本概念。

参与构建NSX-T网络的节点叫做传输节点(Transport Node), 包括ESXi主机、KVM主机和EDGE节点。传输节点上需要配置构建NSX-T网络所需的NSX虚拟交换机,可以新建N-VDS类型的交换机,也可以复用vCenter上所创建的VDS, 如图:

逻辑交换机(logical switch)也叫分段(segment)为虚拟机提供网络接入点,它需要附着于NSX虚拟交换机之上。有些场景下,逻辑交换机并不需要在所有传输节点上都存在,NSX-T使用传输区域来表示传输节点的范围。NSX虚拟交换机在创建时,需要配置所关联的传输区域

阅读全文 »