X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=vswitchd%2Fbridge.c;h=83e35376ae65ba4c48263100e4d4e81178a6f629;hb=d08a2e920631099d68f4efd4e72f6c14987520ce;hp=7997402e1c6e6a934ef00ad9d6891382d4097ee3;hpb=3b6a2571f07e153e850a9bf2044699d8d4434ef0;p=openvswitch diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 7997402e..83e35376 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -73,6 +73,7 @@ #include "xenserver.h" #include "vlog.h" #include "sflow_api.h" +#include "vlan-bitmap.h" VLOG_DEFINE_THIS_MODULE(bridge); @@ -98,6 +99,7 @@ static void dst_set_free(struct dst_set *); struct iface { /* These members are always valid. */ struct list port_elem; /* Element in struct port's "ifaces" list. */ + struct hmap_node name_node; /* In struct bridge's "iface_by_name" hmap. */ struct port *port; /* Containing port. */ char *name; /* Host network device name. */ tag_type tag; /* Tag associated with this interface. */ @@ -147,6 +149,8 @@ struct port { * A bridge port for bonding has at least 2 interfaces. */ struct list ifaces; /* List of "struct iface"s. */ + struct lacp *lacp; /* NULL if LACP is not enabled. */ + /* Bonding info. */ struct bond *bond; @@ -157,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. */ @@ -167,13 +172,10 @@ 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 shash iface_by_name; /* "struct iface"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. */ bool has_bonded_ports; @@ -183,10 +185,15 @@ struct bridge { /* Port mirroring. */ struct mirror *mirrors[MAX_MIRRORS]; + + /* Synthetic local port if necessary. */ + struct ovsrec_port synth_local_port; + struct ovsrec_interface synth_local_iface; + 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; @@ -196,12 +203,16 @@ static struct ovsdb_idl *idl; #define STATS_INTERVAL (5 * 1000) /* In milliseconds. */ static long long int stats_timer = LLONG_MIN; -/* Stores the time after which CFM statistics may be written to the database. - * Only updated when changes to the database require rate limiting. */ -#define CFM_LIMIT_INTERVAL (1 * 1000) /* In milliseconds. */ -static long long int cfm_limiter = LLONG_MIN; +/* Stores the time after which rate limited statistics may be written to the + * database. Only updated when changes to the database require rate limiting. + */ +#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; @@ -209,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], @@ -223,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; @@ -230,14 +248,16 @@ 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 *); static struct port *port_from_dp_ifidx(const struct bridge *, uint16_t dp_ifidx); +static void port_reconfigure_lacp(struct port *); static void port_reconfigure_bond(struct port *); static void port_send_learning_packets(struct port *); @@ -256,10 +276,11 @@ 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 *); static void shash_from_ovs_idl_map(char **keys, char **values, size_t n, struct shash *); @@ -339,6 +360,7 @@ bridge_init(const char *remote) NULL); unixctl_command_register("bridge/reconnect", bridge_unixctl_reconnect, NULL); + lacp_init(); bond_init(); } @@ -347,133 +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); -} - -/* Callback for iterate_and_prune_ifaces(). */ -static bool -check_iface(struct bridge *br, struct iface *iface, void *aux OVS_UNUSED) -{ - if (!iface->netdev) { - /* We already reported a related error, don't bother duplicating it. */ - return false; - } - - if (iface->dp_ifidx < 0) { - VLOG_ERR("%s interface not in %s, dropping", - iface->name, dpif_name(br->dpif)); - return false; - } - - VLOG_DBG("%s has interface %s on port %d", dpif_name(br->dpif), - iface->name, iface->dp_ifidx); - return true; -} - -/* Callback for iterate_and_prune_ifaces(). */ -static bool -set_iface_properties(struct bridge *br OVS_UNUSED, struct iface *iface, - void *aux OVS_UNUSED) -{ - /* Set policing attributes. */ - netdev_set_policing(iface->netdev, - iface->cfg->ingress_policing_rate, - iface->cfg->ingress_policing_burst); - - /* Set MAC address of internal interfaces other than the local - * interface. */ - if (iface->dp_ifidx != ODPP_LOCAL && !strcmp(iface->type, "internal")) { - iface_set_mac(iface); - } - - return true; -} - -/* Calls 'cb' for each interfaces in 'br', passing along the 'aux' argument. - * Deletes from 'br' all the interfaces for which 'cb' returns false, and then - * deletes from 'br' any ports that no longer have any interfaces. */ -static void -iterate_and_prune_ifaces(struct bridge *br, - bool (*cb)(struct bridge *, struct iface *, - void *aux), - void *aux) -{ - struct port *port, *next_port; - - 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 (!cb(br, iface, aux)) { - 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); - } - } -} - /* 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()). @@ -533,383 +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); + HMAP_FOR_EACH (br, node, &all_bridges) { + bridge_refresh_dp_ifidx(br); + bridge_add_ofproto_ports(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; + + 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); } - } else { - bridge_create(br_cfg); } - } - shash_destroy(&old_br); - shash_destroy(&new_br); + mirror_reconfigure(br); - /* Reconfigure all bridges. */ - LIST_FOR_EACH (br, node, &all_bridges) { - bridge_reconfigure_one(br); + bridge_configure_datapath_id(br); + bridge_reconfigure_remotes(br, managers, n_managers); + bridge_configure_netflow(br); + bridge_configure_sflow(br, &sflow_bridge_number); } + free(managers); - /* 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("failed to remove %s interface from %s: %s", - dpif_port.name, dpif_name(br->dpif), - strerror(retval)); + /* 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; + + 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); + SSET_FOR_EACH (name, &dpif_names) { + struct bridge *br = bridge_lookup(name); + if (!br || strcmp(type, br->type)) { + struct dpif *dpif; + + if (!dpif_open(name, type, &dpif)) { + dpif_delete(dpif); + dpif_close(dpif); } } } - shash_destroy(&want_ifaces); } - LIST_FOR_EACH (br, node, &all_bridges) { - struct shash cur_ifaces, want_ifaces; - struct dpif_port_dump dump; - struct dpif_port dpif_port; + sset_destroy(&dpif_names); + sset_destroy(&dpif_types); +} - /* 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); - } +static bool +bridge_add_dp(struct bridge *br) +{ + int error; - /* Get the set of interfaces we want on this datapath. */ - bridge_get_all_ifaces(br, &want_ifaces); + 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; +} - 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; +/* 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; - 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) { - netdev_close(iface->netdev); - iface->netdev = NULL; - } - } + 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); - /* 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; + dpid = bridge_pick_datapath_id(br, ea, hw_addr_iface); + ofproto_set_datapath_id(br->ofproto, dpid); - /* First open the network device. */ - options.name = if_name; - options.type = type; - options.args = &args; - options.ethertype = NETDEV_ETH_TYPE_NONE; + dpid_string = xasprintf("%016"PRIx64, dpid); + ovsrec_bridge_set_datapath_id(br->cfg, dpid_string); + free(dpid_string); +} - 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); +/* 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 (error) { - VLOG_WARN("could not open network device %s (%s)", - if_name, strerror(error)); - continue; - } + if (!cfg) { + ofproto_set_netflow(br->ofproto, NULL); + return; + } - /* 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("ran out of valid port numbers on %s", - dpif_name(br->dpif)); - break; - } else { - VLOG_WARN("failed to add %s interface to %s: %s", - if_name, dpif_name(br->dpif), - strerror(error)); - continue; - } - } - } + memset(&opts, 0, sizeof opts); - /* 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); - } + /* 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; + } + + /* 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; + } + + /* 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); + } + 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); } - shash_destroy(&want_ifaces); + } + + /* Collectors. */ + sset_init(&opts.collectors); + sset_add_array(&opts.collectors, cfg->targets, cfg->n_targets); + + /* Configure. */ + if (ofproto_set_netflow(br->ofproto, &opts)) { + VLOG_ERR("bridge %s: problem setting netflow collectors", br->name); + } + sset_destroy(&opts.collectors); +} + +/* 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; + + if (!cfg) { + ofproto_set_sflow(br->ofproto, NULL); + return; + } + + memset(&oso, 0, sizeof oso); + + sset_init(&oso.targets); + sset_add_array(&oso.targets, cfg->targets, cfg->n_targets); + + oso.sampling_rate = SFL_DEFAULT_SAMPLING_RATE; + if (cfg->sampling) { + oso.sampling_rate = *cfg->sampling; + } + + oso.polling_interval = SFL_DEFAULT_POLLING_INTERVAL; + if (cfg->polling) { + oso.polling_interval = *cfg->polling; + } + + oso.header_len = SFL_DEFAULT_HEADER_SIZE; + if (cfg->header) { + oso.header_len = *cfg->header; + } + + oso.sub_id = (*sflow_bridge_number)++; + oso.agent_device = cfg->agent; - SHASH_FOR_EACH (node, &cur_ifaces) { - struct dpif_port *port_info = node->data; - dpif_port_destroy(port_info); - free(port_info); + 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; } - shash_destroy(&cur_ifaces); } - 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 iface *hw_addr_iface; - char *dpid_string; + ofproto_set_sflow(br->ofproto, &oso); - bridge_fetch_dp_ifaces(br); + sset_destroy(&oso.targets); +} - /* Delete interfaces that cannot be opened. - * - * From this point forward we are guaranteed that every "struct iface" - * has nonnull 'netdev' and correct 'dp_ifidx'. */ - iterate_and_prune_ifaces(br, check_iface, NULL); - - /* 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)); - } +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); +} + +static bool +port_is_bond_fake_iface(const struct port *port) +{ + return port->cfg->bond_fake_iface && !list_is_short(&port->ifaces); +} + +static void +add_del_bridges(const struct ovsrec_open_vswitch *cfg) +{ + struct bridge *br, *next; + struct shash new_br; + size_t i; + + /* 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); } - memcpy(br->ea, ea, ETH_ADDR_LEN); + } - dpid = bridge_pick_datapath_id(br, ea, hw_addr_iface); - ofproto_set_datapath_id(br->ofproto, dpid); + /* 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); + } + } - dpid_string = xasprintf("%016"PRIx64, dpid); - ovsrec_bridge_set_datapath_id(br->cfg, dpid_string); - free(dpid_string); + /* 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); + } + } - /* Set NetFlow configuration on this bridge. */ - if (br->cfg->netflow) { - struct ovsrec_netflow *nf_cfg = br->cfg->netflow; - struct netflow_options opts; + shash_destroy(&new_br); +} - memset(&opts, 0, sizeof opts); +/* 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; - 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; - } + OFPROTO_PORT_FOR_EACH (&ofproto_port, &dump, br->ofproto) { + const char *name = ofproto_port.name; + struct iface *iface; + const char *type; + int error; - 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; - } + /* Ignore the local port. We can't change it anyhow. */ + if (!strcmp(name, br->name)) { + continue; + } - 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); - } - } + /* 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); - 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); + /* 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); } - sset_destroy(&opts.collectors); - } else { - ofproto_set_netflow(br->ofproto, NULL); + netdev_close(iface->netdev); + iface->netdev = NULL; } + } +} - /* 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; +static void +iface_set_dp_ifidx(struct iface *iface, int dp_ifidx) +{ + struct bridge *br = iface->port->bridge; - memset(&oso, 0, sizeof oso); + 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)); - sset_init(&oso.targets); - sset_add_array(&oso.targets, - sflow_cfg->targets, sflow_cfg->n_targets); +} - oso.sampling_rate = SFL_DEFAULT_SAMPLING_RATE; - if (sflow_cfg->sampling) { - oso.sampling_rate = *sflow_cfg->sampling; - } +static void +bridge_refresh_dp_ifidx(struct bridge *br) +{ + struct ofproto_port_dump dump; + struct ofproto_port ofproto_port; + struct port *port; - oso.polling_interval = SFL_DEFAULT_POLLING_INTERVAL; - if (sflow_cfg->polling) { - oso.polling_interval = *sflow_cfg->polling; - } + /* Clear all the "dp_ifidx"es. */ + hmap_clear(&br->ifaces); + HMAP_FOR_EACH (port, hmap_node, &br->ports) { + struct iface *iface; - oso.header_len = SFL_DEFAULT_HEADER_SIZE; - if (sflow_cfg->header) { - oso.header_len = *sflow_cfg->header; + LIST_FOR_EACH (iface, port_elem, &port->ifaces) { + iface->dp_ifidx = -1; + } + } + + /* 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); } + } + } +} - oso.sub_id = sflow_bridge_number++; - oso.agent_device = sflow_cfg->agent; +/* 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; - 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); + HMAP_FOR_EACH_SAFE (port, next_port, hmap_node, &br->ports) { + struct iface *iface, *next_iface; - 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); - } - LIST_FOR_EACH (br, node, &all_bridges) { - struct port *port; + LIST_FOR_EACH_SAFE (iface, next_iface, port_elem, &port->ifaces) { + struct shash args; + int error; - br->has_bonded_ports = false; - HMAP_FOR_EACH (port, hmap_node, &br->ports) { - struct iface *iface; + /* 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)); + } - port_reconfigure_bond(port); + /* Add the port, if necessary. */ + if (iface->netdev && iface->dp_ifidx < 0) { + uint16_t ofp_port; + int error; - LIST_FOR_EACH (iface, port_elem, &port->ifaces) { - iface_update_qos(iface, port->cfg->qos); + 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; + } } - } - } - LIST_FOR_EACH (br, node, &all_bridges) { - iterate_and_prune_ifaces(br, set_iface_properties, NULL); - } - /* Some reconfiguration operations require the bridge to have been run at - * least once. */ - LIST_FOR_EACH (br, node, &all_bridges) { - struct iface *iface; + /* 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; + } - bridge_run_one(br); + /* 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; - HMAP_FOR_EACH (iface, dp_ifidx_node, &br->ifaces) { - iface_update_cfm(iface); + 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); + } } } - - free(managers); - - /* ovs-vswitchd has completed initialization, so allow the process that - * forked us to exit successfully. */ - daemonize_complete(); } static const char * @@ -1136,6 +1186,10 @@ iface_refresh_status(struct iface *iface) int64_t mtu_64; int error; + if (iface_is_synthetic(iface)) { + return; + } + shash_init(&sh); if (!netdev_get_status(iface->netdev, &sh)) { @@ -1175,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"); @@ -1227,6 +1280,27 @@ iface_refresh_cfm_stats(struct iface *iface) return changed; } +static bool +iface_refresh_lacp_stats(struct iface *iface) +{ + bool *db_current = iface->cfg->lacp_current; + bool changed = false; + + if (iface->port->lacp) { + bool current = lacp_slave_is_current(iface->port->lacp, iface); + + if (!db_current || *db_current != current) { + changed = true; + ovsrec_interface_set_lacp_current(iface->cfg, ¤t, 1); + } + } else if (db_current) { + changed = true; + ovsrec_interface_set_lacp_current(iface->cfg, NULL, 0); + } + + return changed; +} + static void iface_refresh_stats(struct iface *iface) { @@ -1257,6 +1331,10 @@ iface_refresh_stats(struct iface *iface) struct netdev_stats stats; + if (iface_is_synthetic(iface)) { + return; + } + /* Intentionally ignore return value, since errors will set 'stats' to * all-1s, and we will deal with that correctly below. */ netdev_get_stats(iface->netdev, &stats); @@ -1342,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); @@ -1373,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); @@ -1394,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) { @@ -1415,12 +1492,12 @@ bridge_run(void) stats_timer = time_msec() + STATS_INTERVAL; } - if (time_msec() >= cfm_limiter) { + if (time_msec() >= db_limiter) { struct ovsdb_idl_txn *txn; 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) { @@ -1428,12 +1505,13 @@ bridge_run(void) LIST_FOR_EACH (iface, port_elem, &port->ifaces) { changed = iface_refresh_cfm_stats(iface) || changed; + changed = iface_refresh_lacp_stats(iface) || changed; } } } if (changed) { - cfm_limiter = time_msec() + CFM_LIMIT_INTERVAL; + db_limiter = time_msec() + DB_LIMIT_INTERVAL; } ovsdb_idl_txn_commit(txn); @@ -1446,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); @@ -1458,8 +1536,8 @@ bridge_wait(void) ovsdb_idl_wait(idl); poll_timer_wait_until(stats_timer); - if (cfm_limiter > time_msec()) { - poll_timer_wait_until(cfm_limiter); + if (db_limiter > time_msec()) { + poll_timer_wait_until(db_limiter); } } @@ -1619,49 +1697,27 @@ 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); hmap_init(&br->ports); hmap_init(&br->ifaces); - shash_init(&br->iface_by_name); + hmap_init(&br->iface_by_name); br->flush = false; - list_push_back(&all_bridges, &br->node); - - VLOG_INFO("created bridge %s on %s", br->name, dpif_name(br->dpif)); - - return br; + hmap_insert(&all_bridges, &br->node, hash_string(br->name, 0)); } static void @@ -1669,24 +1725,22 @@ 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) { port_destroy(port); } - list_remove(&br->node); - ofproto_destroy(br->ofproto); - error = dpif_delete(br->dpif); - if (error && error != ENOENT) { - VLOG_ERR("failed to delete %s: %s", - dpif_name(br->dpif), strerror(error)); + for (i = 0; i < MAX_MIRRORS; i++) { + mirror_destroy(br->mirrors[i]); } - dpif_close(br->dpif); + hmap_remove(&all_bridges, &br->node); + ofproto_destroy(br->ofproto); mac_learning_destroy(br->ml); hmap_destroy(&br->ifaces); hmap_destroy(&br->ports); - shash_destroy(&br->iface_by_name); + hmap_destroy(&br->iface_by_name); free(br->name); + free(br->type); free(br); } } @@ -1696,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; } @@ -1742,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); } } @@ -1793,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; @@ -1811,47 +1866,44 @@ bridge_reconfigure_one(struct bridge *br) br->name, name); } } + 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); - /* If we have a controller, then we need a local port. Complain if the - * user didn't specify one. - * - * XXX perhaps we should synthesize a port ourselves in this case. */ - if (bridge_get_controllers(br, NULL)) { - char local_name[IF_NAMESIZE]; - int error; + br->synth_local_port.interfaces = &br->synth_local_ifacep; + br->synth_local_port.n_interfaces = 1; + br->synth_local_port.name = br->name; - error = dpif_port_get_name(br->dpif, ODPP_LOCAL, - local_name, sizeof local_name); - if (!error && !shash_find(&new_ports, local_name)) { - VLOG_WARN("bridge %s: controller specified but no local port " - "(port named %s) defined", - br->name, local_name); - } + br->synth_local_iface.name = br->name; + br->synth_local_iface.type = "internal"; + + br->synth_local_ifacep = &br->synth_local_iface; + + shash_add(&new_ports, br->name, &br->synth_local_port); } /* 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); @@ -1859,34 +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; - if (ofproto_get_fail_mode(br->ofproto) != fail_mode - && !ofproto_has_primary_controller(br->ofproto)) { - ofproto_flush_flows(br->ofproto); - } - ofproto_set_fail_mode(br->ofproto, fail_mode); - - /* Delete all flows if we're switching from connected to standalone or vice - * versa. (XXX Should we delete all flows if we are switching from one - * controller to another?) */ - - /* 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 @@ -1975,7 +1999,8 @@ bridge_reconfigure_remotes(struct bridge *br, struct ovsrec_controller **controllers; size_t n_controllers; - bool had_primary; + + enum ofproto_fail_mode fail_mode; struct ofproto_controller *ocs; size_t n_ocs; @@ -1997,7 +2022,6 @@ bridge_reconfigure_remotes(struct bridge *br, } else { ofproto_set_extra_in_band_remotes(br->ofproto, managers, n_managers); } - had_primary = ofproto_has_primary_controller(br->ofproto); n_controllers = bridge_get_controllers(br, &controllers); @@ -2014,9 +2038,9 @@ bridge_reconfigure_remotes(struct bridge *br, /* Prevent remote ovsdb-server users from accessing arbitrary Unix * domain sockets and overwriting arbitrary local files. */ - VLOG_ERR_RL(&rl, "%s: not adding Unix domain socket controller " - "\"%s\" due to possibility for remote exploit", - dpif_name(br->dpif), c->target); + VLOG_ERR_RL(&rl, "bridge %s: not adding Unix domain socket " + "controller \"%s\" due to possibility for remote " + "exploit", br->name, c->target); continue; } @@ -2032,92 +2056,22 @@ bridge_reconfigure_remotes(struct bridge *br, free(ocs[0].target); /* From bridge_ofproto_controller_for_mgmt(). */ free(ocs); - if (had_primary != ofproto_has_primary_controller(br->ofproto)) { - ofproto_flush_flows(br->ofproto); - } - - /* If there are no controllers and the bridge is in standalone - * mode, set up a flow that matches every packet and directs - * them to OFPP_NORMAL (which goes to us). Otherwise, the - * switch is in secure mode and we won't pass any traffic until - * a controller has been defined and it tells us to do so. */ - if (!n_controllers - && ofproto_get_fail_mode(br->ofproto) == OFPROTO_FAIL_STANDALONE) { - union ofp_action action; - struct cls_rule rule; - - memset(&action, 0, sizeof action); - action.type = htons(OFPAT_OUTPUT); - action.output.len = htons(sizeof action); - action.output.port = htons(OFPP_NORMAL); - cls_rule_init_catchall(&rule, 0); - ofproto_add_flow(br->ofproto, &rule, &action, 1); - } -} - -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("%s reported interface %s twice", - dpif_name(br->dpif), dpif_port.name); - } else if (iface_from_dp_ifidx(br, dpif_port.port_no)) { - VLOG_WARN("%s reported interface %"PRIu16" twice", - dpif_name(br->dpif), 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); } } @@ -2199,8 +2153,7 @@ dst_is_duplicate(const struct dst_set *set, const struct dst *test) static bool port_trunks_vlan(const struct port *port, uint16_t vlan) { - return (port->vlan < 0 - && (!port->trunks || bitmap_is_set(port->trunks, vlan))); + return (port->vlan < 0 || vlan_bitmap_contains(port->trunks, vlan)); } static bool @@ -2630,8 +2583,11 @@ bridge_special_ofhook_cb(const struct flow *flow, iface = iface_from_dp_ifidx(br, flow->in_port); if (flow->dl_type == htons(ETH_TYPE_LACP)) { - if (iface && iface->port->bond && packet) { - bond_process_lacp(iface->port->bond, iface, packet); + if (iface && iface->port->lacp && packet) { + const struct lacp_pdu *pdu = parse_lacp_packet(packet); + if (pdu) { + lacp_process_pdu(iface->port->lacp, iface, pdu); + } } return false; } @@ -2729,12 +2685,55 @@ static struct ofhooks bridge_ofhooks = { /* Port functions. */ +static void +lacp_send_pdu_cb(void *iface_, const struct lacp_pdu *pdu) +{ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 10); + struct iface *iface = iface_; + uint8_t ea[ETH_ADDR_LEN]; + int error; + + error = netdev_get_etheraddr(iface->netdev, ea); + if (!error) { + struct lacp_pdu *packet_pdu; + struct ofpbuf packet; + + ofpbuf_init(&packet, 0); + packet_pdu = eth_compose(&packet, eth_addr_lacp, ea, ETH_TYPE_LACP, + sizeof *packet_pdu); + *packet_pdu = *pdu; + error = netdev_send(iface->netdev, &packet); + if (error) { + VLOG_WARN_RL(&rl, "port %s: sending LACP PDU on iface %s failed " + "(%s)", iface->port->name, iface->name, + strerror(error)); + } + ofpbuf_uninit(&packet); + } else { + VLOG_ERR_RL(&rl, "port %s: cannot obtain Ethernet address of iface " + "%s (%s)", iface->port->name, iface->name, + strerror(error)); + } +} + static void port_run(struct port *port) { + if (port->lacp) { + lacp_run(port->lacp, lacp_send_pdu_cb); + } + if (port->bond) { + struct iface *iface; + + LIST_FOR_EACH (iface, port_elem, &port->ifaces) { + bool may_enable = lacp_slave_may_enable(port->lacp, iface); + bond_slave_set_lacp_may_enable(port->bond, iface, may_enable); + } + bond_run(port->bond, - ofproto_get_revalidate_set(port->bridge->ofproto)); + ofproto_get_revalidate_set(port->bridge->ofproto), + lacp_negotiated(port->lacp)); if (bond_should_send_learning_packets(port->bond)) { port_send_learning_packets(port); } @@ -2744,27 +2743,29 @@ port_run(struct port *port) static void port_wait(struct port *port) { + if (port->lacp) { + lacp_wait(port->lacp); + } + if (port->bond) { bond_wait(port->bond); } } 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; } @@ -2791,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; @@ -2800,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); } @@ -2815,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 @@ -2833,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; @@ -2904,35 +2911,16 @@ port_reconfigure(struct port *port, const struct ovsrec_port *cfg) /* Get trunked VLANs. */ trunks = NULL; if (vlan < 0 && cfg->n_trunks) { - size_t n_errors; - - trunks = bitmap_allocate(4096); - n_errors = 0; - for (i = 0; i < cfg->n_trunks; i++) { - int trunk = cfg->trunks[i]; - if (trunk >= 0) { - bitmap_set1(trunks, trunk); - } else { - n_errors++; - } - } - if (n_errors) { - VLOG_ERR("port %s: invalid values for %zu trunk VLANs", - port->name, cfg->n_trunks); - } - if (n_errors == cfg->n_trunks) { + trunks = vlan_bitmap_from_array(cfg->trunks, cfg->n_trunks); + if (!trunks) { VLOG_ERR("port %s: no valid trunks, trunking all VLANs", port->name); - bitmap_free(trunks); - trunks = NULL; } } else if (vlan >= 0 && cfg->n_trunks) { VLOG_ERR("port %s: ignoring trunks in favor of implicit vlan", port->name); } - if (trunks == NULL - ? port->trunks != NULL - : port->trunks == NULL || !bitmap_equal(trunks, port->trunks, 4096)) { + if (!vlan_bitmap_equal(trunks, port->trunks)) { need_flush = true; } bitmap_free(port->trunks); @@ -2966,6 +2954,8 @@ port_destroy(struct port *port) VLOG_INFO("destroyed port %s on bridge %s", port->name, br->name); + bond_destroy(port->bond); + lacp_destroy(port->lacp); port_flush_macs(port); bitmap_free(port->trunks); @@ -3017,46 +3007,94 @@ enable_lacp(struct port *port, bool *activep) } } -static struct lacp_settings * -port_reconfigure_bond_lacp(struct port *port, struct lacp_settings *s) +static void +iface_reconfigure_lacp(struct iface *iface) { - if (!enable_lacp(port, &s->active)) { - return NULL; - } + struct lacp_slave_settings s; + int priority, portid; - s->name = port->name; - memcpy(s->id, port->bridge->ea, ETH_ADDR_LEN); - s->priority = atoi(get_port_other_config(port->cfg, "lacp-system-priority", - "0")); - s->fast = !strcmp(get_port_other_config(port->cfg, "lacp-time", "slow"), - "fast"); + portid = atoi(get_interface_other_config(iface->cfg, "lacp-port-id", "0")); + priority = atoi(get_interface_other_config(iface->cfg, + "lacp-port-priority", "0")); - if (s->priority <= 0 || s->priority > UINT16_MAX) { - /* Prefer bondable links if unspecified. */ - s->priority = UINT16_MAX - !list_is_short(&port->ifaces); + if (portid <= 0 || portid > UINT16_MAX) { + portid = iface->dp_ifidx; } - return s; + + if (priority <= 0 || priority > UINT16_MAX) { + priority = UINT16_MAX; + } + + s.name = iface->name; + s.id = portid; + s.priority = priority; + lacp_slave_register(iface->port->lacp, iface, &s); } static void -iface_reconfigure_bond(struct iface *iface) +port_reconfigure_lacp(struct port *port) { - struct lacp_slave_settings s; + static struct lacp_settings s; + struct iface *iface; + uint8_t sysid[ETH_ADDR_LEN]; + const char *sysid_str; + const char *lacp_time; + long long int custom_time; int priority; - s.name = iface->name; - s.id = iface->dp_ifidx; - priority = atoi(get_interface_other_config( - iface->cfg, "lacp-port-priority", "0")); - s.priority = (priority >= 0 && priority <= UINT16_MAX - ? priority : UINT16_MAX); - bond_slave_register(iface->port->bond, iface, iface->netdev, &s); + if (!enable_lacp(port, &s.active)) { + lacp_destroy(port->lacp); + port->lacp = NULL; + return; + } + + sysid_str = get_port_other_config(port->cfg, "lacp-system-id", NULL); + if (sysid_str && eth_addr_from_string(sysid_str, sysid)) { + memcpy(s.id, sysid, ETH_ADDR_LEN); + } else { + memcpy(s.id, port->bridge->ea, ETH_ADDR_LEN); + } + + s.name = port->name; + + /* Prefer bondable links if unspecified. */ + priority = atoi(get_port_other_config(port->cfg, "lacp-system-priority", + "0")); + s.priority = (priority > 0 && priority <= UINT16_MAX + ? priority + : UINT16_MAX - !list_is_short(&port->ifaces)); + + s.strict = !strcmp(get_port_other_config(port->cfg, "lacp-strict", + "false"), + "true"); + + lacp_time = get_port_other_config(port->cfg, "lacp-time", "slow"); + custom_time = atoi(lacp_time); + if (!strcmp(lacp_time, "fast")) { + s.lacp_time = LACP_TIME_FAST; + } else if (!strcmp(lacp_time, "slow")) { + s.lacp_time = LACP_TIME_SLOW; + } else if (custom_time > 0) { + s.lacp_time = LACP_TIME_CUSTOM; + s.custom_time = custom_time; + } else { + s.lacp_time = LACP_TIME_SLOW; + } + + if (!port->lacp) { + port->lacp = lacp_create(); + } + + lacp_configure(port->lacp, &s); + + LIST_FOR_EACH (iface, port_elem, &port->ifaces) { + iface_reconfigure_lacp(iface); + } } static void port_reconfigure_bond(struct port *port) { - struct lacp_settings lacp_settings; struct bond_settings s; const char *detect_s; struct iface *iface; @@ -3102,16 +3140,21 @@ port_reconfigure_bond(struct port *port) } s.fake_iface = port->cfg->bond_fake_iface; - s.lacp = port_reconfigure_bond_lacp(port, &lacp_settings); if (!port->bond) { port->bond = bond_create(&s); } else { - bond_reconfigure(port->bond, &s); + if (bond_reconfigure(port->bond, &s)) { + bridge_flush(port->bridge); + } } LIST_FOR_EACH (iface, port_elem, &port->ifaces) { - iface_reconfigure_bond(iface); + uint16_t stable_id = (port->lacp + ? lacp_slave_get_port_id(port->lacp, iface) + : iface->dp_ifidx); + bond_slave_register(iface->port->bond, iface, stable_id, + iface->netdev); } } @@ -3162,7 +3205,7 @@ iface_create(struct port *port, const struct ovsrec_interface *if_cfg) iface->netdev = NULL; iface->cfg = if_cfg; - shash_add_assert(&br->iface_by_name, iface->name, iface); + hmap_insert(&br->iface_by_name, &iface->name_node, hash_string(name, 0)); list_push_back(&port->ifaces, &iface->port_elem); @@ -3184,13 +3227,16 @@ iface_destroy(struct iface *iface) bond_slave_unregister(port->bond, iface); } - shash_find_and_delete_assert(&br->iface_by_name, iface->name); + if (port->lacp) { + lacp_slave_unregister(port->lacp, iface); + } if (iface->dp_ifidx >= 0) { hmap_remove(&br->ifaces, &iface->dp_ifidx_node); } list_remove(&iface->port_elem); + hmap_remove(&br->iface_by_name, &iface->name_node); netdev_close(iface->netdev); @@ -3204,7 +3250,16 @@ iface_destroy(struct iface *iface) static struct iface * iface_lookup(const struct bridge *br, const char *name) { - return shash_find_data(&br->iface_by_name, name); + struct iface *iface; + + HMAP_FOR_EACH_WITH_HASH (iface, name_node, hash_string(name, 0), + &br->iface_by_name) { + if (!strcmp(iface->name, name)) { + return iface; + } + } + + return NULL; } static struct iface * @@ -3212,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) { @@ -3243,13 +3298,15 @@ iface_set_mac(struct iface *iface) { uint8_t ea[ETH_ADDR_LEN]; - if (iface->cfg->mac && eth_addr_from_string(iface->cfg->mac, ea)) { - if (eth_addr_is_multicast(ea)) { + if (!strcmp(iface->type, "internal") + && iface->cfg->mac && eth_addr_from_string(iface->cfg->mac, ea)) { + if (iface->dp_ifidx == ODPP_LOCAL) { + VLOG_ERR("interface %s: ignoring mac in Interface record " + "(use Bridge record to set local port's mac)", + iface->name); + } else if (eth_addr_is_multicast(ea)) { VLOG_ERR("interface %s: cannot set MAC to multicast address", iface->name); - } else if (iface->dp_ifidx == ODPP_LOCAL) { - VLOG_ERR("ignoring iface.%s.mac; use bridge.%s.mac instead", - iface->name, iface->name); } else { int error = netdev_set_etheraddr(iface->netdev, ea); if (error) { @@ -3264,7 +3321,7 @@ iface_set_mac(struct iface *iface) static void iface_set_ofport(const struct ovsrec_interface *if_cfg, int64_t ofport) { - if (if_cfg) { + if (if_cfg && !ovsdb_idl_row_is_synthetic(&if_cfg->header_)) { ovsrec_interface_set_ofport(if_cfg, &ofport, 1); } } @@ -3343,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); @@ -3379,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; @@ -3424,6 +3481,14 @@ iface_get_carrier(const struct iface *iface) /* XXX */ return netdev_get_carrier(iface->netdev); } + +/* Returns true if 'iface' is synthetic, that is, if we constructed it locally + * instead of obtaining it from the database. */ +static bool +iface_is_synthetic(const struct iface *iface) +{ + return ovsdb_idl_row_is_synthetic(&iface->cfg->header_); +} /* Port mirroring. */ @@ -3488,24 +3553,14 @@ mirror_reconfigure(struct bridge *br) /* Update flooded vlans (for RSPAN). */ rspan_vlans = NULL; if (br->cfg->n_flood_vlans) { - rspan_vlans = bitmap_allocate(4096); - - for (i = 0; i < br->cfg->n_flood_vlans; i++) { - int64_t vlan = br->cfg->flood_vlans[i]; - if (vlan >= 0 && vlan < 4096) { - bitmap_set1(rspan_vlans, vlan); - VLOG_INFO("bridge %s: disabling learning on vlan %"PRId64, - br->name, vlan); - } else { - VLOG_ERR("bridge %s: invalid value %"PRId64 "for flood VLAN", - br->name, vlan); - } - } + rspan_vlans = vlan_bitmap_from_array(br->cfg->flood_vlans, + br->cfg->n_flood_vlans); } if (mac_learning_set_flood_vlans(br->ml, rspan_vlans)) { bridge_flush(br); mac_learning_flush(br->ml); } + free(rspan_vlans); } static void @@ -3530,6 +3585,7 @@ mirror_create(struct bridge *br, struct ovsrec_mirror *cfg) mac_learning_flush(br->ml); br->mirrors[i] = m = xzalloc(sizeof *m); + m->uuid = cfg->header_.uuid; m->bridge = br; m->idx = i; m->name = xstrdup(cfg->name); @@ -3619,19 +3675,6 @@ vlan_is_mirrored(const struct mirror *m, int vlan) return false; } -static bool -port_trunks_any_mirrored_vlan(const struct mirror *m, const struct port *p) -{ - size_t i; - - for (i = 0; i < m->n_vlans; i++) { - if (port_trunks_vlan(p, m->vlans[i])) { - return true; - } - } - return false; -} - static void mirror_reconfigure_one(struct mirror *m, struct ovsrec_mirror *cfg) { @@ -3716,11 +3759,7 @@ mirror_reconfigure_one(struct mirror *m, struct ovsrec_mirror *cfg) /* Update ports. */ mirror_bit = MIRROR_MASK_C(1) << m->idx; HMAP_FOR_EACH (port, hmap_node, &m->bridge->ports) { - if (sset_contains(&m->src_ports, port->name) - || (m->n_vlans - && (!port->vlan - ? port_trunks_any_mirrored_vlan(m, port) - : vlan_is_mirrored(m, port->vlan)))) { + if (sset_contains(&m->src_ports, port->name)) { port->src_mirrors |= mirror_bit; } else { port->src_mirrors &= ~mirror_bit;