X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=vswitchd%2Fbridge.c;h=83e35376ae65ba4c48263100e4d4e81178a6f629;hb=d08a2e920631099d68f4efd4e72f6c14987520ce;hp=ecde7160c0d258c6b6d68413c723aaf21b10d07b;hpb=ebea37cc67751a05dbefec0246fb2a62576f4389;p=openvswitch diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index ecde7160..83e35376 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -161,8 +161,9 @@ struct port { }; struct bridge { - struct list node; /* Node in global list of bridges. */ + struct hmap_node node; /* In 'all_bridges'. */ char *name; /* User-specified arbitrary name. */ + char *type; /* Datapath type. */ struct mac_learning *ml; /* MAC learning table. */ uint8_t ea[ETH_ADDR_LEN]; /* Bridge Ethernet Address. */ uint8_t default_ea[ETH_ADDR_LEN]; /* Default MAC. */ @@ -171,12 +172,9 @@ struct bridge { /* OpenFlow switch processing. */ struct ofproto *ofproto; /* OpenFlow switch. */ - /* Kernel datapath information. */ - struct dpif *dpif; /* Datapath. */ - struct hmap ifaces; /* "struct iface"s indexed by dp_ifidx. */ - /* Bridge ports. */ struct hmap ports; /* "struct port"s indexed by name. */ + struct hmap ifaces; /* "struct iface"s indexed by dp_ifidx. */ struct hmap iface_by_name; /* "struct iface"s indexed by name. */ /* Bonding. */ @@ -194,8 +192,8 @@ struct bridge { struct ovsrec_interface *synth_local_ifacep; }; -/* List of all bridges. */ -static struct list all_bridges = LIST_INITIALIZER(&all_bridges); +/* All bridges, indexed by name. */ +static struct hmap all_bridges = HMAP_INITIALIZER(&all_bridges); /* OVSDB IDL used to obtain configuration. */ static struct ovsdb_idl *idl; @@ -211,7 +209,10 @@ static long long int stats_timer = LLONG_MIN; #define DB_LIMIT_INTERVAL (1 * 1000) /* In milliseconds. */ static long long int db_limiter = LLONG_MIN; -static struct bridge *bridge_create(const struct ovsrec_bridge *br_cfg); +static void add_del_bridges(const struct ovsrec_open_vswitch *); +static void bridge_del_dps(void); +static bool bridge_add_dp(struct bridge *); +static void bridge_create(const struct ovsrec_bridge *); static void bridge_destroy(struct bridge *); static struct bridge *bridge_lookup(const char *name); static unixctl_cb_func bridge_unixctl_dump_flows; @@ -219,12 +220,16 @@ static unixctl_cb_func bridge_unixctl_reconnect; static int bridge_run_one(struct bridge *); static size_t bridge_get_controllers(const struct bridge *br, struct ovsrec_controller ***controllersp); -static void bridge_reconfigure_one(struct bridge *); +static void bridge_add_del_ports(struct bridge *); +static void bridge_add_ofproto_ports(struct bridge *); +static void bridge_del_ofproto_ports(struct bridge *); +static void bridge_refresh_dp_ifidx(struct bridge *); +static void bridge_configure_datapath_id(struct bridge *); +static void bridge_configure_netflow(struct bridge *); +static void bridge_configure_sflow(struct bridge *, int *sflow_bridge_number); static void bridge_reconfigure_remotes(struct bridge *, const struct sockaddr_in *managers, size_t n_managers); -static void bridge_get_all_ifaces(const struct bridge *, struct shash *ifaces); -static void bridge_fetch_dp_ifaces(struct bridge *); static void bridge_flush(struct bridge *); static void bridge_pick_local_hw_addr(struct bridge *, uint8_t ea[ETH_ADDR_LEN], @@ -233,6 +238,9 @@ static uint64_t bridge_pick_datapath_id(struct bridge *, const uint8_t bridge_ea[ETH_ADDR_LEN], struct iface *hw_addr_iface); static uint64_t dpid_from_hash(const void *, size_t nbytes); +static bool bridge_has_bond_fake_iface(const struct bridge *, + const char *name); +static bool port_is_bond_fake_iface(const struct port *); static unixctl_cb_func bridge_unixctl_fdb_show; static unixctl_cb_func cfm_unixctl_show; @@ -240,9 +248,10 @@ static unixctl_cb_func qos_unixctl_show; static void port_run(struct port *); static void port_wait(struct port *); -static struct port *port_create(struct bridge *, const char *name); -static void port_reconfigure(struct port *, const struct ovsrec_port *); -static void port_del_ifaces(struct port *, const struct ovsrec_port *); +static void port_reconfigure(struct port *); +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); static struct iface *port_get_an_iface(const struct port *); @@ -267,8 +276,8 @@ static struct iface *iface_from_dp_ifidx(const struct bridge *, uint16_t dp_ifidx); static void iface_set_mac(struct iface *); static void iface_set_ofport(const struct ovsrec_interface *, int64_t ofport); -static void iface_update_qos(struct iface *, const struct ovsrec_qos *); -static void iface_update_cfm(struct iface *); +static void iface_configure_qos(struct iface *, const struct ovsrec_qos *); +static void iface_configure_cfm(struct iface *); static bool iface_refresh_cfm_stats(struct iface *iface); static bool iface_get_carrier(const struct iface *); static bool iface_is_synthetic(const struct iface *); @@ -360,66 +369,12 @@ bridge_exit(void) { struct bridge *br, *next_br; - LIST_FOR_EACH_SAFE (br, next_br, node, &all_bridges) { + HMAP_FOR_EACH_SAFE (br, next_br, node, &all_bridges) { bridge_destroy(br); } ovsdb_idl_destroy(idl); } -/* Performs configuration that is only necessary once at ovs-vswitchd startup, - * but for which the ovs-vswitchd configuration 'cfg' is required. */ -static void -bridge_configure_once(const struct ovsrec_open_vswitch *cfg) -{ - static bool already_configured_once; - struct sset bridge_names; - struct sset dpif_names, dpif_types; - const char *type; - size_t i; - - /* Only do this once per ovs-vswitchd run. */ - if (already_configured_once) { - return; - } - already_configured_once = true; - - stats_timer = time_msec() + STATS_INTERVAL; - - /* Get all the configured bridges' names from 'cfg' into 'bridge_names'. */ - sset_init(&bridge_names); - for (i = 0; i < cfg->n_bridges; i++) { - sset_add(&bridge_names, cfg->bridges[i]->name); - } - - /* Iterate over all system dpifs and delete any of them that do not appear - * in 'cfg'. */ - sset_init(&dpif_names); - sset_init(&dpif_types); - dp_enumerate_types(&dpif_types); - SSET_FOR_EACH (type, &dpif_types) { - const char *name; - - dp_enumerate_names(type, &dpif_names); - - /* Delete each dpif whose name is not in 'bridge_names'. */ - SSET_FOR_EACH (name, &dpif_names) { - if (!sset_contains(&bridge_names, name)) { - struct dpif *dpif; - int retval; - - retval = dpif_open(name, type, &dpif); - if (!retval) { - dpif_delete(dpif); - dpif_close(dpif); - } - } - } - } - sset_destroy(&bridge_names); - sset_destroy(&dpif_names); - sset_destroy(&dpif_types); -} - /* Looks at the list of managers in 'ovs_cfg' and extracts their remote IP * addresses and ports into '*managersp' and '*n_managersp'. The caller is * responsible for freeing '*managersp' (with free()). @@ -479,417 +434,532 @@ collect_in_band_managers(const struct ovsrec_open_vswitch *ovs_cfg, static void bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) { - struct shash old_br, new_br; - struct shash_node *node; - struct bridge *br, *next; struct sockaddr_in *managers; - size_t n_managers; - size_t i; + struct bridge *br, *next; int sflow_bridge_number; + size_t n_managers; COVERAGE_INC(bridge_reconfigure); - collect_in_band_managers(ovs_cfg, &managers, &n_managers); - - /* Collect old and new bridges. */ - shash_init(&old_br); - shash_init(&new_br); - LIST_FOR_EACH (br, node, &all_bridges) { - shash_add(&old_br, br->name, br); + /* Create and destroy "struct bridge"s, "struct port"s, and "struct + * iface"s according to 'ovs_cfg', with only very minimal configuration + * otherwise. + * + * This is purely an update to bridge data structures. Nothing is pushed + * down to ofproto or lower layers. */ + add_del_bridges(ovs_cfg); + HMAP_FOR_EACH (br, node, &all_bridges) { + bridge_add_del_ports(br); } - for (i = 0; i < ovs_cfg->n_bridges; i++) { - const struct ovsrec_bridge *br_cfg = ovs_cfg->bridges[i]; - if (!shash_add_once(&new_br, br_cfg->name, br_cfg)) { - VLOG_WARN("more than one bridge named %s", br_cfg->name); + + /* 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_dps(); + HMAP_FOR_EACH (br, node, &all_bridges) { + if (br->ofproto) { + bridge_del_ofproto_ports(br); } } - /* Get rid of deleted bridges and add new bridges. */ - LIST_FOR_EACH_SAFE (br, next, node, &all_bridges) { - struct ovsrec_bridge *br_cfg = shash_find_data(&new_br, br->name); - if (br_cfg) { - br->cfg = br_cfg; - } else { + /* 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 dp_ifidx and + * netdev. */ + HMAP_FOR_EACH_SAFE (br, next, node, &all_bridges) { + if (!br->ofproto && !bridge_add_dp(br)) { bridge_destroy(br); } } - SHASH_FOR_EACH (node, &new_br) { - const char *br_name = node->name; - const struct ovsrec_bridge *br_cfg = node->data; - br = shash_find_data(&old_br, br_name); - if (br) { - /* If the bridge datapath type has changed, we need to tear it - * down and recreate. */ - if (strcmp(br->cfg->datapath_type, br_cfg->datapath_type)) { - bridge_destroy(br); - bridge_create(br_cfg); - } - } else { - bridge_create(br_cfg); - } + HMAP_FOR_EACH (br, node, &all_bridges) { + bridge_refresh_dp_ifidx(br); + bridge_add_ofproto_ports(br); } - shash_destroy(&old_br); - shash_destroy(&new_br); - /* Reconfigure all bridges. */ - LIST_FOR_EACH (br, node, &all_bridges) { - bridge_reconfigure_one(br); - } + /* 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; - /* Add and delete ports on all datapaths. - * - * 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. */ - LIST_FOR_EACH (br, node, &all_bridges) { - struct dpif_port_dump dump; - struct shash want_ifaces; - struct dpif_port dpif_port; - - bridge_get_all_ifaces(br, &want_ifaces); - DPIF_PORT_FOR_EACH (&dpif_port, &dump, br->dpif) { - if (!shash_find(&want_ifaces, dpif_port.name) - && strcmp(dpif_port.name, br->name)) { - int retval = dpif_port_del(br->dpif, dpif_port.port_no); - if (retval) { - VLOG_WARN("bridge %s: failed to remove %s interface (%s)", - br->name, dpif_port.name, strerror(retval)); - } + br->has_bonded_ports = false; + HMAP_FOR_EACH (port, hmap_node, &br->ports) { + struct iface *iface; + + port_reconfigure(port); + port_reconfigure_lacp(port); + port_reconfigure_bond(port); + + HMAP_FOR_EACH (iface, dp_ifidx_node, &br->ifaces) { + iface_configure_cfm(iface); + iface_configure_qos(iface, port->cfg->qos); + iface_set_mac(iface); } } - shash_destroy(&want_ifaces); + mirror_reconfigure(br); + + bridge_configure_datapath_id(br); + bridge_reconfigure_remotes(br, managers, n_managers); + bridge_configure_netflow(br); + bridge_configure_sflow(br, &sflow_bridge_number); } - LIST_FOR_EACH (br, node, &all_bridges) { - struct shash cur_ifaces, want_ifaces; - struct dpif_port_dump dump; - struct dpif_port dpif_port; + free(managers); - /* Get the set of interfaces currently in this datapath. */ - shash_init(&cur_ifaces); - DPIF_PORT_FOR_EACH (&dpif_port, &dump, br->dpif) { - struct dpif_port *port_info = xmalloc(sizeof *port_info); - dpif_port_clone(port_info, &dpif_port); - shash_add(&cur_ifaces, dpif_port.name, port_info); - } + /* ovs-vswitchd has completed initialization, so allow the process that + * forked us to exit successfully. */ + daemonize_complete(); +} + +/* Iterate over all system dpifs and delete any of them that do not have a + * configured bridge or that are the wrong type. */ +static void +bridge_del_dps(void) +{ + struct sset dpif_names; + struct sset dpif_types; + const char *type; - /* Get the set of interfaces we want on this datapath. */ - bridge_get_all_ifaces(br, &want_ifaces); + sset_init(&dpif_names); + sset_init(&dpif_types); + dp_enumerate_types(&dpif_types); + SSET_FOR_EACH (type, &dpif_types) { + const char *name; - hmap_clear(&br->ifaces); - SHASH_FOR_EACH (node, &want_ifaces) { - const char *if_name = node->name; - struct iface *iface = node->data; - struct dpif_port *dpif_port; - const char *type; - int error; + dp_enumerate_names(type, &dpif_names); + SSET_FOR_EACH (name, &dpif_names) { + struct bridge *br = bridge_lookup(name); + if (!br || strcmp(type, br->type)) { + struct dpif *dpif; - type = iface ? iface->type : "internal"; - dpif_port = shash_find_data(&cur_ifaces, if_name); - - /* If we have a port or a netdev already, and it's not the type we - * want, then delete the port (if any) and close the netdev (if - * any). */ - if ((dpif_port && strcmp(dpif_port->type, type)) - || (iface && iface->netdev - && strcmp(type, netdev_get_type(iface->netdev)))) { - if (dpif_port) { - error = ofproto_port_del(br->ofproto, dpif_port->port_no); - if (error) { - continue; - } - dpif_port = NULL; - } - if (iface) { - if (iface->port->bond) { - /* The bond has a pointer to the netdev, so remove it - * from the bond before closing the netdev. The slave - * will get added back to the bond later, after a new - * netdev is available. */ - bond_slave_unregister(iface->port->bond, iface); - } - netdev_close(iface->netdev); - iface->netdev = NULL; + if (!dpif_open(name, type, &dpif)) { + dpif_delete(dpif); + dpif_close(dpif); } } + } + } + sset_destroy(&dpif_names); + sset_destroy(&dpif_types); +} - /* If the port doesn't exist or we don't have the netdev open, - * we need to do more work. */ - if (!dpif_port || (iface && !iface->netdev)) { - struct netdev_options options; - struct netdev *netdev; - struct shash args; +static bool +bridge_add_dp(struct bridge *br) +{ + int error; - /* First open the network device. */ - options.name = if_name; - options.type = type; - options.args = &args; - options.ethertype = NETDEV_ETH_TYPE_NONE; + error = ofproto_create(br->name, br->type, &bridge_ofhooks, br, + &br->ofproto); + if (error) { + VLOG_ERR("failed to create bridge %s: %s", + br->name, strerror(error)); + return false; + } + return true; +} - shash_init(&args); - if (iface) { - shash_from_ovs_idl_map(iface->cfg->key_options, - iface->cfg->value_options, - iface->cfg->n_options, &args); - } - error = netdev_open(&options, &netdev); - shash_destroy(&args); +/* Pick local port hardware address and datapath ID for 'br'. */ +static void +bridge_configure_datapath_id(struct bridge *br) +{ + uint8_t ea[ETH_ADDR_LEN]; + uint64_t dpid; + struct iface *local_iface; + struct iface *hw_addr_iface; + char *dpid_string; - if (error) { - VLOG_WARN("could not open network device %s (%s)", - if_name, strerror(error)); - continue; - } + bridge_pick_local_hw_addr(br, ea, &hw_addr_iface); + local_iface = iface_from_dp_ifidx(br, ODPP_LOCAL); + if (local_iface) { + int error = netdev_set_etheraddr(local_iface->netdev, ea); + if (error) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_ERR_RL(&rl, "bridge %s: failed to set bridge " + "Ethernet address: %s", + br->name, strerror(error)); + } + } + memcpy(br->ea, ea, ETH_ADDR_LEN); - /* Then add the port if we haven't already. */ - if (!dpif_port) { - error = dpif_port_add(br->dpif, netdev, NULL); - if (error) { - netdev_close(netdev); - if (error == EFBIG) { - VLOG_ERR("bridge %s: out of valid port numbers", - br->name); - break; - } else { - VLOG_WARN("bridge %s: failed to add %s interface " - "(%s)", - br->name, if_name, strerror(error)); - continue; - } - } - } + dpid = bridge_pick_datapath_id(br, ea, hw_addr_iface); + ofproto_set_datapath_id(br->ofproto, dpid); - /* Update 'iface'. */ - if (iface) { - iface->netdev = netdev; - } - } else if (iface && 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); - netdev_set_config(iface->netdev, &args); - shash_destroy(&args); - } - } - shash_destroy(&want_ifaces); + dpid_string = xasprintf("%016"PRIx64, dpid); + ovsrec_bridge_set_datapath_id(br->cfg, dpid_string); + free(dpid_string); +} - SHASH_FOR_EACH (node, &cur_ifaces) { - struct dpif_port *port_info = node->data; - dpif_port_destroy(port_info); - free(port_info); - } - shash_destroy(&cur_ifaces); +/* Set NetFlow configuration on 'br'. */ +static void +bridge_configure_netflow(struct bridge *br) +{ + struct ovsrec_netflow *cfg = br->cfg->netflow; + struct netflow_options opts; + + if (!cfg) { + ofproto_set_netflow(br->ofproto, NULL); + return; } - sflow_bridge_number = 0; - LIST_FOR_EACH (br, node, &all_bridges) { - uint8_t ea[ETH_ADDR_LEN]; - uint64_t dpid; - struct iface *local_iface; - struct port *port, *next_port; - struct iface *hw_addr_iface; - char *dpid_string; - bridge_fetch_dp_ifaces(br); + memset(&opts, 0, sizeof opts); - /* Delete interfaces that cannot be opened. - * - * Following this loop, every remaining "struct iface" has nonnull - * 'netdev' and correct 'dp_ifidx'. */ - HMAP_FOR_EACH_SAFE (port, next_port, hmap_node, &br->ports) { - struct iface *iface, *next_iface; - - LIST_FOR_EACH_SAFE (iface, next_iface, port_elem, &port->ifaces) { - if (iface->netdev && iface->dp_ifidx >= 0) { - VLOG_DBG("bridge %s: interface %s is on port %d", - br->name, iface->name, iface->dp_ifidx); - } 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. */ - } + /* Get default NetFlow configuration from datapath. + * Apply overrides from 'cfg'. */ + ofproto_get_netflow_ids(br->ofproto, &opts.engine_type, &opts.engine_id); + if (cfg->engine_type) { + opts.engine_type = *cfg->engine_type; + } + if (cfg->engine_id) { + opts.engine_id = *cfg->engine_id; + } - iface_set_ofport(iface->cfg, -1); - iface_destroy(iface); - } - } + /* Configure active timeout interval. */ + opts.active_timeout = cfg->active_timeout; + if (!opts.active_timeout) { + opts.active_timeout = -1; + } else if (opts.active_timeout < 0) { + VLOG_WARN("bridge %s: active timeout interval set to negative " + "value, using default instead (%d seconds)", br->name, + NF_ACTIVE_TIMEOUT_DEFAULT); + opts.active_timeout = -1; + } - if (list_is_empty(&port->ifaces)) { - VLOG_WARN("%s port has no interfaces, dropping", port->name); - port_destroy(port); - } + /* Add engine ID to interface number to disambiguate bridgs? */ + opts.add_id_to_iface = cfg->add_id_to_interface; + if (opts.add_id_to_iface) { + if (opts.engine_id > 0x7f) { + VLOG_WARN("bridge %s: NetFlow port mangling may conflict with " + "another vswitch, choose an engine id less than 128", + br->name); } - - /* Pick local port hardware address, datapath ID. */ - bridge_pick_local_hw_addr(br, ea, &hw_addr_iface); - local_iface = iface_from_dp_ifidx(br, ODPP_LOCAL); - if (local_iface) { - int error = netdev_set_etheraddr(local_iface->netdev, ea); - if (error) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - VLOG_ERR_RL(&rl, "bridge %s: failed to set bridge " - "Ethernet address: %s", - br->name, strerror(error)); - } + if (hmap_count(&br->ports) > 508) { + VLOG_WARN("bridge %s: NetFlow port mangling will conflict with " + "another port when more than 508 ports are used", + br->name); } - memcpy(br->ea, ea, ETH_ADDR_LEN); + } - dpid = bridge_pick_datapath_id(br, ea, hw_addr_iface); - ofproto_set_datapath_id(br->ofproto, dpid); + /* Collectors. */ + sset_init(&opts.collectors); + sset_add_array(&opts.collectors, cfg->targets, cfg->n_targets); - dpid_string = xasprintf("%016"PRIx64, dpid); - ovsrec_bridge_set_datapath_id(br->cfg, dpid_string); - free(dpid_string); + /* Configure. */ + if (ofproto_set_netflow(br->ofproto, &opts)) { + VLOG_ERR("bridge %s: problem setting netflow collectors", br->name); + } + sset_destroy(&opts.collectors); +} - /* Set NetFlow configuration on this bridge. */ - if (br->cfg->netflow) { - struct ovsrec_netflow *nf_cfg = br->cfg->netflow; - struct netflow_options opts; +/* Set sFlow configuration on 'br'. */ +static void +bridge_configure_sflow(struct bridge *br, int *sflow_bridge_number) +{ + const struct ovsrec_sflow *cfg = br->cfg->sflow; + struct ovsrec_controller **controllers; + struct ofproto_sflow_options oso; + size_t n_controllers; + size_t i; - memset(&opts, 0, sizeof opts); + if (!cfg) { + ofproto_set_sflow(br->ofproto, NULL); + return; + } - dpif_get_netflow_ids(br->dpif, &opts.engine_type, &opts.engine_id); - if (nf_cfg->engine_type) { - opts.engine_type = *nf_cfg->engine_type; - } - if (nf_cfg->engine_id) { - opts.engine_id = *nf_cfg->engine_id; - } + memset(&oso, 0, sizeof oso); - opts.active_timeout = nf_cfg->active_timeout; - if (!opts.active_timeout) { - opts.active_timeout = -1; - } else if (opts.active_timeout < 0) { - VLOG_WARN("bridge %s: active timeout interval set to negative " - "value, using default instead (%d seconds)", br->name, - NF_ACTIVE_TIMEOUT_DEFAULT); - opts.active_timeout = -1; - } + sset_init(&oso.targets); + sset_add_array(&oso.targets, cfg->targets, cfg->n_targets); - opts.add_id_to_iface = nf_cfg->add_id_to_interface; - if (opts.add_id_to_iface) { - if (opts.engine_id > 0x7f) { - VLOG_WARN("bridge %s: netflow port mangling may conflict " - "with another vswitch, choose an engine id less " - "than 128", br->name); - } - if (hmap_count(&br->ports) > 508) { - VLOG_WARN("bridge %s: netflow port mangling will conflict " - "with another port when more than 508 ports are " - "used", br->name); - } - } + oso.sampling_rate = SFL_DEFAULT_SAMPLING_RATE; + if (cfg->sampling) { + oso.sampling_rate = *cfg->sampling; + } - sset_init(&opts.collectors); - sset_add_array(&opts.collectors, - nf_cfg->targets, nf_cfg->n_targets); - if (ofproto_set_netflow(br->ofproto, &opts)) { - VLOG_ERR("bridge %s: problem setting netflow collectors", - br->name); - } - sset_destroy(&opts.collectors); - } else { - ofproto_set_netflow(br->ofproto, NULL); - } + oso.polling_interval = SFL_DEFAULT_POLLING_INTERVAL; + if (cfg->polling) { + oso.polling_interval = *cfg->polling; + } - /* Set sFlow configuration on this bridge. */ - if (br->cfg->sflow) { - const struct ovsrec_sflow *sflow_cfg = br->cfg->sflow; - struct ovsrec_controller **controllers; - struct ofproto_sflow_options oso; - size_t n_controllers; + oso.header_len = SFL_DEFAULT_HEADER_SIZE; + if (cfg->header) { + oso.header_len = *cfg->header; + } - memset(&oso, 0, sizeof oso); + oso.sub_id = (*sflow_bridge_number)++; + oso.agent_device = cfg->agent; - sset_init(&oso.targets); - sset_add_array(&oso.targets, - sflow_cfg->targets, sflow_cfg->n_targets); + oso.control_ip = NULL; + n_controllers = bridge_get_controllers(br, &controllers); + for (i = 0; i < n_controllers; i++) { + if (controllers[i]->local_ip) { + oso.control_ip = controllers[i]->local_ip; + break; + } + } + ofproto_set_sflow(br->ofproto, &oso); - oso.sampling_rate = SFL_DEFAULT_SAMPLING_RATE; - if (sflow_cfg->sampling) { - oso.sampling_rate = *sflow_cfg->sampling; - } + sset_destroy(&oso.targets); +} - oso.polling_interval = SFL_DEFAULT_POLLING_INTERVAL; - if (sflow_cfg->polling) { - oso.polling_interval = *sflow_cfg->polling; - } +static bool +bridge_has_bond_fake_iface(const struct bridge *br, const char *name) +{ + const struct port *port = port_lookup(br, name); + return port && port_is_bond_fake_iface(port); +} - oso.header_len = SFL_DEFAULT_HEADER_SIZE; - if (sflow_cfg->header) { - oso.header_len = *sflow_cfg->header; - } +static bool +port_is_bond_fake_iface(const struct port *port) +{ + return port->cfg->bond_fake_iface && !list_is_short(&port->ifaces); +} - oso.sub_id = sflow_bridge_number++; - oso.agent_device = sflow_cfg->agent; +static void +add_del_bridges(const struct ovsrec_open_vswitch *cfg) +{ + struct bridge *br, *next; + struct shash new_br; + size_t i; - oso.control_ip = NULL; - n_controllers = bridge_get_controllers(br, &controllers); - for (i = 0; i < n_controllers; i++) { - if (controllers[i]->local_ip) { - oso.control_ip = controllers[i]->local_ip; - break; - } - } - ofproto_set_sflow(br->ofproto, &oso); + /* Collect new bridges' names and types. */ + shash_init(&new_br); + for (i = 0; i < cfg->n_bridges; i++) { + const struct ovsrec_bridge *br_cfg = cfg->bridges[i]; + if (!shash_add_once(&new_br, br_cfg->name, br_cfg)) { + VLOG_WARN("bridge %s specified twice", br_cfg->name); + } + } - sset_destroy(&oso.targets); - } else { - ofproto_set_sflow(br->ofproto, NULL); - } - - /* Update the controller and related settings. It would be more - * straightforward to call this from bridge_reconfigure_one(), but we - * can't do it there for two reasons. First, and most importantly, at - * that point we don't know the dp_ifidx of any interfaces that have - * been added to the bridge (because we haven't actually added them to - * the datapath). Second, at that point we haven't set the datapath ID - * yet; when a controller is configured, resetting the datapath ID will - * immediately disconnect from the controller, so it's better to set - * the datapath ID before the controller. */ - bridge_reconfigure_remotes(br, managers, n_managers); + /* Get rid of deleted bridges or those whose types have changed. + * Update 'cfg' of bridges that still exist. */ + HMAP_FOR_EACH_SAFE (br, next, node, &all_bridges) { + br->cfg = shash_find_data(&new_br, br->name); + if (!br->cfg || strcmp(br->type, + dpif_normalize_type(br->cfg->datapath_type))) { + bridge_destroy(br); + } } - LIST_FOR_EACH (br, node, &all_bridges) { - struct port *port; - br->has_bonded_ports = false; - HMAP_FOR_EACH (port, hmap_node, &br->ports) { - struct iface *iface; + /* Add new bridges. */ + for (i = 0; i < cfg->n_bridges; i++) { + const struct ovsrec_bridge *br_cfg = cfg->bridges[i]; + struct bridge *br = bridge_lookup(br_cfg->name); + if (!br) { + bridge_create(br_cfg); + } + } - port_reconfigure_lacp(port); - port_reconfigure_bond(port); + shash_destroy(&new_br); +} - LIST_FOR_EACH (iface, port_elem, &port->ifaces) { - iface_update_qos(iface, port->cfg->qos); - netdev_set_policing(iface->netdev, - iface->cfg->ingress_policing_rate, - iface->cfg->ingress_policing_burst); - iface_set_mac(iface); +/* 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) +{ + 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; + } + 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)); + } + if (iface) { + if (iface->port->bond) { + /* The bond has a pointer to the netdev, so remove it from + * the bond before closing the netdev. The slave will get + * added back to the bond later, after a new netdev is + * available. */ + bond_slave_unregister(iface->port->bond, iface); } + netdev_close(iface->netdev); + iface->netdev = NULL; } } +} + +static void +iface_set_dp_ifidx(struct iface *iface, int dp_ifidx) +{ + struct bridge *br = iface->port->bridge; + + assert(iface->dp_ifidx < 0 && dp_ifidx >= 0); + iface->dp_ifidx = dp_ifidx; + hmap_insert(&br->ifaces, &iface->dp_ifidx_node, hash_int(dp_ifidx, 0)); + +} + +static void +bridge_refresh_dp_ifidx(struct bridge *br) +{ + struct ofproto_port_dump dump; + struct ofproto_port ofproto_port; + struct port *port; - /* Some reconfiguration operations require the bridge to have been run at - * least once. */ - LIST_FOR_EACH (br, node, &all_bridges) { + /* Clear all the "dp_ifidx"es. */ + hmap_clear(&br->ifaces); + HMAP_FOR_EACH (port, hmap_node, &br->ports) { struct iface *iface; - bridge_run_one(br); + LIST_FOR_EACH (iface, port_elem, &port->ifaces) { + iface->dp_ifidx = -1; + } + } - HMAP_FOR_EACH (iface, dp_ifidx_node, &br->ifaces) { - iface_update_cfm(iface); + /* Obtain the correct "dp_ifidx"es from ofproto. */ + OFPROTO_PORT_FOR_EACH (&ofproto_port, &dump, br->ofproto) { + uint32_t odp_port = ofp_port_to_odp_port(ofproto_port.ofp_port); + struct iface *iface = iface_lookup(br, ofproto_port.name); + if (iface) { + if (iface->dp_ifidx >= 0) { + VLOG_WARN("bridge %s: interface %s reported twice", + br->name, ofproto_port.name); + } else if (iface_from_dp_ifidx(br, odp_port)) { + VLOG_WARN("bridge %s: interface %"PRIu16" reported twice", + br->name, odp_port); + } else { + iface_set_dp_ifidx(iface, odp_port); + } } } +} - free(managers); +/* Add a dpif 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) +{ + struct port *port, *next_port; + struct ofproto_port ofproto_port; - /* ovs-vswitchd has completed initialization, so allow the process that - * forked us to exit successfully. */ - daemonize_complete(); + HMAP_FOR_EACH_SAFE (port, next_port, hmap_node, &br->ports) { + struct iface *iface, *next_iface; + + LIST_FOR_EACH_SAFE (iface, next_iface, port_elem, &port->ifaces) { + struct shash args; + int error; + + /* Open the netdev or reconfigure it. */ + shash_init(&args); + shash_from_ovs_idl_map(iface->cfg->key_options, + iface->cfg->value_options, + iface->cfg->n_options, &args); + if (!iface->netdev) { + struct netdev_options options; + options.name = iface->name; + options.type = iface->type; + options.args = &args; + options.ethertype = NETDEV_ETH_TYPE_NONE; + error = netdev_open(&options, &iface->netdev); + } else { + error = netdev_set_config(iface->netdev, &args); + } + shash_destroy(&args); + if (error) { + VLOG_WARN("could not %s network device %s (%s)", + iface->netdev ? "reconfigure" : "open", + iface->name, strerror(error)); + } + + /* Add the port, if necessary. */ + if (iface->netdev && iface->dp_ifidx < 0) { + uint16_t ofp_port; + int error; + + error = ofproto_port_add(br->ofproto, iface->netdev, + &ofp_port); + if (!error) { + iface_set_dp_ifidx(iface, ofp_port_to_odp_port(ofp_port)); + } else { + netdev_close(iface->netdev); + iface->netdev = NULL; + } + } + + /* Delete the iface if */ + if (iface->netdev && iface->dp_ifidx >= 0) { + VLOG_DBG("bridge %s: interface %s is on port %d", + br->name, iface->name, iface->dp_ifidx); + } 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. */ + } + iface_set_ofport(iface->cfg, -1); + iface_destroy(iface); + } + } + if (list_is_empty(&port->ifaces)) { + VLOG_WARN("%s port has no interfaces, dropping", port->name); + port_destroy(port); + continue; + } + + /* 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_options options; + struct netdev *netdev; + int error; + + options.name = port->name; + options.type = "internal"; + options.args = NULL; + options.ethertype = NETDEV_ETH_TYPE_NONE; + error = netdev_open(&options, &netdev); + if (!error) { + 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); + } + } + } } static const char * @@ -1159,7 +1229,6 @@ iface_refresh_status(struct iface *iface) ovsrec_interface_set_link_speed(iface->cfg, NULL, 0); } - ovsrec_interface_set_link_state(iface->cfg, iface_get_carrier(iface) ? "up" : "down"); @@ -1351,7 +1420,7 @@ bridge_run(void) /* Let each bridge do the work that it needs to do. */ datapath_destroyed = false; - LIST_FOR_EACH (br, node, &all_bridges) { + HMAP_FOR_EACH (br, node, &all_bridges) { int error = bridge_run_one(br); if (error) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); @@ -1382,7 +1451,6 @@ bridge_run(void) if (cfg) { struct ovsdb_idl_txn *txn = ovsdb_idl_txn_create(idl); - bridge_configure_once(cfg); bridge_reconfigure(cfg); ovsrec_open_vswitch_set_cur_cfg(cfg, cfg->next_cfg); @@ -1403,7 +1471,7 @@ bridge_run(void) struct ovsdb_idl_txn *txn; txn = ovsdb_idl_txn_create(idl); - LIST_FOR_EACH (br, node, &all_bridges) { + HMAP_FOR_EACH (br, node, &all_bridges) { struct port *port; HMAP_FOR_EACH (port, hmap_node, &br->ports) { @@ -1429,7 +1497,7 @@ bridge_run(void) bool changed = false; txn = ovsdb_idl_txn_create(idl); - LIST_FOR_EACH (br, node, &all_bridges) { + HMAP_FOR_EACH (br, node, &all_bridges) { struct port *port; HMAP_FOR_EACH (port, hmap_node, &br->ports) { @@ -1456,7 +1524,7 @@ bridge_wait(void) { struct bridge *br; - LIST_FOR_EACH (br, node, &all_bridges) { + HMAP_FOR_EACH (br, node, &all_bridges) { struct port *port; ofproto_wait(br->ofproto); @@ -1629,34 +1697,16 @@ qos_unixctl_show(struct unixctl_conn *conn, } /* Bridge reconfiguration functions. */ -static struct bridge * +static void bridge_create(const struct ovsrec_bridge *br_cfg) { struct bridge *br; - int error; assert(!bridge_lookup(br_cfg->name)); br = xzalloc(sizeof *br); - error = dpif_create_and_open(br_cfg->name, br_cfg->datapath_type, - &br->dpif); - if (error) { - free(br); - return NULL; - } - - error = ofproto_create(br_cfg->name, br_cfg->datapath_type, &bridge_ofhooks, - br, &br->ofproto); - if (error) { - VLOG_ERR("failed to create switch %s: %s", br_cfg->name, - strerror(error)); - dpif_delete(br->dpif); - dpif_close(br->dpif); - free(br); - return NULL; - } - br->name = xstrdup(br_cfg->name); + br->type = xstrdup(dpif_normalize_type(br_cfg->datapath_type)); br->cfg = br_cfg; br->ml = mac_learning_create(); eth_addr_nicira_random(br->default_ea); @@ -1667,11 +1717,7 @@ bridge_create(const struct ovsrec_bridge *br_cfg) br->flush = false; - list_push_back(&all_bridges, &br->node); - - VLOG_INFO("bridge %s: created", br->name); - - return br; + hmap_insert(&all_bridges, &br->node, hash_string(br->name, 0)); } static void @@ -1679,7 +1725,6 @@ bridge_destroy(struct bridge *br) { if (br) { struct port *port, *next; - int error; int i; HMAP_FOR_EACH_SAFE (port, next, hmap_node, &br->ports) { @@ -1688,20 +1733,14 @@ bridge_destroy(struct bridge *br) for (i = 0; i < MAX_MIRRORS; i++) { mirror_destroy(br->mirrors[i]); } - list_remove(&br->node); + hmap_remove(&all_bridges, &br->node); ofproto_destroy(br->ofproto); - error = dpif_delete(br->dpif); - if (error && error != ENOENT) { - VLOG_ERR("bridge %s: failed to destroy (%s)", - br->name, strerror(error)); - } - dpif_close(br->dpif); mac_learning_destroy(br->ml); hmap_destroy(&br->ifaces); hmap_destroy(&br->ports); hmap_destroy(&br->iface_by_name); - free(br->synth_local_iface.type); free(br->name); + free(br->type); free(br); } } @@ -1711,7 +1750,7 @@ bridge_lookup(const char *name) { struct bridge *br; - LIST_FOR_EACH (br, node, &all_bridges) { + HMAP_FOR_EACH_WITH_HASH (br, node, hash_string(name, 0), &all_bridges) { if (!strcmp(br->name, name)) { return br; } @@ -1757,7 +1796,7 @@ bridge_unixctl_reconnect(struct unixctl_conn *conn, } ofproto_reconnect_controllers(br->ofproto); } else { - LIST_FOR_EACH (br, node, &all_bridges) { + HMAP_FOR_EACH (br, node, &all_bridges) { ofproto_reconnect_controllers(br->ofproto); } } @@ -1808,10 +1847,11 @@ 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_reconfigure_one(struct bridge *br) +bridge_add_del_ports(struct bridge *br) { - enum ofproto_fail_mode fail_mode; struct port *port, *next; struct shash_node *node; struct shash new_ports; @@ -1826,24 +1866,17 @@ bridge_reconfigure_one(struct bridge *br) br->name, name); } } - if (!shash_find(&new_ports, br->name)) { - struct dpif_port dpif_port; - char *type; - + if (bridge_get_controllers(br, NULL) + && !shash_find(&new_ports, br->name)) { VLOG_WARN("bridge %s: no port named %s, synthesizing one", br->name, br->name); - dpif_port_query_by_number(br->dpif, ODPP_LOCAL, &dpif_port); - type = xstrdup(dpif_port.type ? dpif_port.type : "internal"); - dpif_port_destroy(&dpif_port); - br->synth_local_port.interfaces = &br->synth_local_ifacep; br->synth_local_port.n_interfaces = 1; br->synth_local_port.name = br->name; br->synth_local_iface.name = br->name; - free(br->synth_local_iface.type); - br->synth_local_iface.type = type; + br->synth_local_iface.type = "internal"; br->synth_local_ifacep = &br->synth_local_iface; @@ -1851,28 +1884,26 @@ bridge_reconfigure_one(struct bridge *br) } /* Get rid of deleted ports. - * Get rid of deleted interfaces on ports that still exist. */ + * Get rid of deleted interfaces on ports that still exist. + * Update 'cfg' of ports that still exist. */ HMAP_FOR_EACH_SAFE (port, next, hmap_node, &br->ports) { - const struct ovsrec_port *port_cfg; - - port_cfg = shash_find_data(&new_ports, port->name); - if (!port_cfg) { + port->cfg = shash_find_data(&new_ports, port->name); + if (!port->cfg) { port_destroy(port); } else { - port_del_ifaces(port, port_cfg); + port_del_ifaces(port); } } /* Create new ports. - * Add new interfaces to existing ports. - * Reconfigure existing ports. */ + * Add new interfaces to existing ports. */ SHASH_FOR_EACH (node, &new_ports) { struct port *port = port_lookup(br, node->name); if (!port) { - port = port_create(br, node->name); + struct ovsrec_port *cfg = node->data; + port = port_create(br, cfg); } - - port_reconfigure(port, node->data); + port_add_ifaces(port); if (list_is_empty(&port->ifaces)) { VLOG_WARN("bridge %s: port %s has no interfaces, dropping", br->name, port->name); @@ -1880,26 +1911,6 @@ bridge_reconfigure_one(struct bridge *br) } } shash_destroy(&new_ports); - - /* Set the fail-mode */ - fail_mode = !br->cfg->fail_mode - || !strcmp(br->cfg->fail_mode, "standalone") - ? OFPROTO_FAIL_STANDALONE - : OFPROTO_FAIL_SECURE; - ofproto_set_fail_mode(br->ofproto, fail_mode); - - /* Configure OpenFlow controller connection snooping. */ - if (!ofproto_has_snoops(br->ofproto)) { - struct sset snoops; - - sset_init(&snoops); - sset_add_and_free(&snoops, xasprintf("punix:%s/%s.snoop", - ovs_rundir(), br->name)); - ofproto_set_snoops(br->ofproto, &snoops); - sset_destroy(&snoops); - } - - mirror_reconfigure(br); } /* Initializes 'oc' appropriately as a management service controller for @@ -1989,6 +2000,8 @@ bridge_reconfigure_remotes(struct bridge *br, struct ovsrec_controller **controllers; size_t n_controllers; + enum ofproto_fail_mode fail_mode; + struct ofproto_controller *ocs; size_t n_ocs; size_t i; @@ -2042,71 +2055,23 @@ bridge_reconfigure_remotes(struct bridge *br, ofproto_set_controllers(br->ofproto, ocs, n_ocs); free(ocs[0].target); /* From bridge_ofproto_controller_for_mgmt(). */ free(ocs); -} - -static void -bridge_get_all_ifaces(const struct bridge *br, struct shash *ifaces) -{ - struct port *port; - - shash_init(ifaces); - HMAP_FOR_EACH (port, hmap_node, &br->ports) { - struct iface *iface; - - LIST_FOR_EACH (iface, port_elem, &port->ifaces) { - shash_add_once(ifaces, iface->name, iface); - } - if (!list_is_short(&port->ifaces) && port->cfg->bond_fake_iface) { - shash_add_once(ifaces, port->name, NULL); - } - } -} - -/* For robustness, in case the administrator moves around datapath ports behind - * our back, we re-check all the datapath port numbers here. - * - * This function will set the 'dp_ifidx' members of interfaces that have - * disappeared to -1, so only call this function from a context where those - * 'struct iface's will be removed from the bridge. Otherwise, the -1 - * 'dp_ifidx'es will cause trouble later when we try to send them to the - * datapath, which doesn't support UINT16_MAX+1 ports. */ -static void -bridge_fetch_dp_ifaces(struct bridge *br) -{ - struct dpif_port_dump dump; - struct dpif_port dpif_port; - struct port *port; - - /* Reset all interface numbers. */ - HMAP_FOR_EACH (port, hmap_node, &br->ports) { - struct iface *iface; - LIST_FOR_EACH (iface, port_elem, &port->ifaces) { - iface->dp_ifidx = -1; - } - } - hmap_clear(&br->ifaces); + /* Set the fail-mode. */ + fail_mode = !br->cfg->fail_mode + || !strcmp(br->cfg->fail_mode, "standalone") + ? OFPROTO_FAIL_STANDALONE + : OFPROTO_FAIL_SECURE; + ofproto_set_fail_mode(br->ofproto, fail_mode); - DPIF_PORT_FOR_EACH (&dpif_port, &dump, br->dpif) { - struct iface *iface = iface_lookup(br, dpif_port.name); - if (iface) { - if (iface->dp_ifidx >= 0) { - VLOG_WARN("bridge %s: interface %s reported twice", - br->name, dpif_port.name); - } else if (iface_from_dp_ifidx(br, dpif_port.port_no)) { - VLOG_WARN("bridge %s: interface %"PRIu16" reported twice", - br->name, dpif_port.port_no); - } else { - iface->dp_ifidx = dpif_port.port_no; - hmap_insert(&br->ifaces, &iface->dp_ifidx_node, - hash_int(iface->dp_ifidx, 0)); - } + /* Configure OpenFlow controller connection snooping. */ + if (!ofproto_has_snoops(br->ofproto)) { + struct sset snoops; - iface_set_ofport(iface->cfg, - (iface->dp_ifidx >= 0 - ? odp_port_to_ofp_port(iface->dp_ifidx) - : -1)); - } + sset_init(&snoops); + sset_add_and_free(&snoops, xasprintf("punix:%s/%s.snoop", + ovs_rundir(), br->name)); + ofproto_set_snoops(br->ofproto, &snoops); + sset_destroy(&snoops); } } @@ -2788,21 +2753,19 @@ port_wait(struct port *port) } static struct port * -port_create(struct bridge *br, const char *name) +port_create(struct bridge *br, const struct ovsrec_port *cfg) { struct port *port; port = xzalloc(sizeof *port); port->bridge = br; - port->vlan = -1; - port->trunks = NULL; - port->name = xstrdup(name); + port->name = xstrdup(cfg->name); + port->cfg = cfg; list_init(&port->ifaces); hmap_insert(&br->ports, &port->hmap_node, hash_string(port->name, 0)); VLOG_INFO("created port %s on bridge %s", port->name, br->name); - bridge_flush(br); return port; } @@ -2829,8 +2792,9 @@ get_interface_other_config(const struct ovsrec_interface *iface, return value ? value : default_value; } +/* Deletes interfaces from 'port' that are no longer configured for it. */ static void -port_del_ifaces(struct port *port, const struct ovsrec_port *cfg) +port_del_ifaces(struct port *port) { struct iface *iface, *next; struct sset new_ifaces; @@ -2838,8 +2802,8 @@ port_del_ifaces(struct port *port, const struct ovsrec_port *cfg) /* Collect list of new interfaces. */ sset_init(&new_ifaces); - for (i = 0; i < cfg->n_interfaces; i++) { - const char *name = cfg->interfaces[i]->name; + for (i = 0; i < port->cfg->n_interfaces; i++) { + const char *name = port->cfg->interfaces[i]->name; sset_add(&new_ifaces, name); } @@ -2853,6 +2817,50 @@ port_del_ifaces(struct port *port, const struct ovsrec_port *cfg) 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 (!shash_add_once(&new_ifaces, cfg->name, cfg)) { + VLOG_WARN("port %s: %s specified twice as port interface", + port->name, cfg->name); + iface_set_ofport(cfg, -1); + } + } + + /* 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); +} + /* Expires all MAC learning entries associated with 'port' and forces ofproto * to revalidate every flow. */ static void @@ -2871,51 +2879,12 @@ port_flush_macs(struct port *port) } static void -port_reconfigure(struct port *port, const struct ovsrec_port *cfg) +port_reconfigure(struct port *port) { - struct sset new_ifaces; + const struct ovsrec_port *cfg = port->cfg; bool need_flush = false; unsigned long *trunks; int vlan; - size_t i; - - port->cfg = cfg; - - - /* Add new interfaces and update 'cfg' member of existing ones. */ - sset_init(&new_ifaces); - for (i = 0; i < cfg->n_interfaces; i++) { - const struct ovsrec_interface *if_cfg = cfg->interfaces[i]; - struct iface *iface; - - if (!sset_add(&new_ifaces, if_cfg->name)) { - VLOG_WARN("port %s: %s specified twice as port interface", - port->name, if_cfg->name); - iface_set_ofport(if_cfg, -1); - continue; - } - - iface = iface_lookup(port->bridge, if_cfg->name); - if (iface) { - if (iface->port != port) { - VLOG_ERR("bridge %s: %s interface is on multiple ports, " - "removing from %s", - port->bridge->name, if_cfg->name, iface->port->name); - continue; - } - iface->cfg = if_cfg; - } else { - iface = iface_create(port, if_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(if_cfg->name, port->bridge->name) ? "internal" - : if_cfg->type[0] ? if_cfg->type - : "system"); - } - sset_destroy(&new_ifaces); /* Get VLAN tag. */ vlan = -1; @@ -3298,7 +3267,7 @@ iface_find(const char *name) { const struct bridge *br; - LIST_FOR_EACH (br, node, &all_bridges) { + HMAP_FOR_EACH (br, node, &all_bridges) { struct iface *iface = iface_lookup(br, name); if (iface) { @@ -3431,7 +3400,7 @@ iface_delete_queues(unsigned int queue_id, } static void -iface_update_qos(struct iface *iface, const struct ovsrec_qos *qos) +iface_configure_qos(struct iface *iface, const struct ovsrec_qos *qos) { if (!qos || qos->type[0] == '\0') { netdev_set_qos(iface->netdev, NULL, NULL); @@ -3467,7 +3436,7 @@ iface_update_qos(struct iface *iface, const struct ovsrec_qos *qos) } static void -iface_update_cfm(struct iface *iface) +iface_configure_cfm(struct iface *iface) { size_t i; struct cfm cfm;