Assuming this makes it in, will be my 500th commit.

Ethan

On Sun, Apr 22, 2012 at 14:22, Ethan Jackson <et...@nicira.com> wrote:
> The existing bridge_reconfigure() implementation is sub-optimal.
> When adding lots of new ports, on every pass through the run loop
> it allocates a bunch of "struct iface"s and "struct port"s, only to
> destroy them when out of time.  Additionally, when there are errors
> adding or deleting ports, it can fail to converge.  Instead it will
> attempt and fail to add the same set of ports forever.
>
> This patch rewrites bridge_reconfigure() using a new strategy.
> Whenever the database changes, some initial book keeping is done,
> and a list of future work is compiled.  The bridge begins whittling
> down this list, and stops processing database changes until
> finished.
>
> Bug #10902.
> Signed-off-by: Ethan Jackson <et...@nicira.com>
> ---
>  vswitchd/bridge.c |  772 
> ++++++++++++++++++++++++++++++-----------------------
>  1 file changed, 439 insertions(+), 333 deletions(-)
>
> diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
> index 15f6cb7..d7a9e88 100644
> --- a/vswitchd/bridge.c
> +++ b/vswitchd/bridge.c
> @@ -60,6 +60,19 @@ VLOG_DEFINE_THIS_MODULE(bridge);
>
>  COVERAGE_DEFINE(bridge_reconfigure);
>
> +/* Configuration of an uninstantiated iface. */
> +struct if_cfg {
> +    struct list list_node;              /* Node in bridge's if_cfg_queue. */
> +    const struct ovsrec_interface *cfg; /* Interface record. */
> +    const struct ovsrec_port *parent;   /* Parent port record. */
> +};
> +
> +/* OpenFlow port slated for removal from ofproto. */
> +struct ofpp_inmate {
> +    struct list list_node;      /* Node in bridge's ofpp_death_row. */
> +    uint16_t ofp_port;          /* Port to be deleted. */
> +};
> +
>  struct iface {
>     /* These members are always valid. */
>     struct list port_elem;      /* Element in struct port's "ifaces" list. */
> @@ -113,6 +126,9 @@ struct bridge {
>     struct hmap ifaces;         /* "struct iface"s indexed by ofp_port. */
>     struct hmap iface_by_name;  /* "struct iface"s indexed by name. */
>
> +    struct list ofpp_death_row; /* "struct ofpp_inmate"s slated for removal. 
> */
> +    struct list if_cfg_queue;   /* "struct if_cfg"s slated for creation. */
> +
>     /* Port mirroring. */
>     struct hmap mirrors;        /* "struct mirror" indexed by UUID. */
>
> @@ -151,11 +167,11 @@ static long long int db_limiter = LLONG_MIN;
>  * This allows the rest of the code to catch up on important things like
>  * forwarding packets. */
>  #define OFP_PORT_ACTION_WINDOW 10
> -static bool need_reconfigure = false;
> +static bool reconfiguring = false;
>
>  static void add_del_bridges(const struct ovsrec_open_vswitch *);
> -static void bridge_del_ofprotos(void);
> -static bool bridge_add_ofprotos(struct bridge *);
> +static void bridge_update_ofprotos(void);
> +static void bridge_populate_ofpp_death_row(struct bridge *);
>  static void bridge_create(const struct ovsrec_bridge *);
>  static void bridge_destroy(struct bridge *);
>  static struct bridge *bridge_lookup(const char *name);
> @@ -165,10 +181,6 @@ static size_t bridge_get_controllers(const struct bridge 
> *br,
>                                      struct ovsrec_controller 
> ***controllersp);
>  static void bridge_add_del_ports(struct bridge *,
>                                  const unsigned long int *splinter_vlans);
> -static void bridge_add_ofproto_ports(struct bridge *,
> -                                     long long int *port_action_timer);
> -static void bridge_del_ofproto_ports(struct bridge *,
> -                                     long long int *port_action_timer);
>  static void bridge_refresh_ofp_port(struct bridge *);
>  static void bridge_configure_datapath_id(struct bridge *);
>  static void bridge_configure_flow_eviction_threshold(struct bridge *);
> @@ -187,6 +199,9 @@ static void bridge_pick_local_hw_addr(struct bridge *,
>  static uint64_t bridge_pick_datapath_id(struct bridge *,
>                                         const uint8_t bridge_ea[ETH_ADDR_LEN],
>                                         struct iface *hw_addr_iface);
> +static void bridge_queue_if_cfg(struct bridge *,
> +                                const struct ovsrec_interface *,
> +                                const struct ovsrec_port *);
>  static uint64_t dpid_from_hash(const void *, size_t nbytes);
>  static bool bridge_has_bond_fake_iface(const struct bridge *,
>                                        const char *name);
> @@ -195,7 +210,6 @@ static bool port_is_bond_fake_iface(const struct port *);
>  static unixctl_cb_func qos_unixctl_show;
>
>  static struct port *port_create(struct bridge *, const struct ovsrec_port *);
> -static void port_add_ifaces(struct port *);
>  static void port_del_ifaces(struct port *);
>  static void port_destroy(struct port *);
>  static struct port *port_lookup(const struct bridge *, const char *name);
> @@ -216,6 +230,9 @@ static void mirror_refresh_stats(struct mirror *);
>  static void iface_configure_lacp(struct iface *, struct lacp_slave_settings 
> *);
>  static struct iface *iface_create(struct port *port,
>                                   const struct ovsrec_interface *if_cfg);
> +static struct iface *iface_from_if_cfg(struct bridge *, struct if_cfg *);
> +static void iface_refresh_type(struct iface *);
> +static void iface_init(struct iface *);
>  static void iface_destroy(struct iface *);
>  static struct iface *iface_lookup(const struct bridge *, const char *name);
>  static struct iface *iface_find(const char *name);
> @@ -407,23 +424,18 @@ static void
>  bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
>  {
>     unsigned long int *splinter_vlans;
> -    long long int port_action_timer;
> -    struct sockaddr_in *managers;
> -    struct bridge *br, *next;
> -    int sflow_bridge_number;
> -    size_t n_managers;
> +    struct bridge *br;
>
>     COVERAGE_INC(bridge_reconfigure);
>
> -    port_action_timer = LLONG_MAX;
> -    need_reconfigure = false;
> +    reconfiguring = true;
>
> -    /* Create and destroy "struct bridge"s, "struct port"s, and "struct
> -     * iface"s according to 'ovs_cfg', with only very minimal configuration
> -     * otherwise.
> +    /* Destroy "struct bridge"s, "struct port"s, and "struct iface"s 
> according
> +     * to 'ovs_cfg' while update the "if_cfg_queue", with only very minimal
> +     * configuration otherwise.
>      *
> -     * This is mostly an update to bridge data structures.  Very little is
> -     * pushed down to ofproto or lower layers. */
> +     * This is mostly an update to bridge data structures. Nothing is pushed
> +     * down to ofproto or lower layers. */
>     add_del_bridges(ovs_cfg);
>     splinter_vlans = collect_splinter_vlans(ovs_cfg);
>     HMAP_FOR_EACH (br, node, &all_bridges) {
> @@ -431,39 +443,93 @@ bridge_reconfigure(const struct ovsrec_open_vswitch 
> *ovs_cfg)
>     }
>     free(splinter_vlans);
>
> -    /* Delete all datapaths and datapath ports that are no longer configured.
> -     *
> -     * 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.  A datapath always has a
> -     * "local port" so we must delete not-configured datapaths too. */
> -    bridge_del_ofprotos();
> +    /* Delete datapaths that are no longer configured, and create ones which
> +     * don't exist but should. */
> +    bridge_update_ofprotos();
> +
> +    /* Make sure each "struct iface" has a correct ofp_port in its ofproto. 
> */
>     HMAP_FOR_EACH (br, node, &all_bridges) {
> -        if (br->ofproto) {
> -            bridge_del_ofproto_ports(br, &port_action_timer);
> +        bridge_refresh_ofp_port(br);
> +    }
> +
> +    /* Schedule ofp_ports which don't belong for deletion. */
> +    HMAP_FOR_EACH (br, node, &all_bridges) {
> +        bridge_populate_ofpp_death_row(br);
> +    }
> +
> +    /* Clear database records for "if_cfg"s which haven't been instantiated. 
> */
> +    HMAP_FOR_EACH (br, node, &all_bridges) {
> +        struct if_cfg *if_cfg;
> +
> +        LIST_FOR_EACH (if_cfg, list_node, &br->if_cfg_queue) {
> +            iface_clear_db_record(if_cfg->cfg);
>         }
>     }
> +}
>
> -    /* Create datapaths and datapath ports that are missing.
> -     *
> -     * After this is done, we have our final set of bridges, ports, and
> -     * interfaces.  Every "struct bridge" has an ofproto, every "struct port"
> -     * has at least one iface, every "struct iface" has a valid ofp_port and
> -     * netdev. */
> -    HMAP_FOR_EACH_SAFE (br, next, node, &all_bridges) {
> -        if (!br->ofproto) {
> -            if (bridge_add_ofprotos(br)) {
> -                bridge_del_ofproto_ports(br, &port_action_timer);
> -            } else {
> -                bridge_destroy(br);
> +static bool
> +bridge_reconfigure_ofp(void)
> +{
> +    long long int deadline;
> +    struct bridge *br;
> +    bool done = true;
> +
> +    /* Do any work needed to complete configuration.  Don't consider 
> ourselves
> +     * done unless no work was needed in this iteration.  This guarantees 
> that
> +     * ofproto_run() has a chance to respond to newly added ports. */
> +
> +    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_inmate *inmate, *next;
> +
> +        LIST_FOR_EACH_SAFE (inmate, next, list_node, &br->ofpp_death_row) {
> +            ofproto_port_del(br->ofproto, inmate->ofp_port);
> +            list_remove(&inmate->list_node);
> +            free(inmate);
> +            done = false;
> +
> +            time_refresh();
> +            if (time_msec() >= deadline) {
> +                return done;
>             }
>         }
>     }
> +
>     HMAP_FOR_EACH (br, node, &all_bridges) {
> -        bridge_refresh_ofp_port(br);
> -        bridge_add_ofproto_ports(br, &port_action_timer);
> +        struct if_cfg *if_cfg, *next;
> +
> +       LIST_FOR_EACH_SAFE (if_cfg, next, list_node, &br->if_cfg_queue) {
> +            iface_init(iface_from_if_cfg(br, if_cfg));
> +            list_remove(&if_cfg->list_node);
> +            free(if_cfg);
> +            done = false;
> +
> +            time_refresh();
> +            if (time_msec() >= deadline) {
> +                return done;
> +            }
> +        }
>     }
>
> +    return done;
> +}
> +
> +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;
> +
> +    done = bridge_reconfigure_ofp();
> +
>     /* Complete the configuration. */
>     sflow_bridge_number = 0;
>     collect_in_band_managers(ovs_cfg, &managers, &n_managers);
> @@ -497,22 +563,27 @@ bridge_reconfigure(const struct ovsrec_open_vswitch 
> *ovs_cfg)
>     }
>     free(managers);
>
> -    if (!need_reconfigure) {
> +    if (done) {
>         /* ovs-vswitchd has completed initialization, so allow the process 
> that
>          * forked us to exit successfully. */
>         daemonize_complete();
> +        reconfiguring = false;
>     }
> +
> +    return done;
>  }
>
> -/* Iterate over all ofprotos and delete any of them that do not have a
> - * configured bridge or that are the wrong type. */
> +/* Delete ofprotos which aren't configured or have the wrong type.  Create
> + * ofprotos which don't exist but need to. */
>  static void
> -bridge_del_ofprotos(void)
> +bridge_update_ofprotos(void)
>  {
> +    struct bridge *br, *next;
>     struct sset names;
>     struct sset types;
>     const char *type;
>
> +    /* Delete ofprotos with no bridge or with the wrong type. */
>     sset_init(&names);
>     sset_init(&types);
>     ofproto_enumerate_types(&types);
> @@ -521,7 +592,7 @@ bridge_del_ofprotos(void)
>
>         ofproto_enumerate_names(type, &names);
>         SSET_FOR_EACH (name, &names) {
> -            struct bridge *br = bridge_lookup(name);
> +            br = bridge_lookup(name);
>             if (!br || strcmp(type, br->type)) {
>                 ofproto_delete(name, type);
>             }
> @@ -529,17 +600,39 @@ bridge_del_ofprotos(void)
>     }
>     sset_destroy(&names);
>     sset_destroy(&types);
> -}
>
> -static bool
> -bridge_add_ofprotos(struct bridge *br)
> -{
> -    int error = ofproto_create(br->name, br->type, &br->ofproto);
> -    if (error) {
> -        VLOG_ERR("failed to create bridge %s: %s", br->name, 
> strerror(error));
> -        return false;
> +    /* Suppose we have an ofproto named "a" with a port "b" and we need to
> +     * create an ofproto named "b".  Since port "b" exists on "a", creation 
> of
> +     * ofproto "b" will fail because it won't be able to make an internal 
> port.
> +     * To avoid this problem, we remove all ports from datapaths which have 
> the
> +     * same name as a different ofproto.  This situation is unlikely to occur
> +     * frequently, so we don't rate limit it for simplicity. */
> +    HMAP_FOR_EACH (br, node, &all_bridges) {
> +        if (br->ofproto) {
> +            struct ofproto_port ofproto_port;
> +            struct ofproto_port_dump dump;
> +
> +            OFPROTO_PORT_FOR_EACH (&ofproto_port, &dump, br->ofproto) {
> +                struct bridge *ofp_br = bridge_lookup(ofproto_port.name);
> +
> +                if (ofp_br && ofp_br != br) {
> +                    ofproto_port_del(br->ofproto, ofproto_port.ofp_port);
> +                }
> +            }
> +        }
> +    }
> +
> +    /* Add ofprotos for bridges which don't have one yet. */
> +    HMAP_FOR_EACH_SAFE (br, next, node, &all_bridges) {
> +        if (!br->ofproto) {
> +            int error = ofproto_create(br->name, br->type, &br->ofproto);
> +            if (error) {
> +                VLOG_ERR("failed to create bridge %s: %s", br->name,
> +                         strerror(error));
> +                bridge_destroy(br);
> +            }
> +        }
>     }
> -    return true;
>  }
>
>  static void
> @@ -1050,80 +1143,6 @@ add_del_bridges(const struct ovsrec_open_vswitch *cfg)
>     shash_destroy(&new_br);
>  }
>
> -static bool
> -may_port_action(long long int *port_action_timer)
> -{
> -    if (need_reconfigure) {
> -        return false;
> -    }
> -
> -    time_refresh();
> -    if (*port_action_timer == LLONG_MAX) {
> -        *port_action_timer = time_msec() + OFP_PORT_ACTION_WINDOW;
> -    } else if (time_msec() > *port_action_timer) {
> -        need_reconfigure = true;
> -        return false;
> -    }
> -    return true;
> -}
> -
> -/* Delete each ofproto port on 'br' that doesn't have a corresponding "struct
> - * iface".
> - *
> - * 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. */
> -static void
> -bridge_del_ofproto_ports(struct bridge *br,
> -                         long long int *port_action_timer)
> -{
> -    struct ofproto_port_dump dump;
> -    struct ofproto_port ofproto_port;
> -
> -    OFPROTO_PORT_FOR_EACH (&ofproto_port, &dump, br->ofproto) {
> -        const char *name = ofproto_port.name;
> -        struct iface *iface;
> -        const char *type;
> -        int error;
> -
> -        /* Ignore the local port.  We can't change it anyhow. */
> -        if (!strcmp(name, br->name)) {
> -            continue;
> -        }
> -
> -        /* Get the type that 'ofproto_port' should have (ordinarily the
> -         * type of its corresponding iface) or NULL if it should be
> -         * deleted. */
> -        iface = iface_lookup(br, name);
> -        type = (iface ? iface->type
> -                : bridge_has_bond_fake_iface(br, name) ? "internal"
> -                : NULL);
> -
> -        /* If it's the wrong type then delete the ofproto port. */
> -        if (type
> -            && !strcmp(ofproto_port.type, type)
> -            && (!iface || !iface->netdev
> -                || !strcmp(netdev_get_type(iface->netdev), type))) {
> -            continue;
> -        }
> -
> -        if (may_port_action(port_action_timer)) {
> -            error = ofproto_port_del(br->ofproto, ofproto_port.ofp_port);
> -            if (error) {
> -                VLOG_WARN("bridge %s: failed to remove %s interface (%s)",
> -                          br->name, name, strerror(error));
> -            } else {
> -                VLOG_INFO("bridge %s: removed interface %s (%d)", br->name,
> -                          name, ofproto_port.ofp_port);
> -            }
> -        }
> -        if (iface) {
> -            netdev_close(iface->netdev);
> -            iface->netdev = NULL;
> -        }
> -    }
> -}
> -
>  static void
>  iface_set_ofp_port(struct iface *iface, int ofp_port)
>  {
> @@ -1136,13 +1155,45 @@ iface_set_ofp_port(struct iface *iface, int ofp_port)
>  }
>
>  static void
> +bridge_ofproto_port_del(struct bridge *br, struct ofproto_port ofproto_port)
> +{
> +    int error = ofproto_port_del(br->ofproto, ofproto_port.ofp_port);
> +    if (error) {
> +        VLOG_WARN("bridge %s: failed to remove %s interface (%s)",
> +                  br->name, ofproto_port.name, strerror(error));
> +    } else {
> +        VLOG_INFO("bridge %s: removed interface %s (%d)", br->name,
> +                  ofproto_port.name, ofproto_port.ofp_port);
> +    }
> +}
> +
> +/* Update bridges "if_cfg"s, "struct port"s, and "struct iface"s to be
> + * consistent with the ofp_ports in "br->ofproto". */
> +static void
>  bridge_refresh_ofp_port(struct bridge *br)
>  {
>     struct ofproto_port_dump dump;
>     struct ofproto_port ofproto_port;
> -    struct port *port;
> +    struct port *port, *port_next;
> +    struct if_cfg *if_cfg, *if_cfg_next;
> +
> +    /* Find any "if_cfg"s which already exist in the datapath and promote 
> them
> +     * to full fledged "struct iface"s. */
> +    LIST_FOR_EACH_SAFE (if_cfg, if_cfg_next, list_node, &br->if_cfg_queue) {
> +        if (!ofproto_port_query_by_name(br->ofproto, if_cfg->cfg->name,
> +                                        &ofproto_port))  {
> +            struct iface *iface = iface_from_if_cfg(br, if_cfg);
> +
> +            iface_set_ofp_port(iface, ofproto_port.ofp_port);
> +            iface_init(iface);
>
> -    /* Clear all the "ofp_port"es. */
> +            ofproto_port_destroy(&ofproto_port);
> +            list_remove(&if_cfg->list_node);
> +            free(if_cfg);
> +        }
> +    }
> +
> +    /* Clear each "struct iface"s ofp_port so we can get it's correct value. 
> */
>     hmap_clear(&br->ifaces);
>     HMAP_FOR_EACH (port, hmap_node, &br->ports) {
>         struct iface *iface;
> @@ -1162,149 +1213,163 @@ bridge_refresh_ofp_port(struct bridge *br)
>             } else if (iface_from_ofp_port(br, ofproto_port.ofp_port)) {
>                 VLOG_WARN("bridge %s: interface %"PRIu16" reported twice",
>                           br->name, ofproto_port.ofp_port);
> -            } else {
> +            } else if (!strcmp(ofproto_port.type, iface->type)) {
>                 iface_set_ofp_port(iface, ofproto_port.ofp_port);
> +            } else {
> +                /* Port has incorrect type so delete it later. */
> +            }
> +        } else if (bridge_has_bond_fake_iface(br, ofproto_port.name)
> +                   && strcmp(ofproto_port.type, "internal")) {
> +            /* Bond fake iface with the wrong type. */
> +            bridge_ofproto_port_del(br, ofproto_port);
> +        }
> +    }
> +
> +    /* Some ifaces may not have "ofp_port"s in ofproto and therefore don't
> +     * deserve to have "struct iface"s.  Demote these to "if_cfg"s so that
> +     * later they can be added to ofproto. */
> +    HMAP_FOR_EACH_SAFE (port, port_next, hmap_node, &br->ports) {
> +        struct iface *iface, *iface_next;
> +
> +        LIST_FOR_EACH_SAFE (iface, iface_next, port_elem, &port->ifaces) {
> +            if (iface->ofp_port < 0) {
> +                bridge_queue_if_cfg(br, iface->cfg, port->cfg);
> +                iface_destroy(iface);
>             }
>         }
> +
> +        if (list_is_empty(&port->ifaces)) {
> +            port_destroy(port);
> +        }
>     }
>  }
>
> -/* Add an ofproto port for any "struct iface" that doesn't have one.
> - * Delete any "struct iface" for which this fails.
> - * Delete any "struct port" that thereby ends up with no ifaces. */
>  static void
> -bridge_add_ofproto_ports(struct bridge *br,
> -                         long long int *port_action_timer)
> +bridge_populate_ofpp_death_row(struct bridge *br)
>  {
> -    struct port *port, *next_port;
> +    struct ofproto_port_dump dump;
> +    struct ofproto_port ofproto_port;
>
> -    HMAP_FOR_EACH_SAFE (port, next_port, hmap_node, &br->ports) {
> -        struct iface *iface, *next_iface;
> -        struct ofproto_port ofproto_port;
> +    OFPROTO_PORT_FOR_EACH (&ofproto_port, &dump, br->ofproto) {
> +        if (!iface_lookup(br, ofproto_port.name)) {
> +            struct ofpp_inmate *inmate = xmalloc(sizeof *inmate);
> +            inmate->ofp_port = ofproto_port.ofp_port;
> +            list_push_front(&br->ofpp_death_row, &inmate->list_node);
> +        }
> +    }
> +}
>
> -        LIST_FOR_EACH_SAFE (iface, next_iface, port_elem, &port->ifaces) {
> -            int error;
> +/* Initialize 'iface' with a netdev and ofp_port if necessary. */
> +static void
> +iface_init(struct iface *iface)
> +{
> +    struct port *port = iface->port;
> +    struct bridge *br = port->bridge;
> +    struct ofproto_port ofproto_port;
> +    int error;
>
> -            if (iface->ofp_port < 0 && !may_port_action(port_action_timer)) {
> -                iface_clear_db_record(iface->cfg);
> -                iface_destroy(iface);
> -                continue;
> -            }
> +    assert(!iface->netdev);
> +    error = netdev_open(iface->name, iface->type, &iface->netdev);
> +    if (error) {
> +        VLOG_WARN("could not open network device %s (%s)", iface->name,
> +                  strerror(error));
> +    }
>
> -            /* Open the netdev. */
> -            if (!iface->netdev) {
> -                error = netdev_open(iface->name, iface->type, 
> &iface->netdev);
> -                if (error) {
> -                    VLOG_WARN("could not open network device %s (%s)",
> -                              iface->name, strerror(error));
> -                }
> +    if (iface->netdev
> +        && port->cfg->vlan_mode
> +        && !strcmp(port->cfg->vlan_mode, "splinter")) {
> +        netdev_turn_flags_on(iface->netdev, NETDEV_UP, true);
> +    }
>
> -                if (iface->netdev
> -                    && port->cfg->vlan_mode
> -                    && !strcmp(port->cfg->vlan_mode, "splinter")) {
> -                    netdev_turn_flags_on(iface->netdev, NETDEV_UP, true);
> -                }
> -            } else {
> -                error = 0;
> -            }
> +    /* Configure the netdev. */
> +    if (iface->netdev) {
> +        struct shash args;
>
> -            /* Configure the netdev. */
> -            if (iface->netdev) {
> -                struct shash args;
> -
> -                shash_init(&args);
> -                shash_from_ovs_idl_map(iface->cfg->key_options,
> -                                       iface->cfg->value_options,
> -                                       iface->cfg->n_options, &args);
> -                error = netdev_set_config(iface->netdev, &args);
> -                shash_destroy(&args);
> -
> -                if (error) {
> -                    VLOG_WARN("could not configure network device %s (%s)",
> -                              iface->name, strerror(error));
> -                    netdev_close(iface->netdev);
> -                    iface->netdev = NULL;
> -                }
> -            }
> +        shash_init(&args);
> +        shash_from_ovs_idl_map(iface->cfg->key_options,
> +                               iface->cfg->value_options,
> +                               iface->cfg->n_options, &args);
> +        error = netdev_set_config(iface->netdev, &args);
> +        shash_destroy(&args);
>
> -            /* Add the port, if necessary. */
> -            if (iface->netdev && iface->ofp_port < 0) {
> -                uint16_t ofp_port;
> -                int error;
> -
> -                error = ofproto_port_add(br->ofproto, iface->netdev,
> -                                         &ofp_port);
> -                if (!error) {
> -                    VLOG_INFO("bridge %s: added interface %s (%d)", br->name,
> -                              iface->name, ofp_port);
> -                    iface_set_ofp_port(iface, ofp_port);
> -                } else {
> -                    netdev_close(iface->netdev);
> -                    iface->netdev = NULL;
> -                }
> -            }
> +        if (error) {
> +            VLOG_WARN("could not configure network device %s (%s)",
> +                      iface->name, strerror(error));
> +            netdev_close(iface->netdev);
> +            iface->netdev = NULL;
> +        }
> +    }
>
> -            /* Populate stats columns in new Interface rows. */
> -            if (iface->netdev && iface->need_refresh) {
> -                iface_refresh_stats(iface);
> -                iface_refresh_status(iface);
> -                iface->need_refresh = false;
> -            }
> +    /* Add the port, if necessary. */
> +    if (iface->netdev && iface->ofp_port < 0) {
> +        uint16_t ofp_port;
> +        int error;
>
> -            /* Delete the iface if we failed. */
> -            if (iface->netdev && iface->ofp_port >= 0) {
> -                VLOG_DBG("bridge %s: interface %s is on port %d",
> -                         br->name, iface->name, iface->ofp_port);
> -            } else {
> -                if (iface->netdev) {
> -                    VLOG_ERR("bridge %s: missing %s interface, dropping",
> -                             br->name, iface->name);
> -                } else {
> -                    /* We already reported a related error, don't bother
> -                     * duplicating it. */
> -                }
> -                if (!ofproto_port_query_by_name(br->ofproto, port->name,
> -                                                &ofproto_port)) {
> -                    VLOG_INFO("bridge %s: removed interface %s (%d)",
> -                              br->name, port->name, ofproto_port.ofp_port);
> -                    ofproto_port_del(br->ofproto, ofproto_port.ofp_port);
> -                    ofproto_port_destroy(&ofproto_port);
> -                }
> -                iface_clear_db_record(iface->cfg);
> -                iface_destroy(iface);
> -            }
> +        error = ofproto_port_add(br->ofproto, iface->netdev,
> +                                 &ofp_port);
> +        if (!error) {
> +            VLOG_INFO("bridge %s: added interface %s (%d)", br->name,
> +                      iface->name, ofp_port);
> +            iface_set_ofp_port(iface, ofp_port);
> +        } else {
> +            netdev_close(iface->netdev);
> +            iface->netdev = NULL;
>         }
> +    }
>
> -        if (list_is_empty(&port->ifaces)) {
> -            if (!need_reconfigure) {
> -                VLOG_WARN("%s port has no interfaces, dropping", port->name);
> -            }
> -            port_destroy(port);
> -            continue;
> +    /* Populate stats columns in new Interface rows. */
> +    if (iface->netdev && iface->need_refresh) {
> +        iface_refresh_stats(iface);
> +        iface_refresh_status(iface);
> +        iface->need_refresh = false;
> +    }
> +
> +    /* Delete the iface if we failed. */
> +    if (iface->netdev && iface->ofp_port >= 0) {
> +        VLOG_DBG("bridge %s: interface %s is on port %d",
> +                 br->name, iface->name, iface->ofp_port);
> +    } else {
> +        if (iface->netdev) {
> +            VLOG_ERR("bridge %s: missing %s interface, dropping",
> +                     br->name, iface->name);
> +        } else {
> +            /* We already reported a related error, don't bother
> +             * duplicating it. */
>         }
> +        if (!ofproto_port_query_by_name(br->ofproto, port->name,
> +                                        &ofproto_port)) {
> +            VLOG_INFO("bridge %s: removed interface %s (%d)",
> +                      br->name, port->name, ofproto_port.ofp_port);
> +            bridge_ofproto_port_del(br, ofproto_port);
> +            ofproto_port_destroy(&ofproto_port);
> +        }
> +        iface_clear_db_record(iface->cfg);
> +        iface_destroy(iface);
> +    }
>
> -        /* Add bond fake iface if necessary. */
> -        if (port_is_bond_fake_iface(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) {
> -                    /* There are unlikely to be a great number of fake
> -                     * interfaces so we don't bother rate limiting their
> -                     * creation. */
> -                    ofproto_port_add(br->ofproto, netdev, NULL);
> -                    netdev_close(netdev);
> -                } else {
> -                    VLOG_WARN("could not open network device %s (%s)",
> -                              port->name, strerror(error));
> -                }
> +    if (list_is_empty(&port->ifaces)) {
> +        port_destroy(port);
> +        return;
> +    }
> +
> +    /* Add bond fake iface if necessary. */
> +    if (port_is_bond_fake_iface(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) {
> +                ofproto_port_add(br->ofproto, netdev, NULL);
> +                netdev_close(netdev);
>             } else {
> -                /* Already exists, nothing to do. */
> -                ofproto_port_destroy(&ofproto_port);
> +                VLOG_WARN("could not open network device %s (%s)",
> +                          port->name, strerror(error));
>             }
> +        } else {
> +            /* Already exists, nothing to do. */
> +            ofproto_port_destroy(&ofproto_port);
>         }
>     }
>  }
> @@ -1929,26 +1994,30 @@ bridge_run_fast(void)
>  void
>  bridge_run(void)
>  {
> +    static const struct ovsrec_open_vswitch null_cfg;
>     const struct ovsrec_open_vswitch *cfg;
>
>     bool vlan_splinters_changed;
>     struct bridge *br;
>
>     /* (Re)configure if necessary. */
> -    ovsdb_idl_run(idl);
> -    if (ovsdb_idl_is_lock_contended(idl)) {
> -        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
> -        struct bridge *br, *next_br;
> +    if (!reconfiguring) {
> +        ovsdb_idl_run(idl);
>
> -        VLOG_ERR_RL(&rl, "another ovs-vswitchd process is running, "
> -                    "disabling this process until it goes away");
> +        if (ovsdb_idl_is_lock_contended(idl)) {
> +            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
> +            struct bridge *br, *next_br;
>
> -        HMAP_FOR_EACH_SAFE (br, next_br, node, &all_bridges) {
> -            bridge_destroy(br);
> +            VLOG_ERR_RL(&rl, "another ovs-vswitchd process is running, "
> +                        "disabling this process until it goes away");
> +
> +            HMAP_FOR_EACH_SAFE (br, next_br, node, &all_bridges) {
> +                bridge_destroy(br);
> +            }
> +            return;
> +        } else if (!ovsdb_idl_has_lock(idl)) {
> +            return;
>         }
> -        return;
> -    } else if (!ovsdb_idl_has_lock(idl)) {
> -        return;
>     }
>     cfg = ovsrec_open_vswitch_first(idl);
>
> @@ -1982,26 +2051,37 @@ bridge_run(void)
>         }
>     }
>
> -    if (need_reconfigure || ovsdb_idl_get_seqno(idl) != idl_seqno
> -        || vlan_splinters_changed) {
> +    if (ovsdb_idl_get_seqno(idl) != idl_seqno || vlan_splinters_changed) {
>         idl_seqno = ovsdb_idl_get_seqno(idl);
>         if (cfg) {
>             struct ovsdb_idl_txn *txn = ovsdb_idl_txn_create(idl);
>
>             bridge_reconfigure(cfg);
>
> -            ovsrec_open_vswitch_set_cur_cfg(cfg, cfg->next_cfg);
>             ovsdb_idl_txn_commit(txn);
>             ovsdb_idl_txn_destroy(txn); /* XXX */
>         } else {
>             /* We still need to reconfigure to avoid dangling pointers to
>              * now-destroyed ovsrec structures inside bridge data. */
> -            static const struct ovsrec_open_vswitch null_cfg;
> -
>             bridge_reconfigure(&null_cfg);
>         }
>     }
>
> +    if (reconfiguring) {
> +        struct ovsdb_idl_txn *txn = ovsdb_idl_txn_create(idl);
> +
> +        if (cfg) {
> +            if (bridge_reconfigure_continue(cfg)) {
> +                ovsrec_open_vswitch_set_cur_cfg(cfg, cfg->next_cfg);
> +            }
> +        } else {
> +            bridge_reconfigure_continue(&null_cfg);
> +        }
> +
> +        ovsdb_idl_txn_commit(txn);
> +        ovsdb_idl_txn_destroy(txn); /* XXX */
> +    }
> +
>     /* Refresh system and interface stats if necessary. */
>     if (time_msec() >= stats_timer) {
>         if (cfg) {
> @@ -2089,7 +2169,7 @@ bridge_wait(void)
>  {
>     ovsdb_idl_wait(idl);
>
> -    if (need_reconfigure) {
> +    if (reconfiguring) {
>         poll_immediate_wake();
>     }
>
> @@ -2223,6 +2303,9 @@ bridge_create(const struct ovsrec_bridge *br_cfg)
>     hmap_init(&br->iface_by_name);
>     hmap_init(&br->mirrors);
>
> +    list_init(&br->if_cfg_queue);
> +    list_init(&br->ofpp_death_row);
> +
>     hmap_insert(&all_bridges, &br->node, hash_string(br->name, 0));
>  }
>
> @@ -2232,6 +2315,8 @@ bridge_destroy(struct bridge *br)
>     if (br) {
>         struct mirror *mirror, *next_mirror;
>         struct port *port, *next_port;
> +        struct if_cfg *if_cfg, *next_if_cfg;
> +        struct ofpp_inmate *inmate, *next_inmate;
>
>         HMAP_FOR_EACH_SAFE (port, next_port, hmap_node, &br->ports) {
>             port_destroy(port);
> @@ -2239,6 +2324,19 @@ bridge_destroy(struct bridge *br)
>         HMAP_FOR_EACH_SAFE (mirror, next_mirror, hmap_node, &br->mirrors) {
>             mirror_destroy(mirror);
>         }
> +
> +        LIST_FOR_EACH_SAFE (inmate, next_inmate, list_node,
> +                            &br->ofpp_death_row) {
> +            list_remove(&inmate->list_node);
> +            free(inmate);
> +        }
> +
> +        LIST_FOR_EACH_SAFE (if_cfg, next_if_cfg, list_node,
> +                            &br->if_cfg_queue) {
> +            list_remove(&if_cfg->list_node);
> +            free(if_cfg);
> +        }
> +
>         hmap_remove(&all_bridges, &br->node);
>         ofproto_destroy(br->ofproto);
>         hmap_destroy(&br->ifaces);
> @@ -2330,17 +2428,54 @@ bridge_get_controllers(const struct bridge *br,
>     return n_controllers;
>  }
>
> -/* Adds and deletes "struct port"s and "struct iface"s under 'br' to match
> - * those configured in 'br->cfg'. */
> +static void
> +bridge_queue_if_cfg(struct bridge *br,
> +                    const struct ovsrec_interface *cfg,
> +                    const struct ovsrec_port *parent)
> +{
> +    struct if_cfg *if_cfg = xmalloc(sizeof *if_cfg);
> +
> +    if_cfg->cfg = cfg;
> +    if_cfg->parent = parent;
> +    list_insert(&br->if_cfg_queue, &if_cfg->list_node);
> +}
> +
> +static void
> +bridge_update_ifaces(struct bridge *br, struct shash *new_ports)
> +{
> +    struct shash_node *port_node;
> +
> +    SHASH_FOR_EACH (port_node, new_ports) {
> +        const struct ovsrec_port *port = port_node->data;
> +        size_t i;
> +
> +        for (i = 0; i < port->n_interfaces; i++) {
> +            const struct ovsrec_interface *cfg = port->interfaces[i];
> +            struct iface *iface = iface_lookup(br, cfg->name);
> +
> +            if (iface) {
> +                iface->cfg = cfg;
> +                iface_refresh_type(iface);
> +            } else {
> +                bridge_queue_if_cfg(br, cfg, port);
> +            }
> +        }
> +    }
> +}
> +
> +/* Deletes "struct port"s and "struct iface"s under 'br' which aren't
> + * consistent with 'br->cfg'.  Updates 'br->if_cfg_queue' with interfaces 
> which
> + * 'br' needs to complete it's configuration. */
>  static void
>  bridge_add_del_ports(struct bridge *br,
>                      const unsigned long int *splinter_vlans)
>  {
>     struct port *port, *next;
> -    struct shash_node *node;
>     struct shash new_ports;
>     size_t i;
>
> +    assert(list_is_empty(&br->if_cfg_queue));
> +
>     /* Collect new ports. */
>     shash_init(&new_ports);
>     for (i = 0; i < br->cfg->n_ports; i++) {
> @@ -2382,21 +2517,8 @@ bridge_add_del_ports(struct bridge *br,
>         }
>     }
>
> -    /* Create new ports.
> -     * Add new interfaces to existing ports. */
> -    SHASH_FOR_EACH (node, &new_ports) {
> -        struct port *port = port_lookup(br, node->name);
> -        if (!port) {
> -            struct ovsrec_port *cfg = node->data;
> -            port = port_create(br, cfg);
> -        }
> -        port_add_ifaces(port);
> -        if (list_is_empty(&port->ifaces)) {
> -            VLOG_WARN("bridge %s: port %s has no interfaces, dropping",
> -                      br->name, port->name);
> -            port_destroy(port);
> -        }
> -    }
> +    bridge_update_ifaces(br, &new_ports);
> +
>     shash_destroy(&new_ports);
>  }
>
> @@ -2718,51 +2840,6 @@ port_del_ifaces(struct port *port)
>     sset_destroy(&new_ifaces);
>  }
>
> -/* Adds new interfaces to 'port' and updates 'type' and 'cfg' members of
> - * existing ones. */
> -static void
> -port_add_ifaces(struct port *port)
> -{
> -    struct shash new_ifaces;
> -    struct shash_node *node;
> -    size_t i;
> -
> -    /* Collect new ifaces. */
> -    shash_init(&new_ifaces);
> -    for (i = 0; i < port->cfg->n_interfaces; i++) {
> -        const struct ovsrec_interface *cfg = port->cfg->interfaces[i];
> -        if (strcmp(cfg->type, "null")
> -            && !shash_add_once(&new_ifaces, cfg->name, cfg)) {
> -            VLOG_WARN("port %s: %s specified twice as port interface",
> -                      port->name, cfg->name);
> -            iface_clear_db_record(cfg);
> -        }
> -    }
> -
> -    /* Create new interfaces.
> -     * Update interface types and 'cfg' members. */
> -    SHASH_FOR_EACH (node, &new_ifaces) {
> -        const struct ovsrec_interface *cfg = node->data;
> -        const char *iface_name = node->name;
> -        struct iface *iface;
> -
> -        iface = iface_lookup(port->bridge, iface_name);
> -        if (!iface) {
> -            iface = iface_create(port, cfg);
> -        } else {
> -            iface->cfg = cfg;
> -        }
> -
> -        /* Determine interface type.  The local port always has type
> -         * "internal".  Other ports take their type from the database and
> -         * default to "system" if none is specified. */
> -        iface->type = (!strcmp(iface_name, port->bridge->name) ? "internal"
> -                       : cfg->type[0] ? cfg->type
> -                       : "system");
> -    }
> -    shash_destroy(&new_ifaces);
> -}
> -
>  static void
>  port_destroy(struct port *port)
>  {
> @@ -3016,6 +3093,35 @@ iface_create(struct port *port, const struct 
> ovsrec_interface *if_cfg)
>  }
>
>  static void
> +iface_refresh_type(struct iface *iface)
> +{
> +    /* Determine interface type.  The local port always has type
> +     * "internal".  Other ports take their type from the database and
> +     * default to "system" if none is specified. */
> +    iface->type = (!strcmp(iface->name, iface->port->bridge->name) ? 
> "internal"
> +                   : iface->cfg->type[0] ? iface->cfg->type
> +                   : "system");
> +}
> +
> +static struct iface *
> +iface_from_if_cfg(struct bridge *br, struct if_cfg *if_cfg)
> +{
> +    struct iface *iface;
> +    struct port *port;
> +
> +    port = port_lookup(br, if_cfg->parent->name);
> +    if (!port) {
> +        port = port_create(br, if_cfg->parent);
> +    }
> +
> +    assert(!iface_lookup(br, if_cfg->cfg->name));
> +    iface = iface_create(port, if_cfg->cfg);
> +    iface_refresh_type(iface);
> +
> +    return iface;
> +}
> +
> +static void
>  iface_destroy(struct iface *iface)
>  {
>     if (iface) {
> --
> 1.7.9.6
>
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to