在平時使用ovs中,常常用到的ovs命令,參數,與舉例總結,持續更新中…
進程啓動
1.先準備ovs的工做目錄,數據庫存儲路徑等
mkdir -p /etc/openvswitch mkdir -p /var/run/openvswitch
2.先啓動ovsdb-server
ovsdb-server /etc/openvswitch/conf.db \ -vconsole:emer -vsyslog:err -vfile:info \ --remote=punix:/var/run/openvswitch/db.sock \ --private-key=db:Open_vSwitch,SSL,private_key \ --certificate=db:Open_vSwitch,SSL,certificate \ --bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert --no-chdir \ --log-file=/var/log/openvswitch/ovsdb-server.log \ --pidfile=/var/run/openvswitch/ovsdb-server.pid \ --detach --monitor
ps: 若是想清除配置,能夠先刪除/etc/openvswitch/*,而後再手動建立一個數據庫:
ovsdb-tool create /etc/openvswitch/conf.db /usr/share/openvswitch/vswitch.ovsschema
3.初始化ovsdb
針對於新建立的數據庫才須要初始化
ovs-vsctl --no-wait init
4.啓動vswitchd進程
ovs-vswitchd unix:/var/run/openvswitch/db.sock \ -vconsole:emer -vsyslog:err -vfile:info --mlockall --no-chdir \ --log-file=/var/log/openvswitch/ovs-vswitchd.log \ --pidfile=/var/run/openvswitch/ovs-vswitchd.pid \ --detach --monitor
ovs經常使用命令
控制管理類
1.查看網橋和端口
ovs-vsctl show
2.建立一個網橋
ovs-vsctl add-br br0 ovs-vsctl set bridge br0 datapath_type=netdev
3.添加/刪除一個端口
4.設置/清除網橋的openflow協議版本
ovs-vsctl set bridge br0 protocols=OpenFlow13 ovs-vsctl clear bridge br0 protocols
5.查看某網橋當前流表
ovs-ofctl dump-flows br0 ovs-ofctl -O OpenFlow13 dump-flows br0 ovs-appctl bridge/dump-flows br0
6.設置/刪除控制器
ovs-vsctl set-controller br0 tcp:1.2.3.4:6633 ovs-vsctl del-controller br0
7.查看控制器列表
ovs-vsctl list controller
8.設置/刪除被動鏈接控制器
ovs-vsctl set-manager tcp:1.2.3.4:6640 ovs-vsctl get-manager ovs-vsctl del-manager
9.設置/移除可選選項
ovs-vsctl set Interface eth0 options:link_speed=1G ovs-vsctl remove Interface eth0 options link_speed
10.設置fail模式,支持standalone或者secure
standalone(default):清除全部控制器下發的流表,ovs本身接管
secure:按照原來流表繼續轉發
ovs-vsctl del-fail-mode br0 ovs-vsctl set-fail-mode br0 secure ovs-vsctl get-fail-mode br0
11.查看接口id等
ovs-appctl dpif/show
12.查看接口統計
ovs-ofctl dump-ports br0
流表類
流表操做
1.添加普通流表
ovs-ofctl add-flow br0 in_port=1,actions=output:2
2.刪除全部流表
ovs-ofctl del-flows br0
3.按匹配項來刪除流表
ovs-ofctl del-flows br0 "in_port=1"
匹配項
1.匹配vlan tag,範圍爲0-4095
ovs-ofctl add-flow br0 priority=401,in_port=1,dl_vlan=777,actions=output:2
2.匹配vlan pcp,範圍爲0-7
ovs-ofctl add-flow br0 priority=401,in_port=1,dl_vlan_pcp=7,actions=output:2
3.匹配源/目的MAC
ovs-ofctl add-flow br0 in_port=1,dl_src=00:00:00:00:00:01/00:00:00:00:00:01,actions=output:2 ovs-ofctl add-flow br0 in_port=1,dl_dst=00:00:00:00:00:01/00:00:00:00:00:01,actions=output:2
4.匹配以太網類型,範圍爲0-65535
ovs-ofctl add-flow br0 in_port=1,dl_type=0x0806,actions=output:2
5.匹配源/目的IP
條件:指定dl_type=0x0800,或者ip/tcp
ovs-ofctl add-flow br0 ip,in_port=1,nw_src=10.10.0.0/16,actions=output:2 ovs-ofctl add-flow br0 ip,in_port=1,nw_dst=10.20.0.0/16,actions=output:2
6.匹配協議號,範圍爲0-255
條件:指定dl_type=0x0800或者ip
7.匹配IP ToS/DSCP,tos範圍爲0-255,DSCP範圍爲0-63
條件:指定dl_type=0x0800/0x86dd,而且ToS低2位會被忽略(DSCP值爲ToS的高6位,而且低2位爲預留位)
ovs-ofctl add-flow br0 ip,in_port=1,nw_tos=68,actions=output:2 ovs-ofctl add-flow br0 ip,in_port=1,ip_dscp=62,actions=output:2
8.匹配IP ecn位,範圍爲0-3
條件:指定dl_type=0x0800/0x86dd
ovs-ofctl add-flow br0 ip,in_port=1,ip_ecn=2,actions=output:2
9.匹配IP TTL,範圍爲0-255
ovs-ofctl add-flow br0 ip,in_port=1,nw_ttl=128,actions=output:2
10.匹配tcp/udp,源/目的端口,範圍爲0-65535
11.匹配tcp flags
tcp flags=fin,syn,rst,psh,ack,urg,ece,cwr,ns
ovs-ofctl add-flow br0 tcp,tcp_flags=ack,actions=output:2
12.匹配icmp code,範圍爲0-255
條件:指定icmp
ovs-ofctl add-flow br0 icmp,icmp_code=2,actions=output:2
13.匹配vlan TCI
TCI低12位爲vlan id,高3位爲priority,例如tci=0xf123則vlan_id爲0x123和vlan_pcp=7
ovs-ofctl add-flow br0 in_port=1,vlan_tci=0xf123,actions=output:2
14.匹配mpls label
條件:指定dl_type=0x8847/0x8848
ovs-ofctl add-flow br0 mpls,in_port=1,mpls_label=7,actions=output:2
15.匹配mpls tc,範圍爲0-7
條件:指定dl_type=0x8847/0x8848
ovs-ofctl add-flow br0 mpls,in_port=1,mpls_tc=7,actions=output:2
16.匹配tunnel id,源/目的IP
一些匹配項的速記符
速記符 |
匹配項 |
ip |
dl_type=0x800 |
ipv6 |
dl_type=0x86dd |
icmp |
dl_type=0x0800,nw_proto=1 |
icmp6 |
dl_type=0x86dd,nw_proto=58 |
tcp |
dl_type=0x0800,nw_proto=6 |
tcp6 |
dl_type=0x86dd,nw_proto=6 |
udp |
dl_type=0x0800,nw_proto=17 |
udp6 |
dl_type=0x86dd,nw_proto=17 |
sctp |
dl_type=0x0800,nw_proto=132 |
sctp6 |
dl_type=0x86dd,nw_proto=132 |
arp |
dl_type=0x0806 |
rarp |
dl_type=0x8035 |
mpls |
dl_type=0x8847 |
mplsm |
dl_type=0x8848 |
指令動做
1.動做爲出接口
從指定接口轉發出去
ovs-ofctl add-flow br0 in_port=1,actions=output:2
2.動做爲指定group
group id爲已建立的group table
ovs-ofctl add-flow br0 in_port=1,actions=group:666
3.動做爲normal
轉爲L2/L3處理流程
ovs-ofctl add-flow br0 in_port=1,actions=normal
4.動做爲flood
從全部物理接口轉發出去,除了入接口和已關閉flooding的接口
ovs-ofctl add-flow br0 in_port=1,actions=flood
5.動做爲all
從全部物理接口轉發出去,除了入接口
ovs-ofctl add-flow br0 in_port=1,actions=all
6.動做爲local
通常是轉發給本地網橋
ovs-ofctl add-flow br0 in_port=1,actions=local
7.動做爲in_port
從入接口轉發回去
ovs-ofctl add-flow br0 in_port=1,actions=in_port
8.動做爲controller
以packet-in消息上送給控制器
ovs-ofctl add-flow br0 in_port=1,actions=controller
9.動做爲drop
丟棄數據包操做
ovs-ofctl add-flow br0 in_port=1,actions=drop
10.動做爲mod_vlan_vid
修改報文的vlan id,該選項會使vlan_pcp置爲0
ovs-ofctl add-flow br0 in_port=1,actions=mod_vlan_vid:8,output:2
11.動做爲mod_vlan_pcp
修改報文的vlan優先級,該選項會使vlan_id置爲0
ovs-ofctl add-flow br0 in_port=1,actions=mod_vlan_pcp:7,output:2
12.動做爲strip_vlan
剝掉報文內外層vlan tag
ovs-ofctl add-flow br0 in_port=1,actions=strip_vlan,output:2
13.動做爲push_vlan
在報文外層壓入一層vlan tag,須要使用openflow1.1以上版本兼容
ovs-ofctl add-flow -O OpenFlow13 br0 in_port=1,actions=push_vlan:0x8100,set_field:4097-\>vlan_vid,output:2
ps: set field值爲4096+vlan_id,而且vlan優先級爲0,即4096-8191,對應的vlan_id爲0-4095
14.動做爲push_mpls
修改報文的ethertype,而且壓入一個MPLS LSE
ovs-ofctl add-flow br0 in_port=1,actions=push_mpls:0x8847,set_field:10-\>mpls_label,output:2
15.動做爲pop_mpls
剝掉最外層mpls標籤,而且修改ethertype爲非mpls類型
ovs-ofctl add-flow br0 mpls,in_port=1,mpls_label=20,actions=pop_mpls:0x0800,output:2
16.動做爲修改源/目的MAC,修改源/目的IP
17.動做爲修改TCP/UDP/SCTP源目的端口
18.動做爲mod_nw_tos
條件:指定dl_type=0x0800
修改ToS字段的高6位,範圍爲0-255,值必須爲4的倍數,而且不會去修改ToS低2位ecn值
ovs-ofctl add-flow br0 ip,in_port=1,actions=mod_nw_tos:68,output:2
19.動做爲mod_nw_ecn
條件:指定dl_type=0x0800,須要使用openflow1.1以上版本兼容
修改ToS字段的低2位,範圍爲0-3,而且不會去修改ToS高6位的DSCP值
ovs-ofctl add-flow br0 ip,in_port=1,actions=mod_nw_ecn:2,output:2
20.動做爲mod_nw_ttl
修改IP報文ttl值,須要使用openflow1.1以上版本兼容
ovs-ofctl add-flow -O OpenFlow13 br0 in_port=1,actions=mod_nw_ttl:6,output:2
21.動做爲dec_ttl
對IP報文進行ttl自減操做
ovs-ofctl add-flow br0 in_port=1,actions=dec_ttl,output:2
22.動做爲set_mpls_label
對報文最外層mpls標籤進行修改,範圍爲20bit值
ovs-ofctl add-flow br0 in_port=1,actions=set_mpls_label:666,output:2
23.動做爲set_mpls_tc
對報文最外層mpls tc進行修改,範圍爲0-7
ovs-ofctl add-flow br0 in_port=1,actions=set_mpls_tc:7,output:2
24.動做爲set_mpls_ttl
對報文最外層mpls ttl進行修改,範圍爲0-255
ovs-ofctl add-flow br0 in_port=1,actions=set_mpls_ttl:255,output:2
25.動做爲dec_mpls_ttl
對報文最外層mpls ttl進行自減操做
ovs-ofctl add-flow br0 in_port=1,actions=dec_mpls_ttl,output:2
26.動做爲move NXM字段
使用move參數對NXM字段進行操做
ps: 經常使用NXM字段參照表
NXM字段 |
報文字段 |
NXM_OF_ETH_SRC |
源MAC |
NXM_OF_ETH_DST |
目的MAC |
NXM_OF_ETH_TYPE |
以太網類型 |
NXM_OF_VLAN_TCI |
vid |
NXM_OF_IP_PROTO |
IP協議號 |
NXM_OF_IP_TOS |
IP ToS值 |
NXM_NX_IP_ECN |
IP ToS ECN |
NXM_OF_IP_SRC |
源IP |
NXM_OF_IP_DST |
目的IP |
NXM_OF_TCP_SRC |
TCP源端口 |
NXM_OF_TCP_DST |
TCP目的端口 |
NXM_OF_UDP_SRC |
UDP源端口 |
NXM_OF_UDP_DST |
UDP目的端口 |
NXM_OF_SCTP_SRC |
SCTP源端口 |
NXM_OF_SCTP_DST |
SCTP目的端口 |
27.動做爲load NXM字段
使用load參數對NXM字段進行賦值操做
28.動做爲pop_vlan
彈出報文最外層vlan tag
ovs-ofctl add-flow br0 in_port=1,dl_type=0x8100,dl_vlan=777,actions=pop_vlan,output:2
meter表
經常使用操做
因爲meter表是openflow1.3版本之後才支持,因此全部命令須要指定OpenFlow1.3版本以上
ps: 在openvswitch-v2.8以前的版本中,還不支持meter
在v2.8版本以後已經實現,要正常使用的話,須要注意的是datapath類型要指定爲netdev,band type暫時只支持drop,還不支持DSCP REMARK
1.查看當前設備對meter的支持
ovs-ofctl -O OpenFlow13 meter-features br0
2.查看meter表
ovs-ofctl -O OpenFlow13 dump-meters br0
3.查看meter統計
ovs-ofctl -O OpenFlow13 meter-stats br0
4.建立meter表
5.刪除meter表
6.建立流表
ovs-ofctl -O OpenFlow13 add-flow br0 in_port=1,actions=meter:1,output:2
group表
因爲group表是openflow1.1版本之後才支持,因此全部命令須要指定OpenFlow1.1版本以上
經常使用操做
group table支持4種類型
- all:全部buckets都執行一遍
- select: 每次選擇其中一個bucket執行,經常使用於負載均衡應用
- ff(FAST FAILOVER):快速故障修復,用於檢測解決接口等故障
- indirect:間接執行,相似於一個函數方法,被另外一個group來調用
1.查看當前設備對group的支持
ovs-ofctl -O OpenFlow13 dump-group-features br0
2.查看group表
ovs-ofctl -O OpenFlow13 dump-groups br0
3.建立group表
# 類型爲all
ovs-ofctl -O OpenFlow13 add-group br0 group_id=1,type=all,bucket=output:1,bucket=output:2,bucket=output:3
# 類型爲select ovs-ofctl -O OpenFlow13 add-group br0 group_id=2,type=select,bucket=output:1,bucket=output:2,bucket=output:3 # 類型爲select,指定hash方法(5元組,OpenFlow1.5+) ovs-ofctl -O OpenFlow15 add-group br0 group_id=3,type=select,selection_method=hash,fields=ip_src,bucket=output:2,bucket=output:3
4.刪除group表
ovs-ofctl -O OpenFlow13 del-groups br0 group_id=2
5.建立流表
ovs-ofctl -O OpenFlow13 add-flow br0 in_port=1,actions=group:2
goto table配置
數據流先從table0開始匹配,如actions有goto_table,再進行後續table的匹配,實現多級流水線,如需使用goto table,則建立流表時,指定table id,範圍爲0-255,不指定則默認爲table0
1.在table0中添加一條流表條目
ovs-ofctl add-flow br0 table=0,in_port=1,actions=goto_table=1
2.在table1中添加一條流表條目
ovs-ofctl add-flow br0 table=1,ip,nw_dst=10.10.0.0/16,actions=output:2
tunnel配置
如需配置tunnel,必需確保當前系統對各tunnel的remote ip網絡可達
gre
1.建立一個gre接口,而且指定端口id=1001
ovs-vsctl add-port br0 gre1 -- set Interface gre1 type=gre options:remote_ip=1.1.1.1 ofport_request=1001
2.可選選項
將tos或者ttl在隧道上繼承,並將tunnel id設置成123
ovs-vsctl set Interface gre1 options:tos=inherit options:ttl=inherit options:key=123
3.建立關於gre流表
vxlan
1.建立一個vxlan接口,而且指定端口id=2001
ovs-vsctl add-port br0 vxlan1 -- set Interface vxlan1 type=vxlan options:remote_ip=1.1.1.1 ofport_request=2001
2.可選選項
將tos或者ttl在隧道上繼承,將vni設置成123,UDP目的端爲設置成8472(默認爲4789)
ovs-vsctl set Interface vxlan1 options:tos=inherit options:ttl=inherit options:key=123 options:dst_port=8472
3.建立關於vxlan流表
sflow配置
1.對網橋br0進行sflow監控
- agent: 與collector通訊所在的網口名,一般爲管理口
- target: collector監聽的IP地址和端口,端口默認爲6343
- header: sFlow在採樣時截取報文頭的長度
- polling: 採樣時間間隔,單位爲秒
2.查看建立的sflow
ovs-vsctl list sflow
3.刪除對應的網橋sflow配置,參數爲sFlow UUID
ovs-vsctl remove bridge br0 sflow 7b9b962e-fe09-407c-b224-5d37d9c1f2b3
4.刪除網橋下全部sflow配置
QoS配置
ingress policing
1.配置ingress policing,對接口eth0入流限速10Mbps
ovs-vsctl set interface eth0 ingress_policing_rate=10000 ovs-vsctl set interface eth0 ingress_policing_burst=8000
2.清除相應接口的ingress policer配置
ovs-vsctl set interface eth0 ingress_policing_rate=0 ovs-vsctl set interface eth0 ingress_policing_burst=0
3.查看接口ingress policer配置
ovs-vsctl list interface eth0
4.查看網橋支持的Qos類型
ovs-appctl qos/show-types br0
端口鏡像配置
1.配置eth0收到/發送的數據包鏡像到eth1
ovs-vsctl -- set bridge br0 mirrors=@m \ -- --id=@eth0 get port eth0 \ -- --id=@eth1 get port eth1 \ -- --id=@m create mirror name=mymirror select-dst-port=@eth0 select-src-port=@eth0 output-port=@eth1
2.刪除端口鏡像配置
3.清除網橋下全部端口鏡像配置
ovs-vsctl clear bridge br0 mirrors
4.查看端口鏡像配置
ovs-vsctl get bridge br0 mirrors
https://www.sdnlab.com/20966.html
2.設計考慮
2.1.總體數據結構
ovs datapath classifier涉及的數據結構主要有以下。
網橋數據結構
|
struct datapath {
struct rcu_head rcu;
/* 該結構使用雙鏈表組織 */
struct list_head list_node;
/* 從屬該datapath的流表項 */
struct flow_table table;
/* 從屬該datapath的vport信息 */
struct hlist_head *ports;
…
}
|
流表數據結構
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
struct flow_table {
/* 用key組織的流表實例 */
struct table_instance *ti;
/* 用unique flow identifier(ufid)組織的流表實例 */
struct table_instance *ufid_ti;
/* 掩碼信息緩存表 */
struct mask_cache_entry *mask_cache;
/* 掩碼信息列表 */
struct mask_array *mask_array;
/* 記錄當前節拍數 */
unsigned long last_rehash;
/* ti流表實例中存儲的流表項數目 */
unsigned int count;
/* ufid_ti流表實例中存儲的流表項數目 */
unsigned int ufid_count;
}
|
流表實例數據結構
|
struct table_instance {
/* 哈希桶,用於組織各個流表項的具體信息. */
struct flex_array *buckets;
/* 哈希桶大小 */
unsigned int n_buckets;
struct rcu_head rcu;
int node_ver;
u32 hash_seed;
bool keep_flows;
}
|
掩碼信息列表數據結構
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
struct mask_array {
struct rcu_head rcu;
/* 當前已存儲的掩碼信息數目 */
int count;
/* 一共能夠存儲掩碼信息的總數目 */
int max;
/* 具體的掩碼信息 */
struct sw_flow_mask *masks[];
}
struct sw_flow_mask {
/* 引用計數 */
int ref_count;
struct rcu_head rcu;
/* 匹配關鍵字的有效範圍,下文會具體解釋 */
struct sw_flow_key_range range;
/* 匹配關鍵字信息 */
struct sw_flow_key key;
}
|
掩碼信息緩存表數據結構
|
struct mask_cache_entry {
/* hash值 */
u32 skb_hash;
/* 對應哪個掩碼信息,索引值 */
u32 mask_index;
}
|
哈希桶數據結構
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
struct flex_array {
union {
struct {
/* 實際等於sizeof(struct hlist_head) */
int element_size;
/* 一共有多少個struct hlist_head指針. */
int total_nr_elements;
/* 每一個part(頁)能夠存儲多少個struct hlist_head指針 */
int elems_per_part;
u32 reciprocal_value reciprocal_elems;
/* 具體存儲struct hlist_head指針的緩衝區 */
struct flex_array_part *parts[];
};
/* 填充字段.表明了整個結構的大小=頁大小(4096字節) */
char padding[FLEX_ARRAY_BASE_SIZE];
}
}
struct flex_array_part {
/* 緩衝區.一個頁大小,即:4096字節 */
char elements[FLEX_ARRAY_PART_SIZE];
};
|
上述這些數據結構是在源碼中的ovs_flow_tbl_init函數裏面進行初始化操做的。初始化後以及上述這些數據結構之間的關係以下圖所示。

2.2.關鍵信息範圍
從上面2.1節可知,掩碼信息(struct sw_flow_mask結構)中記錄了一個範圍(struct sw_flow_key_range結構),該範圍用於標識須要匹配的關鍵信息最小偏移和最大偏移。爲何須要這樣作?我的感受和ovs-dpdk datapath classifier中描述的miniflow相似,即:匹配過程當中並不是使用報文的全部字段去匹配,而是使用部分字段,例如使用報文的五元組信息(源IP、目的IP、協議號、源端口、目的端口)。那麼使用sw_flow_key_range結構來標識這五元組信息中最小偏移和最大偏移。實際源碼中,關鍵信息是使用struct sw_flow_key結構來描述的。因爲該結構字段較多,這裏不詳細給出。以報文五元組信息爲例,這裏給出的五元組信息所在sw_flow_key結構的位置和實際源碼對應的位置是不相同的,這裏只是給出計算最小偏移和最大偏移的概念,以下圖所示,關鍵信息的有效範圍爲:
最小偏移=M,最大偏移=N

2.3.更新過程
在源碼中,對應更新過程的入口函數是:ovs_flow_cmd_new。這個入口函數是處於內核模塊中,在接收到報文時,經過下面2.4節所述的查找過程,查找失敗時,會將報文的相關信息upcall到用戶空間,在用戶空間經過查找」慢路徑」將對應的actions和mask信息下發到內核空間,在內核空間,處理的入口函數正是ovs_flow_cmd_new。下面將對這個函數的處理過程做詳細描述。描述以前,先掌握一些相關的數據結構,以下所示:
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
|
struct sw_flow {
struct rcu_head rcu;
/* 哈希桶鏈表 */
struct {
struct hlist_node node[2];
u32 hash;
} flow_table, ufid_table;
int stats_last_writer;
/* 關鍵信息.通過掩碼運算後的 */
struct sw_flow_key key;
/* 流id信息 */
struct sw_flow_id id;
/* 指向的掩碼信息 */
struct sw_flow_mask *mask;
/* 指向的流動做信息 */
struct sw_flow_actions *sf_acts;
struct flow_stats *stats[];
}
struct sw_flow_id {
u32 ufid_len;
union {
/* ufid爲128比特,共16字節 */
u32 ufid[4];
struct sw_flow_key *unmasked_key;
}
}
struct sw_flow_actions {
struct rcu_head rcu;
size_t orig_len;
u32 actions_len;
struct nlattr actions[];
}
struct sw_flow_match {
struct sw_flow_key *key;
struct sw_flow_key_range range;
struct sw_flow_mask *mask;
}
|
具體流程以下所示:
1)初始化struct sw_flow *new_flow。分配空間給new_flow,並設置部分的成員值,以下:
new_flow->sf_acts = null;
new_flow->mask = null;
new_flow->id.ufid_len=0;
new_flow->id.unmasked_key=null;
2)構建struct sw_flow_match match信息。根據接收到的關鍵信息和掩碼信息,存儲在match.key和match.mask中。

3)計算new_flow->key = match.key & match.mask。
4)將ufid信息提取出來存儲在new_flow->id.ufid_len和new_flow->id.ufid中。若是未提供任何的UFID信息(此時的new_flow->id.ufid_len爲0),則將match.key信息拷貝一份到new_flow->id.unmasked_key中存儲。
5)將actions信息存儲在變量struct sw_flow_actions acts中。
6)根據接收到的dp_ifindex獲取struct datapath dp信息。
7)若是new_flow->id.ufid_len不爲0,則使用new_flow->id.ufid信息去dp->table.ufid_ti指向的哈希桶中找到對應的struct sw_flow信息。假設找不到。
8)而若是new_flow->id.ufid_len爲0,則須要在dp->table.ti,同時配合在2)中構建出來的match.key和dp->table.mask_array配合找出對應的struct sw_flow信息。這個詳細過程能夠參考下面的2.4節。這裏也假設找不到。
9)通過上面7)和8)步都沒找到對應的struct sw_flow信息。首先設置new_flow->sf_acts=acts(在5)步中獲取)。而後使用match.mask去dp->table.mask_array中查找是否已存在該match.mask信息。若是不存在則接着分配一個struct sw_flow_mask *mask。設置mask->key=match.mask->key, mask->range=match.mask->range, mask->ref_count=1。而且在dp->table.mask_array.masks[i]中存儲該mask的地址。添加完畢以後,以下圖所示。變化的地方用綠色標註出來了。同時new_flow->mask=mask。

10)根據new_flow->key和new_flow->mask.range計算出new_flow->flow_table.hash值。
11)在dp->table.ti->buckets指向的哈希桶中插入new_flow。以下圖所示(假設插入的位置爲part[0]對應的第0個位置)。dp->table.count。
12)若是new_flow->id.ufid_len不爲0,則使用new_flow->id.ufid信息計算出new_flow->ufid_table.hash。而後根據這個hash值在dp->table.ufid_ti->buckets中找到合適的哈希桶存儲對應的new_flow信息。這裏假設找到的位置爲parts[0]的第0個位置。以下圖所示。插入new_flow信息以後,dp->table.ufid_count。

到此爲止,更新過程完畢。
2.4.查找過程
在源碼中,對應查找過程的入口函數是:ovs_vport_receive。具體過程以下:
1)從接收到的報文信息中提取出關鍵信息。存儲到struct sw_flow_key key。
2)從接收到的報文信息中獲取struct vport信息,再從vport信息獲取struct datapath信息,假設爲dp。
3)若是接收到的報文中未帶有skb_hash值信息,則執行:
遍歷每個掩碼,即:dp->table.mask_array->masks[i]。這裏簡單記爲mask。將1)提取出來的關鍵新key與這個掩碼mask作邏輯與運算,得出掩碼過的信息,記爲masked_key。經過masked_key和mask.range信息計算出hash值在dp->table.ti->buckets中找到對應的哈希桶,並遍歷該桶上的全部struct sw_flow信息,記爲flow。執行比較:若是flow->mask指向的是mask,flow->flow_table.hash值和計算出的hash值相等,且flow->key和masked_key信息在mask.range指定的範圍內徹底相同,則認爲成功匹配,返回flow信息。不然匹配失敗,返回NULL。
4)若是接收到的報文中帶有skb_hash值信息,則執行:
4)-1:根據舊的skb_hash值和key->recirc_id值從新計算出新的skb_hash值。
4)-2:將skb_hash值分紅4段,每段1字節,記爲hash。遍歷每一段的hash值,執行:獲取dp->table.mask_cache[hash]表項,記爲entry,若是entry.skb_hash值和skb_hash值相等,則使用entry.mask_index指向的掩碼信息去dp->table.ti->buckets中找到對應的struct sw_flow信息(過程和上述第3)步相同)。若是找到對應的flow,則返回flow,過程當中會更新entry.mask_index值來實際指向具體的掩碼信息索引。不然,匹配失敗,將entry.skb_hash值置0,返回NULL。而若是每個entry.skb_hash值和skb_hash值不相等,則遍歷完每一段hash值以後,從中選擇最佳候選entry,最佳候選的條件是:其skb_hash值最小者,假設記爲ce。最後使用ce.mask_index指向的掩碼信息去dp->table.ti->buckets中找到對應的struct sw_flow信息(過程和上述第3)步相同)。若是找到對應的flow,則返回flow,同時將ce->skb_hash值更新爲skb_hash值。固然在查找的過程當中(上述第3)步),也會更新ce->mask_index來指向實際的掩碼信息索引。
5) 若是在上述第3)和第4)步中都匹配失敗了,則須要將報文的信息upcall到用戶空間,由用戶空間負責查找對應的流動做信息,返回給內核。這個過程具體請參考上述2.3節。
到此爲止,查找過程結束。
2.5.執行過程
在2.4節查找過程當中,若是查找成功,則須要執行對應的流動做。入口函數是:ovs_execute_actions。
而若是查找失敗,upcall到用戶空間,找到對應的流動做以後,調用執行,到內核空間,入口函數對應的是:ovs_packet_cmd_execute。該函數最終會調用到ovs_execute_actions。
2.6.掩碼信息比較
在上述2.3和2.4節所述的更新過程和查找過程當中都會碰見用新構造的掩碼信息與datapath結構的table.mask_array做比較,以檢測掩碼信息是否須要新增。而比較的方法以下:
假設新構造的掩碼信息爲mask,與table.mask_array->masksi比較:
1)mask.range.start和exist_mask.range.start相等。
2)mask.range.end和exist_mask.range.end相等。
3)mask和exist_mask在range範圍內徹底相同。
同時符合上面三個條件才認爲兩個掩碼徹底相同。
2.7.流信息比較
在上述2.4節所述的查找過程當中,對接收到的報文進行匹配表項時,須要對流信息做比較。假設接收到的報文提取出來的關鍵信息爲key,匹配的掩碼信息爲mask,經過mask & key計算出掩碼後的報文關鍵信息,記爲masked_key,經過masked_key和mask.range計算出hash值。根據這個hash值找到對應的哈希桶,遍歷這個哈希桶中存儲的每個流信息,記爲flow。如今須要比較flow信息進而找到匹配的流表項。比較以下:
1)flow->mask指向的是mask。
2)flow->flow_table.hash和計算出的hash值相等。
3)flow->key和masked_key在mask.range範圍內徹底相同。
同時符合上面三個條件才認爲找到匹配的流表項。
2.8.mask_cache表項
在ovs_dp_process_packet函數中查找匹配的流表項時,若是報文的skb中已經帶有skb_hash值,則將這個skb_hash值(32比特)分爲4段,每段8比特,每段的哈希值暫記爲hash,用這個hash值去datapath結構中的table.mask_cache緩存表中查找對應的掩碼信息索引。每一個表項(struct mask_cache_entry結構)存儲了skb_hash和mask_index信息。初始化的時候,這個緩存表中全部表項都置0,所以,用報文的skb_hash值,分4段去查找,都沒法找到合適的表項。這時須要從中選出最佳候選的表項,而最佳候選的表項爲其skb_hash值最小。所以,初始化的時候,最終會選擇table.mask_cache[0]爲最佳候選表項。
接着根據上述2.4節所述的查找過程,找到合適的流表項信息。若是匹配成功,則最佳候選表項table.mask_cache[0].mask_index記錄了掩碼信息索引(index),即:table.mask_array->masks[index]。同時table.mask_cache[0].skb_hash賦值爲skb_hash。假設index爲0,則對應以下圖所示。
後續若是收到的報文帶的skb_hash值與table.mask_cache[0].skb_hash值相等時,則首先使用table.mask_cache[0].mask_index索引的掩碼信息去找匹配的流表信息。固然,若是匹配成功,table.mask_cache[0].mask_index可能並不是爲0(以前存儲的值),有可能更新爲其餘值。而若是匹配失敗,則table.mask_cache[0].skb_hash置0。

2.9.mask_array擴充
當datapath結構中的table.mask_array->count >= table.mask_array->max時,則須要擴充mask_array空間。已當前table.mask_array->max * 2的大小進行擴充。擴充先後的效果以下圖所示。橙色線指向的掩碼信息在擴充以後,會釋放掉old的掩碼信息空間。擴充老是按照當前max數值的2倍大小進行擴充,例如:16 -> 32 -> 64 -> 128 -> …。從源碼中暫時未看到這個擴充的最大值。

2.10.table_instance擴充
table_instance擴充有兩個條件觸發:
1)當datapath結構中的table.count > table.ti->n_buckets時,觸發擴充。
2)datapath結構中的table.last_rehash記錄了上次執行擴充或初始化table時系統的jiffies值。若是超過10分鐘,則須要從新擴充,只是此次的擴充並不是增大空間,而是以相同的大小從新分配空間。以爲這樣作的意義是從新生成table_instance結構中的hash_seed值,從新安排哈希桶的鏈表長度,分散存儲,減小匹配的比較次數。
咱們主要以第一種條件爲例,描述擴充的過程。這種擴充是在原有的哈希桶數目(n_buckets)基礎之上,以2倍的大小進行擴充。擴充先後,table_instance結構的變化以下圖所示。

根據上圖可知,擴充以後,table_instance中的hash_seed更新爲新的隨機數了。這樣,在從舊的table_instance將哈希桶中對應的各個流信息拷貝到新的table_instance時,須要從新計算哈希桶的位置,從新安排了。這樣作的好處時:能夠從新分散每一個哈希桶中流信息鏈表的長度,減小在匹配時流的比較次數。以下圖所示,以前Flow_A和Flow_B都位於第0個哈希桶,擴充以後,Flow_A處於了第0個哈希桶,而Flow_B則處於第1025個哈希桶了。這樣在查找Flow_B的時候,比較的次數就減小了一次。在大規模查找的過程當中,這種改變能夠大大提升查找的效率。

2.11.示例
假設ovs用戶空間的」慢路徑」存儲的流表信息以下所示:
|
table=0, src_ip=11.11.11.0/24, dst_ip=192.0.0.0/8, actions=output:1
table=0, src_ip=2.2.2.0/24, dst_ip=2.0.0.0/8, actions=output:2
table=0, dst_ip=8.0.0.0/8, actions=drop
|
初始化的時候,ovs內核空間的」快路徑」沒有存儲任何的流路徑信息。以下圖所示:

收到第一個報文:src_ip=11.11.11.25, dst_ip=192.1.1.1
收到第一個報文,匹配結果Miss,upcall到用戶空間,查表將結果發送回內核空間的datapath。根據上述2.3節所述的更新過程,會新增相應的掩碼信息(mask_A)和流信息(flow_A)。以下圖所示。

收到第二個報文:src_ip=11.11.11.63, dst_ip=192.168.7.8
根據上述2.4節所述的查找過程,匹配成功。
收到第三個報文:src_ip=2.2.2.4, dst_ip=2.7.7.7
根據上述2.4節所述的查找過程,匹配失敗。由於掩碼信息和mask_A徹底相同,所以無需新增掩碼信息,只須要將mask_A的ref_count引用計數加1便可。可是須要新增相應的流信息(flow_B),以下圖所示。

收到第四個報文:dst_ip=8.12.34.56
根據上述2.4節所述的查找過程,匹配失敗。須要新增相應的掩碼信息(mask_B)和流信息(flow_C)。以下圖所示

vim /usr/lib/python2.7/site-packages/nova/network/linux_net.py
|
圖1
查看虛擬機2網卡:
查看宿主機linux網橋:
分別查看經過修改圖1中nova/network代碼設置mtu哪些設備生效:
這樣說明,若是圖1中代碼設置了mtu值,則在tap、qbr、qvb、qvo上的mtu值都會被同時設置成相應的值。
驗證結束。
www.isjian.com/openstack/openstack-base-use-openvswitch
openstack底層技術-使用openvswitch
Posted on January 23, 2017 by opengers in openstack
Open vSwitch介紹
在過去,數據中心的服務器是直接連在硬件交換機上,後來VMware實現了服務器虛擬化技術,使虛擬服務器(VMs)可以鏈接在虛擬交換機上,藉助這個虛擬交換機,能夠爲服務器上運行的VMs或容器提供邏輯的虛擬的以太網接口,這些邏輯接口都鏈接到虛擬交換機上,有三種比較流行的虛擬交換機: VMware virtual switch, Cisco Nexus 1000V,和Open vSwitch
Open vSwitch(OVS)是運行在虛擬化平臺上的虛擬交換機,其支持OpenFlow協議,也支持gre/vxlan/IPsec等隧道技術。在OVS以前,基於Linux的虛擬化平臺好比KVM或Xen上,缺乏一個功能豐富的虛擬交換機,所以OVS迅速崛起並開始在Xen/KVM中流行起來,而且應用於愈來愈多的開源項目,好比openstack neutron中的網絡解決方案
在虛擬交換機的Flow控制器或管理工具方面,一些商業產品都集成有控制器或管理工具,好比Cisco 1000V的Virtual Supervisor Manager(VSM)
,VMware的分佈式交換機中的vCenter
。而OVS則須要藉助第三方控制器或管理工具實現複雜的轉發策略。例如OVS支持OpenFlow 協議,咱們就可使用任何支持OpenFlow協議的控制器來對OVS進行遠程管理。OpenStack Neutron中的ML2插件也可以實現對OVS的管理。但這並不意味着OVS必需要有一個控制器才能工做。在不鏈接外部控制器狀況下,OVS自身能夠依靠MAC地址學習實現二層數據包轉發功能,就像Linux Bridge
在基於Linux內核的系統上,應用最普遍的仍是系統自帶的虛擬交換機Linux Bridge
,它是一個單純的基於MAC地址學習的二層交換機,簡單高效,但同時缺少一些高級特性,好比OpenFlow,VLAN tag,QOS,ACL,Flow等,並且在隧道協議支持上,Linux Bridge只支持vxlan,OVS支持gre/vxlan/IPsec等,這也決定了OVS更適用於實現SDN技術
OVS支持如下features
- 支持NetFlow, IPFIX, sFlow, SPAN/RSPAN等流量監控協議
- 精細的ACL和QoS策略
- 可使用OpenFlow和OVSDB協議進行集中控制
- Port bonding,LACP,tunneling(vxlan/gre/Ipsec)
- 適用於Xen,KVM,VirtualBox等hypervisors
- 支持標準的802.1Q VLAN協議
- 基於VM interface的流量管理策略
- 支持組播功能
- flow-caching engine(datapath模塊)
文章使用環境
centos7 openvswitch 2.5 OpenFlow 1.4`
OVS架構
先看下OVS總體架構,用戶空間主要組件有數據庫服務ovsdb-server和守護進程ovs-vswitchd。kernel中是datapath內核模塊。最上面的Controller表示OpenFlow控制器,控制器與OVS是經過OpenFlow協議進行鏈接,控制器不必定位於OVS主機上,下面分別介紹圖中各組件

ovs-vswitchd
ovs-vswitchd
守護進程是OVS的核心部件,它和datapath
內核模塊一塊兒實現OVS基於流的數據交換。做爲核心組件,它使用openflow協議與上層OpenFlow控制器通訊,使用OVSDB協議與ovsdb-server
通訊,使用netlink
和datapath
內核模塊通訊。ovs-vswitchd
在啓動時會讀取ovsdb-server
中配置信息,而後配置內核中的datapaths
和全部OVS switches,當ovsdb中的配置信息改變時(例如使用ovs-vsctl工具),ovs-vswitchd
也會自動更新其配置以保持與數據庫同步
ovs-vswitchd
須要加載datapath
內核模塊才能正常運行。它會自動配置datapath
flows,所以咱們沒必要再使用ovs-dpctl
去手動操做datapath
,但ovs-dpctl
仍可用於調試場合
在OVS中,ovs-vswitchd
從OpenFlow控制器獲取流表規則,而後把從datapath
中收到的數據包在流表中進行匹配,找到匹配的flows並把所需應用的actions返回給datapath
,同時做爲處理的一部分,ovs-vswitchd
會在datapath
中設置一條datapath flows用於後續相同類型的數據包能夠直接在內核中執行動做,此datapath flows至關於OpenFlow flows的緩存。對於datapath
來講,其並不知道用戶空間OpenFlow的存在,datapath內核模塊信息以下
# modinfo openvswitch filename: /lib/modules/3.10.0-327.el7.x86_64/kernel/net/openvswitch/openvswitch.ko license: GPL description: Open vSwitch switching datapath rhelversion: 7.2 srcversion: F75F2B83324DCC665887FD5 depends: libcrc32c intree: Y ...
ovsdb-server
ovsdb-server
是OVS輕量級的數據庫服務,用於整個OVS的配置信息,包括接口/交換內容/VLAN等,OVS主進程ovs-vswitchd
根據數據庫中的配置信息工做,下面是ovsdb-server
進程詳細信息
ps -ef |grep ovsdb-server root 22166 22165 0 Jan17 ? 00:02:32 ovsdb-server /etc/openvswitch/conf.db -vconsole:emer -vsyslog:err -vfile:info --remote=punix:/var/run/openvswitch/db.sock --private-key=db:Open_vSwitch,SSL,private_key --certificate=db:Open_vSwitch,SSL,certificate --bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert --no-chdir --log-file=/var/log/openvswitch/ovsdb-server.log --pidfile=/var/run/openvswitch/ovsdb-server.pid --detach --monitor
/etc/openvswitch/conf.db
是數據庫文件存放位置,文件形式存儲保證了服務器重啓不會影響其配置信息,ovsdb-server
須要文件才能啓動,可使用ovsdb-tool create
命令建立並初始化此數據庫文件
--remote=punix:/var/run/openvswitch/db.sock
實現了一個Unix sockets鏈接,OVS主進程ovs-vswitchd
或其它命令工具(ovsdb-client)經過此socket鏈接管理ovsdb
/var/log/openvswitch/ovsdb-server.log
是日誌記錄
OpenFlow
OpenFlow是開源的用於管理交換機流表的協議,OpenFlow在OVS中的地位能夠參考上面架構圖,它是Controller和ovs-vswitched間的通訊協議。須要注意的是,OpenFlow是一個獨立的完整的流表協議,不依賴於OVS,OVS只是支持OpenFlow協議,有了支持,咱們可使用OpenFlow控制器來管理OVS中的流表,OpenFlow不只僅支持虛擬交換機,某些硬件交換機也支持OpenFlow協議
OVS經常使用做SDN交換機(OpenFlow交換機),其中控制數據轉發策略的就是OpenFlow flow。OpenStack Neutron中實現了一個OpenFlow控制器用於向OVS下發OpenFlow flows控制虛擬機間的訪問或隔離。本文討論的默認是做爲SDN交換機場景下
OpenFlow flow的流表項存放於用戶空間主進程ovs-vswitchd
中,OVS除了鏈接OpenFlow控制器獲取這種flow,文章後面會提到的命令行工具ovs-ofctl
工具也能夠手動管理OVS中的OpenFlow flow,能夠查看man ovs-ofctl
瞭解
在OVS中,OpenFlow flow是最重要的一種flow, 然而還有其它幾種flows存在,文章下面OVS概念部分會提到
Controller
Controller指OpenFlow控制器。OpenFlow控制器能夠經過OpenFlow協議鏈接到任何支持OpenFlow的交換機,好比OVS。控制器經過向交換機下發流表規則來控制數據流向。除了能夠經過OpenFlow控制器配置OVS中flows,也可使用OVS提供的ovs-ofctl
命令經過OpenFlow協議去鏈接OVS,從而配置flows,命令也可以對OVS的運行情況進行動態監控。
Kernel Datapath
下面討論場景是OVS做爲一個OpenFlow交換機
datapath是一個Linux內核模塊,它負責執行數據交換。關於datapath,The Design and Implementation of Open vSwitch中有描述
The datapath module in the kernel receives the packets first, from a physical NIC or a VM’s virtual NIC. Either ovs-vswitchd has instructed the datapath how to handle packets of this type, or it has not. In the former case, the datapath module simply follows the instructions, called actions, given by ovs-vswitchd, which list physical ports or tunnels on which to transmit the packet. Actions may also specify packet modifications, packet sampling, or instructions to drop the packet. In the other case, where the datapath has not been told what to do with the packet, it delivers it to ovs-vswitchd. In userspace, ovs-vswitchd determines how the packet should be handled, then it passes the packet back to the datapath with the desired handling. Usually, ovs-vswitchd also tells the datapath to cache the actions, for handling similar future packets.
爲了說明datapath,來看一張更詳細的架構圖,圖中的大部分組件上面都有提到

用戶空間ovs-vswitchd
和內核模塊datapath
決定了數據包的轉發,首先,datapath
內核模塊收到進入數據包(物理網卡或虛擬網卡),而後查找其緩存(datapath flows),當有一個匹配的flow時它執行對應的操做,不然datapath
會把該數據包送入用戶空間由ovs-vswitchd
負責在其OpenFlow flows中查詢(圖1中的First Packet),ovs-vswitchd
查詢後把匹配的actions返回給datapath
並設置一條datapath flows到datapath
中,這樣後續進入的同類型的數據包(圖1中的Subsequent Packets)由於緩存匹配會被datapath
直接處理,不用再次進入用戶空間。
datapath
專一於數據交換,它不須要知道OpenFlow的存在。與OpenFlow打交道的是ovs-vswitchd
,ovs-vswitchd
存儲全部Flow規則供datapath
查詢或緩存.
雖然有ovs-dpctl
管理工具的存在,但咱們不必去手動管理datapath
,這是用戶空間ovs-vswitchd
的工做
OVS概念
這部分說下OVS中的重要概念,使用OpenStack neutron+vxlan部署模式下網絡節點OVS網橋做爲例子
# ovs-vsctl show e44abab7-2f65-4efd-ab52-36e92d9f0200 Manager "ptcp:6640:127.0.0.1" is_connected: true Bridge br-ext Controller "tcp:127.0.0.1:6633" is_connected: true fail_mode: secure Port br-ext Interface br-ext type: internal Port "eth1" Interface "eth1" Port phy-br-ext Interface phy-br-ext type: patch options: {peer=int-br-ext} Bridge br-tun Controller "tcp:127.0.0.1:6633" is_connected: true fail_mode: secure Port br-tun Interface br-tun type: internal Port patch-int Interface patch-int type: patch options: {peer=patch-tun} Port "vxlan-080058ca" Interface "vxlan-080058ca" type: vxlan options: {df_default="true", in_key=flow, local_ip="8.0.88.201", out_key=flow, remote_ip="8.0.88.202"} Bridge br-int Controller "tcp:127.0.0.1:6633" is_connected: true fail_mode: secure Port "qr-11591618-c4" tag: 3 Interface "qr-11591618-c4" type: internal Port patch-tun Interface patch-tun type: patch options: {peer=patch-int} Port int-br-ext Interface int-br-ext type: patch options: {peer=phy-br-ext}
Bridge
Bridge表明一個以太網交換機(Switch),一個主機中能夠建立一個或者多個Bridge。Bridge的功能是根據必定規則,把從端口收到的數據包轉發到另外一個或多個端口,上面例子中有三個Bridge,br-tun
,br-int
,br-ext
添加一個網橋br0
Port
端口Port與物理交換機的端口概念相似,Port是OVS Bridge上建立的一個虛擬端口,每一個Port都隸屬於一個Bridge。Port有如下幾種類型
能夠把操做系統中已有的網卡(物理網卡em1/eth0,或虛擬機的虛擬網卡tapxxx)掛載到ovs上,ovs會生成一個同名Port處理這塊網卡進出的數據包。此時端口類型爲Normal。
以下,主機中有一塊物理網卡eth1
,把其掛載到OVS網橋br-ext
上,OVS會自動建立同名Port eth1
。
ovs-vsctl add-port br-ext eth1
#Bridge br-ext中出現Port "eth1"
有一點要注意的是,掛載到OVS上的網卡設備不支持分配IP地址,所以若以前eth1
配置有IP地址,掛載到OVS以後IP地址將不可訪問。這裏的網卡設備不僅包括物理網卡,也包括主機上建立的虛擬網卡
Internal類型是OVS內部建立的虛擬網卡接口,每建立一個Port,OVS會自動建立一個同名接口(Interface)掛載到新建立的Port上。接口的概念下面會提到。
下面建立一個網橋br0,並建立一個Internal類型的Port p0
ovs-vsctl add-br br0 ovs-vsctl add-port br0 p0 -- set Interface p0 type=internal #查看網橋br0 ovs-vsctl show br0 Bridge "br0" fail_mode: secure Port "p0" Interface "p0" type: internal Port "br0" Interface "br0" type: internal
能夠看到有兩個Port。當ovs建立一個新網橋時,默認會建立一個與網橋同名的Internal Port。在OVS中,只有」internal」類型的設備才支持配置IP地址信息,所以咱們能夠爲br0
接口配置一個IP地址,固然p0
也能夠配置IP地址
ip addr add 192.168.10.11/24 dev br0 ip link set br0 up #添加默認路由 ip route add default via 192.168.10.1 dev br0
上面兩種Port類型區別在於,Internal類型會自動建立接口(Interface),而Normal類型是把主機中已有的網卡接口添加到OVS中
當主機中有多個ovs網橋時,可使用Patch Port把兩個網橋連起來。Patch Port老是成對出現,分別鏈接在兩個網橋上,從一個Patch Port收到的數據包會被轉發到另外一個Patch Port,相似於Linux系統中的veth
。使用Patch鏈接的兩個網橋跟一個網橋沒什麼區別,OpenStack Neutron中使用到了Patch Port。上面網橋br-ext
中的Port phy-br-ext
與br-int
中的Port int-br-ext
是一對Patch Port
可使用ovs-vsctl
建立patch設備,以下建立兩個網橋br0,br1
,而後使用一對Patch Port
鏈接它們
ovs-vsctl add-br br0 ovs-vsctl add-br br1 ovs-vsctl \ -- add-port br0 patch0 -- set interface patch0 type=patch options:peer=patch1 \ -- add-port br1 patch1 -- set interface patch1 type=patch options:peer=patch0 #結果以下 #ovs-vsctl show Bridge "br0" Port "br0" Interface "br0" type: internal Port "patch0" Interface "patch0" type: patch options: {peer="patch1"} Bridge "br1" Port "br1" Interface "br1" type: internal Port "patch1" Interface "patch1" type: patch options: {peer="patch0"}
鏈接兩個網橋不止上面一種方法,linux中支持建立Veth
設備對,咱們能夠首先建立一對Veth
設備對,而後把這兩個Veth
分別添加到兩個網橋上,其效果跟OVS中建立Patch Port同樣,只是性能會有差異
OVS中支持添加隧道(Tunnel)端口,常見隧道技術有兩種gre
或vxlan
。隧道技術是在現有的物理網絡之上構建一層虛擬網絡,上層應用只與虛擬網絡相關,以此實現的虛擬網絡比物理網絡配置更加靈活,並可以實現跨主機的L2通訊以及必要的租戶隔離。不一樣隧道技術其大致思路均是將以太網報文使用隧道協議封裝,而後使用底層IP網絡轉發封裝後的數據包,其差別性在於選擇和構造隧道的協議不一樣。Tunnel在OpenStack中用做實現大二層網絡以及租戶隔離,以應對公有云大規模,多租戶的複雜網絡環境。
OpenStack是多節點結構,同一子網的虛擬機可能被調度到不一樣計算節點上,所以須要有隧道技術來保證這些同子網不一樣節點上的虛擬機可以二層互通,就像他們鏈接在同一個交換機上,同時也要保證能與其它子網隔離。
OVS在計算和網絡節點上創建隧道Port來鏈接各節點上的網橋br-int
,這樣全部網絡和計算節點上的br-int
互聯造成了一個大的虛擬的跨全部節點的邏輯網橋(內部靠tunnel id或VNI隔離不一樣子網),這個邏輯網橋對虛擬機和qrouter是透明的,它們以爲本身鏈接到了一個大的br-int
上。從某個計算節點虛擬機發出的數據包會被封裝進隧道經過底層網絡傳輸到目的主機而後解封裝。
上面網橋br-tun
中Port "vxlan-080058ca"
就是一個vxlan
類型tunnel端口。下面使用兩臺主機測試建立vxlan隧道
#主機192.168.7.21上 ovs-vsctl add-br br-vxlan #主機192.168.7.23上 ovs-vsctl add-br br-vxlan #主機192.168.7.21上添加鏈接到7.23的Tunnel Port ovs-vsctl add-port br-vxlan tun0 -- set Interface tun0 type=vxlan options:remote_ip=192.168.7.23 #主機192.168.7.23上添加鏈接到7.21的Tunnel Port ovs-vsctl add-port br-vxlan tun0 -- set Interface tun0 type=vxlan options:remote_ip=192.168.7.21
而後,兩個主機上橋接到br-vxlan
的虛擬機就像鏈接到同一個交換機同樣,能夠實現跨主機的L2鏈接,同時又徹底與物理網絡隔離。
Interface
Interface是鏈接到Port的網絡接口設備,是OVS與外部交換數據包的組件,在一般狀況下,Port和Interface是一對一的關係,只有在配置Port爲 bond模式後,Port和Interface是一對多的關係。這個網絡接口設備多是建立Internal
類型Port時OVS自動生成的虛擬網卡,也多是系統的物理網卡或虛擬網卡(TUN/TAP)掛載在ovs上。 OVS中只有」Internal」類型的網卡接口才支持配置IP地址
Interface
是一塊網絡接口設備,負責接收或發送數據包,Port是OVS網橋上創建的一個虛擬端口,Interface
掛載在Port上。
Controller
OpenFlow控制器。OVS能夠同時接受一個或者多個OpenFlow控制器的管理。主要做用是下發流表(Flow Tables)到OVS,控制OVS數據包轉發規則。控制器與OVS經過網絡鏈接,不必定要在同一主機上
能夠看到上面實例中三個網橋br-int
,br-ext
,br-tun
都鏈接到控制器Controller "tcp:127.0.0.1:6633
上
datapath
OVS內核模塊,負責執行數據交換。其內部有做爲緩存使用的flows,關於datapath,下面會細說
流(flows)
flows是OVS進行數據轉發策略控制的核心數據結構,區別於Linux Bridge是個單純基於MAC地址學習的二層交換機,flows的存在使OVS做爲一款SDN交換機成爲雲平臺網絡虛擬機化主要組件
OVS中有多種flows存在,用於不一樣目的,但最主要的仍是OpenFlow flows這種,文中未明確說明的flows都是指OpenFlow flows
OVS中最重要的一種flows,Controller控制器下發的就是這種flows,OVS架構部分已經簡單介紹過,關於openflow的具體使用,會在另外一篇文章中說明
OVS在使用OpenFlow flow時,須要與OpenFlow控制器創建TCP鏈接,若此TCP鏈接不依賴OVS,即沒有OVS依然能夠創建鏈接,此時就是out-of-band control
模式,這種模式下不須要」hidden」 flows
可是在in-band control
模式下,TCP鏈接的創建依賴OVS控制的網絡,但此時OVS依賴OpenFLow控制器下發的flows才能正常工做,無法創建TCP鏈接也就沒法下發flows,這就產生矛盾了,所以須要存在一些」hidden」 flows,這些」hidden」 flows保證了TCP鏈接可以正常創建。關於in-band control
詳細介紹,參考OVS官方文檔Design Decisions In Open vSwitch 中In-Band Control部分
「hidden」 flows優先級高於OpenFlow flows,它們不須要手動設置。可使用ovs-appctl
查看這些flows,下面命令輸出內容包括OpenFlow flows
,"hidden" flows
ovs-appctl bridge/dump-flows <br>
datapath flows是datapath
內核模塊維護的flows,由內核模塊維護意味着咱們並不須要去修改管理它。與OpenFlow flows不一樣的是,它不支持優先級,而且只有一個表,這些特色使它很是適合作緩存。與OpenFlow同樣的是它支持通配符,也支持指令集(多個action)
datapath flows能夠來自用戶空間ovs-vswitchd
緩存,也能夠是datapath內核模塊進行MAC地址學習到的flows,這取決與OVS是做爲SDN交換機,仍是像Linux Bridge那樣只是一個簡單基於MAC地址學習的二層交換機
幾種flows對比
咱們能夠修改和配置的是OpenFlow flows。datapath flow和」hidden」 flows由OVS自身管理,咱們沒必要去修改它。固然,調試場景下仍是可使用工具修改的
flows命令行工具
介紹下上面三種flows管理工具,不具體說明,具體使用能夠查看相關man手冊
-
ovs-ofctl dump-flows <br>
打印指定網橋內的全部OpenFlow flows,能夠存在多個流表(flow tables),按表順序顯示。不包括」hidden」 flows。這是最經常使用的查看flows命令,固然這條命令對全部OpenFlow交換機都有效,不僅僅是OVS
-
ovs-appctl bridge/dump-flows <br>
打印指定網橋內全部OpenFlow flows,包括」hidden」 flows,in-band control
模式下排錯能夠用到
-
ovs-dpctl dump-flows [dp]
打印內核模塊中datapath flows,[dp]
能夠省略,默認主機中只有一個datapath system@ovs-system
man手冊能夠找到很是詳細的用法說明,注意ovs-ofctl
管理的是OpenFlow flows
OVS中管理工具的使用及區別
上面介紹了OVS用戶空間進程以及控制器和OpenFlow協議,這裏說下相關的命令行工具的使用及區別
ovs-vsctl
ovs-vsctl
是一個管理或配置ovs-vswitchd
的高級命令行工具,高級是說其操做對用戶友好,封裝了對數據庫的操做細節。它是管理OVS最經常使用的命令,除了配置flows以外,其它大部分操做好比Bridge/Port/Interface/Controller/Database/Vlan等均可以完成
#添加網橋br0 ovs-vsctl add-br br0 #列出全部網橋 ovs-vsctl list-br #添加一個Port p1到網橋br0 ovs-vsctl add-port br0 p1 #查看網橋br0上全部Port ovs-vsctl list-ports br0 #獲取br0網橋的OpenFlow控制器地址,沒有控制器則返回空 ovs-vsctl get-controller br0 #設置OpenFlow控制器,控制器地址爲192.168.1.10,端口爲6633 ovs-vsctl set-controller br0 tcp:192.168.1.10:6633 #移除controller ovs-vsctl del-controller br0 #刪除網橋br0 ovs-vsctl del-br br0 #設置端口p1的vlan tag爲100 ovs-vsctl set Port p1 tag=100 #設置Port p0類型爲internal ovs-vsctl set Interface p0 type=internal #添加vlan10端口,並設置vlan tag爲10,Port類型爲Internal ovs-vsctl add-port br0 vlan10 tag=10 -- set Interface vlan10 type=internal #添加隧道端口gre0,類型爲gre,遠端IP爲1.2.3.4 ovs-vsctl add-port br0 gre0 -- set Interface gre0 type=gre options:remote_ip=1.2.3.4
ovsdb-tool
ovsdb-tool
是一個專門管理OVS數據庫文件的工具,不經常使用,它不直接與ovsdb-server
進程通訊
#可使用此工具建立並初始化database文件 ovsdb-tool create [db] [schema] #可使用ovsdb-client get-schema [database]獲取某個數據庫的schema(json格式) #能夠查看數據庫更改記錄,具體到操做命令,這個比較有用 ovsdb-tool show-log -m record 48: 2017-01-07 03:34:15.147 "ovs-vsctl: ovs-vsctl --timeout=5 -- --if-exists del-port tapcea211ae-10" table Interface row "tapcea211ae-10" (151f66b6): delete row table Port row "tapcea211ae-10" (cc9898cd): delete row table Bridge row "br-int" (fddd5e27): table Open_vSwitch row a9fc1666 (a9fc1666): record 49: 2017-01-07 04:18:23.671 "ovs-vsctl: ovs-vsctl --timeout=5 -- --if-exists del-port tap5b4345ea-d5 -- add-port br-int tap5b4345ea-d5 -- set Interface tap5b4345ea-d5 "external-ids:attached-mac=\"fa:16:3e:50:1b:5b\"" -- set Interface tap5b4345ea-d5 "external-ids:iface-id=\"5b4345ea-d5ea-4285-be99-0e4cadf1600a\"" -- set Interface tap5b4345ea-d5 "external-ids:vm-id=\"0aa2d71e-9b41-4c88-9038-e4d042b6502a\"" -- set Interface tap5b4345ea-d5 external-ids:iface-status=active" table Port insert row "tap5b4345ea-d5" (4befd532): table Interface insert row "tap5b4345ea-d5" (b8a5e830): table Bridge row "br-int" (fddd5e27): table Open_vSwitch row a9fc1666 (a9fc1666): ...
ovsdb-client
ovsdb-client
是ovsdb-server
進程的命令行工具,主要是從正在運行的ovsdb-server
中查詢信息,操做的是數據庫相關
ovs-ofctl
ovs-ofctl
是專門管理配置OpenFlow交換機的命令行工具,咱們能夠用它手動配置OVS中的OpenFlow flows,注意其不能操做datapath flows和」hidden」 flows
#查看br-tun中OpenFlow flows ovs-ofctl dump-flows br-tun #查看br-tun端口信息 ovs-ofctl show br-tun #添加新的flow:對於從端口p0進入交換機的數據包,若是它不包含任何VLAN tag,則自動爲它添加VLAN tag 101 ovs-ofctl add-flow br0 "priority=3,in_port=100,dl_vlan=0xffff,actions=mod_vlan_vid:101,normal" #對於從端口3進入的數據包,若其vlan tag爲100,去掉其vlan tag,並從端口1發出 ovs-ofctl add-flow br0 in_port=3,dl_vlan=101,actions=strip_vlan,output:1 #添加新的flow: 修改從端口p1收到的數據包的源地址爲9.181.137.1,show 查看p1端口ID爲100 ovs-ofctl add-flow br0 "priority=1 idle_timeout=0,in_port=100,actions=mod_nw_src:9.181.137.1,normal" #添加新的flow: 重定向全部的ICMP數據包到端口 p2 ovs-ofctl add-flow br0 idle_timeout=0,dl_type=0x0800,nw_proto=1,actions=output:102 #刪除編號爲 100 的端口上的全部流表項 ovs-ofctl del-flows br0 "in_port=100"
ovs-vsctl
是一個綜合的配置管理工具,ovsdb-client
傾向於從數據庫中查詢某些信息,而ovsdb-tool
是維護數據庫文件工具
文章地址http://www.isjian.com/openstack/openstack-base-use-openvswitch/
參考文章
https://www.sdxcentral.com/cloud/open-source/definitions/what-is-open-vswitch/ http://openvswitch.org/features/ https://www.ibm.com/developerworks/cn/cloud/library/1401_zhaoyi_openswitch/ http://openvswitch.org/slides/OpenStack-131107.pdf http://horms.net/projects/openvswitch/2010-10/openvswitch.en.pdf http://benpfaff.org/papers/ovs.pdf https://networkheresy.com/category/open-vswitch/