概述
ovs的patch端口,用于连接两个网桥,命令如下
ovs-vsctl add-port br10 patch3 -- set interface patch3 type=patch options:peer=patch4 -- add-port br12 patch4 -- set interface patch4 type=patch options:peer=patch3
添加patch端口流程
添加端口时,会先后调用 port_construct 和 port_add,下面看一下这两个函数对于patch端口的特殊处理
a. port_construct
static int
port_construct(struct ofport *port_)
if (netdev_vport_is_patch(netdev)) {
/* By bailing out here, we don't submit the port to the sFlow module
* to be considered for counter polling export. This is correct
* because the patch port represents an interface that sFlow considers
* to be "internal" to the switch as a whole, and therefore not a
* candidate for counter polling. */
port->odp_port = ODPP_NONE;
ofport_update_peer(port);
return 0;
}
更新peer设备,比如上面的命令,给br10添加patch3,给br12添加patch4,
会调用两次ofport_update_peer,第一次调用给br10添加patch3时,遍历所有bridge,寻找peer patch4时会失败,因为patch4还没有添加
到bridge;第二次调用给br12添加patch4时,遍历所有bridge,寻找peer patch3会成功,此时会同时设置patch3和patch4的peer设备。
static void
ofport_update_peer(struct ofport_dpif *ofport)
{
const struct ofproto_dpif *ofproto;
struct dpif_backer *backer;
char *peer_name;
if (!netdev_vport_is_patch(ofport->up.netdev)) {
return;
}
backer = ofproto_dpif_cast(ofport->up.ofproto)->backer;
backer->need_revalidate = REV_RECONFIGURE;
if (ofport->peer) {
ofport->peer->peer = NULL;
ofport->peer = NULL;
}
peer_name = netdev_vport_patch_peer(ofport->up.netdev);
if (!peer_name) {
return;
}
//遍历所有bridge,寻找peer
HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
struct ofport *peer_ofport;
struct ofport_dpif *peer;
char *peer_peer;
//patch peer必须在同一个datapath中
if (ofproto->backer != backer) {
continue;
}
peer_ofport = shash_find_data(&ofproto->up.port_by_name, peer_name);
if (!peer_ofport) {
continue;
}
//找到peer设备后,设置本设备的peer为peer设备,同时也要设置peer设备的peer为本设备
peer = ofport_dpif_cast(peer_ofport);
peer_peer = netdev_vport_patch_peer(peer->up.netdev);
if (peer_peer && !strcmp(netdev_get_name(ofport->up.netdev),
peer_peer)) {
ofport->peer = peer;
ofport->peer->peer = ofport;
}
free(peer_peer);
break;
}
free(peer_name);
}
b. port_add
如果是patch类型端口,不会将其添加到datapath中,所以通过 ovs-appctl dpctl/show 是看不到patch端口的
static int
port_add(struct ofproto *ofproto_, struct netdev *netdev)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
const char *devname = netdev_get_name(netdev);
char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
const char *dp_port_name;
//如果是patch类型端口,则返回。不会将其添加到datapath中
if (netdev_vport_is_patch(netdev)) {
sset_add(&ofproto->ghost_ports, netdev_get_name(netdev));
return 0;
}
dp_port_name = netdev_vport_get_dpif_port(netdev, namebuf, sizeof namebuf);
if (!dpif_port_exists(ofproto->backer->dpif, dp_port_name)) {
odp_port_t port_no = ODPP_NONE;
int error;
将端口添加到datapath中
error = dpif_port_add(ofproto->backer->dpif, netdev, &port_no);
if (error) {
return error;
}
if (netdev_get_tunnel_config(netdev)) {
simap_put(&ofproto->backer->tnl_backers,
dp_port_name, odp_to_u32(port_no));
}
}
if (netdev_get_tunnel_config(netdev)) {
sset_add(&ofproto->ghost_ports, devname);
} else {
sset_add(&ofproto->ports, devname);
}
}
br10和br12必须在同一个datapath,否则寻找peer就会失败,ofport->peer就会为空,后面数据转发时也不会从peer设备发出。
patch端口数据转发的处理
假如出端口为patch port,流程如下:
static void
compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
const struct xlate_bond_recirc *xr, bool check_stp)
//如果patch端口有peer,则发送给peer
if (xport->peer) {
apply_nested_clone_actions(ctx, xport, xport->peer);
return;
}
//如果patch端口没有peer
if (xport->is_tunnel) {
...
} else {
//因为xport没有peer,所以xport->odp_port 为ODPP_NONE。
//比如通过patch端口连接两个不同类型datapath的网桥,patch端口的peer就是空的,所以也不能互相转发。
odp_port = xport->odp_port;
out_port = odp_port;
}
if (out_port != ODPP_NONE) {
}
static void
apply_nested_clone_actions(struct xlate_ctx *ctx, const struct xport *in_dev,
struct xport *out_dev)
//in_port 修改成出端口的id
flow->in_port.ofp_port = out_dev->ofp_port;
//临时设置成peer端口所在的桥
ctx->xbridge = out_dev->xbridge;
//查找peer端口所在的桥的openflow table,相当于peer端口收到报文的处理
xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, true,false);
//查找 openflow table
rule = rule_dpif_lookup_from_table();
xlate_recursively(ctx, rule, table_id <= old_table_id);
actions = rule_get_actions(&rule->up);
//执行action
do_xlate_actions(actions->ofpacts, actions->ofpacts_len, ctx);
//恢复出端口所在桥
ctx->xbridge = in_dev->xbridge;
最后会将流表和action安装到datapath中,指导后续报文转发。
实验
下面做一个小实验,拓扑图如下:
image.png
创建三个网桥br10,br11和br12,其中br10和br12为netdev类型,br11为system类型。
br10和br11通过patch端口patch1/patch2相连接,br10和br12通过patch端口patch3/patch4相连接。
br10上还添加了一个物理网卡enp129s0f0,其直连的网卡enp129s0f1配置ip地址2.2.2.2/24。
root@ubuntu:~# ovs-vsctl add-br br10 -- set bridge br10 datapath_type=netdev
root@ubuntu:~# ovs-vsctl add-br br12 -- set bridge br12 datapath_type=netdev
root@ubuntu:~# ovs-vsctl add-port br10 patch3 -- set interface patch3 type=patch options:peer=patch4 -- add-port br12 patch4 -- set interface patch4 type=patch options:peer=patch3
root@ubuntu:~# ovs-vsctl add-port br10 enp129s0f0
root@ubuntu:~# ovs-vsctl add-br br11 -- set bridge br11 datapath_type=system
root@ubuntu:~# ovs-vsctl add-port br10 patch1 -- set interface patch1 type=patch options:peer=patch2 -- add-port br11 patch2 -- set interface patch2 type=patch options:peer=patch1
root@ubuntu:~# ovs-vsctl show
e436075d-bffe-4cce-8cab-91cf99f0a4b2
Bridge "br10"
Port "enp129s0f0"
Interface "enp129s0f0"
Port "patch3"
Interface "patch3"
type: patch
options: {peer="patch4"}
Port "patch1"
Interface "patch1"
type: patch
options: {peer="patch2"}
Port "br10"
Interface "br10"
type: internal
Bridge "br11"
Port "br11"
Interface "br11"
type: internal
Port "patch2"
Interface "patch2"
type: patch
options: {peer="patch1"}
Bridge "br12"
Port "patch4"
Interface "patch4"
type: patch
options: {peer="patch3"}
Port "br12"
Interface "br12"
type: internal
//查看datapath信息
//可看到有两个datapath:netdev和system,并且datapath中不包含任何patch端口
root@ubuntu:~# ovs-appctl dpctl/show
netdev@ovs-netdev:
lookups: hit:2022051 missed:25 lost:0
flows: 1
port 0: ovs-netdev (tap)
port 1: br10 (tap)
port 2: enp129s0f0
port 3: br12 (tap)
system@ovs-system:
lookups: hit:0 missed:0 lost:0
flows: 0
masks: hit:0 total:1 hit/pkt:0.00
port 0: ovs-system (internal)
port 1: br11 (internal)
//给enp129s0f1 配置ip,并ping任意同网段的ip,目的是发送arp广播报文
root@ubuntu:~# ip link set dev enp129s0f1 2.2.2.2/24
root@ubuntu:~# ping 2.2.2.7
PING 2.2.2.7 (2.2.2.7) 56(84) bytes of data.
From 2.2.2.2 icmp_seq=1 Destination Host Unreachable
...
//只有netdev datapath有流表,system datapath没有
root@ubuntu:~# ovs-appctl dpctl/dump-flows netdev@ovs-netdev
flow-dump from non-dpdk interfaces:
recirc_id(0),in_port(2),packet_type(ns=0,id=0),eth(src=3c:fd:fe:a2:1f:a7,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=2.2.2.2,tip=2.2.2.7,op=1/0xff), packets:1522, bytes:91320, used:0.030s, actions:1,3
root@ubuntu:~#
root@ubuntu:~# ovs-appctl dpctl/dump-flows system@ovs-system
root@ubuntu:~#
//查看网桥br10上端口统计信息,enp129s0f0收到arp广播报文后,flood到br10上所有端口(patch1没有,因为它连接的是不同类型的网桥)
root@ubuntu:~# ovs-ofctl dump-ports br10
OFPST_PORT reply (xid=0x2): 4 ports
port patch1: rx pkts=0, bytes=0, drop=?, errs=?, frame=?, over=?, crc=?
tx pkts=0, bytes=0, drop=?, errs=?, coll=?
port patch3: rx pkts=0, bytes=0, drop=?, errs=?, frame=?, over=?, crc=?
tx pkts=17260, bytes=1045224, drop=?, errs=?, coll=?
port LOCAL: rx pkts=34, bytes=2780, drop=0, errs=0, frame=0, over=0, crc=0
tx pkts=2025556, bytes=147632755, drop=0, errs=0, coll=0
port enp129s0f0: rx pkts=1035304, bytes=64562809, drop=0, errs=0, frame=0, over=0, crc=0
tx pkts=0, bytes=0, drop=0, errs=0, coll=0
//查看网桥br11上端口统计信息,因为patch2没收到任何报文,所有br11上端口统计信息全0
root@ubuntu:~# ovs-ofctl dump-ports br11
OFPST_PORT reply (xid=0x2): 2 ports
port LOCAL: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
tx pkts=0, bytes=0, drop=0, errs=0, coll=0
port patch2: rx pkts=0, bytes=0, drop=?, errs=?, frame=?, over=?, crc=?
tx pkts=0, bytes=0, drop=?, errs=?, coll=?
//查看网桥br12上端口统计信息,patch4从patch3收到报文,flood到其他端口
root@ubuntu:~# ovs-ofctl dump-ports br12
OFPST_PORT reply (xid=0x2): 2 ports
port LOCAL: rx pkts=8, bytes=648, drop=0, errs=0, frame=0, over=0, crc=0
tx pkts=19764, bytes=1197319, drop=0, errs=0, coll=0
port patch4: rx pkts=17430, bytes=1055750, drop=?, errs=?, frame=?, over=?, crc=?
tx pkts=0, bytes=0, drop=?, errs=?, coll=?
结论:
a. patch端口只存在网桥上,datapath中不会存在
b. 如果出端口为patch端口,则相当于其peer设备收到报文,在peer设备所在网桥查找openflow流表进行转发
c. 不同类型datapath的网桥不能通过patch端口相连接
也可参考:ovs patch端口实现原理 - 简书 (jianshu.com)
最后
以上就是潇洒石头为你收集整理的ovs patch端口实现原理的全部内容,希望文章能够帮你解决ovs patch端口实现原理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复