依据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);
}
}
}
版权声明:本文博主原创文章。博客,未经同意不得转载。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章