OVS——大雜燴

其餘資料php

http://docs.openvswitch.org/en/latest/tutorials/ovs-conntrack/css

OVS架構解析--dpdk datapath數據通路

1.  架構說明

1.1.  總體架構

OVS(openvswitch)是開源的虛擬交換機。也是當前市場上雲環境中部署份額最大的交換機。支持 openflow協議,ovsdb協議管理。html

一個OVS實例包括,ovsdb-server、ovs-vswitchd、datapath快轉模塊(linux內核中實現,可選的。dpdk模式是在用戶態實現快轉,並不須要內核態的datapath模塊)。node

 

  • ovsdb-server:做用是對ovsdb操做。
  • ovs-vswitchd:核心模塊,做用是實現OpenFlow交換機、和controller通訊、和db通訊、實現用戶態轉發、和內核態快轉路徑通訊。
  • datapath:在內核空間實現報文快速轉發。

上圖從總體架構說明了ovs的工做方式。ovs包括ovsdb配置管理方式和openflow流錶轉發控制方式。python

 

  1. ovsdb配置管理方式:管理者經過OVSDB管理協議管理OVS交換機。OVSDB管理協議的規範文件是RFC 7047(The Open vSwitch Database Management Protocol)。RFC7047主要包括,定義OVSDB的結構、交互協議(JSON-RPC)、DB的操做類型。
  2. openflow流表控制方式:controller控制器經過OpenFlow協議給OVS交換機下發流表,控制交換機的轉發行爲。controller不經過OVSDB,而是直接向OVS交換機下發流表。

 

1.2.  核心組件及其關聯關係

ovsdb-server和ovs-vswitchd之間是經過socket交互信息。linux

ovs-vswitchd經過netlink和內核態快轉模塊通訊。git

好比經過ovs-vsctl命令增長ovs交換機接口,ovs-vsctl會經過ovsdb-server向ovsdb更新數據,ovs-vswitchd監測到ovsdb變化時,會更新交換機配置,好比添加接口。github

dpdk方式的ovs除了不使用內核模塊外,架構和圖中相同。sql

1.3.    內部模塊及其關聯關係

爲了有個總體的瞭解,下面列幾張總體的架構圖,不作詳細解釋,後文會有流程解釋。
 

2.  vswitchd和ovsdb通訊

IDL:接口描述語言。IDL是用來描述軟件組件接口的一種計算機語言。IDL經過一種中立的方式來描述接口,使得在不一樣平臺上運行的對象和用不一樣語言編寫的程序能夠相互通訊交流。也就是說,用一種通用的格式,好比下面數據就是描述一個Open_vSwitch表,最後生成C語言描述的表操做.c文件
 
 
使用ovsschema格式定義數據庫表,IDL解析器會把該文件內容解析成對數據庫初始化、操做等函數,生成ovsdb-idl.c文件。
 

2.1.  創建鏈接

ovsdb_idl_create創建一個ovsdb的鏈接session,形如:idl =ovsdb_idl_create(remote, &ovsrec_idl_class, true, true)。docker

remote相似:unix:/var/run/openvswitch/db.sock。

後續使用該idl(struct ovsdb_idl)和ovsdb通訊,更新數據。

2.2.  接收數據

使用jsonrpc_session_recv函數接收數據,形如:msg = jsonrpc_session_recv(idl->session)。

接收消息的結構是:

struct jsonrpc_msg {

    enum jsonrpc_msg_type type;

    char *method;              /* Request or notification only. */

    struct json *params;       /* Request or notification only. */

    struct json *result;       /* Successful reply only. */

    struct json *error;         /* Error reply only. */

    struct json *id;           /* Request or reply only. */

};

 

其中type是JSON-RPC 1.0定義的消息類型,包括request、notification、reply、error:

/* Messages. */

enum jsonrpc_msg_type {

    JSONRPC_REQUEST,          /* Request. */

    JSONRPC_NOTIFY,           /* Notification.*/

    JSONRPC_REPLY,            /* Successfulreply. */

   JSONRPC_ERROR              /* Error reply. */

};

 

params、result、error、id是不一樣類型的消息對應的消息數據。

當解析消息後,監測到須要更新本地數據時,調用ovsdb_idl_parse_update函數,解析消息並更新本地數據。
 

2.3.  json數據解析

 

/* A JSON value. */

struct json {

    enum json_type type;

    union {

        struct shash *object;  /* Contains "struct json *"s. */

        struct json_array array;

        long long int integer;

        double real;

        char *string;

    } u;

};

 

type字段:說明了該json數據是聯合體中的哪種類型。

/* Type of a JSON value. */

enum json_type {

    JSON_NULL,                 /* null */

    JSON_FALSE,                /* false */

    JSON_TRUE,                 /* true */

    JSON_OBJECT,               /* {"a": b, "c": d, ...}*/

    JSON_ARRAY,                /* [1, 2, 3, ...] */

    JSON_INTEGER,              /* 123. */

    JSON_REAL,                 /* 123.456. */

    JSON_STRING,               /* "..." */

    JSON_N_TYPES

};

 

聯合體u:表示數據能夠解析的類型。

例如,當type是JSON_OBJECT類型時,且是update2更新操做,那麼object字段保存着多個數據表,每張表數據中又攜帶着待更新的多個row數據,和每row對應的操做(modify、insert、delete、initial)。而後遍歷每一個表的每行數據,並執行對應的數據操做(modify、insert、delete、initial)對本地數據更新。

注:本地數據和遠端的OVSDB並不相同,本地數據是vswitchd從數據庫取出數據後臨時放到本地結構中的。

2.4.  更新數據改變標記

當監聽到ovsdb-server發來的rpc消息時,若是數據庫發送改變就改變對應的change_seqno。後續vswitchd根據change_seqno的值是否發生了變化,決定是否從新配置ovs交換機。

3.  dpdk加速處理

3.1.  ovs dpdk加速配置

在使用dpdk 類型的datapath加速以前,須要設置dpdk-init=true啓動參數。

設置方法:

ovs-vsctl --no-wait set Open_vSwitch .other_config:dpdk-init=true

設置dpdk的相關參數,都經過other_config選項完成。

主要的參數有:

 

  • dpdk-init

 

指定ovs是否初始化和支持dpdk端口。

 

  • dpdk-lcore-mask

 

指明dpdk使用的邏輯核。同dpdk的-c參數。

 

  • dpdk-socket-mem

 

指明不一樣numa節點提早申請的大頁內存。同dpdk的--socket-mem參數。

 

  • dpdk-hugepage-dir

 

大頁文件系統mount的目錄。同dpdk的--huge-dir參數。

 

  • vhost-sock-dir

 

設置vhost-user 套接字的路徑。

 

  • dpdk-extra

 

其餘的dpdk配置參數。

3.2.  dpdk初始化

 

主要包括:

1)    dpdk eal初始化。

2)    啓動dpdk接口狀態監控線程(使用dpdk的庫函數),若是狀態發送變化,則更新netdev設備的變化標記。

3)     註冊dpdk類型的netdev class。其中包括dpdk設備類型,ring類型、vhost、vhost client類型。

 

4.  數據結構抽象關係

4.1.  分層抽象

 
 

 

  • ofproto  class

 

openflow交換機實現類,用來實現一個openflow交換機。主要包括建立、構造、操做openflowflow等相關方法。

 

  • dpif  class

 

datapath接口類,用來和datapath交互。主要包括datapath的open、run、端口操做、端口數據監聽等相關方法。datapath是數據面的一種抽象。

 

  • netdev  class

 

網絡設備抽象類,用來和網絡設備交互。主要包括網卡的設置、網卡結構的抽象、數據包發送接收等相關方法。

 

 

  • ofproto  class

 

openflow交換機實現類,用來實現一個openflow交換機。主要包括建立、構造、操做openflowflow等相關方法。

 

  • dpif  class

 

datapath接口類,用來和datapath交互。主要包括datapath的open、run、端口操做、端口數據監聽等相關方法。datapath是數據面的一種抽象。

 

  • netdev  class

 

網絡設備抽象類,用來和網絡設備交互。主要包括網卡的設置、網卡結構的抽象、數據包發送接收等相關方法。

 

bridge網橋經過ofproto  class構造一個openflow交換機。再經過dpif  class打開(若是沒有對應類型的datapath,就建立一個)對應類型的datapath通路。使用netdev  class構造一個抽象網絡設備,上層抽象爲端口,而後對網絡設備收發包等操做。

         須要說明的是,datapath是按類型分類的,如今ovs有兩種類型的datapath:system(對應linux內核數據通路)、netdev(dpdk用戶態數據通路)。因此使用同一種datapath類型的ovs網橋共享同一個datapath對象。以下圖所示。

 


 

4.2.  主要數據結構關係

該部分說明的內容是關於dpdk類型的datapath。

 

 

注:A  B,表示A是一個變量而非指針,它的結構和內容是B。

流程解釋以下:

1)        bridge層

 

1.1    struct  bridge對應每一個ovs網橋最上層的結構。它經過成員指針變量ofproto,聯繫到struct  ofproto交換機結構內容。

 

2)        ofproto層

 

2.1   因爲聯繫到的struct ofproto內容是struct ofproto_dpif結構的一個up成員變量。因此經過struct ofproto地址能夠cast到struct ofproto_dpif結構內容,經過該內容和dpif層交互。

 

2.2   經過struct ofproto_dpif的成員指針變量dpif_backer,聯繫到struct  dpif_backer結構內容。該結構是dpif操做的入口點。

 

3)        dpif層

 

3.1   經過struct  dpif_backer的成員指針變量dpif,聯繫到structdpif結構內容。

 

3.2  因爲struct dpif結構內容是struct  dpif_netdev結構的dpif成員變量,因此經過structdpif地址能夠cast到struct dpif_netdev結構內容。

 

3.3   struct dpif_netdev結構內容中有指針成員變量dp,經過dp能夠聯繫到struct  dp_netdev結構內容。該內容是datapath的抽象結構內容。

 

4)        datapath層

 

4.1  struct  dp_netdev的成員指針變量ports是一個表結構,它聯繫着多個port端口內容。端口的結構是struct  dp_netdev_port。struct  dp_netdev另一個成員指針變量netdev,聯繫着dp層的struct  netdev結構內容,該結構內容是網卡的邏輯抽象。

 

4.2  struct  dp_netdev_port的指針成員變量rxqs也是一個表結構,它聯繫着多個隊列內容。隊列的結構是struct  dp_netdev_rxq.它的成員變量core_id表示該隊列所在的core。

 

4.3   經過struct dp_netdev_rxq的成員指針變量rxq,聯繫到dp層的struct  netdev_rxq結構內容。structdp_netdev_rxq的成員變量queue_id表示該隊列id。

 

5)        netdev層

 

5.1   因爲struct  netdev結構內容是struct  netdev_dpdk結構的一個up成員變量。因此經過struct  netdev地址能夠cast到struct  netdev_dpdk結構內容。

 

5.2    經過struct  detdev_dpdk結構內容的成員指針變量netdev_class和dpdk類型網卡交互。

5.3   因爲struct netdev_rxq結構內容是struct netdev_rxq_dpdk結構內容的一個up成員變量。因此經過struct netdev_rxq地址能夠cast到struct netdev_rxq_dpdk結構內容。該內容是dpdk類型的netdev_rxq,它的成員變量port_id是dpdk網絡設備的port。

 

 

5.  vswitchd啓動

簡要的歸納下vswitchd啓動的內容。

1)   和ovsdb-server通訊初始化,創建

2)   dpdk初始化

3)   ofproto(OpenFlow交換機)初始化

4)   netdev初始化

5)   網橋配置

 

更新網橋(添加、刪除)

 

更新端口

 

建立ofproto(OpenFlow交換機),建立或打開dpif_backer

 

添加端口,添加到pmd中

 

配置網橋、端口屬性

 

datapath run

 

dp_netdev的pmd更新

 

dpif_run(運行dpif-netdev的datapath,配置netdev等,接收發送報文)

 

ofproto run,配置ofproto須要的參數和功能(netflow、sflow、ipfix、mac學習)

 

OpenFlow控制器鏈接相關run

 

 

 

6.  附錄-數據結構查詢

6.1.  ofproto_class

是一個OpenFlow交換機的實現類結構,提供的類功能不少,主要分爲:

1.        工廠函數功能。如初始化、枚舉支持的datapath類型。

2.        datapath類型處理。

3.        OpenFlow交換機功能。如構造、運行等。

4.        OpenFlow流表功能。

5.        OpenFlow配置。

6.        OpenFlow計量。

7.        OpenFlow 1.1 group功能。

8.        獲取datapath信息功能。

9.        鏈接表功能。

 

 

6.2.  dpif_class

datapath接口實現類,每種datapath都有對應的接口實現實例。dpif有兩種實現類:dpif_netlink_class、dpif_netdev_class。即system、netdev。好比,dpdk的netdevdatapath類型的實現實例dpif_netdev_class。

 

 

6.3.  netdev_class

網絡設備實現類。包括抽象的設備結構和收發包功能。

6.4.  bridge

6.5.  ofproto

6.6.  port

6.7.  iface

6.8.  ofport

6.9.  ofport_dpif

6.10.  ofproto_port

6.11.  dpif_port

dp向dpif返回的端口信息。

6.12.  ofproto_dpif

6.13.  dpif_backer

datapath類型共享實現實例。

6.14.  udpif

6.15.  dpif

datapath接口。

6.16.  dpif_netdev

netdev類型的datapath的接口。

6.17.  dp_netdev

基於網絡設備接口的datapath。

6.18.  dp_netdev_port

基於netdev類型的datapath的端口。

掛載在dp_netdev的ports成員中。

6.19.  netdev

抽象的網絡設備。

6.20.  netdev_dpdk

dpdk類型的netdev結構,繼承自netdev結構。

6.21.  dp_netdev_rxq

用來表示core和隊列的對應關係。

6.22.  netdev_rxq

網絡設備的收包隊列結構,以隊列區分。

6.23.  netdev_rxq_dpdk

dpdk的收包隊列結構,繼承自netdev_rxq.

端口號和netdev_dpdk中的端口號相同。

使用dpdk的接口函數rte_zmalloc申請,受dpdk的內存管理控制。

6.24.  dp_netdev_pmd_thread

6.25.  rxq_poll

6.26.  tx_port

OVS 架構

OVS 是產品級的虛擬交換機,大量應用在生產環境中,支撐整個數據中心虛擬網絡的運轉。OVS 基於 SDN 的思想,將整個核心架構分爲控制面和數據面,數據面負責數據的交換工做,控制面實現交換策略,指導數據面工做。

431521-20171224102317818-1090106576.png

從總體上看,OVS 能夠劃分爲三大塊,管理面、數據面和控制面。

數據面就是以用戶態的 ovs-vswitchd 和內核態的 datapath 爲主的轉發模塊,以及與之相關聯的數據庫模塊 ovsdb-server,控制面主要是由 ovs-ofctl 模塊負責,基於 OpenFlow 協議與數據面進行交互。而管理面則是由 OVS 提供的各類工具來負責,這些工具的提供也是爲了方便用戶對底層各個模塊的控制管理,提升用戶體驗。下面就對這些工具進行一個逐一的闡述。

ovs-ofctl:這個是控制面的模塊,但本質上它也是一個管理工具,主要是基於 OpenFlow 協議對 OpenFlow 交換機進行監控和管理,經過它能夠顯示一個 OpenFlow 交換機的當前狀態,包括功能、配置和表中的項。使用時,有不少參數,咱們能夠經過 ovs-ofctl --help 查看。

  1.  
    經常使用命令:
  2.  
     
  3.  
    ovs-ofctl show switch-name :輸出交換機信息,包括其流量表和端口信息。
  4.  
     
  5.  
    ovs-ofctl dump-ports switch-name:輸出交換機的端口統計信息,包括收發包、丟包、錯誤包等數量。
  6.  
     
  7.  
    ovs-ofctl add-flow switch-name:爲交換機配置流策略。

ovs-dpctl:用來配置交換機的內核模塊 datapath,它能夠建立,修改和刪除 datapath,通常,單個機器上的 datapath 有 256 條(0-255)。一條 datapath 對應一個虛擬網絡設備。該工具還能夠統計每條 datapath 上的設備經過的流量,打印流的信息等,更過參數經過 ovs-dpctl --help 查看。

  1.  
    經常使用命令:
  2.  
     
  3.  
    ovs-dpctl show :顯示全部 datapath 的基本信息。
  4.  
     
  5.  
    ovs-dpctl dump-dps :顯示全部 datapath 的名字。
  6.  
     
  7.  
    ovs-dpctl dump-flows DP :顯示一條 datapath DP 上的流信息。

ovs-appctl:查詢和控制運行中的 OVS 守護進程,包括 ovs-switchd,datapath,OpenFlow 控制器等,兼具 ovs-ofctl、ovs-dpctl 的功能,是一個很是強大的命令。ovs-vswitchd 等進程啓動以後就以一個守護進程的形式運行,爲了可以很好的讓用戶控制這些進程,就有了這個命令。詳細能夠 ovs-appctl --help 查看。

ovs-vsctl:查詢和更新 ovs-vswitchd 的配置,這也是一個很強大的命令,網橋、端口、協議等相關的命令都由它來完成。此外,還負責和 ovsdb-server 相關的數據庫操做。

  1.  
    經常使用命令:
  2.  
     
  3.  
    ovs-vsctl show :顯示主機上已有的網橋及端口信息。
  4.  
     
  5.  
    ovs-vsctl add-br br0:添加網橋 br0。

ovsdb-client:訪問 ovsdb-server 的客戶端程序,經過 ovsdb-server 執行一些數據庫操做。

  1.  
    經常使用命令:
  2.  
     
  3.  
    ovsdb-client dump:用來查看ovsdb內容。
  4.  
     
  5.  
    ovsdb-client transact :用來執行一條類 sql。

ovsdb-tool:和 ovsdb-client 要藉助 ovsdb-server 才能進行相關數據庫操做不一樣,ovsdb-tool 能夠直接操做數據庫。

OVS 源碼結構

OVS 源碼結構中,主要包含如下幾個主要的模塊,數據交換邏輯在 vswitchd 和 datapath 中實現,vswitchd 是最核心的模塊,OpenFlow 的相關邏輯都在 vswitchd 中實現,datapath 則不是必須的模塊。ovsdb 用於存儲 vswitch 自己的配置信息,如端口、拓撲、規則等。控制面部分採用的是 OVS 自家實現的 OVN,和其餘控制器相比,OVN 對 OVS 和 OpenStack 有更好的兼容性和性能。

431521-20171224102359443-1589744207.png

從圖中能夠看出 OVS 的分層結構,最上層 vswitchd 主要與 ovsdb 通訊,作配置下發和更新等,中間層是 ofproto ,用於和 OpenFlow 控制器通訊,並基於下層的 ofproto provider 提供的接口,完成具體的設備操做和流表操做等工做。

dpif 層實現對流表的操做。

netdev 層實現了對網絡設備(如 Ethernet)的抽象,基於 netdev provider 接口實現多種不一樣平臺的設備,如 Linux 內核的 system, tap, internal 等,dpdk 系的 vhost, vhost-user 等,以及隧道相關的 gre, vxlan 等。

數據轉發流程

經過一個例子來看看 OVS 中數據包是如何進行轉發的。

431521-20171224102412506-951322711.png

1)ovs 的 datapath 接收到從 ovs 鏈接的某個網絡端口發來的數據包,從數據包中提取源/目的 IP、源/目的 MAC、端口等信息。

2)ovs 在內核態查看流表結構(經過 hash),若是命中,則快速轉發。

3)若是沒有命中,內核態不知道如何處置這個數據包,因此,經過 netlink upcall 機制從內核態通知用戶態,發送給 ovs-vswitchd 組件處理。

4)ovs-vswitchd 查詢用戶態精確流表和模糊流表,若是還不命中,在 SDN 控制器接入的狀況下,通過 OpenFlow 協議,通告給控制器,由控制器處理。

5)若是模糊命中, ovs-vswitchd 會同時刷新用戶態精確流表和內核態精確流表,若是精確命中,則只更新內核態流表。

6)刷新後,從新把該數據包注入給內核態 datapath 模塊處理。

7)datapath 從新發起選路,查詢內核流表,匹配;報文轉發,結束。

總結

OVS 爲了方便用戶操做,提供了不少管理工具,咱們日常在使用過程當中只需記住每一個工具的做用,具體的命令可使用 -h 或 --help 查看。

建立一個OVS 交換機

建立一個叫ovs-switch的交換機

  1.  
    $ ovs-vsctl add-br ovs-switch
  2.  
     

建立一個端口 p0,設置端口 p0 的 OpenFlow 端口編號爲 100(若是在建立端口的時候沒有指定 OpenFlow 端口編號,OVS 會自動生成一個)。

 

  1.  
    $ ovs-vsctl add-port ovs-switch p0 -- set Interface p0 ofport_request=100
  2.  
     

設置網絡接口設備的類型爲"internal"。對於 internal 類型的的網絡接口,OVS 會同時在 Linux 系統中建立一個能夠用來收發數據的模擬網絡設備。咱們能夠爲這個網絡設備配置 IP 地址、進行數據監聽等操做。

 

  1.  
    $ ovs-vsctl set Interface p0 type=internal
  2.  
    $ ethtool -i p0
  3.  
    driver: openvswitch
  4.  
    version:
  5.  
    firmware-version:
  6.  
    bus-info:
  7.  
    supports-statistics: no
  8.  
    supports-test: no
  9.  
    supports-eeprom-access: no
  10.  
    supports-register-dump: no

爲了不網絡接口上的地址和本機已有網絡地址衝突,咱們能夠建立一個虛擬網絡空間 ns0,把 p0 接口移入網絡空間 ns0,並配置 IP 地址爲 192.168.1.100

 

  1.  
    $ ip netns add ns0
  2.  
    $ ip link set p0 netns ns0
  3.  
    $ ip netns exec ns0 ip addr add 192.168.1.100/24 dev p0
  4.  
    $ ip netns exec ns0 ifconfig p0 promisc up

使用一樣的方法建立端口 p一、p2

 

 

建立的端口信息

 

端口

說明

p0

IP 地址: 192.168.1.100/24
網絡名稱空間: ns0
網絡接口 MAC地址: 66:4e:cc:ae:4d:20
OpenFlow Port Number: 100

p1

IP 地址: 192.168.1.101/24
網絡名稱空間: ns1
網絡接口 MAC地址: 46:54:8a:95:dd:f8
OpenFlow Port Number: 101

p2

IP 地址: 192.168.1.102/24, 
網絡名稱空間: ns2
網絡接口 MAC地址: 86:3b:c8:d0:44:10
OpenFlow Port Number: 102

   

建立全部的端口以後, 查看 OVS 交換機的信息

 

  1.  
    $ ovs-vsctl show
  2.  
    30282710-d401-4187-8e13-52388f693df7
  3.  
    Bridge ovs-switch
  4.  
    Port "p0"
  5.  
    Interface "p0"
  6.  
    type: internal
  7.  
    Port "p2"
  8.  
    Interface "p2"
  9.  
    type: internal
  10.  
    Port "p1"
  11.  
    Interface "p1"
  12.  
    type: internal
  13.  
    Port ovs-switch
  14.  
    Interface ovs-switch
  15.  
    type: internal

 

使用 ovs-ofctl 建立並測試 OpenFlow 命令

查看 Open vSwitch 中的端口信息。從輸出結果中,能夠得到交換機對應的 datapath ID (dpid),以及每一個端口的 OpenFlow 端口編號,端口名稱,當前狀態等等。

  1.  
    $ ovs-ofctl show ovs-switch
  2.  
    OFPT_FEATURES_REPLY (xid= 0x2): dpid:00001232a237ea45
  3.  
    n_tables: 254, n_buffers:256
  4.  
    capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
  5.  
    actions: OUTPUT SET_VLAN_VID SET_VLAN_PCP STRIP_VLAN SET_DL_SRC SET_DL_DST
  6.  
    SET_NW_SRC SET_NW_DST SET_NW_TOS SET_TP_SRC SET_TP_DST ENQUEUE
  7.  
    100(p0): addr:54:01:00:00:00:00
  8.  
    config: PORT_DOWN
  9.  
    state: LINK_DOWN
  10.  
    speed: 0 Mbps now, 0 Mbps max
  11.  
    101(p1): addr:54:01:00:00:00:00
  12.  
    config: PORT_DOWN
  13.  
    state: LINK_DOWN
  14.  
    speed: 0 Mbps now, 0 Mbps max
  15.  
    102(p2): addr:54:01:00:00:00:00
  16.  
    config: PORT_DOWN
  17.  
    state: LINK_DOWN
  18.  
    speed: 0 Mbps now, 0 Mbps max
  19.  
    LOCAL(ovs-switch): addr: 12:32:a2:37:ea:45
  20.  
    config: 0
  21.  
    state: 0
  22.  
    speed: 0 Mbps now, 0 Mbps max
  23.  
    OFPT_GET_CONFIG_REPLY (xid= 0x4): frags=normal miss_send_len=0

 

若是想得到網絡接口的 OpenFlow 編號,也能夠在 OVS 的數據庫中查詢

 

  1.  
    $ ovs-vsctl get Interface p0 ofport
  2.  
    100

 

查看 datapath 的信息

 

 
  
  1.  
    $ ovs-dpctl show
  2.  
    system@ovs-system:
  3.  
    lookups: hit: 12173 missed:712 lost:0
  4.  
    flows: 0
  5.  
    port 0: ovs-system (internal)
  6.  
    port 1: ovs-switch (internal)
  7.  
    port 2: p0 (internal)
  8.  
    port 3: p1 (internal)
  9.  
    port 4: p2 (internal)

屏蔽數據包

屏蔽全部進入 OVS 的以太網廣播數據包

 

  1.  
    $ ovs-ofctl add-flow ovs-switch "table=0, dl_src=01:00:00:00:00:00/01:00:00:00:00:00, actions=drop"
  2.  
     

 

 屏蔽 STP 協議的廣播數據包

 

  1.  
    $ ovs-ofctl add-flow ovs-switch "table=0, dl_dst=01:80:c2:00:00:00/ff:ff:ff:ff:ff:f0, actions=drop"
  2.  
     

 

修改數據包

添加新的 OpenFlow 條目,修改從端口 p0 收到的數據包的源地址爲 9.181.137.1

 

  1.  
    $ ovs-ofctl add-flow ovs-switch "priority=1 idle_timeout=0,\
  2.  
    in_port=100,actions=mod_nw_src:9.181.137.1,normal"
從端口 p0(192.168.1.100)發送測試數據到端口 p1(192.168.1.101)

$ ip netns exec ns0 ping 192.168.1.101

在接收端口 p1 監控數據,發現接收到的數據包的來源已經被修改成 9.181.137.1

 

 
  
  1.  
    $ ip netns exec ns1 tcpdump -i p1 icmp
  2.  
    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
  3.  
    listening on p1, link-type EN10MB (Ethernet), capture size 65535 bytes
  4.  
    15:59:16.885770 IP 9.181.137.1 > 192.168.1.101: ICMP echo request, id 23111, seq 457, length 64
  5.  
    15:59:17.893809 IP 9.181.137.1 > 192.168.1.101: ICMP echo request, id 23111, seq 458, length 64

 

重定向數據包

添加新的 OpenFlow 條目,重定向全部的 ICMP 數據包到端口 p2

 

  1.  
    $ ovs-ofctl add-flow ovs-switch idle_timeout=0,dl_type=0x0800,nw_proto=1,actions=output:102
  2.  
     

 

 從端口 p0 (192.168.1.100)發送數據到端口 p1(192.168.1.101)

 

  1.  
    $ ip netns exec ns0 ping 192.168.1.101
  2.  
     

 

 在端口 p2 上監控數據,發現數據包已被轉發到端口 p2

 

  1.  
    $ ip netns exec ns3 tcpdump -i p2 icmp
  2.  
    tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
  3.  
    listening on p2, link-type EN10MB (Ethernet), capture size 65535 bytes
  4.  
    16:07:35.677770 IP 192.168.1.100 > 192.168.1.101: ICMP echo request, id 23147, seq 25, length 64
  5.  
    16:07:36.685824 IP 192.168.1.100 > 192.168.1.101: ICMP echo request, id 23147, seq 26, length 64

 

修改數據包的 VLAN Tag

除了使用"ping"、"tcpdump"和"iperf" 等 Linux 命令之外,咱們也可使用 OVS 提供的 ovs-appctl ofproto/trace 工具來測試 OVS 對數據包的轉發情況。ovs-appctl ofproto/trace 能夠用來生成測試用的模擬數據包,並一步步的展現 OVS 對數據包的流處理過程。在如下的例子中,咱們演示一下如何使用這個命令:

修改端口 p1 的 VLAN tag 爲 101,使端口 p1 成爲一個隸屬於 VLAN 101 的端口

 

  1.  
    $ ovs-vsctl set Port p1 tag=101
  2.  
     

 

 如今因爲端口 p0 和 p1 屬於不一樣的 VLAN,它們之間沒法進行數據交換。咱們使用 ovs-appctl ofproto/trace 生成一個從端口 p0 發送到端口 p1 的數據包,這個數據包不包含任何 VLAN tag,並觀察 OVS 的處理過程

在第一行輸出中,"Flow:"以後的字段描述了輸入的流的信息。因爲咱們沒有指定太多信息,因此多數字段 (例如 dl_type 和 vlan_tci)被 OVS 設置爲空值。

在第二行的輸出中,"Rule:" 以後的字段描述了匹配成功的流表項。

在第三行的輸出中,"OpenFlow actions"以後的字段描述了實際執行的操做。

最後一段以"Final flow"開始的字段是整個處理過程的總結,"Datapath actions: 4,1"表明數據包被髮送到 datapath 的 4 和 1 號端口。

 

  1.  
    $ ovs-appctl ofproto/trace ovs-switch in_port= 100,dl_src=66:4e:cc:ae:4d:20,
  2.  
    dl_dst= 46:54:8a:95:dd:f8 -generate
  3.  
    Flow:metadata= 0,in_port=100,vlan_tci=0x0000,dl_src=66:4e:cc:ae:4d:20,
  4.  
    dl_dst= 46:54:8a:95:dd:f8,dl_type=0x0000
  5.  
    Rule: table= 0 cookie=0 priority=0
  6.  
    OpenFlow actions=NORMAL
  7.  
    no learned MAC for destination, flooding
  8.  
     
  9.  
    Final flow: unchanged
  10.  
    Relevant fields: skb_priority= 0,in_port=100,vlan_tci=0x0000/0x1fff,\
  11.  
    dl_src= 66:4e:cc:ae:4d:20,dl_dst=46:54:8a:95:dd:f8,dl_type=0x0000,nw_frag=no
  12.  
    Datapath actions: 4,1


建立一條新的 Flow:對於從端口 p0 進入交換機的數據包,若是它不包含任何 VLAN tag,則自動爲它添加 VLAN tag 101

 

 

  1.  
    $ ovs-ofctl add-flow ovs-switch "priority=3,in_port=100,dl_vlan=0xffff,\
  2.  
     

actions=mod_vlan_vid:101,normal"

 

 再次嘗試從端口 p0 發送一個不包含任何 VLAN tag 的數據包,發現數據包進入端口 p0 以後, 會被加上 VLAN tag101, 同時轉發到端口 p1 上

 

  1.  
    $ ovs-appctl ofproto/trace ovs-switch in_port= 100,dl_src=66:4e:cc:ae:4d:20,
  2.  
    dl_dst= 46:54:8a:95:dd:f8 –generate
  3.  
    Flow: metadata= 0,in_port=100,vlan_tci=0x0000,dl_src=66:4e:cc:ae:4d:20,
  4.  
    dl_dst= 46:54:8a:95:dd:f8,dl_type=0x0000
  5.  
    Rule: table= 0 cookie=0 priority=3,in_port=100,vlan_tci=0x0000
  6.  
    OpenFlow actions=mod_vlan_vid: 101,NORMAL
  7.  
    forwarding to learned port
  8.  
     
  9.  
    Final flow: metadata= 0,in_port=100,dl_vlan=101,dl_vlan_pcp=0,dl_src=66:4e:cc:ae:4d:20,
  10.  
    dl_dst= 46:54:8a:95:dd:f8,dl_type=0x0000
  11.  
    Relevant fields: skb_priority= 0,in_port=100,vlan_tci=0x0000/0x1fff,dl_src=66:4e:cc:ae:4d:20,
  12.  
    dl_dst= 46:54:8a:95:dd:f8,dl_type=0x0000,nw_frag=no
  13.  
    Datapath actions: 3

 反過來從端口 p1 發送數據包,因爲 p1 如今是帶有 VLAN tag 101 的 Access 類型的端口,因此數據包進入端口 p1 以後,會被 OVS 添加 VLAN tag 101 併發送到端口 p0

 $ ovs-appctl ofproto/trace ovs-switch in_port=101,dl_dst=66:4e:cc:ae:4d:20,

  1.  
    dl_src= 46:54:8a:95:dd:f8 -generate
  2.  
    Flow: metadata= 0,in_port=101,vlan_tci=0x0000,dl_src=46:54:8a:95:dd:f8,
  3.  
    dl_dst= 66:4e:cc:ae:4d:20,dl_type=0x0000
  4.  
    Rule: table= 0 cookie=0 priority=0
  5.  
    OpenFlow actions=NORMAL
  6.  
    forwarding to learned port
  7.  
     
  8.  
    Final flow: unchanged
  9.  
    Relevant fields: skb_priority= 0,in_port=101,vlan_tci=0x0000,dl_src=46:54:8a:95:dd:f8,
  10.  
    dl_dst= 66:4e:cc:ae:4d:20,dl_type=0x0000,nw_frag=no
  11.  
    Datapath actions: push_vlan(vid= 101,pcp=0),2

 

其餘 OpenFlow 經常使用的操做

查看交換機中的全部 Table
ovs-ofctl dump-tables ovs-switch
查看交換機中的全部流表項
ovs-ofctl dump-flows ovs-switch
刪除編號爲 100 的端口上的全部流表項
ovs-ofctl del-flows ovs-switch "in_port=100"
查看交換機上的端口信息
ovs-ofctl show ovs-switch

 

 

 

 

OVS架構解析--dpdk datapath數據通路

 

https://blog.csdn.net/chen98765432101/article/details/79835435

 1.  架構說明

1.1.  總體架構

OVS(openvswitch)是開源的虛擬交換機。也是當前市場上雲環境中部署份額最大的交換機。支持 openflow協議,ovsdb協議管理。

一個OVS實例包括,ovsdb-server、ovs-vswitchd、datapath快轉模塊(linux內核中實現,可選的。dpdk模式是在用戶態實現快轉,並不須要內核態的datapath模塊)。

 

  • ovsdb-server:做用是對ovsdb操做。
  • ovs-vswitchd:核心模塊,做用是實現OpenFlow交換機、和controller通訊、和db通訊、實現用戶態轉發、和內核態快轉路徑通訊。
  • datapath:在內核空間實現報文快速轉發。

上圖從總體架構說明了ovs的工做方式。ovs包括ovsdb配置管理方式和openflow流錶轉發控制方式。

 

  1. ovsdb配置管理方式:管理者經過OVSDB管理協議管理OVS交換機。OVSDB管理協議的規範文件是RFC 7047(The Open vSwitch Database Management Protocol)。RFC7047主要包括,定義OVSDB的結構、交互協議(JSON-RPC)、DB的操做類型。
  2. openflow流表控制方式:controller控制器經過OpenFlow協議給OVS交換機下發流表,控制交換機的轉發行爲。controller不經過OVSDB,而是直接向OVS交換機下發流表。

 

1.2.  核心組件及其關聯關係

ovsdb-server和ovs-vswitchd之間是經過socket交互信息。

ovs-vswitchd經過netlink和內核態快轉模塊通訊。

好比經過ovs-vsctl命令增長ovs交換機接口,ovs-vsctl會經過ovsdb-server向ovsdb更新數據,ovs-vswitchd監測到ovsdb變化時,會更新交換機配置,好比添加接口。

dpdk方式的ovs除了不使用內核模塊外,架構和圖中相同。

1.3.    內部模塊及其關聯關係

爲了有個總體的瞭解,下面列幾張總體的架構圖,不作詳細解釋,後文會有流程解釋。
 

2.  vswitchd和ovsdb通訊

IDL:接口描述語言。IDL是用來描述軟件組件接口的一種計算機語言。IDL經過一種中立的方式來描述接口,使得在不一樣平臺上運行的對象和用不一樣語言編寫的程序能夠相互通訊交流。也就是說,用一種通用的格式,好比下面數據就是描述一個Open_vSwitch表,最後生成C語言描述的表操做.c文件
 
 
使用ovsschema格式定義數據庫表,IDL解析器會把該文件內容解析成對數據庫初始化、操做等函數,生成ovsdb-idl.c文件。
 

2.1.  創建鏈接

ovsdb_idl_create創建一個ovsdb的鏈接session,形如:idl =ovsdb_idl_create(remote, &ovsrec_idl_class, true, true)。

remote相似:unix:/var/run/openvswitch/db.sock。

後續使用該idl(struct ovsdb_idl)和ovsdb通訊,更新數據。

2.2.  接收數據

使用jsonrpc_session_recv函數接收數據,形如:msg = jsonrpc_session_recv(idl->session)。

接收消息的結構是:

struct jsonrpc_msg {

    enum jsonrpc_msg_type type;

    char *method;              /* Request or notification only. */

    struct json *params;       /* Request or notification only. */

    struct json *result;       /* Successful reply only. */

    struct json *error;         /* Error reply only. */

    struct json *id;           /* Request or reply only. */

};

 

其中type是JSON-RPC 1.0定義的消息類型,包括request、notification、reply、error:

/* Messages. */

enum jsonrpc_msg_type {

    JSONRPC_REQUEST,          /* Request. */

    JSONRPC_NOTIFY,           /* Notification.*/

    JSONRPC_REPLY,            /* Successfulreply. */

   JSONRPC_ERROR              /* Error reply. */

};

 

params、result、error、id是不一樣類型的消息對應的消息數據。

當解析消息後,監測到須要更新本地數據時,調用ovsdb_idl_parse_update函數,解析消息並更新本地數據。
 

2.3.  json數據解析

 

/* A JSON value. */

struct json {

    enum json_type type;

    union {

        struct shash *object;  /* Contains "struct json *"s. */

        struct json_array array;

        long long int integer;

        double real;

        char *string;

    } u;

};

 

type字段:說明了該json數據是聯合體中的哪種類型。

/* Type of a JSON value. */

enum json_type {

    JSON_NULL,                 /* null */

    JSON_FALSE,                /* false */

    JSON_TRUE,                 /* true */

    JSON_OBJECT,               /* {"a": b, "c": d, ...}*/

    JSON_ARRAY,                /* [1, 2, 3, ...] */

    JSON_INTEGER,              /* 123. */

    JSON_REAL,                 /* 123.456. */

    JSON_STRING,               /* "..." */

    JSON_N_TYPES

};

 

聯合體u:表示數據能夠解析的類型。

例如,當type是JSON_OBJECT類型時,且是update2更新操做,那麼object字段保存着多個數據表,每張表數據中又攜帶着待更新的多個row數據,和每row對應的操做(modify、insert、delete、initial)。而後遍歷每一個表的每行數據,並執行對應的數據操做(modify、insert、delete、initial)對本地數據更新。

注:本地數據和遠端的OVSDB並不相同,本地數據是vswitchd從數據庫取出數據後臨時放到本地結構中的。

2.4.  更新數據改變標記

當監聽到ovsdb-server發來的rpc消息時,若是數據庫發送改變就改變對應的change_seqno。後續vswitchd根據change_seqno的值是否發生了變化,決定是否從新配置ovs交換機。

3.  dpdk加速處理

3.1.  ovs dpdk加速配置

在使用dpdk 類型的datapath加速以前,須要設置dpdk-init=true啓動參數。

設置方法:

ovs-vsctl --no-wait set Open_vSwitch .other_config:dpdk-init=true

設置dpdk的相關參數,都經過other_config選項完成。

主要的參數有:

 

  • dpdk-init

 

指定ovs是否初始化和支持dpdk端口。

 

  • dpdk-lcore-mask

 

指明dpdk使用的邏輯核。同dpdk的-c參數。

 

  • dpdk-socket-mem

 

指明不一樣numa節點提早申請的大頁內存。同dpdk的--socket-mem參數。

 

  • dpdk-hugepage-dir

 

大頁文件系統mount的目錄。同dpdk的--huge-dir參數。

 

  • vhost-sock-dir

 

設置vhost-user 套接字的路徑。

 

  • dpdk-extra

 

其餘的dpdk配置參數。

3.2.  dpdk初始化

 

主要包括:

1)    dpdk eal初始化。

2)    啓動dpdk接口狀態監控線程(使用dpdk的庫函數),若是狀態發送變化,則更新netdev設備的變化標記。

3)     註冊dpdk類型的netdev class。其中包括dpdk設備類型,ring類型、vhost、vhost client類型。

 

4.  數據結構抽象關係

4.1.  分層抽象

 
 

 

  • ofproto  class

 

openflow交換機實現類,用來實現一個openflow交換機。主要包括建立、構造、操做openflowflow等相關方法。

 

  • dpif  class

 

datapath接口類,用來和datapath交互。主要包括datapath的open、run、端口操做、端口數據監聽等相關方法。datapath是數據面的一種抽象。

 

  • netdev  class

 

網絡設備抽象類,用來和網絡設備交互。主要包括網卡的設置、網卡結構的抽象、數據包發送接收等相關方法。

 

 

  • ofproto  class

 

openflow交換機實現類,用來實現一個openflow交換機。主要包括建立、構造、操做openflowflow等相關方法。

 

  • dpif  class

 

datapath接口類,用來和datapath交互。主要包括datapath的open、run、端口操做、端口數據監聽等相關方法。datapath是數據面的一種抽象。

 

  • netdev  class

 

網絡設備抽象類,用來和網絡設備交互。主要包括網卡的設置、網卡結構的抽象、數據包發送接收等相關方法。

 

bridge網橋經過ofproto  class構造一個openflow交換機。再經過dpif  class打開(若是沒有對應類型的datapath,就建立一個)對應類型的datapath通路。使用netdev  class構造一個抽象網絡設備,上層抽象爲端口,而後對網絡設備收發包等操做。

         須要說明的是,datapath是按類型分類的,如今ovs有兩種類型的datapath:system(對應linux內核數據通路)、netdev(dpdk用戶態數據通路)。因此使用同一種datapath類型的ovs網橋共享同一個datapath對象。以下圖所示。

 


 

4.2.  主要數據結構關係

該部分說明的內容是關於dpdk類型的datapath。

 

 

注:A  B,表示A是一個變量而非指針,它的結構和內容是B。

流程解釋以下:

1)        bridge層

 

1.1    struct  bridge對應每一個ovs網橋最上層的結構。它經過成員指針變量ofproto,聯繫到struct  ofproto交換機結構內容。

 

2)        ofproto層

 

2.1   因爲聯繫到的struct ofproto內容是struct ofproto_dpif結構的一個up成員變量。因此經過struct ofproto地址能夠cast到struct ofproto_dpif結構內容,經過該內容和dpif層交互。

 

2.2   經過struct ofproto_dpif的成員指針變量dpif_backer,聯繫到struct  dpif_backer結構內容。該結構是dpif操做的入口點。

 

3)        dpif層

 

3.1   經過struct  dpif_backer的成員指針變量dpif,聯繫到structdpif結構內容。

 

3.2  因爲struct dpif結構內容是struct  dpif_netdev結構的dpif成員變量,因此經過structdpif地址能夠cast到struct dpif_netdev結構內容。

 

3.3   struct dpif_netdev結構內容中有指針成員變量dp,經過dp能夠聯繫到struct  dp_netdev結構內容。該內容是datapath的抽象結構內容。

 

4)        datapath層

 

4.1  struct  dp_netdev的成員指針變量ports是一個表結構,它聯繫着多個port端口內容。端口的結構是struct  dp_netdev_port。struct  dp_netdev另一個成員指針變量netdev,聯繫着dp層的struct  netdev結構內容,該結構內容是網卡的邏輯抽象。

 

4.2  struct  dp_netdev_port的指針成員變量rxqs也是一個表結構,它聯繫着多個隊列內容。隊列的結構是struct  dp_netdev_rxq.它的成員變量core_id表示該隊列所在的core。

 

4.3   經過struct dp_netdev_rxq的成員指針變量rxq,聯繫到dp層的struct  netdev_rxq結構內容。structdp_netdev_rxq的成員變量queue_id表示該隊列id。

 

5)        netdev層

 

5.1   因爲struct  netdev結構內容是struct  netdev_dpdk結構的一個up成員變量。因此經過struct  netdev地址能夠cast到struct  netdev_dpdk結構內容。

 

5.2    經過struct  detdev_dpdk結構內容的成員指針變量netdev_class和dpdk類型網卡交互。

5.3   因爲struct netdev_rxq結構內容是struct netdev_rxq_dpdk結構內容的一個up成員變量。因此經過struct netdev_rxq地址能夠cast到struct netdev_rxq_dpdk結構內容。該內容是dpdk類型的netdev_rxq,它的成員變量port_id是dpdk網絡設備的port。

 

 

5.  vswitchd啓動

簡要的歸納下vswitchd啓動的內容。

1)   和ovsdb-server通訊初始化,創建

2)   dpdk初始化

3)   ofproto(OpenFlow交換機)初始化

4)   netdev初始化

5)   網橋配置

 

更新網橋(添加、刪除)

 

更新端口

 

建立ofproto(OpenFlow交換機),建立或打開dpif_backer

 

添加端口,添加到pmd中

 

配置網橋、端口屬性

 

datapath run

 

dp_netdev的pmd更新

 

dpif_run(運行dpif-netdev的datapath,配置netdev等,接收發送報文)

 

ofproto run,配置ofproto須要的參數和功能(netflow、sflow、ipfix、mac學習)

 

OpenFlow控制器鏈接相關run

 

 

 

6.  附錄-數據結構查詢

6.1.  ofproto_class

是一個OpenFlow交換機的實現類結構,提供的類功能不少,主要分爲:

1.        工廠函數功能。如初始化、枚舉支持的datapath類型。

2.        datapath類型處理。

3.        OpenFlow交換機功能。如構造、運行等。

4.        OpenFlow流表功能。

5.        OpenFlow配置。

6.        OpenFlow計量。

7.        OpenFlow 1.1 group功能。

8.        獲取datapath信息功能。

9.        鏈接表功能。

 

 

6.2.  dpif_class

datapath接口實現類,每種datapath都有對應的接口實現實例。dpif有兩種實現類:dpif_netlink_class、dpif_netdev_class。即system、netdev。好比,dpdk的netdevdatapath類型的實現實例dpif_netdev_class。

 

 

6.3.  netdev_class

網絡設備實現類。包括抽象的設備結構和收發包功能。

6.4.  bridge

6.5.  ofproto

6.6.  port

6.7.  iface

6.8.  ofport

6.9.  ofport_dpif

6.10.  ofproto_port

6.11.  dpif_port

dp向dpif返回的端口信息。

6.12.  ofproto_dpif

6.13.  dpif_backer

datapath類型共享實現實例。

6.14.  udpif

6.15.  dpif

datapath接口。

6.16.  dpif_netdev

netdev類型的datapath的接口。

6.17.  dp_netdev

基於網絡設備接口的datapath。

6.18.  dp_netdev_port

基於netdev類型的datapath的端口。

掛載在dp_netdev的ports成員中。

6.19.  netdev

抽象的網絡設備。

6.20.  netdev_dpdk

dpdk類型的netdev結構,繼承自netdev結構。

6.21.  dp_netdev_rxq

用來表示core和隊列的對應關係。

6.22.  netdev_rxq

網絡設備的收包隊列結構,以隊列區分。

6.23.  netdev_rxq_dpdk

dpdk的收包隊列結構,繼承自netdev_rxq.

端口號和netdev_dpdk中的端口號相同。

使用dpdk的接口函數rte_zmalloc申請,受dpdk的內存管理控制。

6.24.  dp_netdev_pmd_thread

6.25.  rxq_poll

6.26.  tx_port

 

OVS經常使用命令與使用總結

 

說明

在平時使用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
  • 1

2.建立一個網橋

ovs-vsctl add-br br0 ovs-vsctl set bridge br0 datapath_type=netdev

 

3.添加/刪除一個端口

# for system interfaces ovs-vsctl add-port br0 eth1 ovs-vsctl del-port br0 eth1 # for DPDK ovs-vsctl add-port br0 dpdk1 -- set interface dpdk1 type=dpdk options:dpdk-devargs=0000:01:00.0 # for DPDK bonds ovs-vsctl add-bond br0 dpdkbond0 dpdk1 dpdk2 \ -- set interface dpdk1 type=dpdk options:dpdk-devargs=0000:01:00.0 \ -- set interface dpdk2 type=dpdk options:dpdk-devargs=0000:02:00.0

 

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

# ICMP ovs-ofctl add-flow br0 ip,in_port=1,nw_proto=1,actions=output:2

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

# 匹配源tcp端口179 ovs-ofctl add-flow br0 tcp,tcp_src=179/0xfff0,actions=output:2 # 匹配目的tcp端口179 ovs-ofctl add-flow br0 tcp,tcp_dst=179/0xfff0,actions=output:2 # 匹配源udp端口1234 ovs-ofctl add-flow br0 udp,udp_src=1234/0xfff0,actions=output:2 # 匹配目的udp端口1234 ovs-ofctl add-flow br0 udp,udp_dst=1234/0xfff0,actions=output:2

 

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

# 匹配tunnel id ovs-ofctl add-flow br0 in_port=1,tun_id=0x7/0xf,actions=output:2 # 匹配tunnel源IP ovs-ofctl add-flow br0 in_port=1,tun_src=192.168.1.0/255.255.255.0,actions=output:2 # 匹配tunnel目的IP ovs-ofctl add-flow br0 in_port=1,tun_dst=192.168.1.0/255.255.255.0,actions=output:2

一些匹配項的速記符

速記符 匹配項
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

# 修改源MAC ovs-ofctl add-flow br0 in_port=1,actions=mod_dl_src:00:00:00:00:00:01,output:2 # 修改目的MAC ovs-ofctl add-flow br0 in_port=1,actions=mod_dl_dst:00:00:00:00:00:01,output:2 # 修改源IP ovs-ofctl add-flow br0 in_port=1,actions=mod_nw_src:192.168.1.1,output:2 # 修改目的IP ovs-ofctl add-flow br0 in_port=1,actions=mod_nw_dst:192.168.1.1,output:2

 

17.動做爲修改TCP/UDP/SCTP源目的端口

# 修改TCP源端口 ovs-ofctl add-flow br0 tcp,in_port=1,actions=mod_tp_src:67,output:2 # 修改TCP目的端口 ovs-ofctl add-flow br0 tcp,in_port=1,actions=mod_tp_dst:68,output:2 # 修改UDP源端口 ovs-ofctl add-flow br0 udp,in_port=1,actions=mod_tp_src:67,output:2 # 修改UDP目的端口 ovs-ofctl add-flow br0 udp,in_port=1,actions=mod_tp_dst:68,output:2

 

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字段進行操做

# 將報文源MAC複製到目的MAC字段,而且將源MAC改成00:00:00:00:00:01 ovs-ofctl add-flow br0 in_port=1,actions=move:NXM_OF_ETH_SRC[]-\>NXM_OF_ETH_DST[],mod_dl_src:00:00:00:00:00:01,output:2

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字段進行賦值操做

# push mpls label,而且把10(0xa)賦值給mpls label ovs-ofctl add-flow br0 in_port=1,actions=push_mpls:0x8847,load:0xa-\>OXM_OF_MPLS_LABEL[],output:2 # 對目的MAC進行賦值 ovs-ofctl add-flow br0 in_port=1,actions=load:0x001122334455-\>OXM_OF_ETH_DST[],output:2

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表

# 限速類型以kbps(kilobits per second)計算,超過20kb/s則丟棄 ovs-ofctl -O OpenFlow13 add-meter br0 meter=1,kbps,band=type=drop,rate=20 # 同上,增長burst size參數 ovs-ofctl -O OpenFlow13 add-meter br0 meter=2,kbps,band=type=drop,rate=20,burst_size=256 # 同上,增長stats參數,對meter進行計數統計 ovs-ofctl -O OpenFlow13 add-meter br0 meter=3,kbps,stats,band=type=drop,rate=20,burst_size=256 # 限速類型以pktps(packets per second)計算,超過1000pkt/s則丟棄 ovs-ofctl -O OpenFlow13 add-meter br0 meter=4,pktps,band=type=drop,rate=1000

5.刪除meter表

# 刪除所有meter表 ovs-ofctl -O OpenFlow13 del-meters br0 # 刪除meter id=1 ovs-ofctl -O OpenFlow13 del-meter br0 meter=1

 

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流表

# 封裝gre轉發 ovs-ofctl add-flow br0 ip,in_port=1,nw_dst=10.10.0.0/16,actions=output:1001 # 解封gre轉發 ovs-ofctl add-flow br0 in_port=1001,actions=output:1

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流表

# 封裝vxlan轉發 ovs-ofctl add-flow br0 ip,in_port=1,nw_dst=10.10.0.0/16,actions=output:2001 # 解封vxlan轉發 ovs-ofctl add-flow br0 in_port=2001,actions=output:1

sflow配置

1.對網橋br0進行sflow監控

  • agent: 與collector通訊所在的網口名,一般爲管理口
  • target: collector監聽的IP地址和端口,端口默認爲6343
  • header: sFlow在採樣時截取報文頭的長度
  • polling: 採樣時間間隔,單位爲秒
ovs-vsctl -- --id=@sflow create sflow agent=eth0 target=\"10.0.0.1:6343\" header=128 sampling=64 polling=10 -- set bridge br0 sflow=@sflow

2.查看建立的sflow

ovs-vsctl list sflow

3.刪除對應的網橋sflow配置,參數爲sFlow UUID

ovs-vsctl remove bridge br0 sflow 7b9b962e-fe09-407c-b224-5d37d9c1f2b3

4.刪除網橋下全部sflow配置

ovs-vsctl -- clear bridge br0 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.刪除端口鏡像配置

ovs-vsctl -- --id=@m get mirror mymirror -- remove bridge br0 mirrors @m

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涉及的數據結構主要有以下。

網橋數據結構

 

 

流表數據結構

 

 

流表實例數據結構

 

 

掩碼信息列表數據結構

 

 

掩碼信息緩存表數據結構

 

 

哈希桶數據結構

 

 

上述這些數據結構是在源碼中的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)初始化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用戶空間的」慢路徑」存儲的流表信息以下所示:

 

 

初始化的時候,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)。以下圖所示

 

 

As part of my work in OpenDaylight, we are looking at creating a router using Open vSwitch... Why? Well OpenStack requires some limited L3 capabilities and we think that we can handle those in a distributed router.

Test Topology

My test topology looks like this:

We have a host in an external network 172.16.1.0/24, one host in an internal network 10.10.10.0/24 and two hosts in another internal network 10.10.20.0/24.

As such, The hosts in the 10.x.x.x range should be able to speak to each other, but should not be able to speak to external hosts.

The host 10.10.10.2 has a floating IP of 172.16.1.10 and should be reachable on this address from the external 172.16.1.0/24network. To do this, we'll use DNAT for traffic from 172.16.1.2 -> 172.16.1.10 and SNAT for traffic back from10.10.10.2 -> 172.16.1.2

If you'd like to recreate this topology you can checkout the OpenDaylight OVSDB project source on GitHub and:

vagrant up mininet
vagrant ssh mininet
cd /vagrant/resources/mininet
sudo mn --custom topo.py --topo l3

The Pipeline

Our router is implemented using the following pipeline:

Table 0 - Classifier

In this table we work out what traffic is interesting for us before pushing it further along the pipeline

Table 100 - ACL

While we don't use this table today, the idea would be to filter traffic in this table (or series of tables) and to then resubmit to the classifier once we have scrubbed them.

Table 105 - ARP Responder

In this table we use some OVS-Jitsu to take an incoming ARP Request and turn it in to an ARP reply

Table 5 - L3 Rewrite

In this table, we make any L3 modifications we need to before a packet is routed

Table 10 - L3 Routing

The L3 routing table is where the routing magic happens. Here we modify the Source MAC address, Decrement the TTL and push to the L2 tables for forwarding

Table 15 - L3 Forwarding

In the L3 forwarding table we resolve a destination IP address to the correct MAC address for L2 forwarding.

Table 20 - L2 Rewrites

While we aren't using this table in this example, typically we would push/pop any L2 encapsulations here like a VLAN tag or a VXLAN/GRE Tunnel ID.

Table 25 - L2 Forwarding

In this table we do our L2 lookup and forward out the correct port. We also handle L2 BUM traffic here using OpenFlow Groups - no VLANs!

The Flows

To program the flows, paste the following in to mininet:

複製代碼
## Set Bridge to use OpenFlow 1.3
sh ovs-vsctl set Bridge s1 "protocols=OpenFlow13"

## Create Groups
sh ovs-ofctl add-group -OOpenFlow13 s1 group_id=1,type=all,bucket=output:1
sh ovs-ofctl add-group -OOpenFlow13 s1 group_id=2,type=all,bucket=output:2,4
sh ovs-ofctl add-group -OOpenFlow13 s1 group_id=3,type=all,bucket=output:3

## Table 0 - Classifier
# Send ARP to ARP Responder
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=0, priority=1000, dl_type=0x0806, actions=goto_table=105"
# Send L3 traffic to L3 Rewrite Table
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=0, priority=100, dl_dst=00:00:5E:00:02:01, action=goto_table=5"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=0, priority=100, dl_dst=00:00:5E:00:02:02, action=goto_table=5"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=0, priority=100, dl_dst=00:00:5E:00:02:03, action=goto_table=5"
# Send L3 to L2 Rewrite Table
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=0, priority=0, action=goto_table=20"

## Table 5 - L3 Rewrites
# Exclude connected subnets
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=5, priority=65535, dl_type=0x0800, nw_dst=10.10.10.0/24 actions=goto_table=10"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=5, priority=65535, dl_type=0x0800, nw_dst=10.10.20.0/24 actions=goto_table=10"
# DNAT
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=5, priority=100, dl_type=0x0800,  nw_dst=172.16.1.10 actions=mod_nw_dst=10.10.10.2, goto_table=10"
# SNAT
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=5, priority=100, dl_type=0x0800,  nw_src=10.10.10.2, actions=mod_nw_src=172.16.1.10,  goto_table=10"
# If no rewrite needed, continue to table 10
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=5, priority=0, actions=goto_table=10"

## Table 10 - IPv4 Routing
sh  ovs-ofctl add-flow -OOpenFlow13 s1 "table=10, dl_type=0x0800, nw_dst=10.10.10.0/24, actions=mod_dl_src=00:00:5E:00:02:01, dec_ttl, goto_table=15"
sh  ovs-ofctl add-flow -OOpenFlow13 s1 "table=10, dl_type=0x0800, nw_dst=10.10.20.0/24, actions=mod_dl_src=00:00:5E:00:02:02, dec_ttl, goto_table=15"
sh  ovs-ofctl add-flow -OOpenFlow13 s1 "table=10, dl_type=0x0800, nw_dst=172.16.1.0/24, actions=mod_dl_src=00:00:5E:00:02:03, dec_ttl, goto_table=15"
# Explicit drop if cannot route
sh  ovs-ofctl add-flow -OOpenFlow13 s1 "table=10, priority=0, actions=output:0"

## Table 15 - L3 Forwarding
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=15, dl_type=0x0800, nw_dst=10.10.10.2, actions=mod_dl_dst:00:00:00:00:00:01, goto_table=20"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=15, dl_type=0x0800, nw_dst=10.10.20.2, actions=mod_dl_dst:00:00:00:00:00:02, goto_table=20"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=15, dl_type=0x0800, nw_dst=10.10.20.4, actions=mod_dl_dst:00:00:00:00:00:04, goto_table=20"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=15, dl_type=0x0800, nw_dst=172.16.1.2, actions=mod_dl_dst:00:00:00:00:00:03, goto_table=20"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=15, priority=0, actions=goto_table=20"

## Table 20 - L2 Rewrite
# Go to next table
sh  ovs-ofctl add-flow -OOpenFlow13 s1 "table=20, priority=0, actions=goto_table=25"

## Table 25 - L2 Forwarding
# Use groups for BUM traffic
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=25, in_port=1, dl_dst=01:00:00:00:00:00/01:00:00:00:00:00, actions=group=1"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=25, in_port=2, dl_dst=01:00:00:00:00:00/01:00:00:00:00:00, actions=group=2"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=25, in_port=3, dl_dst=01:00:00:00:00:00/01:00:00:00:00:00, actions=group=3"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=25, in_port=4, dl_dst=01:00:00:00:00:00/01:00:00:00:00:00, actions=group=2"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=25, dl_dst=00:00:00:00:00:01,actions=output=1"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=25, dl_dst=00:00:00:00:00:02,actions=output=2"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=25, dl_dst=00:00:00:00:00:03,actions=output=3"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=25, dl_dst=00:00:00:00:00:04,actions=output=4"

## Table 105 - ARP Responder
# Respond to ARP for Router Addresses
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=105, dl_type=0x0806, nw_dst=10.10.10.1, actions=move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[], mod_dl_src:00:00:5E:00:02:01, load:0x2->NXM_OF_ARP_OP[], move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[], move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[], load:0x00005e000201->NXM_NX_ARP_SHA[], load:0x0a0a0a01->NXM_OF_ARP_SPA[], in_port"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=105,  dl_type=0x0806, nw_dst=10.10.20.1, actions=move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],  mod_dl_src:00:00:5E:00:02:02, load:0x2->NXM_OF_ARP_OP[], move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[], move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[], load:0x00005e000202->NXM_NX_ARP_SHA[], load:0xa0a1401->NXM_OF_ARP_SPA[], in_port"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=105,  dl_type=0x0806, nw_dst=172.16.1.1, actions=move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],  mod_dl_src:00:00:5E:00:02:03, load:0x2->NXM_OF_ARP_OP[], move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[], move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[], load:0x00005e000203->NXM_NX_ARP_SHA[], load:0xac100101->NXM_OF_ARP_SPA[], in_port"
# Proxy ARP for all floating IPs go below
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=105, dl_type=0x0806, nw_dst=172.16.1.10, actions=move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[], mod_dl_src:00:00:5E:00:02:03, load:0x2->NXM_OF_ARP_OP[], move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[], move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[], load:0x00005e000203->NXM_NX_ARP_SHA[], load:0xac10010a->NXM_OF_ARP_SPA[], in_port"
# if we made it here, the arp packet is to be handled as any other regular L2 packet
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=105, priority=0, action=resubmit(,20)"
複製代碼

If you'd like to paste these in without comments, you can use this Gist

Testing

We can run a pingall to test this out:

複製代碼
mininet> pingall
*** Ping: testing ping reachability
h1 -> h2 h3 h4
h2 -> h1 X h4
h3 -> X X X
h4 -> h1 h2 X
*** Results: 41% dropped (7/12 received)
複製代碼

hosts 1,2 and 4 can speak to each other. Everything initiated by h3 is dropped (as expected) but h1 can speak to h3 (thanks to NAT). We can test our DNAT and Proxy ARP for Floating IP's using this command:

複製代碼
mininet> h3 ping 172.16.1.10
PING 172.16.1.10 (172.16.1.10) 56(84) bytes of data.
64 bytes from 172.16.1.10: icmp_seq=1 ttl=63 time=1.30 ms
64 bytes from 172.16.1.10: icmp_seq=2 ttl=63 time=0.043 ms
64 bytes from 172.16.1.10: icmp_seq=3 ttl=63 time=0.045 ms
64 bytes from 172.16.1.10: icmp_seq=4 ttl=63 time=0.050 ms
^C
--- 172.16.1.10 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.043/0.360/1.305/0.545 ms
複製代碼

Cool! It works!

Conclusion

So far we've implemented the nuts and bolts of routing, but we are missing one crucial piece - ICMP handling. Without this useful things like Path MTU Discovery won't work and neither will diagnostics tools like Ping and Traceroute. I think we can do this using a Open vSwitch but first we'll need to add some new NXM fields to ICMP Data and ICMP Checksum and to also make the existing OXM's writable through set_field. I'm going to start talking to the OVS community about this to see if it's possible so watch this space!

@dave_tucker

Helpful Links and Further Reading

ovs-ofctl Man Page Neutron ARP Responder Write Up Address Resolution Protocol OpenFlow 1.3.1 Spec

基於Open vSwitch搭建虛擬路由器

 

As part of my work in OpenDaylight, we are looking at creating a router using Open vSwitch... Why? Well OpenStack requires some limited L3 capabilities and we think that we can handle those in a distributed router.

Test Topology

My test topology looks like this:

We have a host in an external network 172.16.1.0/24, one host in an internal network 10.10.10.0/24 and two hosts in another internal network 10.10.20.0/24.

As such, The hosts in the 10.x.x.x range should be able to speak to each other, but should not be able to speak to external hosts.

The host 10.10.10.2 has a floating IP of 172.16.1.10 and should be reachable on this address from the external 172.16.1.0/24network. To do this, we'll use DNAT for traffic from 172.16.1.2 -> 172.16.1.10 and SNAT for traffic back from10.10.10.2 -> 172.16.1.2

If you'd like to recreate this topology you can checkout the OpenDaylight OVSDB project source on GitHub and:

vagrant up mininet
vagrant ssh mininet
cd /vagrant/resources/mininet
sudo mn --custom topo.py --topo l3

The Pipeline

Our router is implemented using the following pipeline:

Table 0 - Classifier

In this table we work out what traffic is interesting for us before pushing it further along the pipeline

Table 100 - ACL

While we don't use this table today, the idea would be to filter traffic in this table (or series of tables) and to then resubmit to the classifier once we have scrubbed them.

Table 105 - ARP Responder

In this table we use some OVS-Jitsu to take an incoming ARP Request and turn it in to an ARP reply

Table 5 - L3 Rewrite

In this table, we make any L3 modifications we need to before a packet is routed

Table 10 - L3 Routing

The L3 routing table is where the routing magic happens. Here we modify the Source MAC address, Decrement the TTL and push to the L2 tables for forwarding

Table 15 - L3 Forwarding

In the L3 forwarding table we resolve a destination IP address to the correct MAC address for L2 forwarding.

Table 20 - L2 Rewrites

While we aren't using this table in this example, typically we would push/pop any L2 encapsulations here like a VLAN tag or a VXLAN/GRE Tunnel ID.

Table 25 - L2 Forwarding

In this table we do our L2 lookup and forward out the correct port. We also handle L2 BUM traffic here using OpenFlow Groups - no VLANs!

The Flows

To program the flows, paste the following in to mininet:

複製代碼
複製代碼
## Set Bridge to use OpenFlow 1.3
sh ovs-vsctl set Bridge s1 "protocols=OpenFlow13"

## Create Groups
sh ovs-ofctl add-group -OOpenFlow13 s1 group_id=1,type=all,bucket=output:1
sh ovs-ofctl add-group -OOpenFlow13 s1 group_id=2,type=all,bucket=output:2,4
sh ovs-ofctl add-group -OOpenFlow13 s1 group_id=3,type=all,bucket=output:3

## Table 0 - Classifier
# Send ARP to ARP Responder
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=0, priority=1000, dl_type=0x0806, actions=goto_table=105"
# Send L3 traffic to L3 Rewrite Table
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=0, priority=100, dl_dst=00:00:5E:00:02:01, action=goto_table=5"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=0, priority=100, dl_dst=00:00:5E:00:02:02, action=goto_table=5"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=0, priority=100, dl_dst=00:00:5E:00:02:03, action=goto_table=5"
# Send L3 to L2 Rewrite Table
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=0, priority=0, action=goto_table=20"

## Table 5 - L3 Rewrites
# Exclude connected subnets
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=5, priority=65535, dl_type=0x0800, nw_dst=10.10.10.0/24 actions=goto_table=10"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=5, priority=65535, dl_type=0x0800, nw_dst=10.10.20.0/24 actions=goto_table=10"
# DNAT
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=5, priority=100, dl_type=0x0800,  nw_dst=172.16.1.10 actions=mod_nw_dst=10.10.10.2, goto_table=10"
# SNAT
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=5, priority=100, dl_type=0x0800,  nw_src=10.10.10.2, actions=mod_nw_src=172.16.1.10,  goto_table=10"
# If no rewrite needed, continue to table 10
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=5, priority=0, actions=goto_table=10"

## Table 10 - IPv4 Routing
sh  ovs-ofctl add-flow -OOpenFlow13 s1 "table=10, dl_type=0x0800, nw_dst=10.10.10.0/24, actions=mod_dl_src=00:00:5E:00:02:01, dec_ttl, goto_table=15"
sh  ovs-ofctl add-flow -OOpenFlow13 s1 "table=10, dl_type=0x0800, nw_dst=10.10.20.0/24, actions=mod_dl_src=00:00:5E:00:02:02, dec_ttl, goto_table=15"
sh  ovs-ofctl add-flow -OOpenFlow13 s1 "table=10, dl_type=0x0800, nw_dst=172.16.1.0/24, actions=mod_dl_src=00:00:5E:00:02:03, dec_ttl, goto_table=15"
# Explicit drop if cannot route
sh  ovs-ofctl add-flow -OOpenFlow13 s1 "table=10, priority=0, actions=output:0"

## Table 15 - L3 Forwarding
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=15, dl_type=0x0800, nw_dst=10.10.10.2, actions=mod_dl_dst:00:00:00:00:00:01, goto_table=20"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=15, dl_type=0x0800, nw_dst=10.10.20.2, actions=mod_dl_dst:00:00:00:00:00:02, goto_table=20"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=15, dl_type=0x0800, nw_dst=10.10.20.4, actions=mod_dl_dst:00:00:00:00:00:04, goto_table=20"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=15, dl_type=0x0800, nw_dst=172.16.1.2, actions=mod_dl_dst:00:00:00:00:00:03, goto_table=20"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=15, priority=0, actions=goto_table=20"

## Table 20 - L2 Rewrite
# Go to next table
sh  ovs-ofctl add-flow -OOpenFlow13 s1 "table=20, priority=0, actions=goto_table=25"

## Table 25 - L2 Forwarding
# Use groups for BUM traffic
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=25, in_port=1, dl_dst=01:00:00:00:00:00/01:00:00:00:00:00, actions=group=1"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=25, in_port=2, dl_dst=01:00:00:00:00:00/01:00:00:00:00:00, actions=group=2"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=25, in_port=3, dl_dst=01:00:00:00:00:00/01:00:00:00:00:00, actions=group=3"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=25, in_port=4, dl_dst=01:00:00:00:00:00/01:00:00:00:00:00, actions=group=2"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=25, dl_dst=00:00:00:00:00:01,actions=output=1"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=25, dl_dst=00:00:00:00:00:02,actions=output=2"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=25, dl_dst=00:00:00:00:00:03,actions=output=3"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=25, dl_dst=00:00:00:00:00:04,actions=output=4"

## Table 105 - ARP Responder
# Respond to ARP for Router Addresses
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=105, dl_type=0x0806, nw_dst=10.10.10.1, actions=move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[], mod_dl_src:00:00:5E:00:02:01, load:0x2->NXM_OF_ARP_OP[], move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[], move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[], load:0x00005e000201->NXM_NX_ARP_SHA[], load:0x0a0a0a01->NXM_OF_ARP_SPA[], in_port"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=105,  dl_type=0x0806, nw_dst=10.10.20.1, actions=move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],  mod_dl_src:00:00:5E:00:02:02, load:0x2->NXM_OF_ARP_OP[], move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[], move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[], load:0x00005e000202->NXM_NX_ARP_SHA[], load:0xa0a1401->NXM_OF_ARP_SPA[], in_port"
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=105,  dl_type=0x0806, nw_dst=172.16.1.1, actions=move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],  mod_dl_src:00:00:5E:00:02:03, load:0x2->NXM_OF_ARP_OP[], move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[], move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[], load:0x00005e000203->NXM_NX_ARP_SHA[], load:0xac100101->NXM_OF_ARP_SPA[], in_port"
# Proxy ARP for all floating IPs go below
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=105, dl_type=0x0806, nw_dst=172.16.1.10, actions=move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[], mod_dl_src:00:00:5E:00:02:03, load:0x2->NXM_OF_ARP_OP[], move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[], move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[], load:0x00005e000203->NXM_NX_ARP_SHA[], load:0xac10010a->NXM_OF_ARP_SPA[], in_port"
# if we made it here, the arp packet is to be handled as any other regular L2 packet
sh ovs-ofctl add-flow -OOpenFlow13 s1 "table=105, priority=0, action=resubmit(,20)"
複製代碼
複製代碼

If you'd like to paste these in without comments, you can use this Gist

Testing

We can run a pingall to test this out:

複製代碼
複製代碼
mininet> pingall
*** Ping: testing ping reachability
h1 -> h2 h3 h4
h2 -> h1 X h4
h3 -> X X X
h4 -> h1 h2 X
*** Results: 41% dropped (7/12 received)
複製代碼
複製代碼

hosts 1,2 and 4 can speak to each other. Everything initiated by h3 is dropped (as expected) but h1 can speak to h3 (thanks to NAT). We can test our DNAT and Proxy ARP for Floating IP's using this command:

複製代碼
複製代碼
mininet> h3 ping 172.16.1.10
PING 172.16.1.10 (172.16.1.10) 56(84) bytes of data.
64 bytes from 172.16.1.10: icmp_seq=1 ttl=63 time=1.30 ms
64 bytes from 172.16.1.10: icmp_seq=2 ttl=63 time=0.043 ms
64 bytes from 172.16.1.10: icmp_seq=3 ttl=63 time=0.045 ms
64 bytes from 172.16.1.10: icmp_seq=4 ttl=63 time=0.050 ms
^C
--- 172.16.1.10 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.043/0.360/1.305/0.545 ms
複製代碼
複製代碼

Cool! It works!

Conclusion

So far we've implemented the nuts and bolts of routing, but we are missing one crucial piece - ICMP handling. Without this useful things like Path MTU Discovery won't work and neither will diagnostics tools like Ping and Traceroute. I think we can do this using a Open vSwitch but first we'll need to add some new NXM fields to ICMP Data and ICMP Checksum and to also make the existing OXM's writable through set_field. I'm going to start talking to the OVS community about this to see if it's possible so watch this space!

@dave_tucker

Helpful Links and Further Reading

ovs-ofctl Man Page Neutron ARP Responder Write Up Address Resolution Protocol OpenFlow 1.3.1 Spec

 

openstack的虛擬機網卡、網橋等(tap、qbr、qvb、qvo)mtu設置

 
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值都會被同時設置成相應的值。
驗證結束。
 





openstack底層技術-使用openvswitch

 

原文地址

www.isjian.com/openstack/openstack-base-use-openvswitch

 

 

openstack底層技術-使用openvswitch

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主機上,下面分別介紹圖中各組件

ovs1

ovs-vswitchd

ovs-vswitchd守護進程是OVS的核心部件,它和datapath內核模塊一塊兒實現OVS基於流的數據交換。做爲核心組件,它使用openflow協議與上層OpenFlow控制器通訊,使用OVSDB協議與ovsdb-server通訊,使用netlinkdatapath內核模塊通訊。ovs-vswitchd在啓動時會讀取ovsdb-server中配置信息,而後配置內核中的datapaths和全部OVS switches,當ovsdb中的配置信息改變時(例如使用ovs-vsctl工具),ovs-vswitchd也會自動更新其配置以保持與數據庫同步

# ps -ef |grep ovs-vs root 22176 22175 0 Jan17 ? 00:16:56 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-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,來看一張更詳細的架構圖,圖中的大部分組件上面都有提到

ovs1

用戶空間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-vswitchdovs-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-tunbr-intbr-ext

添加一個網橋br0

ovs-vsctl add-br br0 

Port

端口Port與物理交換機的端口概念相似,Port是OVS Bridge上建立的一個虛擬端口,每一個Port都隸屬於一個Bridge。Port有如下幾種類型

  • Normal

能夠把操做系統中已有的網卡(物理網卡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

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中

  • Patch

當主機中有多個ovs網橋時,可使用Patch Port把兩個網橋連起來。Patch Port老是成對出現,分別鏈接在兩個網橋上,從一個Patch Port收到的數據包會被轉發到另外一個Patch Port,相似於Linux系統中的veth。使用Patch鏈接的兩個網橋跟一個網橋沒什麼區別,OpenStack Neutron中使用到了Patch Port。上面網橋br-ext中的Port phy-br-extbr-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同樣,只是性能會有差異

#建立veth設備對veth-a,veth-b ip link add veth-a type veth peer name veth-b #使用Veth鏈接兩個網橋 ovs-vsctl add-port br0 veth-a ovs-vsctl add-port br1 veth-b 
  • Tunnel

OVS中支持添加隧道(Tunnel)端口,常見隧道技術有兩種grevxlan。隧道技術是在現有的物理網絡之上構建一層虛擬網絡,上層應用只與虛擬網絡相關,以此實現的虛擬網絡比物理網絡配置更加靈活,並可以實現跨主機的L2通訊以及必要的租戶隔離。不一樣隧道技術其大致思路均是將以太網報文使用隧道協議封裝,而後使用底層IP網絡轉發封裝後的數據包,其差別性在於選擇和構造隧道的協議不一樣。Tunnel在OpenStack中用做實現大二層網絡以及租戶隔離,以應對公有云大規模,多租戶的複雜網絡環境。

OpenStack是多節點結構,同一子網的虛擬機可能被調度到不一樣計算節點上,所以須要有隧道技術來保證這些同子網不一樣節點上的虛擬機可以二層互通,就像他們鏈接在同一個交換機上,同時也要保證能與其它子網隔離。

OVS在計算和網絡節點上創建隧道Port來鏈接各節點上的網橋br-int,這樣全部網絡和計算節點上的br-int互聯造成了一個大的虛擬的跨全部節點的邏輯網橋(內部靠tunnel id或VNI隔離不一樣子網),這個邏輯網橋對虛擬機和qrouter是透明的,它們以爲本身鏈接到了一個大的br-int上。從某個計算節點虛擬機發出的數據包會被封裝進隧道經過底層網絡傳輸到目的主機而後解封裝。

上面網橋br-tunPort "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

  • OpenFlow flows

OVS中最重要的一種flows,Controller控制器下發的就是這種flows,OVS架構部分已經簡單介紹過,關於openflow的具體使用,會在另外一篇文章中說明

  • 「hidden」 flows

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是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-clientovsdb-server進程的命令行工具,主要是從正在運行的ovsdb-server中查詢信息,操做的是數據庫相關

#列出主機上的全部databases,默認只有一個庫Open_vSwitch ovsdb-client list-dbs #獲取指定數據庫的schema信息 ovsdb-client get-schema [DATABASE] #列出指定數據庫的全部表 ovsdb-client list-tables [DATABASE] #dump指定數據庫全部數據,默認dump全部table數據,若是指定table,只dump指定table數據 ovsdb-client dump [DATABASE] [TABLE] #監控指定數據庫中的指定表記錄改變 ovsdb-client monitor DATABASE TABLE 

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/

相關文章
相關標籤/搜索