OVN 流表基础 -- 基于 kubeOVN (一)

2023-05-16

文章目录

  • Kubectl ko 工具分析
    • Nbctl Sbctl
    • Trace
  • Ovn 流表
    • Match
    • Action
    • Register
    • Table 介绍
      • Logical Switch Datapaths
      • Logical Router Datapaths

Kubectl ko 工具分析

Kubectl ko 下可以执行 nbctl,sbctl,vsctl,ofctl,trace 等等命令

# kubectl ko --help
kubectl ko {subcommand} [option...]
Available Subcommands:
  [nb|sb] [status|kick|backup|dbstatus|restore]     ovn-db operations show cluster status, kick stale server, backup database, get db consistency status or restore ovn nb db when met 'inconsistent data' error
  nbctl [ovn-nbctl options ...]    invoke ovn-nbctl
  sbctl [ovn-sbctl options ...]    invoke ovn-sbctl
  vsctl {nodeName} [ovs-vsctl options ...]   invoke ovs-vsctl on the specified node
  ofctl {nodeName} [ovs-ofctl options ...]   invoke ovs-ofctl on the specified node
  dpctl {nodeName} [ovs-dpctl options ...]   invoke ovs-dpctl on the specified node
  appctl {nodeName} [ovs-appctl options ...]   invoke ovs-appctl on the specified node
  tcpdump {namespace/podname} [tcpdump options ...]     capture pod traffic
  trace {namespace/podname} {target ip address} [target mac address] {icmp|tcp|udp} [target tcp or udp port]    trace ovn microflow of specific packet
  diagnose {all|node} [nodename]    diagnose connectivity of all nodes or a specific node
  env-check check the environment configuration
  tuning {install-fastpath|local-install-fastpath|remove-fastpath|install-stt|local-install-stt|remove-stt} {centos7|centos8}} [kernel-devel-version]  deploy  kernel optimisation components to the system
  reload restart all kube-ovn components

Nbctl Sbctl

先获取到 leader pod,如 ovn-nb-leader,和 ovn-sb-leader

kubectl get pod -n kube-system -l ovn-nb-leader=true | grep ovn-central | head -n 1 | awk '{print $1}'
kubectl get pod -n kube-system -l ovn-sb-leader=true | grep ovn-central | head -n 1 | awk '{print $1}'

然后进入到 leader pod 中执行

kubectl exec "$OVN_NB_POD" -n $KUBE_OVN_NS -c ovn-central -- ovn-nbctl "$@"
kubectl exec "$OVN_SB_POD" -n $KUBE_OVN_NS -c ovn-central -- ovn-sbctl "$@"

即查看流表命令 ovn-sbctl lflow-list == kubectl ko sbctl lflow-list

Trace

展示流表匹配流程
Kubectl ko trace {namespace/podname} {target ip address} [target mac address] {icmp|tcp|udp} [target tcp or udp port]

  • namespace/podname 选定 pod
  • Target ip address 访问的 IP 地址
  • Target mac address 访问的 Mac 地址
  • 协议类型,icmp/tcp/udp
  • Target tcp or udp port,tcp 或 udp 端口号
kubectl ko trace default/pod8 10.96.0.10 udp 53

// 即 trace pod8 访问 10.96.0.10 的 udp 53 端口
  • Ko 背后逻辑
    先找到 ovn-sb-leader $OVN_SB_POD

ls: 通过 pod annotation 获取到的 logical_switch
Inport:pod 的 logical_switch_port 的命名
Mac:通过 annotation 获取到的 mac
gwMac:通过 ovn 查询 logical_route_port 看 mac (underlay 模式,需要访问网关获取)
af:4 or 6
type:tcp or udp

kubectl exec "$OVN_SB_POD" -n $KUBE_OVN_NS -c ovn-central -- ovn-trace --ct=new "$ls" "inport == \"$podName.$namespace\" && ip.ttl == 64 && eth.src == $mac && ip$af.src == $podIP && eth.dst == $gwMac && ip$af.dst == $dst && $type.src == 10000 && $type.dst == $4"

kubectl exec ovn-central-7f7c579877-qlkbb -n kube-system -c ovn-central -- ovn-trace --ct=new ovn-default "inport == \"pod8.default\" && ip.ttl == 64 && eth.src == 00:00:00:1B:3E:8B && ip4.src == 10.16.3.47 && eth.dst == 00:00:00:63:B3:F9 && ip4.dst == 10.96.0.10 && udp.src == 10000 && udp.dst == 53" 


# udp,reg14=0x1e,vlan_tci=0x0000,dl_src=00:00:00:1b:3e:8b,dl_dst=00:00:00:63:b3:f9,nw_src=10.16.3.47,nw_dst=10.96.0.10,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=10000,tp_dst=53

ingress(dp="ovn-default", inport="pod8.default")
------------------------------------------------
 0. ls_in_port_sec_l2 (northd.c:5607): inport == "pod8.default", priority 50, uuid 59013590
    next;
 6. ls_in_pre_lb (northd.c:6002): ip4 && ip4.dst == 10.96.0.0/12, priority 100, uuid 95834334
    reg0[2] = 1;
    next;
 7. ls_in_pre_stateful (northd.c:6042): reg0[2] == 1 && ip4 && udp, priority 120, uuid b6ecaf0b
    reg1 = ip4.dst;
    reg2[0..15] = udp.dst;
    ct_lb_mark;

ct_lb_mark
----------
 8. ls_in_acl_hint (northd.c:6119): ct.new && !ct.est, priority 7, uuid 325fce8b
    reg0[7] = 1;
    reg0[9] = 1;
    next;
 9. ls_in_acl (northd.c:6713): ip && (!ct.est || (ct.est && ct_mark.blocked == 1)), priority 1, uuid 6a459a10
    reg0[1] = 1;
    next;
12. ls_in_lb (northd.c:7028): ct.new && ip4.dst == 10.96.0.10 && udp.dst == 53, priority 120, uuid fba6a6c7
    reg0[1] = 0;
    reg1 = 10.96.0.10;
    reg2[0..15] = 53;
    ct_lb_mark(backends=10.16.0.48:53,10.16.0.5:53);

ct_lb_mark /* default (use --ct to customize) */
------------------------------------------------
14. ls_in_after_lb (northd.c:7165): ip4.dst == 10.16.0.5, priority 50, uuid 92e4c3a1
    eth.dst = 00:00:00:3e:8e:4f;
    next;
16. ls_in_pre_hairpin (northd.c:7253): ip && ct.trk, priority 100, uuid 2478265d
    reg0[6] = chk_lb_hairpin();
    reg0[12] = chk_lb_hairpin_reply();
    *** chk_lb_hairpin_reply action not implemented
    next;
25. ls_in_l2_lkup (northd.c:8674): eth.dst == 00:00:00:3e:8e:4f, priority 50, uuid 49fad5a5
    outport = "coredns-6d8c4cb4d-6c4rb.kube-system";
    output;

egress(dp="ovn-default", inport="pod8.default", outport="coredns-6d8c4cb4d-6c4rb.kube-system")
----------------------------------------------------------------------------------------------
 0. ls_out_pre_lb (northd.c:6012): ip, priority 100, uuid dfdb1c2b
    reg0[2] = 1;
    next;
 2. ls_out_pre_stateful (northd.c:6062): reg0[2] == 1, priority 110, uuid 953b71bb
    ct_lb_mark;

ct_lb_mark /* default (use --ct to customize) */
------------------------------------------------
 3. ls_out_acl_hint (northd.c:6182): ct.est && ct_mark.blocked == 0, priority 1, uuid bc0f3aca
    reg0[10] = 1;
    next;
 9. ls_out_port_sec_l2 (northd.c:5704): outport == "coredns-6d8c4cb4d-6c4rb.kube-system", priority 50, uuid c717b137
    output;
    /* output to "coredns-6d8c4cb4d-6c4rb.kube-system", type "" */

稍后会结合功能讲解流表,这里不再赘述

Ovn 流表

流表示例如下:

Datapath: "join" (73d52ffc-620d-4fc5-b6b3-19becad7623c)  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 == "join-ovn-cluster"), action=(next;)
  table=0 (ls_in_port_sec_l2  ), priority=50   , match=(inport == "node-master"), action=(next;)
  table=0 (ls_in_port_sec_l2  ), priority=50   , match=(inport == "node-worker"), action=(next;)
  table=0 (ls_in_port_sec_l2  ), priority=50   , match=(inport == "node-worker2"), action=(next;)
  table=1 (ls_in_port_sec_ip  ), priority=0    , match=(1), action=(next;)
  table=2 (ls_in_port_sec_nd  ), priority=0    , match=(1), action=(next;)
  table=3 (ls_in_lookup_fdb   ), priority=0    , match=(1), action=(next;)
  table=4 (ls_in_put_fdb      ), priority=0    , match=(1), action=(next;)
  table=5 (ls_in_pre_acl      ), priority=110  , match=(eth.dst == $svc_monitor_mac), action=(next;)
  ......

Datapath:logical_router or logical_switch
Pipeline:ingress or egress,代表流方向。 Ovn 流水线 pipleline 的方式处理
table=0(ls_in_port_sec_l2 ):table 索引和名称
priority:在该 table 里的优先级,越大越高
match:匹配规则
action:操作

Ovs 流表查看:kubectl ko ofctl master dump-flows br-int

Match

  • eth.src[40] 源地址广播/组播

广播/组播 源 mac 为 xxxxxxx1 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx,广播是特殊的组播包为全1,像 01:02:03:04:05:06 就是组播包源 mac;
match=(eth.src[40]), action=(drop;) 第一条意思就是 组播包丢弃

  • vlan.present 带 vlan 的包
    match=(vlan.present), action=(drop;) 带 vlan 丢弃

  • inport == “node-master” 从 node-master port 进来的包

Node-master 是 logical_switch_port

# kubectl ko vsctl master list Interface  | grep -C 20 ovn0 // 在 master 看 ovs port
// 缩略
external_ids        : {iface-id=node-master, ip="100.64.0.2,dd:100:64::2", ovn-installed="true", ovn-installed-ts="1663729450921"}
mac_in_use          : "00:00:00:21:85:b9"
mtu                 : 1400
name                : ovn0
type                : internal

可以看到 在 master 节点 ovn0 在 ovs 上的配置,iface-id 即 lsp 标记。
match=(inport == “node-master”), action=(next;) 从 node-master 进来的包送到下一张表。

  • outport == “coredns-6d8c4cb4d-6c4rb.kube-system” 从 lsp 出去的包

  • ip4.dst == 100.64.0.2 / ip6.dst == dd: 100:64::2 / eth.dst == 00:00:00:21:85:b9 / ip6.src == dd: 100:64::/64 / ip4.src == 127.0.0.0/8 / ip4.src == {10.16.0.1, 10.16.255.255} / icmp4.type == 8 && icmp4.code == 0 / icmp6.type == 128 && icmp6.code == 0 / ip4 / ip6 / arp/ arp.tpa == 100.64.0.1 / arp.op == 1

    • ipv4 or ipv6 的源,目的网段
    • 源或目的 mac 地址
    • ipv4 or ipv6 的地址范围
    • icmp4.type == 8 && icmp4.code == 0 icmp4 request;icmp6.type == 128 && icmp6.code == 0 icmp6 request。
    • 单纯只写 ip4 or ip6
    • Arp
    • arp.tpa or arp.op
      arp.op:ARP请求(1),ARP应答(2),RARP请求(3),RARP应答(4)。
      arp.tpa:target protocol address 目标 IP 地址
      unsigned char arp_sha[6]; /* sender hardware address /
      unsigned long arp_spa; /
      sender protocol address /
      unsigned char arp_tha[6]; /
      target hardware address /
      unsigned long arp_tpa; /
      target protocol address */
  • nd || nd_rs || nd_ra || mldv1 || mldv2

    • ND 邻居发现(Neighbor Discovery)
    • RS 路由请求(Router Soliciation)
    • RA 路由回答(Router Adertisment)
    • mldv1 || mldv2 MulticastListenerDiscovery 协议 IPv6组播
  • reg0[2] == 1 && ip4 && tcp
    reg0: 寄存器0[2] 是 1 且 是 ipv4 tcp。

  • ct.new, ct.est,ct.trk,ct.rel,ct.rpl

ct:ovs 的 conntrack 功能增加了 ct 流表的概念,将需要跟踪状态的报文提交进 ct 里去,标记连接状态,供后续报文查询连接状态使用。
参考:http://www.openvswitch.org//support/dist-docs/ovs-fields.7.txt

new:数据包来自一个新的连接
est:数据包来自一个已经建立的连接
rel:数据包与一个已存在的连接相关联
rpl:数据包来自一个连接的回复方向
ink:数据包状态是无效的
trk:数据包已经过 conntrack

Action

  • Drop 丢弃
  • Next 到下一张 table
  • Output
Datapath: "join" (73d52ffc-620d-4fc5-b6b3-19becad7623c)  Pipeline: ingress
...

table=25(ls_in_l2_lkup      ), priority=50   , match=(eth.dst == 00:00:00:21:85:b9), action=(outport = "node-master"; output;)

示例流表即到 join 上的流,如果目的 mac 是 master 节点的 ovn0 网卡的 mac,就从 node-master 这个 lsp 丢出。

  • 其他
    • ct_lb_mark / ct_lb_mark(backends=10.16.0.48:9153,10.16.0.5:9153) 连接 LB 跟踪器
    • ct_snat / (ct_snat(10.16.0.1); ) 源 nat 成 10.16.0.1
    • (arp { eth.dst = ff:ff:ff:ff:ff:ff; arp.spa = reg1; arp.tpa = reg0; arp.op = 1; output; }; )
      构造 arp 请求包。
    • action=(reg0 = 0; handle_dhcpv6_reply;) 向代理路由器发送 IPv6 前缀代理消息
    • (ip4.dst <-> ip4.src; ip.ttl = 255; icmp4.type = 0; flags.loopback = 1; next; )
      回复 icmp4
    • (reg9[2] = lookup_arp(inport, arp.spa, arp.sha); next;)
      reg9[2] will be 1 if the lookup_arp in the previous table was successful or skipped, meaning no need to learn mac binding from the packet
      这里是标记 reg9[2] 的意思。
    • (reg0[6] = chk_lb_hairpin(); reg0[12] = chk_lb_hairpin_reply(); next;)
      检查 lb_hairpin,标记 reg0[6] 和 reg0[12],主要是判断 访问者本身就是 endpoint,经过 lb 后源 和 目的 IP 相同;后面看 hairping LB 再详细介绍。

Register

ovs 寄存器,当一个数据包进入交换机时,所有的寄存器都被清零,用户可以通过 Action 的指令修改寄存器中的值。
一般有 reg(32 bits,reg0-reg15),xreg(64 bits,xreg0-xreg7),xxreg(128 bits,xxreg0-xxreg3);

xxreg ipv6 广泛使用

路由时lb 时Arp or ipv6 ND其他
reg0下一跳 ipv4 地址reg0[11],查询是否 inport 是否在 mac learning tablereg0[1] :是否需要 tracker 流 for acl;reg0[2]:是否需要 tracker 流 for LB;reg0[3]:dhcp 配置是否获取成功;reg0[4]:dns 是否解析成功;reg0[5]:IPv6 RA 配置是否获取成功;reg0[6] 和reg0[12]:一个是 检查 lb_hairpin,一个是检查 lb_hairpin_reply。reg0[7]:acl 可能 allow,且流是被追踪的;reg0[8]:acl 可能 allow,且流是未被追踪的;reg0[9]:acl 可能 drop;reg0[10]:acl 可能是 drop,且需要改 tracker;reg0[13]:stateful 流
reg1网关 ipv4 地址,所选择的 router_port IPv4 地址。vip
reg2前 16 位:vip_port;transport port
reg7从 Logical Router Port 来的流量在 lr_in_ip_routing_pre table 中设置为 0;
reg8前 16 位:ecmp group id;后 16 位:ecmp number id
reg9reg9[16…31]:目的端口,LB 的 DNAT 会通过此值获得端口。 (不止 lb,发往 ovs contrack 的所有)去 OVN_Southbound mac_binding 表查询;reg9[2] = 1,代表已有或者 不需要 mac_learn。

具体使用介绍 https://github.com/ovn-org/ovn/blob/main/northd/ovn-northd.8.xml

Table 介绍

分为 logical switch 和 logical router 表,且 ingress 和 egress 不同。

Logical Switch Datapaths

  • Ingress
    table=0 (ls_in_port_sec_l2 ):准入控制
    • 如之前所说的带 vlan 或 组播包丢弃
    • 如 match=(inport == “pod8.default”), action=(next;) 允许 pod8 的流量进入

table=1 (ls_in_port_sec_ip ):准入控制

  • 如 inport == “kata2.default” && eth.src == 00:00:00:fb:cc:14 && ip4.src == {192.166.100.5}), action=(next;) 要求 kata2 进来的包 mac 和 ip 匹配到到下一个表 (匹配不到会有 drop)

table=5/6 (ls_in_pre_acl/ls_in_pre_lb): prepares flows acl 和 lb

  • 如 match=(ip4 && ip4.dst == 10.96.0.0/12), action=(reg0[2] = 1; next;)目的地址到 10.96.0.0/12 网段的流量标记 reg0[2]
    table=7 (ls_in_pre_stateful):prepares flows for 有状态流
  • 如 match=(reg0[2] == 1 && ip4 && udp), action=(reg1 = ip4.dst; reg2[0…15] = udp.dst; ct_lb_mark;) reg[0] == 1 就是上面 lb 标记的流量,加上匹配 udp/tcp/sctp 过滤后,reg1 存目的地址,reg2[0…15] 16 存端口号

table=8 (ls_in_acl_hint):设置 hints,为后续处理设置一些提示

  • 如 match=(ct.new && !ct.est), action=(reg0[7] = 1; reg0[9] = 1; next;) 如果 conntrack 是一个新连接,则标记 reg0[7],[9];并不是为了判断 ct 状态,而是不同 ct 状态有不同的 acl 不需要匹配。

table=9 (ls_in_acl):acl

  • 如配置安全组后流表 match=(reg0[9] == 1 && (inport==@ovn.sg.sg1 && ip4 && ip4.dst==0.0.0.0/0 && icmp4)), action=(/* drop */) 从 sg1 安全组的端口发出的 icmp 包 被drop 掉。
    注:在 ls inport 等于实际 pod 或 vm 的 egress 策略

table=10/11 (ls_in_qos_mark/ls_in_qos_meter):nbctl 里的 qos table,关于 dscp marking。未使用

table=12 (ls_in_lb):LB 规则

  • 如 match=(ct.new && ip4.dst == 10.96.0.10 && tcp.dst == 53), action=(reg0[1] = 0; reg1 = 10.96.0.10; reg2[0…15] = 53; ct_lb_mark(backends=10.16.0.48:53,10.16.0.5:53); ) 设置寄存器并 ct_lb 处理。
    对应 service 如下:
  Name:              kube-dns
  Namespace:         kube-system
  Selector:          k8s-app=kube-dns
  Type:              ClusterIP
  IP Family Policy:  SingleStack
  IP Families:       IPv4
  IP:                10.96.0.10
  IPs:               10.96.0.10
  Port:              dns  53/UDP
  TargetPort:        53/UDP
  Endpoints:         10.16.0.48:53,10.16.0.5:53
  Port:              dns-tcp  53/TCP
  TargetPort:        53/TCP
  Endpoints:         10.16.0.48:53,10.16.0.5:53

table=13 (ls_in_acl_after_lb):配置 acl 时选项 --apply-after-lb,字面意思,未使用
table=14 (ls_in_after_lb):after lb 的操作

  • 如 match=(ip4.dst == 10.16.4.138), action=(eth.dst = 00:00:00:c6:a4:f9; next;) 目的 IP 为 10.16.4.138,目的 mac 设为 00:00:00:c6:a4:f9

table=16 (ls_in_pre_hairpin) 配置 lb 后,如果 匹配 ip && ct.trk(ct 跟踪),则需要 hairpinned

  • 如 match=(ip && ct.trk), action=(reg0[6] = chk_lb_hairpin(); reg0[12] = chk_lb_hairpin_reply(); next;);

table=17 (ls_in_nat_hairpin):需要 hairpin 的,snat 操作

  • 如 match=(ip && ct.new && ct.trk && reg0[6] == 1), action=(ct_snat_to_vip; next;) action 为 ct_snat_to_vip

table=18 (ls_in_hairpin):hairpin 操作

  • 如 match=((reg0[6] == 1 || reg0[12] == 1)), action=(eth.dst <-> eth.src; outport = inport; flags.loopback = 1; output;) ,源目的 mac 互换,output 直接设置为 input,然后返回

table=19 (ls_in_arp_rsp):arp 回复流表

  • 如 match=(arp.tpa == 192.168.2.1 && arp.op == 1), action=(eth.dst = eth.src; eth.src = 00:00:00:c1:89:90; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = 00:00:00:c1:89:90; arp.tpa = arp.spa; arp.spa = 192.168.2.1; outport = inport; flags.loopback = 1; output;),如果请求 192.168.2.1 的 mac,action 目的 mac 设为请求包的源 mac,源 mac 设为 00:00:00:c1:89:90,output 设为 inport。然后发出完成 arp 回复

table=20 (ls_in_dhcp_options):获取 dhcp 配置,对应 subnet 创建时的 dhcpOptions 的配置。

  • 如 match=(inport == “pod9.default” && eth.src == 00:00:00:08:7e:05 && ip4.src == 0.0.0.0 && ip4.dst == 255.255.255.255 && udp.src == 68 && udp.dst == 67), action=(reg0[3] = put_dhcp_opts(offerip = 192.168.2.16, lease_time = 3600, netmask = 255.255.255.0, router = 192.168.2.1, server_id = 169.254.0.254); next;),如果是 pod9,源 mac 为 00:00:00:08:7e:05,源 0.0.0.0/68,目的 255.255.255.255/67,获取到 action 中的 dhcp 配置

table=21 (ls_in_dhcp_response):dhcp 回复

  • 如 match=(inport == “pod9.default” && eth.src == 00:00:00:08:7e:05 && ip4 && udp.src == 68 && udp.dst == 67 && reg0[3]), action=(eth.dst = eth.src; eth.src = 00:00:02:2E:2F:B8; ip4.src = 169.254.0.254; udp.src = 67; udp.dst = 68; outport = inport; flags.loopback = 1; output;),匹配条件加上了 table=20 action 中的 reg0[3] 的标识;然后构造 dhcp 回复报文发回。

table=22/23 (ls_in_dns_lookup/ls_in_dns_response):查询 dns 配置和回复 dns 请求,未使用

table=24 (ls_in_external_port):从 external logical ports,如 localnet 来的流,未使用

table=25 (ls_in_l2_lkup):实际的交换行为

  • 如 match=(eth.dst == 00:00:00:08:7e:05), action=(outport = “pod9.default”; output;),目的 mac 是 00:00:00:08:7e:05 从 pod9 的 lsp 发出

table=26 (ls_in_l2_unknown):未知流的处理

  • 如 match=(outport == “none”), action=(drop;),未设置 output 的流,drop。

  • Egress
    table=0 (ls_out_pre_lb):与 ingress ls_in_pre_lb 类似

    • 如 match=(ip && outport == “subnet-ovn-cluster”), action=(next;),output 为到 router port,next
      table=1-9 (ls_out_pre_acl,ls_out_pre_stateful,ls_out_acl_hint,ls_out_acl,ls_out_stateful,ls_out_port_sec_ip,ls_out_port_sec_l2)与 ingress 对应流表功能类似

Logical Router Datapaths

  • ingress
    table=0 (lr_in_admission):准入控制
    • 如 match=(vlan.present || eth.src[40]), action=(drop;) vlan 或组播丢弃

table=1 (lr_in_lookup_neighbor):arp 和 ipv6 nd,判断是否需要学习 mac binding。如果已有不需要学习,设置 reg9[2]。

  • 如 match=(inport == “ovn-cluster-subnet” && arp.spa == 192.168.2.0/24 && arp.op == 1), action=(reg9[2] = lookup_arp(inport, arp.spa, arp.sha); next;) subnet 上发出的 arp 请求,如果已记录的进行 reg9[2] 设置。

table=2 (lr_in_learn_neighbor):判断是否 reg9[2] == 1,如果不为 1,则需要记录 mac binding。

  • priority=100 , match=(reg9[2] == 1), action=(next;)
  • priority=90 , match=(arp), action=(put_arp(inport, arp.spa, arp.sha); next;)
  • reg9[2] 不为 1 时,learn mac binding

table=3 (lr_in_ip_input):logical_router 核心表,基础功能。

  • 如 match=(ip4.dst == 192.168.2.1 && icmp4.type == 8 && icmp4.code == 0), action=(ip4.dst <-> ip4.src; ip.ttl = 255; icmp4.type = 0; flags.loopback = 1; next; ),ping 网关,lr 回复的流表

ipv6 icmp:match=(ip6.dst == {dd:10:16::1, fe80::200:ff:fe63:b3f9} && icmp6.type == 128 && icmp6.code == 0), action=(ip6.dst <-> ip6.src; ip.ttl = 255; icmp6.type = 129; flags.loopback = 1; next; )

  • 如 match=(ip4.dst == {192.168.2.1}), action=(drop;),如果到网关的其他流量 drop。

table=4(lr_in_unsnat):egress 时做了 snat,那么回包需要取消之前的 snat

table=5(lr_in_defrag):将数据包发送到连接跟踪器进行跟踪,如在 lr 上的 三层,四层 lb

kubectl ko nbctl lb-add lb0 10.96.99.99:8080 10.16.0.10:80,10.16.0.15:80,10.16.0.2:80 tcp
kubectl ko nbctl lr-lb-add ovn-cluster lb0

  • 如 match=(ip && ip4.dst == 10.96.99.99 && tcp), action=(reg0 = 10.96.99.99; reg9[16…31] = tcp.dst; ct_dnat;),如果匹配到 lb vip,reg0 存 vip 地址,reg9[16…31] 存目的 port (8080),然后 ct_dnat 进行处理。

table=6(lr_in_dnat):数据包 dnat 处理

  • 如 match=(ct.new && ip4 && reg0 == 10.96.99.99 && tcp && reg9[16…31] == 8080), action=(ct_lb_mark(backends=10.16.0.10:80,10.16.0.15:80,10.16.0.2:80); ),匹配到 table5 的标记后,ct_lb_mark 后端几个 endpoint。

table=7(lr_in_ecmp_stateful):ECMP对称应答处理

table=8(lr_in_nd_ra_options):IPv6 ND RA 配置处理

  • 如 match=(inport == “ovn-cluster-subnet-dual” && ip6.dst == ff02::2 && nd_rs), action=(reg0[5] = put_nd_ra_opts(addr_mode = “dhcpv6_stateful”, slla = 00:00:00:37:30:f1, prefix = bb00::/64); next;) ,其中 subnet-dual 是个在 ovn-cluster vpc 里的双栈子网,从 subnet-dual port 来的流量,目的 mac 是 ff02::2(rs 报文目的 mac),回复 dhcp,mode 为 dhcpv6_stateful,前缀 bb00::/64。

table=9(lr_in_nd_ra_response) :IPv6 RA 回复

  • 如 match=(inport == “ovn-cluster-subnet-dual” && ip6.dst == ff02::2 && nd_ra && reg0[5]), action=(eth.dst = eth.src; eth.src = 00:00:00:37:30:f1; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe37:30f1; outport = inport; flags.loopback = 1; output;),对应上条 table 进行回复。

table=10(lr_in_ip_routing_pre):路由转发前配置,通常为 logical_route_port 带 options:route_table 配置的使用,未使用

table=11(lr_in_ip_routing):路由转发

  • 如 match=(ip4.dst == 192.168.2.0/24), action=(ip.ttl–; reg8[0…15] = 0; reg0 = ip4.dst; reg1 = 192.168.2.1; eth.src = 00:00:00:c1:89:90; outport = “ovn-cluster-subnet”; flags.loopback = 1; next;),目的地址是 lr 下的子网,ttl 减1,设置寄存器,设置源 mac 为网关(192.168.2.1 lrp)的 mac,设置 outport 为 lrp。

table=12(lr_in_ip_routing_ecmp):ECMP 路由

table=13(lr_in_policy):策略路由

  • 如 match=(ip4.src == $subnet.master_ip4), action=(reg0 = 100.64.0.2; reg1 = 100.64.0.1; eth.src = 00:00:00:e9:15:ff; outport = “ovn-cluster-join”; flags.loopback = 1; reg8[0…15] = 0; next;),如果源地址是 master 节点上 subnet 子网上的 port,源 mac 改为 join 网络网关的 mac,然后 outport 设置为 join 子网的网关 port。

由此可以看出先匹配静态路由,再匹配策略路由,静态路由会先设置 outport,但不会发出,然后过策略路由表,策略路由匹配上会更改 outport。

table=14(lr_in_policy_ecmp):ECMP 策略路由

table=15(lr_in_arp_resolve):arp/nd 决定,根据之前路由设置的 outport 和 寄存器 reg0 存的 ip 设置目的 mac

  • 如 match=(outport == “ovn-cluster-join” && reg0 == 100.64.0.2), action=(eth.dst = 00:00:00:21:85:b9; next;),匹配到上面 table13 的流量,设置目的 mac 为 100.64.0.2 的 mac,即 master 节点上 ovn0 的 mac。

table=16(lr_in_chk_pkt_len):检查包长度,在给 gw_port 设置 options:gateway_mtu 时生效。

table=17(lr_in_larger_pkts):同上,为从 logical_router_port 到 gw_port 的流量使用。

table=18(lr_in_gw_redirect):分布式逻辑路由中,当 logical_router_port 设置 chassises 时使用。

table=19(lr_in_arp_request):如果 目的 mac 未确定,通过 reg0 和 reg1 存的 ip 地址进行 arp 请求;如果确定 mac,则发出。

  • match=(eth.dst == 00:00:00:00:00:00 && ip4), action=(arp { eth.dst = ff:ff:ff:ff:ff:ff; arp.spa = reg1; arp.tpa = reg0; arp.op = 1; output; }; )

  • match=(1), action=(output;)

  • Egress
    table=0(lr_out_chk_dnat_local):检查是否需要 DNAT,通常与 ingress 中 SNAT 对应
    table=1(lr_out_undnat):已经建立连接后的流是否做 dnat,不如创建 lr-lb,就会多出下面流表

    • match=(ip), action=(flags.loopback = 1; ct_dnat;),去 ct_dnat 里检查
      table=2(lr_out_post_undnat):相对于上一张表,如果是新连接 ct_commit。
      table=3(lr_out_snat):查询 LR Snat 的配置
      table=4(lr_out_post_snat):执行 Snat,通常设置 force_snat_for_lb 时使用,后续有机会介绍。
      table=5(lr_out_egr_loop):分布式 LR,且一个 LRP 配置了 gw chassis 时使用。
      table=6(lr_out_delivery):发送。
    • match=(outport == “ovn-cluster-join”), action=(output;),outport + output

参考文档:https://www.mankier.com/8/ovn-northd

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OVN 流表基础 -- 基于 kubeOVN (一) 的相关文章

  • Testing ovn manually based on LXD (by quqi99)

    作者 xff1a 张华 发表于 xff1a 2022 05 27 版权声明 xff1a 可以任意转载 xff0c 转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 准备两个LXD容器 lxc list 43 43 43 43
  • ovn metadata (by quqi99)

    作者 xff1a 张华 发表于 xff1a 2022 08 25 版权声明 xff1a 可以任意转载 xff0c 转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 问题 客户描述虚机的metadata功能偶尔有问题 xff0c
  • ovn-central raft HA (by quqi99)

    作者 xff1a 张华 发表于 xff1a 2022 10 12 版权声明 xff1a 可以任意转载 xff0c 转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 What s raft RAFT https raft git
  • OVN简介

    作者简介 xff1a 郑敏先 xff0c 就职于诺云系统 xff08 上海 xff09 有限公司 工作地点为南京的诺云研发中心 担任解决方案工程师 本人博客为 xff1a http blog csdn net zhengmx100 一 为什
  • devstack安装OpenStack Pike版本 (OVN+VLAN)

    控制节点配置文件 Sample DevStack local conf This sample file is intended to be used for your typical DevStack environment that 3
  • OVN – OVN OpenStack(二)

    OpenStack networking ovn 项目为Neutron提供了一个基于ML2的OVN插件 xff0c 它使用OVN组件代替了各种Neutron的Python agent xff0c 也不再使用 RabbitMQ xff0c 而
  • OVN 架构分析

    架构分析Base flow L2 L3 forwardingOVN L2 gateway OVN 是 Open vSwitch 社区在 2015 年 1 月份才宣布的一个子项目 xff0c OVN 使用 Open vSwitch功能提供一个
  • OVN-软件定义网络(一)

    前言 测试环境是用github上开源代码搭建 编译完成后进行如下操作 环境配置 控制节点 创建逻辑交换机 ovn nbctl db 61 unix run openvswitch ovnnb db sock ls add ly ls 在逻辑
  • openstack和ovn架构

  • ovn 架构介绍

    ovn是什么就不多说了 xff0c 网上有很多介绍的文章 这里主要是学习下ovn的架构 xff0c 并通过实践认识一下ovn ovn代码最初是在ovs源码下 xff0c 但是从版本v2 13 0开始 xff0c ovn被移除ovs xff0
  • ovn-controller源码分析

    ovn controller是运行在chassis hypervisor上的后台进程 xff0c 向上通过OVSDB协议连接到OVN sourthbound数据库 xff0c 向下通过OVSDB协议连接到ovs数据库 xff0c 并通过op
  • OpenvSwitch 的 Open Virtual Network(OVN)项目

    几天前 xff08 1 月 13 日 xff09 xff0c OpenvSwitch 团队正式宣布了 OVN xff08 Open Virtual Network xff09 项目 xff0c 参考 Open Virtual Network
  • 【kubernetes/k8s概念】kube-ovn架构和部署安装

    Kube OVN是一款由灵雀云自主研发的开源企业级云原生Kubernetes容器网络编排系统 xff0c 它通过将OpenStack领域成熟的网络功能平移到Kubernetes xff0c 极大增强了Kubernetes容器网络的安全性 可
  • 【kubernetes/k8s概念】OVN NorthBound DB 及 ovn-nbctl 命令

    OVN 北向数据库 xff08 OVN Northbound DB xff09 是 OVN 和 CMS 之间的接口 xff0c Northbound DB 的数据几乎都是由 CMS 产生的 xff0c ovn northd 监听这个数据库的
  • 【kubernetes/k8s概念】OVN SouthBound DB 及 ovn-sbctl 命令

    OVN 南向数据库 xff08 OVN Southbound DB xff09 xff0c 南向数据库是系统的中心 xff0c 客户端是上层的 ovn northd 和下层运行在每一个传输节点的 ovn controller 南向数据库包括
  • OVN 简介

    文章目录 OVN 介绍OVN的架构OVN 应用OVN 信息流配置数据状态信息 Chassis 设置逻辑网络 OVN 介绍 Open vSwitch xff08 OVS xff09 是一款开源的 虚拟交换机 xff0c 控制协议方面它不但支持
  • OVN 流表基础 -- 基于 kubeOVN (一)

    文章目录 Kubectl ko 工具分析Nbctl SbctlTrace Ovn 流表MatchActionRegisterTable 介绍Logical Switch DatapathsLogical Router Datapaths K
  • OVS和OVN 2.8新功能

    OVS和OVN 2 8新功能 本文最初整理在我的github上SDN Learning notes 本文翻译自ovs官方文档 本文档主要是关于2017年8月底发布的Open vSwitch 2 8中添加的内容 xff0c 重点介绍OVN中的
  • OVN实验----L3互通

    概述 在L2互通基础上 xff0c 完成跨网段互访 物理拓扑 如上一个实验OVN实验 L2互通 逻辑拓扑 按照上个实验OVN实验 L2互通 的操作方式 xff0c 再配置一组容器blue xff0c 网段192 168 2 0 24 配置完
  • OVN实验----NAT

    概述 在L2互通 L3互通实验基础上通过NAT实现访问公网 架构图如下 xff0c 这里两台逻辑路由器LR1和GLR是通过一台逻辑交换机LSjoin互连的 xff0c GLR和物理网络设备通过LSlocal相连 物理拓扑 如上一个实验OVN

随机推荐