zoukankan      html  css  js  c++  java
  • 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);
            }
        }
    }
    



    版权声明:本文博主原创文章。博客,未经同意不得转载。

  • 相关阅读:
    jQuery实现动态搜索显示功能
    面试
    Struts1和Struts2的区别和对比(完整版)
    JAVA调用增删改的存储过程
    Spring MVC入门
    jQuery Ajax通用js封装
    js ==与===区别
    shell脚本awk
    C++对象模型初窥
    再见,2021
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4854465.html
Copyright © 2011-2022 走看看