OVS 派OFPT_PORT_STATUS 流程
依据openflow合约[OFP1.0-38],当从物理端口ovs datapath 添加,改动或者删除的时候。都会先运行详细动作。然后通过ofp_port_status异步消息告知Controller,比方当我们运行 ovs-vsctl add-port br0 eth0 之类的命令后,就会更新ovsdb数据库。某一个轮询时全局变量 reconfiguring
变为true,从而会又一次配置这个ovs。
if (reconfiguring) {
// cfg 条目能够追踪到ovsdb中某个配置发生改变
if (cfg) {
if (!reconf_txn) {
reconf_txn = ovsdb_idl_txn_create(idl);
}
// 又一次配置每一个cfg,核心入口
if (bridge_reconfigure_continue(cfg)) {
ovsrec_open_vswitch_set_cur_cfg(cfg, cfg->next_cfg);
}
} else {
bridge_reconfigure_continue(&null_cfg);
}
}
接下来详细运行配置:
static bool
bridge_reconfigure_continue(const struct ovsrec_open_vswitch *ovs_cfg)
{
struct sockaddr_in *managers;
int sflow_bridge_number;
size_t n_managers;
struct bridge *br;
bool done; assert(reconfiguring);
// reconfigure首先要做的就是先删除旧端口,而后依据配置构建新端口
done = bridge_reconfigure_ofp(); /* Complete the configuration. */
sflow_bridge_number = 0;
collect_in_band_managers(ovs_cfg, &managers, &n_managers);
HMAP_FOR_EACH (br, node, &all_bridges) {
struct port *port; /* We need the datapath ID early to allow LACP ports to use it as the
* default system ID. */
bridge_configure_datapath_id(br); HMAP_FOR_EACH (port, hmap_node, &br->ports) {
struct iface *iface; port_configure(port); LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
iface_configure_cfm(iface);
iface_configure_qos(iface, port->cfg->qos);
iface_set_mac(iface);
}
}
bridge_configure_mirrors(br);
bridge_configure_flow_eviction_threshold(br);
bridge_configure_forward_bpdu(br);
bridge_configure_mac_idle_time(br);
bridge_configure_remotes(br, managers, n_managers);
bridge_configure_netflow(br);
bridge_configure_sflow(br, &sflow_bridge_number);
bridge_configure_stp(br);
bridge_configure_tables(br);
}
free(managers); if (done) {
/* ovs-vswitchd has completed initialization, so allow the process that
* forked us to exit successfully. */
daemonize_complete();
reconfiguring = false; VLOG_INFO("%s (Open vSwitch) %s", program_name, VERSION);
} return done;
}
这里先删除全部的port,再加入:
static bool
bridge_reconfigure_ofp(void)
{
long long int deadline;
struct bridge *br; time_refresh();
deadline = time_msec() + OFP_PORT_ACTION_WINDOW; /* The kernel will reject any attempt to add a given port to a datapath if
* that port already belongs to a different datapath, so we must do all
* port deletions before any port additions. */
HMAP_FOR_EACH (br, node, &all_bridges) {
struct ofpp_garbage *garbage, *next; LIST_FOR_EACH_SAFE (garbage, next, list_node, &br->ofpp_garbage) {
/* It's a bit dangerous to call bridge_run_fast() here as ofproto's
* internal datastructures may not be consistent. Eventually, when
* port additions and deletions are cheaper, these calls should be
* removed. */
bridge_run_fast();
ofproto_port_del(br->ofproto, garbage->ofp_port);
list_remove(&garbage->list_node);
free(garbage); time_refresh();
if (time_msec() >= deadline) {
return false;
}
bridge_run_fast();
}
} HMAP_FOR_EACH (br, node, &all_bridges) {
struct if_cfg *if_cfg, *next; HMAP_FOR_EACH_SAFE (if_cfg, next, hmap_node, &br->if_cfg_todo) {
//这里是核心,在我们的ovs bridge上添加一个接口
iface_create(br, if_cfg, -1);
time_refresh();
if (time_msec() >= deadline) {
return false;
}
}
} return true;
}
依据配置 if_cfg 给br添加一个interface,假设指定的openflowport号是负数。 则表示自己主动分配:
static bool
iface_create(struct bridge *br, struct if_cfg *if_cfg, int ofp_port)
{
const struct ovsrec_interface *iface_cfg = if_cfg->cfg;
const struct ovsrec_port *port_cfg = if_cfg->parent; struct netdev *netdev;
struct iface *iface;
struct port *port;
int error; /* Get rid of 'if_cfg' itself. We already copied out the interesting
* bits. */
hmap_remove(&br->if_cfg_todo, &if_cfg->hmap_node);
free(if_cfg); /* Do the bits that can fail up front.
*
* It's a bit dangerous to call bridge_run_fast() here as ofproto's
* internal datastructures may not be consistent. Eventually, when port
* additions and deletions are cheaper, these calls should be removed. */
bridge_run_fast();
assert(!iface_lookup(br, iface_cfg->name));
error = iface_do_create(br, iface_cfg, port_cfg, &ofp_port, &netdev);
bridge_run_fast();
if (error) {
iface_clear_db_record(iface_cfg);
return false;
} /* Get or create the port structure. */
port = port_lookup(br, port_cfg->name);
if (!port) {
port = port_create(br, port_cfg);
} /* Create the iface structure. */
iface = xzalloc(sizeof *iface);
list_push_back(&port->ifaces, &iface->port_elem);
hmap_insert(&br->iface_by_name, &iface->name_node,
hash_string(iface_cfg->name, 0));
iface->port = port;
iface->name = xstrdup(iface_cfg->name);
iface->ofp_port = -1;
iface->netdev = netdev;
iface->type = iface_get_type(iface_cfg, br->cfg);
iface->cfg = iface_cfg; iface_set_ofp_port(iface, ofp_port); /* Populate initial status in database. */
iface_refresh_stats(iface);
iface_refresh_status(iface); /* Add bond fake iface if necessary. */
if (port_is_bond_fake_iface(port)) {
struct ofproto_port ofproto_port; if (ofproto_port_query_by_name(br->ofproto, port->name,
&ofproto_port)) {
struct netdev *netdev;
int error; error = netdev_open(port->name, "internal", &netdev);
if (!error) {
// 将这个网络设备增加到我们的openflow switch中
ofproto_port_add(br->ofproto, netdev, NULL);
netdev_close(netdev);
} else {
VLOG_WARN("could not open network device %s (%s)",
port->name, strerror(error));
}
} else {
/* Already exists, nothing to do. */
ofproto_port_destroy(&ofproto_port);
}
} return true;
}
调用ofproto(openflow sw接口)详细实现的port_add方法:
int
ofproto_port_add(struct ofproto *ofproto, struct netdev *netdev,
uint16_t *ofp_portp)
{
uint16_t ofp_port;
int error; error = ofproto->ofproto_class->port_add(ofproto, netdev, &ofp_port);
// 看 dpif_linux_class 的详细实现
if (!error) {
// 更新我们的openflow交换机(即ofproto)
update_port(ofproto, netdev_get_name(netdev));
}
if (ofp_portp) {
*ofp_portp = error ? OFPP_NONE : ofp_port;
}
return error;
}
static void
update_port(struct ofproto *ofproto, const char *name)
{
struct ofproto_port ofproto_port;
struct ofputil_phy_port pp;
struct netdev *netdev;
struct ofport *port; COVERAGE_INC(ofproto_update_port); /* Fetch 'name''s location and properties from the datapath. */
netdev = (!ofproto_port_query_by_name(ofproto, name, &ofproto_port)
? ofport_open(ofproto, &ofproto_port, &pp)
: NULL);
if (netdev) {
port = ofproto_get_port(ofproto, ofproto_port.ofp_port);
if (port && !strcmp(netdev_get_name(port->netdev), name)) {
struct netdev *old_netdev = port->netdev; /* 'name' hasn't changed location. Any properties changed? */
if (!ofport_equal(&port->pp, &pp)) {
ofport_modified(port, &pp);
} update_mtu(ofproto, port); /* Install the newly opened netdev in case it has changed.
* Don't close the old netdev yet in case port_modified has to
* remove a retained reference to it.*/
port->netdev = netdev;
port->change_seq = netdev_change_seq(netdev); if (port->ofproto->ofproto_class->port_modified) {
port->ofproto->ofproto_class->port_modified(port);
} netdev_close(old_netdev);
} else {
/* If 'port' is nonnull then its name differs from 'name' and thus
* we should delete it. If we think there's a port named 'name'
* then its port number must be wrong now so delete it too. */
if (port) {
ofport_remove(port);
}
ofport_remove_with_name(ofproto, name);
// 看这里
ofport_install(ofproto, netdev, &pp);
}
} else {
/* Any port named 'name' is gone now. */
ofport_remove_with_name(ofproto, name);
}
ofproto_port_destroy(&ofproto_port);
}
static void
ofport_install(struct ofproto *p,
struct netdev *netdev, const struct ofputil_phy_port *pp)
{
const char *netdev_name = netdev_get_name(netdev);
struct ofport *ofport;
int error; /* Create ofport. */
ofport = p->ofproto_class->port_alloc();
if (!ofport) {
error = ENOMEM;
goto error;
}
ofport->ofproto = p;
ofport->netdev = netdev;
ofport->change_seq = netdev_change_seq(netdev);
ofport->pp = *pp;
ofport->ofp_port = pp->port_no; /* Add port to 'p'. */
hmap_insert(&p->ports, &ofport->hmap_node, hash_int(ofport->ofp_port, 0));
shash_add(&p->port_by_name, netdev_name, ofport); update_mtu(p, ofport); /* Let the ofproto_class initialize its private data. */
error = p->ofproto_class->port_construct(ofport);
if (error) {
goto error;
}
// 更新操作完毕后。发送通知消息到Controller
connmgr_send_port_status(p->connmgr, pp, OFPPR_ADD);
return; error:
VLOG_WARN_RL(&rl, "%s: could not add port %s (%s)",
p->name, netdev_name, strerror(error));
if (ofport) {
ofport_destroy__(ofport);
} else {
netdev_close(netdev);
}
}
发送port_status 和端口改变原因到SDN Controller:
void
connmgr_send_port_status(struct connmgr *mgr,
const struct ofputil_phy_port *pp, uint8_t reason)
{
/* XXX Should limit the number of queued port status change messages. */
struct ofputil_port_status ps;
struct ofconn *ofconn; ps.reason = reason;
ps.desc = *pp;
LIST_FOR_EACH (ofconn, node, &mgr->all_conns) {
if (ofconn_receives_async_msg(ofconn, OAM_PORT_STATUS, reason)) {
struct ofpbuf *msg; msg = ofputil_encode_port_status(&ps, ofconn->protocol);
ofconn_send(ofconn, msg, NULL);
}
}
}
版权声明:本文博主原创文章。博客,未经同意不得转载。
OVS 派OFPT_PORT_STATUS 流程的更多相关文章
- OVS处理upcall流程分析
处理upcall总体框架: 1.由函数handle_upcalls()批量处理(in batches)的是由内核传上来的dpif_upcalls,会解析出upcall的类型.这里主要看在内核中匹配流表 ...
- Open vSwitch for CentOS
原文发表于cu:2016-06-02 本文属于重发,ovs当前的安装方式可能略有不同. 参考文档: 官方文档: http://openvswitch.org/support/dist-docs-2.5 ...
- 探索 OpenStack 之(8):Neutron 深入探索之 OVS + GRE 之 完整网络流程 篇
前两篇博文分别研究了Compute节点和Neutron节点内部的网络架构.本文通过一些典型流程案例来分析具体网络流程过程. 0. 环境 同 学习OpenStack之(7):Neutron 深入学习之 ...
- ovs + kernel datapath 的分片与重组流程
非VXLAN的收发包调用栈 netdev_frame_hook() netdev_port_receive() ovs_vport_receive() ...
- OVS 总体架构、源码结构及数据流程全面解析
在前文「从 Bridge 到 OVS」中,我们已经对 OVS 进行了一番探索.本文决定从 OVS 的整体架构到各个组件都进行一个详细的介绍. OVS 架构 OVS 是产品级的虚拟交换机,大量应用在生产 ...
- openVswitch(OVS)源代码分析之工作流程(数据包处理)
上篇分析到数据包的收发,这篇开始着手分析数据包的处理问题.在openVswitch中数据包的处理是其核心技术,该技术分为三部分来实现:第一.根据skb数据包提取相关信息封装成key值:第二.根据提取到 ...
- openVswitch(OVS)源码分析之工作流程(哈希桶结构体的解释)
这篇blog是专门解决前篇openVswitch(OVS)源码分析之工作流程(哈希桶结构体的疑惑)中提到的哈希桶结构flex_array结构体成员变量含义的问题. 引用下前篇blog中分析讨论得到的f ...
- openVswitch(OVS)源代码分析之工作流程(flow流表查询)
原文链接: openVswitch(OVS)源代码分析之工作流程(flow流表查询)
- ovs处理openflow消息的流程
OVS处理各个openflow消息的详细代码在 ofproto/ofproto.c 中: static enum ofperr handle_openflow__(struct ofconn *ofc ...
随机推荐
- mybatis-generator使用
开发工具:eclipse,依赖环境 :maven 首先在eclipse marketplace中安装mybatis-generator,如图: 安装后需要重启. 新建一个maven项目MybatisG ...
- 【例题5-5 UVA 12096 】The SetStack Computer
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 用set来解决这个问题. 考虑如何表示 { {{}} }这个集合 我们可以把{}这个集合和一个数字映射->1 然后把1加入到某 ...
- ORACLE RMAN备份及还原 RMAN能够进行增量备份:数据库,表空间,数据文件
ORACLE RMAN备份及还原 RMAN能够进行增量备份:数据库.表空间.数据文件 仅仅有使用过的block能够被备份成backup set 表空间与数据文件相应关系:dba_data_file ...
- thinkphp中view页面中的volist标签转化为原生php分析(多去看源代码,你会发现不仅简单,方便你理解,还节约时间)
thinkphp中view页面中的volist标签转化为原生php分析(多去看源代码,你会发现不仅简单,方便你理解,还节约时间) 一.总结 1.标签和原生php之间的关系:标签只是为了方便你使用,标签 ...
- CImage将图片转为指定像素大小
CFileDialog fDlg(true, "jpg", "", OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, &q ...
- iOS进阶路线以及进阶书籍
第一,熟悉ARC机制:首先要了解ARC的前世今生.假设了解不清楚会导致两种可能,1,一个对象的引用莫名奇异为空.或失效了.这个一般都能在开发阶段及时发现,由于会导致应用异常.2.导致内存溢出:不了解A ...
- 安装Centos时“sda必须有一个GPT磁盘标签”
http://jingyan.baidu.com/article/c45ad29c272326051753e2d1.html
- 【Heritrix基础教程之3】Heritrix的基本架构 分类: H3_NUTCH 2014-06-01 16:56 1267人阅读 评论(0) 收藏
Heritrix可分为四大模块: 1.控制器CrawlController 2.待处理的uri列表 Frontier 3.线程池 ToeThread 4.各个步骤的处理器 (1)Pre-fetch ...
- 【poj2528】Mayor's posters
Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 59254 Accepted: 17167 Description The ...
- Redis内存管理的基石zmallc.c源代码解读(一)
当我第一次阅读了这个文件的源代码的时候.我笑了,忽然想起前几周阿里电话二面的时候,问到了自己定义内存管理函数并处理8字节对齐问题. 当时无言以对,在面试官无数次的提示下才答了出来,结果显而易见,挂掉了 ...