精华内容
下载资源
问答
  • 在本篇文章中,我将解释什么是Logical Flow以及如何使用ovn-trace去更好地理解它们。同时,我也会用一些例子来解释,为什么使用Logical Flow这种抽象模型能让新特性添加变得出乎意料简单。 But First, OpenFlow...

    在本篇文章中,我将解释什么是Logical Flow以及如何使用ovn-trace去更好地理解它们。同时,我也会用一些例子来解释,为什么使用Logical Flow这种抽象模型能让新特性的添加变得出乎意料的简单。

    But First, OpenFlow Basics

    在深入Logical Flow之前,对于OpenFlow有一个基本的了解是非常必要的。OpenFlow是一个用来对Open vSwitch的packet processing pipeline进行编辑的协议。它能够让你定义一系列伴有rule(flow)的table,每个rule中还包含了priority,match,和一系列的action。对于每个table,能够匹配的flow中优先级最高(数字越大,优先级越高)的将被执行。

    首先,让我们来想象一个简单的virtual switch,它有着两个端口,port1和port2

                            +--------+
                (1)         |        |          (2)
               port1 -------| br-int |-------- port2
                            |        |
                            +--------+


    我们可以用以下命令创建一个有着两个port的bridge:

    $ ovs-vsctl add-br br-int
    $ ovs-vsctl add-port br-int port1
    $ ovs-vsctl add-port br-int port2
    
    $ ovs-vsctl show
    3b1995d8-9683-45db-8929-36c62abdbd31
        Bridge br-int
            Port "port1"
                Interface "port1"
            Port br-int
                Interface br-int
                    type: internal
            Port "port2"
                Interface "port2"
    

      

    最简单的例子是创建一个table让所有从port1进入的包转发到port2,所有从port2进入的包转发到port1

        Table  Priority  Match      Actions
        -----  --------  ---------- -------
        0      0         in_port=1  output:2
        0      0         in_port=2  output:1

     

    我们可以用ovs-ofctl命令来编辑ovs中的pipeline:

    $ ovs-ofctl del-flows br-int
    $ ovs-ofctl add-flow br-int
    $ ovs-ofctl add-flow br-int "table=0, priority=0, in_port=1, actions=output:2"
    $ ovs-ofctl add-flow br-int "table=0, priority=0, in_port=2, actions=output:1"
    
    $ ovs-ofctl dump-flows br-int
    NXST_FLOW reply (xid=0x4):
      cookie=0x0, duration=9.679s, table=0, n_packets=0, n_bytes=0, idle_age=9, priority=0,in_port=1 actions=output:2
      cookie=0x0, duration=2.287s, table=0, n_packets=0, n_bytes=0, idle_age=2, priority=0,in_port=2 actions=output:1
    

      

    我们还可以对这个例子进行扩展,从而来演示不同priority的使用。现在我们只允许源mac地址为00:00:00:00:01的包进入port1以及只允许源mac地址为00:00:00:00:00:02的包进入port2(basic source port security)。我们接着使用table 0来实现port security,再用table 1决定包的走向。

     

    (当然,这些都可以在一个table中完成,但是这样就不能演示table和priority的使用了,而这恰恰是这个例子的主要目的)

        Table  Priority  Match                               Actions
        -----  --------  ----------------------------------- ------------
        0      10        in_port=1,dl_src=00:00:00:00:00:01  resubmit(,1)
        0      10        in_port=2,dl_src=00:00:00:00:00:02  resubmit(,1)
        0      0                                             drop
        1      0         in_port=1                           output:2
        1      0         in_port=2                           output:1

    同样,我们使用ovs-ofctl编辑如下pipeline:

    $ ovs-ofctl del-flows br-int
    $ ovs-ofctl add-flow br-int "table=0, priority=10, in_port=1, dl_src=00:00:00:00:00:01, actions=resubmit(,1)"
    $ ovs-ofctl add-flow br-int "table=0, priority=10, in_port=2, dl_src=00:00:00:00:00:02, actions=resubmit(,1)"
    $ ovs-ofctl add-flow br-int "table=0, priority=0, actions=drop"
    $ ovs-ofctl add-flow br-int "table=1, priority=0, in_port=1,actions=output:2"
    $ ovs-ofctl add-flow br-int "table=1, priority=0, in_port=2,actions=output:1"
    
    $ ovs-ofctl dump-flows br-int
    NXST_FLOW reply (xid=0x4):
     cookie=0x0, duration=72.132s, table=0, n_packets=0, n_bytes=0, idle_age=72, priority=10,in_port=1,dl_src=00:00:00:00:00:01 actions=resubmit(,1)
     cookie=0x0, duration=60.565s, table=0, n_packets=0, n_bytes=0, idle_age=60, priority=10,in_port=2,dl_src=00:00:00:00:00:02 actions=resubmit(,1)
     cookie=0x0, duration=28.127s, table=0, n_packets=0, n_bytes=0, idle_age=28, priority=0 actions=drop
     cookie=0x0, duration=13.887s, table=1, n_packets=0, n_bytes=0, idle_age=13, priority=0,in_port=1 actions=output:2
     cookie=0x0, duration=4.023s, table=1, n_packets=0, n_bytes=0, idle_age=4, priority=0,in_port=2 actions=output:1
    

      

    Open vSwitch还提供了一种能够追踪包从整个pipeline流通路径的机制。在这里,我们将追踪一个有着期望的mac地址的包从port1流入的过程。追踪程序的输出显示包被重新提交到了table 1并且之后从port 2输出了。输出的内容有点啰嗦,我们只要看"Rule"和"OpenFlow actions"这些列就可以知道哪些flow被执行了。

    $ ovs-appctl ofproto/trace br-int in_port=1,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02 -generate
    Bridge: br-int
    Flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,dl_type=0x0000
    
    Rule: table=0 cookie=0 priority=10,in_port=1,dl_src=00:00:00:00:00:01
    OpenFlow actions=resubmit(,1)
    
        Resubmitted flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,dl_type=0x0000
        Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0 reg8=0x0 reg9=0x0 reg10=0x0 reg11=0x0 reg12=0x0 reg13=0x0 reg14=0x0 reg15=0x0
        Resubmitted  odp: drop
        Resubmitted megaflow: recirc_id=0,in_port=1,dl_src=00:00:00:00:00:01,dl_type=0x0000
        Rule: table=1 cookie=0 priority=0,in_port=1
        OpenFlow actions=output:2
    
    Final flow: unchanged
    Megaflow: recirc_id=0,in_port=1,dl_src=00:00:00:00:00:01,dl_type=0x0000
    Datapath actions: 3
    

      

    OpenFlow可以用来构建更加复杂的pipeline。如果想知道更多细节,参见ovs-ofctl(8) man page。

     

    OVN Logical Flows

    上一节对OpenFlow进行了概述,展示了如何使用OpenFlow在单个switch里面构建packet processing pipelines。即使只在一台机器上对这些pipeline进行配置都让人觉得很麻烦,更不要说配置成千上万的机器了。但是只要有一个SDN controller,我们就能轻松地对许多switch进行配置,而这正是OVN在Open vSwtich这个项目中扮演的角色。OVN会完成所有OpenFlow的配置工作,用以实现你通过高层的接口配置的network topologies以及security policies。

    那么OVN是怎么知道每台机器上需要的flow的呢?OVN解决这个问题的核心抽象模型就是Logical Flow。从概念上来说,Logical Flows和OpenFlow是类似的,它们都由table组成,table中包含flow,每个flow都有priority,match和action。两者最大的不同是,logical flow对整个网络的行为进行了详细地描述并且能扩展到任意数量的主机上。并且它把对于具体网络行为的定义和对于现实的物理设备的布局(有多少机器以及机器端口的分布)分离了开来。

    OVN通过logical flow对网络进行编辑。之后,这些logical flow又会分发到每台机器上运行ovn-controller中。而ovn-controller知道根据当前的物理环境(本地端口在哪以及如何到达其他机器)将这些logical flow编译到OpenFlow中。

    接着让我们用OVN来创建一个和上一节类似的例子。我们要创建的是一个带有两个logical ports的OVN logical switch。

    $ ovn-nbctl ls-add sw0
    
    $ ovn-nbctl lsp-add sw0 sw0-port1
    $ ovn-nbctl lsp-set-address sw0-port1 00:00:00:00:00:01
    $ ovn-nbctl lsp-set-port-security sw0-port1 00:00:00:00:00:01
    
    $ ovn-nbctl lsp-add sw0 sw0-port2
    $ ovn-nbctl lsp-set-addresses sw0-port2 00:00:00:00:00:02
    $ ovn-nbctl lsp-set-port-security sw0-port2 00:00:00:00:00:02
    
    $ ovn-nbctl show sw0
        switch 48d5f699-7ffe-4627-a369-2fc905e44b32 (sw0)
            port sw0-port1
                addresses: ["00:00:00:00:00:01"]
            port sw0-port2
                addresses: ["00:00:00:00:00:02"]
    

      

    OVN定义了一个logical switch,sw0,使用了两个pipeline:一个ingress pipeline以及一个egress pipeline。当一个包流入网络时,生成该包的机器上的ingress pipeline将被执行。如果该包的目的地是同一台机器,那么egress pipeline也将被执行。

    sw0-port1 and sw0-port2 on the same host:
    
        +--------------------------------------------------------------------------+
        |                                                                          |
        |                               Host A                                     |
        |                                                                          |
        |   +---------+                                              +---------+   |
        |   |sw0-port1| --> ingress pipeline --> egress pipeline --> |sw0-port2|   |
        |   +---------+                                              +---------+   |
        |                                                                          |
        +--------------------------------------------------------------------------+

    如果该包的目的地在远程机器上,那么该包首先要经过一个tunnel进行传输,然后在远程机器上执行egress pipeline

    sw0-port1 and sw0-port2 on separate hosts:
    
        +--------------------------------------+
        |                                      |
        |             Host A                   |
        |                                      |
        |   +---------+                        |
        |   |sw0-port1| --> ingress pipeline   |
        |   +---------+           ||           |
        |                         ||           |
        +-------------------------||-----------+
                                  ||
                                  \/
                             geneve tunnel
                                  ||
                                  ||
        +-------------------------||-----------+
        |                         ||           |
        |             Host B      ||           |
        |                         ||           |
        |   +---------+           \/           |
        |   |sw0-port2| < -- egress pipeline   |
        |   +---------+                        |
        |                                      |
        +--------------------------------------+

    你可以使用"ovn-sbctl lflow-list"命令来查看完整的logical flow。它看起来会和OpenFlow有些相似,但是还是有非常不一样的地方的:

    1. Ports是一个逻辑概念,它位于网络中的某处,而不是一个switch中的physical ports
    2. pipeline中的每一个table除了编号以外还多了一个名字。这个名字描述了pipeline在该阶段的作用
    3. 匹配更灵活。支持复杂的布尔运算,对于程序员应该是很熟悉的了
    4. OVN logical flows扩展的action远远超过了OpenFlow。我们可以用logical flow的语法控制一些高级的特性,例如DHCP。具体的match和syntax的语法可以参见ovn-sb(5)中关于Logical_Flow的文档

    在本例中,pipeline中还保留了很多额外的stage,用于未被用到的特性,所以下面很多table的flow实际上没有做任何事情

     

        $ ovn-sbctl lflow-list
        Datapath: "sw0" (d7bf4a7b-e915-4502-8f9d-5995d33f5d10)  Pipeline: ingress
          table=0 (ls_in_port_sec_l2  ), priority=100  , match=(eth.src[40]), action=(drop;)
          table=0 (ls_in_port_sec_l2  ), priority=100  , match=(vlan.present), action=(drop;)
          table=0 (ls_in_port_sec_l2  ), priority=50   , match=(inport == "sw0-port1" && eth.src == {00:00:00:00:00:01}), action=(next;)
          table=0 (ls_in_port_sec_l2  ), priority=50   , match=(inport == "sw0-port2" && eth.src == {00:00:00:00:00:02}), action=(next;)
          table=1 (ls_in_port_sec_ip  ), priority=0    , match=(1), action=(next;)
          table=2 (ls_in_port_sec_nd  ), priority=90   , match=(inport == "sw0-port1" && eth.src == 00:00:00:00:00:01 && arp.sha == 00:00:00:00:00:01), action=(next;)
          table=2 (ls_in_port_sec_nd  ), priority=90   , match=(inport == "sw0-port1" && eth.src == 00:00:00:00:00:01 && ip6 && nd && ((nd.sll == 00:00:00:00:00:00 || nd.sll == 00:00:00:00:00:01) || ((nd.tll == 00:00:00:00:00:00 || nd.tll == 00:00:00:00:00:01)))), action=(next;)
          table=2 (ls_in_port_sec_nd  ), priority=90   , match=(inport == "sw0-port2" && eth.src == 00:00:00:00:00:02 && arp.sha == 00:00:00:00:00:02), action=(next;)
          table=2 (ls_in_port_sec_nd  ), priority=90   , match=(inport == "sw0-port2" && eth.src == 00:00:00:00:00:02 && ip6 && nd && ((nd.sll == 00:00:00:00:00:00 || nd.sll == 00:00:00:00:00:02) || ((nd.tll == 00:00:00:00:00:00 || nd.tll == 00:00:00:00:00:02)))), action=(next;)
          table=2 (ls_in_port_sec_nd  ), priority=80   , match=(inport == "sw0-port1" && (arp || nd)), action=(drop;)
          table=2 (ls_in_port_sec_nd  ), priority=80   , match=(inport == "sw0-port2" && (arp || nd)), action=(drop;)
          table=2 (ls_in_port_sec_nd  ), priority=0    , match=(1), action=(next;)
          table=3 (ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
          table=4 (ls_in_pre_lb       ), priority=0    , match=(1), action=(next;)
          table=5 (ls_in_pre_stateful ), priority=100  , match=(reg0[0] == 1), action=(ct_next;)
          table=5 (ls_in_pre_stateful ), priority=0    , match=(1), action=(next;)
          table=6 (ls_in_acl          ), priority=0    , match=(1), action=(next;)
          table=7 (ls_in_qos_mark     ), priority=0    , match=(1), action=(next;)
          table=8 (ls_in_lb           ), priority=0    , match=(1), action=(next;)
          table=9 (ls_in_stateful     ), priority=100  , match=(reg0[1] == 1), action=(ct_commit(ct_label=0/1); next;)
          table=9 (ls_in_stateful     ), priority=100  , match=(reg0[2] == 1), action=(ct_lb;)
          table=9 (ls_in_stateful     ), priority=0    , match=(1), action=(next;)
          table=10(ls_in_arp_rsp      ), priority=0    , match=(1), action=(next;)
          table=11(ls_in_dhcp_options ), priority=0    , match=(1), action=(next;)
          table=12(ls_in_dhcp_response), priority=0    , match=(1), action=(next;)
          table=13(ls_in_l2_lkup      ), priority=100  , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
          table=13(ls_in_l2_lkup      ), priority=50   , match=(eth.dst == 00:00:00:00:00:01), action=(outport = "sw0-port1"; output;)
          table=13(ls_in_l2_lkup      ), priority=50   , match=(eth.dst == 00:00:00:00:00:02), action=(outport = "sw0-port2"; output;)
        Datapath: "sw0" (d7bf4a7b-e915-4502-8f9d-5995d33f5d10)  Pipeline: egress
          table=0 (ls_out_pre_lb      ), priority=0    , match=(1), action=(next;)
          table=1 (ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
          table=2 (ls_out_pre_stateful), priority=100  , match=(reg0[0] == 1), action=(ct_next;)
          table=2 (ls_out_pre_stateful), priority=0    , match=(1), action=(next;)
          table=3 (ls_out_lb          ), priority=0    , match=(1), action=(next;)
          table=4 (ls_out_acl         ), priority=0    , match=(1), action=(next;)
          table=5 (ls_out_qos_mark    ), priority=0    , match=(1), action=(next;)
          table=6 (ls_out_stateful    ), priority=100  , match=(reg0[1] == 1), action=(ct_commit(ct_label=0/1); next;)
          table=6 (ls_out_stateful    ), priority=100  , match=(reg0[2] == 1), action=(ct_lb;)
          table=6 (ls_out_stateful    ), priority=0    , match=(1), action=(next;)
          table=7 (ls_out_port_sec_ip ), priority=0    , match=(1), action=(next;)
          table=8 (ls_out_port_sec_l2 ), priority=100  , match=(eth.mcast), action=(output;)
          table=8 (ls_out_port_sec_l2 ), priority=50   , match=(outport == "sw0-port1" && eth.dst == {00:00:00:00:00:01}), action=(output;)
          table=8 (ls_out_port_sec_l2 ), priority=50   , match=(outport == "sw0-port2" && eth.dst == {00:00:00:00:00:02}), action=(output;)
    

      

    立即logical flow最好的方式就是使用ovn-trace命令。ovn-trace能够让你看到OVN对一个包是怎么处理的。

    ovn-trace需要两个参数:

    $ ovn-trace DATAPATH MICROFLOW
    

      

    DATAPATH标识了sample packet开始进入的logical datapath(一个logical switch或者一个logical router)。MICROFLOW描述了模拟的sample packet。具体的细节详见ovn-trace(8) man page。

    给定上文中的OVN配置,让我们来看看OVN会怎么处理一个由sw0-port1进入并将发往sw0-port2的包。ovn-trace的输出结果有多个详略程度可供选择。第一个是--minimal,它会告诉你这个包发生了些什么,但是会省略很多不必要的细节。在这个例子中,我们将看到的最终结果是该包将被发往sw0-port2。

    $ ovn-trace --minimal sw0 'inport == "sw0-port1" && eth.src == 00:00:00:00:00:01 && eth.dst == 00:00:00:00:00:02'
    # reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,dl_type=0x0000 output("sw0-port2");
    

      

    下一个等级是--summary。在这个模式,我们能知道更多的关于包处理的细节,包括那个pipeline被执行了。如果我们对于同一个sample packet使用ovn-trace,我们将看到如下内容:

    1. 包从sw0-port1进入网络(sw0)并且运行了ingress pipeline
    2. 我们可以看到"sw0-port2"设置到了"output"这个变量中,这以为着该包的目的端口是"sw0-port2"
    3. 包从ingress pipeline输出,并且输出到"sw0"的egress pipeline并且输出变量设置为"sw0-port2"
    4. egress pipeline中的output action将被执行,它将把包输出到当前"output"变量对应的值中,即"sw0-port2"
        $ ovn-trace --summary sw0 'inport == "sw0-port1" && eth.src == 00:00:00:00:00:01 && eth.dst == 00:00:00:00:00:02'
        # reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,dl_type=0x0000
        ingress(dp="sw0", inport="sw0-port1") {
            outport = "sw0-port2";
            output;
            egress(dp="sw0", inport="sw0-port1", outport="sw0-port2") {
                output;
                /* output to "sw0-port2", type "" */;
            };
        };
    

      

    当你在debug或者要修改代码的时候,你可能需要更细节的输出。ovn-trace有一个--detail选项。在这种模式下,你将获得更多的细节,关于包流动过程中遇到的每一个meaningful logical flow。你可以看到table number,pipeline stage name,full match,以及flow的priority number。你还可以看到负责创建该logical flow的OVN源代码的位置

        $ ovn-trace --detailed sw0 'inport == "sw0-port1" && eth.src == 00:00:00:00:00:01 && eth.dst == 00:00:00:00:00:02'
        # reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,dl_type=0x0000
    
        ingress(dp="sw0", inport="sw0-port1")
        -------------------------------------
         0. ls_in_port_sec_l2 (ovn-northd.c:2827): inport == "sw0-port1" && eth.src == {00:00:00:00:00:01}, priority 50
            next(1);
        13. ls_in_l2_lkup (ovn-northd.c:3095): eth.dst == 00:00:00:00:00:02, priority 50
            outport = "sw0-port2";
            output;
    
        egress(dp="sw0", inport="sw0-port1", outport="sw0-port2")
        ---------------------------------------------------------
         8. ls_out_port_sec_l2 (ovn-northd.c:3170): outport == "sw0-port2" && eth.dst == {00:00:00:00:00:02}, priority 50
            output;
            /* output to "sw0-port2", type "" */
    

      

    另一个使用ovn-trace的例子是观察一个包为什么会被丢弃。我们已经设置了port security,现在让我们来看看从sw0-port1发出一个有着非预期源mac地址的包,它的执行路径是什么样的。从输出我们可以看到,这个包进入了sw0但是不能匹配table 0中任何一个flow,这意味着这个包会被丢弃。我们还可以看到table 0被命名为"ls_in_port_sec_l2",其实就是"Logical Switch ingress L2 port security"的缩写。

        $ ovn-trace --detailed sw0 'inport == "sw0-port1" && eth.src == 00:00:00:00:00:ff && eth.dst == 00:00:00:00:00:02'
    # reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:ff,dl_dst=00:00:00:00:00:02,dl_type=0x0000
    
        ingress(dp="sw0", inport="sw0-port1")
        -------------------------------------
        0. ls_in_port_sec_l2: no match (implicit drop)
    

      

    另一个相似的例子是,一个包有着未知的目的mac地址。在这种情况下,我们将看到这个包成功通过了table 0,但是未能匹配table 13,"ls_in_l2_lkup","Logical Switch ingress L2 lookup"的缩写。

        $ ovn-trace --detailed sw0 'inport == "sw0-port1" && eth.src == 00:00:00:00:00:01 && eth.dst == 00:00:00:00:00:ff'
        # reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:ff,dl_type=0x0000
    
        ingress(dp="sw0", inport="sw0-port1")
        -------------------------------------
         0. ls_in_port_sec_l2 (ovn-northd.c:2827): inport == "sw0-port1" && eth.src == {00:00:00:00:00:01}, priority 50
            next(1);
        13. ls_in_l2_lkup: no match (implicit drop)
    

      

    到目前为止我们已经看过了在单个L2 logical network中的几个例子。接下来我们来创建一个新的环境用来演示ovn-trace怎么跨多个网络进行工作。我们将会创建两个network,每个有2个port,并且将他们连接到一个logical router上。

    #!/bin/bash
    
    # Create the first logical switch and its two ports.
    ovn-nbctl ls-add sw0
    
    ovn-nbctl lsp-add sw0 sw0-port1
    ovn-nbctl lsp-set-addresses sw0-port1 "00:00:00:00:00:01 10.0.0.51"
    ovn-nbctl lsp-set-port-security sw0-port1 "00:00:00:00:00:01 10.0.0.51"
    
    ovn-nbctl lsp-add sw0 sw0-port2
    ovn-nbctl lsp-set-addresses sw0-port2 "00:00:00:00:00:02 10.0.0.52"
    ovn-nbctl lsp-set-port-security sw0-port2 "00:00:00:00:00:02 10.0.0.52"
    
    # Create the second logical switch and its two ports.
    ovn-nbctl ls-add sw1
    
    ovn-nbctl lsp-add sw1 sw1-port1
    ovn-nbctl lsp-set-addresses sw1-port1 "00:00:00:00:00:03 192.168.1.51"
    ovn-nbctl lsp-set-port-security sw1-port1 "00:00:00:00:00:03 192.168.1.51"
    
    ovn-nbctl lsp-add sw1 sw1-port2
    ovn-nbctl lsp-set-addresses sw1-port2 "00:00:00:00:00:04 192.168.1.52"
    ovn-nbctl lsp-set-port-security sw1-port2 "00:00:00:00:00:04 192.168.1.52"
    
    # Create a logical router between sw0 and sw1.
    ovn-nbctl create Logical_Router name=lr0
    
    ovn-nbctl lrp-add lr0 lrp0 00:00:00:00:ff:01 10.0.0.1/24
    ovn-nbctl lsp-add sw0 sw0-lrp0 \
        -- set Logical_Switch_Port sw0-lrp0 type=router \
        options:router-port=lrp0 addresses='"00:00:00:00:ff:01"'
    
    ovn-nbctl lrp-add lr0 lrp1 00:00:00:00:ff:02 192.168.1.1/24
    ovn-nbctl lsp-add sw1 sw1-lrp1 \
        -- set Logical_Switch_Port sw1-lrp1 type=router \
        options:router-port=lrp1 addresses='"00:00:00:00:ff:02"'
    

      

    我们可以使用"ovn-nbctl show"命令来观察最终的逻辑网络的配置

    $ ovn-nbctl show
        switch bf4ba6c6-91c5-4f56-9981-72643816f923 (sw1)
            port sw1-lrp1
                addresses: ["00:00:00:00:ff:02"]
            port sw1-port2
                addresses: ["00:00:00:00:00:04 192.168.1.52"]
            port sw1-port1
                addresses: ["00:00:00:00:00:03 192.168.1.51"]
        switch 13b80127-4b36-46ea-816a-1ba4ffd6ac57 (sw0)
            port sw0-port1
                addresses: ["00:00:00:00:00:01 10.0.0.51"]
            port sw0-lrp0
                addresses: ["00:00:00:00:ff:01"]
            port sw0-port2
                addresses: ["00:00:00:00:00:02 10.0.0.52"]
        router 68935017-967a-4c4a-9dad-5d325a9f203a (lr0)
            port lrp0
                mac: "00:00:00:00:ff:01"
                networks: ["10.0.0.1/24"]
            port lrp1
                mac: "00:00:00:00:ff:02"
                networks: ["192.168.1.1/24"]
    

      

    我们现在可以对一个包进行追踪,这个包从sw0-port1发往sw1-port2,中间需要经过路由器。minimal output将会显示最终的结果是,这个包会从sw1-port2输出。我们还将看到过程中对这个包所做的修改。当包经过logical router时,TTL会减小,源和目的mac地址都会针对下一跳进行更新。

    $ ovn-trace --minimal sw0 'inport == "sw0-port1" && \
                               eth.src == 00:00:00:00:00:01 && \
                               ip4.src == 10.0.0.51 && \
                               eth.dst == 00:00:00:00:ff:01 && \
                               ip4.dst == 192.168.1.52 && \
                               ip.ttl == 32'
    # ip,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:ff:01,nw_src=10.0.0.51,nw_dst=192.168.1.52,nw_proto=0,nw_tos=0,nw_ecn=0,nw_ttl=32
    ip.ttl--;
    eth.src = 00:00:00:00:ff:02;
    eth.dst = 00:00:00:00:00:04;
    output("sw1-port2");
    

      

    如果你想要观察得更仔细,可以同样执行上述命令,将--minimal改为--summary或者--detailed即可。你也可以对sample packet进行改变,看看到底会发生什么。

     

    A Powerful Abstraction

    我在文章的最开始就已经说过,我觉得OVN的Logical Flows是非常强大的抽象,它可以让对OVN添加特性变得异常简单。既然现在我们对logical flow有了一定的了解,下面我将说明一些最近新添加的特性,用于演示向OVN添加特性是多么地简单。

     

    SOURCE BASED ROUTING

    OVN已经支持了L3 gateways,它能够提供OVN logical network和physical network的连接。一个典型的OVN网络一般会有一个L3 gateway位于某台机器上。使用单个L3 gateway的缺陷是所有发往physical network的流量必须流经L3 gateway所在的机器。

    最近Gurucharan Shetty添加了在OVN logical network中对于multiple L3 gateway的支持。它能够基于源IP地址在gateway之间分发流量。

    我们并不需要知道这一改变的所有细节。我只想说明的是我们仅仅需要改动非常少量的代码就能实现这一特性。让我们来看一看diffstat。

    Documentation:
     NEWS                          |    1 
     ovn/ovn-nb.xml                |   28 +++++
     ovn/utilities/ovn-nbctl.8.xml |    8 +
    
    Database schema update:
     ovn/ovn-nb.ovsschema          |    8 +
    
    Command line utility support for new db schema additions:
     ovn/utilities/ovn-nbctl.c     |   43 ++++++--
    
    Changes to how OVN builds logical flows to add support for this feature:
     ovn/northd/ovn-northd.c       |   24 +++-
    
    Test code:
     tests/ovn-nbctl.at            |   42 ++++----
     tests/ovn.at                  |  219 ++++++++++++++++++++++++++++++++++++++++++
    
     8 files changed, 334 insertions(+), 39 deletions(-)
    

      

    最终要的是ovn-northd.c中的24行代码变动。这些代码用于更新logical flow的创建。这让我非常震惊,因为这个特性对于网络的行为有着非常重要的影响,但是却只用几行的C代码就搞定了。

     

    DSCP

    另一个通过logical flow添加特性的例子是这个patch,它基于arbitrary traffic classifier为设定IP包中的DSCP域提供了支持。这个patch在OVN northbound database中添加了一个新的QoS table。在这个table中定义了一个match(或者traffic classfier)以及相应DSCP值,用于设置那些匹配该classfier的包。

    这个改变对应了ovn-northd.c中的80行代码。这个patch看起来比它实际的要大一些,因为它会为QoS创建一个新的pipeline stage并且还需要对它之后的stage进行重新编号。实现这个特性,只需要能插入能够匹配配置好的match(traffic classfier),之后在执行OVN logical flow actions"ip.dscp=VALUE; next"的flow就可以了。

     

    DHCP

    OVN支持DHCPv4和DHCPv6,所有这些都是通过logical flow实现的。在很多情况下,如果要改变它们的行为,只需要改变那些生成DHCP相关的logical flow的代码就可以了。

    最近的一个例子是这个patch,它添加了对无状态DHCPv6的支持。有了无状态DHCPv6,我们能够提供一些configuration entries(例如DNS地址),但是不提供IPv6地址。这对于DHCPv6的logical flows只是一个小小的调整,只要OVN创建的应答能够有选择地包含IPv6地址选项就可以了。

     

    Conclusion

    我希望你对OVN Logical Flows已经有了更深的理解,它其实就是一个用于定义逻辑网络行为的,可扩展到多台机器上的match-action pipeline。

    转载于:https://www.cnblogs.com/YaoDD/p/7489141.html

    展开全文
  • OUI log文件和trace文件位置

    来源于:Location of runInstaller(OUI) log/trace (文档 ID 1629698.1)

    适用于:
    Oracle Database - Enterprise Edition - Version 11.2.0.1 and later
    Information in this document applies to any platform.
     ***Checked for relevance on 15-Apr-2013***
     目的:
    从哪里找到runInstaller(addNode.sh,config.sh等等)log文件和trace文件的位置?
    答案:
    对于每一次的runInstaller 运行,有三种文件会生成在下面的位置之一
     /tmp/OraInstall${TIMESTAMP}
     $CENTRAL_INVENTORY/logs
     $TEMP/OraInstall${TIMESTAMP}
     $TMPDIR/OraInstall${TIMESTAMP}
     $ORACLE_HOME/cfgtoollogs/oui
     这三种文件是:
     installActions${TIMESTAMP}.log
     oraInstall${TIMESTAMP}.err
     oraInstall${TIMESTAMP}.out 
    
     为了找到CENTRAL_INVENTORY的位置,请查看oraInst.loc的内容,而不同os下,oraInst.loc的位置是不同的:
     Linux和AIX:/etc/oraInst.loc
     Solaris和HP-UX:/var/opt/oracle/oraInst.loc
     Windows: HKEY_LOCAL_MACHINE -> SOFTWARE -> ORACLE -> inst_loc
     在下面的例子中,CENTRAL_INVENTORY 在/home/oracle/oraInventory,因为 "inventory_loc"被设置指向它。
         $ cat /etc/oraInst.loc
        inventory_loc=/home/oracle/oraInventory
        inst_group=oinstall
     
    展开全文
  • 在错误从os级别remove掉 trace file 之后,怎么找到该trace file内容?

    在错误的从os级别remove掉 trace file 之后,怎么找到该trace file的内容?


    参考原文:


    适用于:
    Oracle Database - Enterprise Edition - Version 8.1.7.4 to 11.2.0.1.0 [Release 8.1.7 to 11.2]
    Generic UNIX
    Generic Linux


    目标:

    当错误的从从os级别remove(这个remove是指rm)掉 trace file 之后,oracle进程的trace file 是不会被重新创建的。

    那怎么看到这些trace file的内容?

    解决方案:


    这种行为的解释 和解决方案在
    Bug 8367394: A NEW TRACE FILE IS NOT BEING CREATED IF THE INITIAL ONE WAS REMOVED

    给出了。--->注意:我看了一下该bug的workground,是restart instance。

    在下面的例子中,请注意从11g开始,trace file的位置不在bdump 下,而是在{ADR_HOME}/trace/下。

    当进程是alive的时候,进程不会在 trace file上执行close()函数。
    进程依然持有 指向trace file 的  file descriptor。

    trace file 的名字包括进程的pid,
    因此,除非进程被重启,否则我们不能关闭 file descriptor,也不能创建一个用新文件名或者老文件名的新文件


    这并不意味着,在紧急情况下,你不能访问该trace file。
    当该trace file 被delete掉后,只要file descriptor依然open,你就可以获得该文件的内容,该内容依然被正常写。

    通过如下方法经过file descriptor 来访问 file

    ps -ef|grep v10204|grep dbw0
    oracle 11283 1 0 16:23 ? 00:00:00 ora_dbw0_v10204

    lsof -p 11283|grep dbw0
    COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
    oracle 11283 oracle 2 REG 3,1 767 20728692 /bdump/v10204_dbw0_11283.trc

    从上面的结果中,我们可以看到fd 为2,如下也能验证fd 为2

    ls -lA /proc/11283/fd | grep dbw0
    l-wx------ 1 oracle dba-64 Mar 25 16:24 2 -> /bdump/v10204_dbw0_11283.trc


    从os级别 remove掉trace file ,fd 依然存在,只是file 被delete掉了。

    ls -lA /proc/11283/fd | grep dbw0
    l-wx------ 1 oracle dba-64 Mar 25 16:24 2 -> /bdump/v10204_dbw0_11283.trc (deleted)

    这个fd (file descriptor)在它被关闭 或者 进程被重启之前 是存在的。
    你可以访问它的内容:
    cat /proc/11283/fd/2 > /tmp/v10204_dbw0_11283.trc

    展开全文
  • ray trace 第三章 翻译

    2015-09-17 17:21:10
    Phinecos(洞庭散人) 专注于开源技术研究与应用 ...这将涉及到在相交点处产生新光线,并且计算新光线方向。此外,作者还将运用Lambert-Beer 定律来解释光线在物体内部吸收情况。最后作者将展示如
    
    
    

    【译】光线跟踪:理论与实现(三) 折射与Lambert-Beer 定律

    Introduction

          作者在这一篇中将解释如何去跟踪折射光线。这将涉及到在相交点处产生新的光线,并且计算新光线的方向。此外,作者还将运用Lambert-Beer 定律来解释光线在物体内部的吸收情况。最后作者将展示如何加入反锯齿的效果,并且如何对光线跟踪器进行加速优化。

    Refractions

    折射的情况如图1所示,注意观察光线在几何体表面是如何改变方向的,又是如何穿过几何体后面那个点的。在这个点后面的物体会看起来是倒转的镜像。

          几何体表面处光线的弯曲程度取决于两种物质的折射率:光线进入几何体前所在的物质的折射率,构成几何体的物质的折射率。例如:空气和真空的折射率为1.0,20摄氏度的水的折射率为1.33。
       2008041302.jpg

       下面这段代码应该让你感到很熟悉了吧。它就是构造折射光线,递归地跟踪它,并将结果颜色值加入到产生折射光的光线中去。有一点值得注意:法向量乘以了一个值’result’。这个值是对每个几何体的相交测试时获得的,值是1或0,分别表示是否命中。当然,还有第3个选择:-1,这表示是从几何体内部命中的。这点也是很重要的:如果一个光线命是从外部命中一个几何体的,那其实是没有命中这个几何体,而是它附件的物质。因此,其法向量应该取反。

        // calculate refraction
            float refr = prim->GetMaterial()->GetRefraction();
            if ((refr > 0) && (a_Depth < TRACEDEPTH))
            {
                float rindex = prim->GetMaterial()->GetRefrIndex();
                float n = a_RIndex / rindex;
                vector3 N = prim->GetNormal( pi ) * (float)result;
                float cosI = -DOT( N, a_Ray.GetDirection() );
                float cosT2 = 1.0f - n * n * (1.0f - cosI * cosI);
                if (cosT2 > 0.0f)
                {
                    vector3 T = (n * a_Ray.GetDirection()) + (n * cosI - sqrtf( cosT2 )) * N;
                    Color rcol( 000 );
                    float dist;
                    Raytrace( Ray( pi + T * EPSILON, T ), rcol, a_Depth + 1, rindex, dist );
                    a_Acc += rcol * transparency;
                }

            }


    下图就是加入折射的效果图:
       2008041303.jpg

    毫无疑问,你会注意到现在光线跟踪器很慢的,这是因为每条光线要与每个几何体进行相交测试来找出最近的相交点。当然,有很多方法可以对其进行改进,作者在后面的文章中会使用一种空间细分的方法来对相交测试的数量进行限制的。

    Lambert-Beer定律

          上面的图中,你会发现球是蓝色的,因此折射图的颜色也是稍微偏蓝色的。这是因为折射光返回的颜色值会与几何体颜色相乘。这在反射,散射以及镜面光的计算中都有这种情况。

          现在让我们来想象有这么一个水池,里面充满了带颜色的物质(比如说水里面混合着蓝墨水)。池子的浅处大概10cm深,深处呢有1米深。如果你从上往底下看,很明显可以看到在较深的那端的底部受到颜色的影响会比浅处的要大。这种效应就叫Beer定律。

          Beer定律可以用下列公式表示:

    light_out = light_in * e(e * c * d)

    这个公式主要是用来计算溶解在水中的物质的光吸收度的。’e’是一个常量,表明溶剂的吸收度(准确来说,是单位为L/mol*cm的摩尔吸光率)。’c’是溶质的数量,单位mol/L.’d’是光线的路径长度。一般我们可以简化公式如下:

    light_out = light_in * e(d * C)

    这个d是路径长度,C是一个常量,表示物质的密度,减小它的值会使得光线在穿越物体时的时间增大。

    吸收及透明度的计算需要以颜色因子来单位进行逐个计算。

                    // apply Beer's law
                    Color absorbance = prim->GetMaterial()->GetColor() * 0.15f * -dist;
                    Color transparency = Color( expf( absorbance.r ), expf( absorbance.g ), expf( absorbance.b ) );
                    a_Acc += rcol * transparency;

    下面是效果图:
    2008041301.jpg
       对于目前程序中使用的场景来说,应用这个定律对于画面的质量没有多大影响。不过一旦你开始使用复杂的场景,情况就大不一样了。

    很多光线跟踪器都使用下述简单的方法:每个物体都有一个“反射”变量,它会与折射光返回的颜色值相乘,同时还有一个“折射”变量,会与折射光返回的颜色值相乘。然而对于折射光来说,这并不正确:每条折射光线在进入和退出几何体时会被计算两次。而且,从一个薄的物体穿过与穿过一个厚的物体有相同的衰减度。最大的问题更在于我们直观上会感觉不对:光线密度在几何体表面没有减小,而只会在几何体内部减小。

    SuperSampling

    假设我们使用下列代码来替换产生光线处的代码:

    for ( int tx = 0; tx < 4; tx++ ) for ( int ty = 0; ty < 4; ty++ )
    {
        vector3 dir = vector3( m_SX + m_DX * tx / 4.0f, m_SY + m_DY * ty / 4.0f0 ) - o;
        NORMALIZE( dir );
        Ray r( o, dir );
        float dist;
        Primitive* prim = Raytrace( r, acc, 11.0f, dist );
    }


    int red = (int)(acc.r * 16);
    int green = (int)(acc.g * 16);
    int blue = (int)(acc.b * 16); 

    这段代码作用是为每个像素点发射16条光线,因此结果图像具有抗锯齿效果,但缺点就是耗时太多。

    也许你注意到了光线跟踪器返回的是指向几何体的指针,它指向被primary ray命中的几何体。我们做如下修改,代码的性能就大幅提升:

    // fire primary rays
    Color acc( 000 );
    vector3 dir = vector3( m_SX, m_SY, 0 ) - o;
    NORMALIZE( dir );
    Ray r( o, dir );
    float dist;
    Primitive* prim = Raytrace( r, acc, 11.0f, dist );
    int red, green, blue;
    if (prim != lastprim)
    {
            lastprim = prim;
        Color acc( 000 );
        for ( int tx = -1; tx < 2; tx++ ) for ( int ty = -1; ty < 2; ty++ )
        {
            vector3 dir = vector3( m_SX + m_DX * tx / 2.0f, m_SY + m_DY * ty / 2.0f0 ) - o;
            NORMALIZE( dir );
            Ray r( o, dir );
            float dist;
            Primitive* prim = Raytrace( r, acc, 11.0f, dist );
        }

        red = (int)(acc.r * (256 / 9));
        green = (int)(acc.g * (256 / 9));
        blue = (int)(acc.b * (256 / 9));
    }


    else
    {
        red = (int)(acc.r * 256);
        green = (int)(acc.g * 256);
        blue = (int)(acc.b * 256);
    }

    if (red > 255) red = 255;
    if (green > 255) green = 255;

    if (blue > 255) blue = 255;

    ok,it’s over.在下一篇中作者将介绍“空间分割”思想的运用。

    原文链接:http://www.devmaster.net/articles/raytracing_series/part3.php

    作者:洞庭散人

    出处:http://phinecos.cnblogs.com/    

    本博客遵从Creative Commons Attribution 3.0 License,若用于非商业目的,您可以自由转载,但请保留原作者信息和文章链接URL。
    展开全文
  • 在错误从os级别remove掉 trace file 之后,怎么找到该trace file内容? 參考原文: How to Find the Content of Trace File Generated for an Oracle Process after Removing the Trace File by Mistake ...
  • 在物理dg中对RFS进程进行trace的方法 来源于: How To Trace The Remote File Server (RFS) Process In Physical Standby Database (文档 ID 1481125.1) 适用于: Oracle Database - Enterprise Edition - ...
  • Trace Metrics一旦你应用程序开始在组件之间跟踪trace和segment,你就要享受trace和segment metrics好处。trace和 segment metric中没有什么特殊,他们都是十分简单实体,就像在核心metric小节中描述那样...
  • 不使用trace 找到绑定变量值  How To Find The Value of a Bind Variable Without Tracing  (文档 ID 273121.1)   目的 在这个文档中是展示如何找到变
  • 开启dblink oracle net trace/tracing --对dblink进行跟踪方法
  • trace订阅协议当你给你应用程序配置使用“Simple Tracing”级别时,每当一个trace被选择和报告时,你能够订阅tracing模块,并接收TraceInfo 信息。订阅使用Kamon.tracer.subscribe(...) 方法,如下所示:Scala:...
  • LTE用户文档 (如有不当地方,欢迎指正!) 7 使用 Fading Trace 本节描述如何在 LTE 仿真中...通过使用专用 matlab 脚本 (/lte/model/fading-traces/fading-trace-generator.m)提供代码生成 fading t...
  • 原始 trace文件各项内容解释 ...今天浏览metalink,看到这篇Interpreting Raw SQL_TRACE,比较老一篇文章了,但是确实很有用,所以决定大略翻译一下吧。 我们知道有几种方法可以得到一个SQ...
  • 今天浏览metalink,看到这篇Interpreting Raw SQL_TRACE,比较老一篇文章了,但是确实很有用,所以决定大略翻译一下吧。 我们知道有几种方法可以得到一个SQL语句执行时后台的trace文件,一个是用...
  • 今天浏览metalink,看到这篇Interpreting ...Raw SQL_TRACE,比较老一篇文章了,但是确实很有用,所以决定大略翻译一下吧。 我们知道有几种方法可以得到一个SQL语句执行时后台的trace文件,一个...
  • Erlang Trace Tool Builder心得

    千次阅读 2013-05-11 17:33:57
    在学习过程中顺便把Tracer翻译出来,现跟大家分享     1.Trace Tool Builder(erlang跟踪工具) 主要特性:   用一个函数调用来跟踪多个节点上文件端口 可以往在formatting过程中读取记录跟踪信息...
  • Stack Trace简介

    2012-06-06 21:09:59
    1.中文翻译叫做堆栈跟踪,一个调试工具,或者叫做调试方法。 它展示方式就是线程和JVM监测snapshot,根据程序复杂程度...其实一共有3个方法生成stack trace,这个貌似是最普遍方法。 2.打印出来了以
  • 运行tkprof来翻译第二步输出跟踪文件成为一个可读文件袋.这一步也可以创建一个sql脚本在数据库中存储统计4.解释说明第三步生成输出文件.5.可以在第三步运行一个sql脚本将统计存储在数据库给跟踪文件...
  •  下面我就总结下本书中关于Debug和Trace的一些应用,算作一种读书笔记。  粗略概括下关于修改BUG的几种方法: 通过调试器调试  顾名思义就是跟踪源代码进行调试,微软还提供了远程调试的功能。通过源...
  • HDtrans的翻译机制

    2009-10-10 14:35:00
    为了保持简单的设计原则,HDtrans没有采用寄存器生存期分析等复杂优化技术,仅仅使用了trace linearization和sieve技术,优化trace生成和间接指令的翻译。 直接跳转最大限度的利用已翻译的基本块。如果跳转的目标...
  • TracePro中文使用手册

    2010-03-23 10:19:02
    HGO/OPT team翻译,Lottie整理的TracePro中文使用手册,偶从网上获得,不敢藏私,大家一起学习。
  •  下面我就总结下本书中关于Debug和Trace的一些应用,算作一种读书笔记。  粗略概括下关于修改BUG的几种方法: 通过调试器调试  顾名思义就是跟踪源代码进行调试,微软还提供了远程调试的功能。通过源代码...
  • dump 分析模式之 INCORRECT STACK TRACE 翻译自 MDA-Anthology Page288 初学者常犯错误是认为 WinDbg !analyze 和 kv 给出信息是准确. WinDbg 只是一个工具, 有时候会缺少一些必要信息来得到正确栈...
  • 目前互联网公司应用架构基本都是前后端分离,...REST全称:Representational State Transfer,翻译成中文就是“表述性状态转移”,表述对象就是资源,在webrertful架构中都是通过uri来一一对应资源,比如:/...
  • traceview缩小操作

    千次阅读 2014-04-28 13:51:53
    关于traceview使用有往上一大堆文档,当然最权威可以参考google dev: http://developer.android.com/tools/debugging/debugging-tracing.html 但是国内文章一大抄一大转载,除了翻译google原文外,都没有...

空空如也

空空如也

1 2 3 4 5 ... 10
收藏数 183
精华内容 73
关键字:

trace的翻译