ovn port 和 ovs port 的映射关系
1. ovn port 数据库记录
bash
▶ k ko nbctl show
switch c6f88b64-1312-4a37-ba2a-e5a1b37a116d (ovn-default)
port coredns-67dc9c7c5d-d7rd2.kube-system
addresses: ["f2:bc:37:c9:59:59 10.16.0.5"]
port coredns-67dc9c7c5d-96xws.kube-system
addresses: ["da:62:b0:4e:53:36 10.16.0.6"] # 比如,我们关注这个
port kube-ovn-pinger-k7h9q.kube-system
addresses: ["62:f7:ad:22:68:b4 10.16.0.7"]
port ovn-default-ovn-cluster
type: router
router-port: ovn-cluster-ovn-default
switch b97a9121-0bf5-4c9f-92b0-37a3e5638d50 (join)
port node-debian
addresses: ["ea:30:e5:82:2f:38 100.64.0.2"]
port join-ovn-cluster
type: router
router-port: ovn-cluster-join
router b3eb152a-74d1-4164-8611-a6d81b238367 (ovn-cluster)
port ovn-cluster-ovn-default
mac: "6a:9e:fa:44:8b:fd"
networks: ["10.16.0.1/16"]
port ovn-cluster-join
mac: "42:64:9c:ca:a8:ce"
networks: ["100.64.0.1/16"]
addresses: ["da:62:b0:4e:53:36 10.16.0.6"] # 比如,我们关注这个
2. ovs port 和 interface 数据库记录
bash
root@debian:/kube-ovn# ovs-vsctl list Interface 5dd727623250_h
_uuid : 3bd1432e-6c6a-4b99-addf-1981e0f3913f
admin_state : up
bfd : {}
bfd_status : {}
cfm_fault : []
cfm_fault_status : []
cfm_flap_count : []
cfm_health : []
cfm_mpid : []
cfm_remote_mpids : []
cfm_remote_opstate : []
duplex : full
error : []
external_ids : {iface-id=coredns-67dc9c7c5d-96xws.kube-system, ip="10.16.0.6", ovn-installed="true", ovn-installed-ts="1743400875708", pod_name=coredns-67dc9c7c5d-96xws, pod_namespace=kube-system, pod_netns="/var/run/netns/cni-df0516b7-3d93-ec24-6e08-1a5dc9963e71", vendor=kube-ovn}
ifindex : 36
ingress_policing_burst: 0
ingress_policing_kpkts_burst: 0
ingress_policing_kpkts_rate: 0
ingress_policing_rate: 0
lacp_current : []
link_resets : 3
link_speed : 10000000000
link_state : up
lldp : {}
mac : []
mac_in_use : "86:4c:16:34:ad:1b" # 这个 mac 和 ovn nb db 逻辑面并不一致
mtu : 1400
mtu_request : []
name : "5dd727623250_h" # 12 位加一个简单后缀,避免名字过长的一个问题
ofport : 7
ofport_request : []
options : {}
other_config : {}
statistics : {collisions=0, rx_bytes=12017116, rx_crc_err=0, rx_dropped=0, rx_errors=0, rx_frame_err=0, rx_missed_errors=0, rx_multicast_packets=0, rx_over_err=0, rx_packets=98218, tx_bytes=11494934, tx_dropped=0, tx_errors=0, tx_packets=120581}
status : {driver_name=veth, driver_version="1.0", firmware_version=""}
type : ""
root@debian:/kube-ovn#
root@debian:/kube-ovn# ovs-vsctl list port 5dd727623250_h
_uuid : a5e886db-9960-40ad-b243-9063eba325d0
bond_active_slave : []
bond_downdelay : 0
bond_fake_iface : false
bond_mode : []
bond_updelay : 0
cvlans : []
external_ids : {}
fake_bridge : false
interfaces : [3bd1432e-6c6a-4b99-addf-1981e0f3913f]
lacp : []
mac : []
name : "5dd727623250_h" # 12 位加一个简单后缀,避免名字过长的一个问题
other_config : {}
protected : false
qos : []
rstp_statistics : {}
rstp_status : {}
statistics : {}
status : {}
tag : []
trunks : []
vlan_mode : []
root@debian:/kube-ovn#
在 ovs 层面,port 本身还是偏向于业务抽象,它对应了一个 interfaces 列表(类似 bond 的逻辑) interface 中维护的就是具体的网络接口信息,比如 mac 地址, qos,mtu,链路状态等。
从 ovs 的资源展示来看,其实 ovn 和 ovs 的资源关联并不清晰,所以从代码的角度再看一下
3. 关于 veth-pair 两端的命名
4. 关于 ovs 添加端口
go
// Add veth pair host end to ovs port
output, err := ovs.Exec(ovs.MayExist, "add-port", "br-int", hostNicName, "--",
"set", "interface", hostNicName, fmt.Sprintf("external_ids:iface-id=%s", ifaceID),
fmt.Sprintf("external_ids:vendor=%s", util.CniTypeName),
fmt.Sprintf("external_ids:pod_name=%s", podName),
fmt.Sprintf("external_ids:pod_namespace=%s", podNamespace),
fmt.Sprintf("external_ids:ip=%s", ipStr),
fmt.Sprintf("external_ids:pod_netns=%s", netns))
if err != nil {
return nil, fmt.Errorf("add nic to ovs failed %w: %q", err, output)
}
5. 最简单的 ovn ovs 实践
bash
Test #1 - ovs-sandbox
$ git clone http://github.com/openvswitch/ovs.git
$ cd ovs
$ git checkout -b ovn origin/ovn
$ ./boot.sh && ./configure && make
$ make sandbox SANDBOXFLAGS="--ovn"
Test #2 - ovs-sandbox
$ ovn-nbctl lswitch-add sw0
$ ovn-nbctl lport-add sw0 sw0-port1
$ ovn-nbctl lport-add sw0 sw0-port2
$ ovn-nbctl lport-set-macs sw0-port1 00:00:00:00:00:01
$ ovn-nbctl lport-set-macs sw0-port2 00:00:00:00:00:02
$ ovs-vsctl add-port br-int lport1 -- \
set Interface lport1 external_ids:iface-id=sw0-port1
$ ovs-vsctl add-port br-int lport2 -- \
set Interface lport2 external_ids:iface-id=sw0-port2
Test #3 - ovs-sandbox
# Trace OpenFlow flows for a packet from port 1 to 2
$ ovs-appctl ofproto/trace br-int \
in_port=1,dl_src=00:00:00:00:00:01,\
dl_dst=00:00:00:00:00:02 -generate
从这里的实践来看,可以看到,所谓的对应,从目前来看,就是一个 iface-id ,就这样流表就是自动下发了。
6. 关于流表下发过程
可以看到 ovn-controller 向 ovn-northd 申请了 iface-id 对应的 nb port 名(也是 ovs port 名)的 mac 和 ip,然后可以看到 lport 的流表就自动下发了(installed in OVS),然后就记录到全局流表 sb db 中。
7. 分析 ovn-controller Claiming port 源码流程
关键在于这个对象,这个对象应该就是基于 req-id 去对应构建的,但是这么重要的功能为什么不单独做一个固定属性呢?而是可选属性呢?
这么重要的功能为什么不单独做一个固定属性呢?而是可选属性呢?
事实上却是如此: