openshift-sdn是紅帽推出的一款容器集羣網絡方案。一直集成於openshift平臺中。 但紅帽將項目代碼進行了開源。html
實際上,咱們經過一些修改,徹底能夠將openshift-sdn做爲一款通用的容器集羣的網絡方案。java
openshift-sdn官方建議使用network-operator工具進行網絡部署,實際上在該項目中咱們甚至能夠扒出一套基本完整的部署模板。基於這套模板咱們能夠直接部署openshift-sdn。node
爲了加深你們的理解,本文咱們會詳細地介紹整個方案的功能、使用和原理。咱們相信,若是你徹底理解了本文的內容,你也能在集羣的openshift-sdn網絡出現故障時,能遊刃有餘地進行排障。git
openshift-sdn依賴於了openvswitch技術,也就是虛擬交換機,在k8s集羣的每一個節點上都要求部署好openvswitch並啓動服務:github
systemctl status openvswitch-switch.service
openshift-sdn經過構建和維護一套流表,以及一些路由和iptables策略,就實現了基本的容器網絡需求:docker
除此以外,還提供了豐富的擴展能力:數據庫
能夠說openshift-sdn的功能已經趨於完備。後端
openshift-sdn包括了管控面和數據面。api
沒有任何特殊的操做,規劃好集羣裏pod、service的網段、 並部署好openshift-sdn組件後,咱們就能夠部署pod了數組
在使用mulit-tenant模式時,集羣中每一個namespace都會被建立出一個同名的netnamespace
,這是openshift-sdn設計的crd,咱們看看裏頭記錄了啥:
kubectl get netnamespaces kube-system -o yaml apiVersion: network.openshift.io/v1 kind: NetNamespace metadata: creationTimestamp: 2020-07-08T09:47:15Z generation: 1 name: kube-system resourceVersion: "33838361" selfLink: /apis/network.openshift.io/v1/netnamespaces/kube-system uid: 017460a8-c100-11ea-b605-fa163e6fe7d6 netid: 4731218 netname: kube-system
總體看下來,惟一有意義的字段就是netid了,這個整型表示了全局惟一的id,當不一樣的netnamespace,彼此之間的netid不一樣時,他們對應的namespace下的pod,就彼此不通。
當某個netnamespace的netid爲0,表示這個netnamespace下的pod能夠與任何namespace下的pod互通。
經過這種邏輯,咱們能夠基於namespace來設計租戶,實現租戶隔離
若是集羣的pod IP不夠用了怎麼辦?這是衆多開源的容器網絡方案的共同問題。openshift-sdn提供了一個靈活的擴展機制。
剛纔提到集羣部署時要先規劃好集羣pod的CIDR和service的CIDR,當部署好openshift-sdn後,咱們能夠看到:
# kubectl get clusternetwork default -o yaml apiVersion: network.openshift.io/v1 clusterNetworks: - CIDR: 10.178.40.0/21 hostSubnetLength: 10 hostsubnetlength: 10 kind: ClusterNetwork metadata: creationTimestamp: 2020-07-09T03:04:22Z generation: 1 name: default resourceVersion: "36395511" selfLink: /apis/network.openshift.io/v1/clusternetworks/default uid: e3b4a921-c190-11ea-b605-fa163e6fe7d6 network: 10.178.40.0/21 pluginName: redhat/openshift-ovs-multitenant serviceNetwork: 10.178.32.0/21 vxlanPort: 4789
openshift-sdn設計的一個CRD,名爲ClusterNetwork,這個CRD的對象記錄了集羣裏使用的網絡網段,當集羣裏有多個這種ClusterNetwork對象時,openshift-sdn只會取名爲default
的那個對象。
關注裏面的內容,咱們發現clusterNetworks
是一個數組,他的每一個成員均可以定義一個CIDR和hostsubnetlength。也就是說,咱們修改了他,就能夠給集羣擴充網段。
這裏咱們看到在結構體中還有兩個字段:hostsubnetlength
和network
,值分別與clusterNetworks
數組的惟一一個成員的字段相對應。這是openshift-sdn
的歷史遺留問題,早先版本不支持配置clusterNetworks
數組,後面添加後,這兩個字段只有當數組長度爲1時,會進行一次校驗。
咱們將default這個ClusterNetwork
的內容改爲:
# kubectl get clusternetwork default -o yaml apiVersion: network.openshift.io/v1 clusterNetworks: - CIDR: 10.178.40.0/21 hostSubnetLength: 10 - CIDR: 10.132.0.0/14 hostSubnetLength: 9 hostsubnetlength: 10 kind: ClusterNetwork metadata: creationTimestamp: 2020-07-09T03:04:22Z generation: 2 name: default resourceVersion: "36395511" selfLink: /apis/network.openshift.io/v1/clusternetworks/default uid: e3b4a921-c190-11ea-b605-fa163e6fe7d6 network: 10.178.40.0/21 pluginName: redhat/openshift-ovs-multitenant serviceNetwork: 10.178.32.0/21 vxlanPort: 4789
但這僅僅修改了控制面,數據面的修改尚未作,節點上此時根本不知道有這個新增的網段。
關於數據面的改動,官方的作法是:將每一個node進行驅逐:kubectl drain $nodename
, 而後重啓node, 重啓後節點上ovs流表會清空、ovs-node 組件會重啓,並從新配置流表和路由、iptables規則。
這樣對數據面的影響未免太大了!之後我IP不夠用了, 還要把集羣裏每一個node重啓一次,至關於全部在用的業務容器都要至少重建一次!有沒有優雅一點的方案呢?
咱們對openshift-sdn進行了深刻的研究和社區追蹤,並聚焦於如何優雅地、不影響業務容器地、完成網段的擴展。
咱們實踐發現,老節點上node組件重啓後,就會從新同步最新的clusternetwork信息,將新的網段配置到節點的路由表,和ovs流表中, 可是,已有的容器仍是沒法訪問新加入的網段。
進行詳細的排查,咱們發現老的容器裏,訪問新網段會走的路由是:
default via 10.178.40.1 dev eth0
正常來講,訪問集羣pod cidr的路由是:
10.178.40.0/21 dev eth0 scope link
因而咱們寫了個工具,在老節點上運維了一把,往已有的容器中加入到達新網段的路由。如:
10.132.0.0/14 dev eth0
測試了一下網絡終於通了~
在反覆的實踐後,咱們使用該方案對用戶的業務集羣進行了網段擴容。
可是咱們不由產生了疑問,爲啥訪問新的網段,不能夠走網關呢?咱們意識到:爲了更好地支持,有必要進行更深刻的瞭解。openshift-sdn的官方文檔對此沒有特別細緻的解釋,所以咱們決定從新梳理一遍了一通源碼和流表,好好地整理清楚,openshift-sdn,究竟是怎麼作的?
openshift-sdn給集羣增長了一些CRD,包括
openshift-sdn的組件包含了中心化的控制器,去中心化的agent和CNI插件,agent會直接影響節點上的數據面,他們各自負責的主要內容包括:
咱們在一個k8s集羣中部署了openshift-sdn網絡,經過對路由、流表、iptables的分析,能夠勾畫出網絡的架構。
首先看容器裏的內容。當咱們使用openshift-sdn時,須要先提供整個集羣規劃的pod IP CIDR,以及每一個node上能夠從CIDR裏分配多少IP做爲子段。咱們這裏規劃10.178.40.0/21
爲集羣的pod cidr, 每一個節點上能夠分配2^10個IP ,這樣集羣裏只能支持兩個節點。兩個節點的IP段分別爲:10.178.40.0/22
和10.178.44.0/22
隨意建立一個pod,進入容器中檢查IP和路由:
# docker exec -it bfdf04f24e01 bash root@hytest-5db48599dc-95gfh:/# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 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 3: eth0@if95: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1350 qdisc noqueue state UP group default link/ether 0a:58:0a:b2:28:0f brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 10.178.40.15/22 brd 10.178.43.255 scope global eth0 valid_lft forever preferred_lft forever root@hytest-5db48599dc-95gfh:/# ip r default via 10.178.40.1 dev eth0 10.178.40.0/22 dev eth0 proto kernel scope link src 10.178.40.15 10.178.40.0/21 dev eth0 224.0.0.0/4 dev eth0
能夠看到IP:10.178.40.15/22
是處於網段10.178.40.0/22
中的。路由表的含義,從底向上爲:
到此爲止,咱們知道了容器裏的配置,要想了解更多,就要接着看宿主機配置(爲了可讀性咱們不展現一些無關的網卡和路由):
# ip a 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1400 qdisc pfifo_fast state UP group default qlen 1000 link/ether fa:16:3e:6f:e7:d6 brd ff:ff:ff:ff:ff:ff inet 10.173.32.63/21 brd 10.173.39.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::f816:3eff:fe6f:e7d6/64 scope link valid_lft forever preferred_lft forever 85: vxlan_sys_4789: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65485 qdisc noqueue master ovs-system state UNKNOWN group default qlen 1000 link/ether ae:22:fc:f9:77:92 brd ff:ff:ff:ff:ff:ff inet6 fe80::ac22:fcff:fef9:7792/64 scope link valid_lft forever preferred_lft forever 86: ovs-system: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 8a:95:6e:5c:65:cb brd ff:ff:ff:ff:ff:ff 87: br0: <BROADCAST,MULTICAST> mtu 1350 qdisc noop state DOWN group default qlen 1000 link/ether 0e:52:ed:b2:b2:49 brd ff:ff:ff:ff:ff:ff 88: tun0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1350 qdisc noqueue state UNKNOWN group default qlen 1000 link/ether 06:60:ae:a8:f5:22 brd ff:ff:ff:ff:ff:ff inet 10.178.40.1/22 brd 10.178.43.255 scope global tun0 valid_lft forever preferred_lft forever inet6 fe80::460:aeff:fea8:f522/64 scope link valid_lft forever preferred_lft forever 95: vethadbc25e1@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1350 qdisc noqueue master ovs-system state UP group default link/ether 06:48:6c:da:8f:4b brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet6 fe80::448:6cff:feda:8f4b/64 scope link valid_lft forever preferred_lft forever
# ip r default via 10.173.32.1 dev eth0 10.173.32.0/21 dev eth0 proto kernel scope link src 10.173.32.63 10.178.32.0/21 dev tun0 10.178.40.0/21 dev tun0 scope link
宿主機的IP是位於eth0上的10.173.32.63
,咱們看到機器上還有一些特殊的網卡:
經過執行如下命令能夠看到:
# ovs-vsctl show fde6a881-3b54-4c50-a86f-49dcddaa5a95 Bridge "br0" fail_mode: secure Port "vethadbc25e1" Interface "vethadbc25e1" Port "tun0" Interface "tun0" type: internal Port "br0" Interface "br0" type: internal Port "vxlan0" Interface "vxlan0" type: vxlan options: {dst_port="4789", key=flow, remote_ip=flow} ovs_version: "2.8.4"
tun0、vxlan0、各個veth,都是在ovs網橋上開的端口,當這些端口收到包時,會直接被內核態的datapath監聽並進行流表的規則匹配,以肯定包最終的處理方式。
veth是與容器內的eth0直連的,容器裏的包經過這對vethpair發送到宿主機,而且直接被datapath接管。
宿主機上有一個vxlan0,專門用來封裝/解封vxlan協議的包。在ovs流表中,會將須要封裝的包發給vxlan0進行封裝。
當pod訪問其餘節點的pod時,流表會將包引向vxlan0,IP地址封裝爲node的IP,封裝好以後,能夠直接經過宿主機的網絡發到對端節點所在的node。
宿主機上有一個tun0,在宿主機的路由中,能夠看到:
10.178.32.0/21 dev tun0
表示的是k8s集羣裏service 的網段,經過tun0發出10.178.40.0/21 dev tun0 scope link
表示的是,k8s裏的集羣pod CIDR,經過tun0發出。因此當node訪問集羣裏任何一個pod/service,都要走tun0, tun0 是openvswitch在虛擬交換機上開啓的一個端口(port),從tun0流入的數據包(pod發給對端的包),會被內核態的datapath監聽到,並去走內核態的、緩存好的流表規則。流表規則記錄了一個數據包應該如何被正確地處理。
ovs-vswitchd 本質是一個守護進程,是 OvS 的核心部件。ovs-vswitchd 和 Datapath 一塊兒實現 OvS 基於流表(Flow-based Switching)的數據交換。它經過 OpenFlow 協議能夠與 OpenFlow 控制器通訊,使用 ovsdb 協議與 ovsdb-server 數據庫服務通訊,使用 netlink 和 Datapath 內核模塊通訊。ovs-vswitchd 支持多個獨立的 Datapath,ovs-vswitchd 須要加載 Datapath 內核模塊才能正常運行。ovs-vswitchd 在啓動時讀取 ovsdb-server 中的配置信息,而後自動配置 Datapaths 和 OvS Switches 的 Flow Tables,因此用戶不須要額外的經過執行 ovs-dpctl 指令工具去操做 Datapath。當 ovsdb 中的配置內容被修改,ovs-vswitched 也會自動更新其配置以保持數據同步。ovs-vswitchd 也能夠從 OpenFlow 控制器獲取流表項。
接下來咱們就要看流表是如何配置的~
經過執行:ovs-ofctl dump-flows br0 -O openflow13 table=XX
命令咱們能夠看到ovs中某個表的流規則, table0是這個規則集合的入口。因此咱們能夠從table=0開始看起
# ovs-ofctl dump-flows br0 -O openflow13 table=0 cookie=0x0, duration=82110.449s, table=0, n_packets=0, n_bytes=0, priority=250,ip,in_port=tun0,nw_dst=224.0.0.0/4 actions=drop cookie=0x0, duration=82110.450s, table=0, n_packets=2, n_bytes=84, priority=200,arp,in_port=vxlan0,arp_spa=10.178.40.0/21,arp_tpa=10.178.40.0/22 actions=move:NXM_NX_TUN_ID[0..31]->NXM_NX_REG0[],goto_table:10 cookie=0x0, duration=82110.450s, table=0, n_packets=1, n_bytes=98, priority=200,ip,in_port=vxlan0,nw_src=10.178.40.0/21 actions=move:NXM_NX_TUN_ID[0..31]->NXM_NX_REG0[],goto_table:10 cookie=0x0, duration=82110.450s, table=0, n_packets=0, n_bytes=0, priority=200,ip,in_port=vxlan0,nw_dst=10.178.40.0/21 actions=move:NXM_NX_TUN_ID[0..31]->NXM_NX_REG0[],goto_table:10 cookie=0x0, duration=82110.450s, table=0, n_packets=2, n_bytes=84, priority=200,arp,in_port=tun0,arp_spa=10.178.40.1,arp_tpa=10.178.40.0/21 actions=goto_table:30 cookie=0x0, duration=82110.450s, table=0, n_packets=1, n_bytes=98, priority=200,ip,in_port=tun0 actions=goto_table:30 cookie=0x0, duration=82110.450s, table=0, n_packets=0, n_bytes=0, priority=150,in_port=vxlan0 actions=drop cookie=0x0, duration=82110.450s, table=0, n_packets=37, n_bytes=2678, priority=150,in_port=tun0 actions=drop cookie=0x0, duration=82110.450s, table=0, n_packets=4, n_bytes=168, priority=100,arp actions=goto_table:20 cookie=0x0, duration=82110.450s, table=0, n_packets=2, n_bytes=196, priority=100,ip actions=goto_table:20 cookie=0x0, duration=82110.450s, table=0, n_packets=0, n_bytes=0, priority=0 actions=drop
咱們主要關注規則的後半段,從priority
開始到action
以前的一串,是匹配邏輯:
以後的actions
,表示針對前面的規則獲得的包,要進行如何處理,通常有:
drop
丟棄goto_table:**
轉到某個表繼續匹配規則set_field:10.173.32.62->tun_dst
表示封裝包目的地址load:0x483152->NXM_NX_REG1[]
寄存器賦值操做,用來將某個租戶的vnid保存到寄存器,後續作租戶隔離的判斷,這裏將0x483152記錄到REG1中,REG0表示源地址所屬的vnid,REG1表示目的地址,REG2表示包要從哪一個port發出(ovs上每一個port都有id)output:***
表示從ovs網橋上的某個端口設備發出 好比vxlan0move:NXM_NX_REG0[]->NXM_NX_TUN_ID[0..31]
表示將REG0中的值拷貝到封裝包的vnid字段中大體清楚流表裏的主要語法後,咱們能夠結合一個機器上的ovs流表內容,分析一下從pod訪問service的時候,整個處理鏈路:
cookie=0x0, duration=17956.652s, table=0, n_packets=20047, n_bytes=1412427, priority=100,ip actions=goto_table:20
進入table20 cookie=0x0, duration=17938.360s, table=20, n_packets=0, n_bytes=0, priority=100,ip,in_port=vethadbc25e1,nw_src=10.178.40.15 actions=load:0->NXM_NX_REG0[],goto_table:21
規則,進入table21,並且作了load操做,給REG0設置值爲0,意思是這個數據包的源IP能適配任何租戶 cookie=0x0, duration=18155.706s, table=21, n_packets=3, n_bytes=182, priority=0 actions=goto_table:30
進入table30 cookie=0x0, duration=12410.821s, table=30, n_packets=0, n_bytes=0, priority=100,ip,nw_dst=10.178.32.0/21 actions=goto_table:60
cookie=0x0, duration=12438.404s, table=60, n_packets=0, n_bytes=0, priority=100,udp,nw_dst=10.178.32.32,tp_dst=53 actions=load:0x483152->NXM_NX_REG1[],load:0x2->NXM_NX_REG2[],goto_table:80
。 注意這裏咱們在action中作了load操做,告知將目的地址的vnid設置爲4731218,這個值是ovs經過service所屬的namespace的信息獲得的,是multi-tenant的特性;並設置了REG2,表示:若是包要發出,就要從id爲2的port發出ovs-vsctl list interface
, 能夠看到ofport
值爲2的設備是tun0.也就是說包是從tun0發出。-A OPENSHIFT-MASQUERADE -s 10.178.40.0/21 -m comment --comment "masquerade pod-to-service and pod-to-external traffic" -j MASQUERADE
這條iptables規則實現,這樣源IP就再也不是pod而是node的IP【openshift-sdn支持開啓ct支持,開啓ct支持後,就不須要作這個額外的masq了,但開啓該功能要求ovs達到2.6的版本】 cookie=0x0, duration=19046.682s, table=0, n_packets=21270, n_bytes=10574507, priority=200,ip,in_port=tun0 actions=goto_table:30
直接進入table30 cookie=0x0, duration=13508.548s, table=30, n_packets=1, n_bytes=98, priority=100,ip,nw_dst=10.178.40.0/21 actions=goto_table:90
cookie=0xb4e80ae4, duration=13531.936s, table=90, n_packets=1, n_bytes=98, priority=100,ip,nw_dst=10.178.44.0/22 actions=move:NXM_NX_REG0[]->NXM_NX_TUN_ID[0..31],set_field:10.173.32.62->tun_dst,output:vxlan0
,意味着要從vxlan0這個port發出,而且咱們記錄了tun_dst爲10.173.32.62, 還將此時的REG0,也就是源IP的vnid記錄到包中,做爲封裝包中的內容。cookie=0x0, duration=14361.893s, table=0, n_packets=1, n_bytes=98, priority=200,ip,in_port=vxlan0,nw_src=10.178.40.0/21 actions=move:NXM_NX_TUN_ID[0..31]->NXM_NX_REG0[],goto_table:10
,cookie=0x0, duration=14361.893s, table=0, n_packets=0, n_bytes=0, priority=200,ip,in_port=vxlan0,nw_dst=10.178.40.0/21 actions=move:NXM_NX_TUN_ID[0..31]->NXM_NX_REG0[],goto_table:10
當遇到這種狀況時,選擇哪一條規則是咱們沒法肯定的,也就是說可能隨便選一條,可是此處兩個規則都導向了table10。而且還將封包中的vnid取出,複製到REG0這個寄存器裏 cookie=0xc694ebd2, duration=19282.596s, table=10, n_packets=3, n_bytes=182, priority=100,tun_src=10.173.32.63 actions=goto_table:30
.封裝的包的源地址是否是合法的?若是不合法,那麼就應該drop掉,若是沒問題就進入table30 cookie=0x0, duration=19341.929s, table=30, n_packets=21598, n_bytes=10737703, priority=200,ip,nw_dst=10.178.44.0/22 actions=goto_table:70
,匹配了目的IP,進入table70 cookie=0x0, duration=19409.718s, table=70, n_packets=21677, n_bytes=10775797, priority=100,ip,nw_dst=10.178.44.22 actions=load:0x483152->NXM_NX_REG1[],load:0x5->NXM_NX_REG2[],goto_table:80
進入table80,而且咱們將目的端的vnid設置爲了0x483152。 目的端出口的port的id爲0x5整個openshift-sdn的流表示意圖以下:
咱們逐個解釋一下每一個table主要的負責內容:
table10
:由vxlan收包並處理時,會走table10表,10表會判斷封包的源IP是不是其餘節點的nodeIP,若是不是就丟棄table20
: 由veth收到的包會進入20表,也就是pod發出的包,會進入20表,20表中主要是作了源IP的vnid的設置table21
: table20處理完畢後會進入table21,在裏面會處理k8s networkpolicy的邏輯,若是判斷這個包的訪問路徑是通的,就會進入30表table30
:30表值主要的選路表,這裏會判斷協議是ip仍是arp:
table40
:將請求本地podIP的arp請求從對應的veth發出table50
: 對於請求集羣裏網段的IP的arp請求,封裝後經過vxlan0發出table60
: 檢查要訪問的具體是哪一個service,根據service所屬的namespace的租戶id,配置包的目的vnid,並配置目的出口爲tun0,進入table80table70
: 訪問本機其餘pod IP時,檢查pod所屬的namespace的租戶id,配置包的目的vnid,並配置目的出口爲目的pod的veth,進入table80table80
: 根據REG進行vnid的校驗,REG0=REG1或REG0=0或REG1=0時,校驗經過table90
: 記錄了集羣裏每一個node的網段對應的nodeIP,在該表裏設置要封裝的內容:
table120
: 收到組播時作的邏輯判斷table110
: 發出組播時作的邏輯判斷table100
: 訪問外部IP時作的判斷,一般只會單純的設置走tun0table110
: 訪問外部IP時作的networkpolicy判斷基於上面的整理,咱們能夠知道,在使用openshift-sdn的時候,集羣裏各類網絡訪問的鏈路:
注意這裏的第二點,pod到pod是不須要走tun0的,也就是說,集羣裏全部的cluster network對應的cidr,都被視爲一個「二層」,不須要依賴網關的轉發。上文中咱們在擴展集羣網段時,須要在老容器里加一條直連路由,緣由就在這:
老容器發包到新容器時,走網關轉發,包的目的MAC是老節點的tun0的mac,這個包直接被流表封裝發出到對端,對端解封后送到對端容器,對端容器會發現包的目的MAC本地沒有,所以確定會丟棄。因此咱們不能讓這種pod-to-pod的訪問鏈路走網關,而應該是經過直連路由。
若是你以爲一條一條地看流表,特別麻煩,那麼有一個很方便的實踐方法,好比:
先經過ovs-vsctl list interface
命令查看到IP在ovs網橋上對應的網口的id。
ovs-vsctl list interface |less _uuid : e6ca4571-ac3b-46d4-b155-c541affa5a96 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 : {ip="10.178.40.15", sandbox="6c0a268503b577936a34dd762cc6ca7a3e3f323d1b0a56820b2ef053160266ff"} ifindex : 95 ingress_policing_burst: 0 ingress_policing_rate: 0 lacp_current : [] link_resets : 0 link_speed : 10000000000 link_state : up lldp : {} mac : [] mac_in_use : "06:48:6c:da:8f:4b" mtu : 1350 mtu_request : [] name : "vethadbc25e1" ofport : 12 ofport_request : [] options : {} other_config : {} statistics : {collisions=0, rx_bytes=182, rx_crc_err=0, rx_dropped=0, rx_errors=0, rx_frame_err=0, rx_over_err=0, rx_packets=3, tx_bytes=2930, tx_dropped=0, tx_errors=0, tx_packets=41} status : {driver_name=veth, driver_version="1.0", firmware_version=""} type : "" ...
如上,咱們看到10.178.40.15
這個IP所在的端口,ofport
字段是12。 接着,執行:
ovs-appctl ofproto/trace br0 'ip,in_port=12,nw_src=10.178.40.15,nw_dst=10.173.32.62'
在這條命令中,咱們模擬往某個port(id爲12)塞一個包,源IP是10.178.40.15,目的IP是10.173.32.62。
輸出是:
Flow: ip,in_port=12,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,nw_src=10.178.40.15,nw_dst=10.173.32.62,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=0 bridge("br0") ------------- 0. ip, priority 100 goto_table:20 20. ip,in_port=12,nw_src=10.178.40.15, priority 100 load:0->NXM_NX_REG0[] goto_table:21 21. priority 0 goto_table:30 30. ip, priority 0 goto_table:100 100. priority 0 goto_table:101 101. priority 0 output:2 Final flow: unchanged Megaflow: recirc_id=0,eth,ip,in_port=12,nw_src=10.178.40.15,nw_dst=10.173.32.62,nw_frag=no Datapath actions: 3
會把整個鏈路走的全部的表,以及最後從哪一個口發出,作的封裝(此例中不作封裝,Final flow=unchanged)所有顯示出來。
本文咱們由淺入深地介紹了openshift-sdn這個網絡方案,瞭解了他的架構和用法,並深刻地探索了它的實現。 ovs流表的閱讀和跟蹤是一個比較吃力的活,但當咱們啃下來以後,會發現openshift-sdn的流表設計仍是比較簡潔易懂的,但願讀完本文的你能有所收穫~
https://blog.csdn.net/Jmilk/j...
https://www.cnblogs.com/sammy...
https://docs.openshift.com/co...
https://docs.openshift.com/co...
本文由博客羣發一文多發等運營工具平臺 OpenWrite 發佈