X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=vswitchd%2Fbridge.c;h=c2e89eb838de330afc06f2c0b4c0f25b9ad1a1b6;hb=1f441586403f0fe315ff905775a3e055c088aeec;hp=aa48602ff01376709dd8408ecd7e6011004624a6;hpb=149f577a25508779b756515be1f1bdcefa3710fa;p=openvswitch diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index aa48602f..c2e89eb8 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -61,6 +61,7 @@ #include "vswitchd/vswitch-idl.h" #include "xenserver.h" #include "xtoxll.h" +#include "sflow_api.h" #define THIS_MODULE VLM_bridge #include "vlog.h" @@ -105,8 +106,8 @@ struct mirror { char *name; /* Selection criteria. */ - struct svec src_ports; - struct svec dst_ports; + struct shash src_ports; /* Name is port name; data is always NULL. */ + struct shash dst_ports; /* Name is port name; data is always NULL. */ int *vlans; size_t n_vlans; @@ -193,11 +194,14 @@ static struct list all_bridges = LIST_INITIALIZER(&all_bridges); /* Maximum number of datapaths. */ enum { DP_MAX = 256 }; -static struct bridge *bridge_create(const char *name); +static struct bridge *bridge_create(const struct ovsrec_bridge *br_cfg); static void bridge_destroy(struct bridge *); static struct bridge *bridge_lookup(const char *name); static unixctl_cb_func bridge_unixctl_dump_flows; static int bridge_run_one(struct bridge *); +static const struct ovsrec_controller *bridge_get_controller( + const struct ovsrec_open_vswitch *ovs_cfg, + const struct bridge *br); static void bridge_reconfigure_one(const struct ovsrec_open_vswitch *, struct bridge *); static void bridge_reconfigure_controller(const struct ovsrec_open_vswitch *, @@ -234,18 +238,11 @@ static void port_update_bond_compat(struct port *); static void port_update_vlan_compat(struct port *); static void port_update_bonding(struct port *); -#if 0 -static void mirror_create(struct bridge *, const char *name); +static struct mirror *mirror_create(struct bridge *, const char *name); static void mirror_destroy(struct mirror *); static void mirror_reconfigure(struct bridge *); -static void mirror_reconfigure_one(struct mirror *); +static void mirror_reconfigure_one(struct mirror *, struct ovsrec_mirror *); static bool vlan_is_mirrored(const struct mirror *, int vlan); -#else -static bool vlan_is_mirrored(const struct mirror *m UNUSED, int vlan UNUSED) -{ - return false; -} -#endif static struct iface *iface_create(struct port *port, const struct ovsrec_interface *if_cfg); @@ -292,7 +289,7 @@ void bridge_init(const struct ovsrec_open_vswitch *cfg) { struct svec bridge_names; - struct svec dpif_names; + struct svec dpif_names, dpif_types; size_t i; unixctl_command_register("fdb/show", bridge_unixctl_fdb_show, NULL); @@ -304,31 +301,37 @@ bridge_init(const struct ovsrec_open_vswitch *cfg) svec_sort(&bridge_names); svec_init(&dpif_names); - dp_enumerate(&dpif_names); - for (i = 0; i < dpif_names.n; i++) { - const char *dpif_name = dpif_names.names[i]; + svec_init(&dpif_types); + dp_enumerate_types(&dpif_types); + for (i = 0; i < dpif_types.n; i++) { struct dpif *dpif; int retval; + size_t j; - retval = dpif_open(dpif_name, &dpif); - if (!retval) { - struct svec all_names; - size_t j; + dp_enumerate_names(dpif_types.names[i], &dpif_names); - svec_init(&all_names); - dpif_get_all_names(dpif, &all_names); - for (j = 0; j < all_names.n; j++) { - if (svec_contains(&bridge_names, all_names.names[j])) { - goto found; + for (j = 0; j < dpif_names.n; j++) { + retval = dpif_open(dpif_names.names[j], dpif_types.names[i], &dpif); + if (!retval) { + struct svec all_names; + size_t k; + + svec_init(&all_names); + dpif_get_all_names(dpif, &all_names); + for (k = 0; k < all_names.n; k++) { + if (svec_contains(&bridge_names, all_names.names[k])) { + goto found; + } } + dpif_delete(dpif); + found: + svec_destroy(&all_names); + dpif_close(dpif); } - dpif_delete(dpif); - found: - svec_destroy(&all_names); - dpif_close(dpif); } } svec_destroy(&dpif_names); + svec_destroy(&dpif_types); unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows, NULL); @@ -449,8 +452,8 @@ reconfigure_iface(const struct ovsrec_interface *iface_cfg, struct iface *iface) } static bool -check_iface_netdev(struct bridge *br UNUSED, struct iface *iface, - void *aux UNUSED) +check_iface_netdev(struct bridge *br OVS_UNUSED, struct iface *iface, + void *aux OVS_UNUSED) { if (!iface->netdev) { int error = set_up_iface(iface->cfg, iface, true); @@ -465,7 +468,8 @@ check_iface_netdev(struct bridge *br UNUSED, struct iface *iface, } static bool -check_iface_dp_ifidx(struct bridge *br, struct iface *iface, void *aux UNUSED) +check_iface_dp_ifidx(struct bridge *br, struct iface *iface, + void *aux OVS_UNUSED) { if (iface->dp_ifidx >= 0) { VLOG_DBG("%s has interface %s on port %d", @@ -480,8 +484,8 @@ check_iface_dp_ifidx(struct bridge *br, struct iface *iface, void *aux UNUSED) } static bool -set_iface_properties(struct bridge *br UNUSED, struct iface *iface, - void *aux UNUSED) +set_iface_properties(struct bridge *br OVS_UNUSED, struct iface *iface, + void *aux OVS_UNUSED) { /* Set policing attributes. */ netdev_set_policing(iface->netdev, @@ -537,6 +541,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) struct shash_node *node; struct bridge *br, *next; size_t i; + int sflow_bridge_number; COVERAGE_INC(bridge_reconfigure); @@ -567,11 +572,16 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) SHASH_FOR_EACH (node, &new_br) { const char *br_name = node->name; const struct ovsrec_bridge *br_cfg = node->data; - if (!shash_find_data(&old_br, br_name)) { - br = bridge_create(br_name); - if (br) { - br->cfg = br_cfg; + 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); } } shash_destroy(&old_br); @@ -665,6 +675,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) shash_destroy(&cur_ifaces); shash_destroy(&want_ifaces); } + sflow_bridge_number = 0; LIST_FOR_EACH (br, struct bridge, node, &all_bridges) { uint8_t ea[8]; uint64_t dpid; @@ -706,10 +717,10 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) dpif_get_netflow_ids(br->dpif, &opts.engine_type, &opts.engine_id); if (nf_cfg->engine_type) { - opts.engine_type = nf_cfg->engine_type; + opts.engine_type = *nf_cfg->engine_type; } if (nf_cfg->engine_id) { - opts.engine_id = nf_cfg->engine_id; + opts.engine_id = *nf_cfg->engine_id; } opts.active_timeout = nf_cfg->active_timeout; @@ -746,6 +757,44 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) ofproto_set_netflow(br->ofproto, NULL); } + /* Set sFlow configuration on this bridge. */ + if (br->cfg->sflow) { + const struct ovsrec_sflow *sflow_cfg = br->cfg->sflow; + const struct ovsrec_controller *ctrl; + struct ofproto_sflow_options oso; + + memset(&oso, 0, sizeof oso); + + oso.targets.n = sflow_cfg->n_targets; + oso.targets.names = sflow_cfg->targets; + + oso.sampling_rate = SFL_DEFAULT_SAMPLING_RATE; + if (sflow_cfg->sampling) { + oso.sampling_rate = *sflow_cfg->sampling; + } + + oso.polling_interval = SFL_DEFAULT_POLLING_INTERVAL; + if (sflow_cfg->polling) { + oso.polling_interval = *sflow_cfg->polling; + } + + oso.header_len = SFL_DEFAULT_HEADER_SIZE; + if (sflow_cfg->header) { + oso.header_len = *sflow_cfg->header; + } + + oso.sub_id = sflow_bridge_number++; + oso.agent_device = sflow_cfg->agent; + + ctrl = bridge_get_controller(ovs_cfg, br); + oso.control_ip = ctrl ? ctrl->local_ip : NULL; + ofproto_set_sflow(br->ofproto, &oso); + + svec_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 @@ -1051,7 +1100,7 @@ bridge_get_local_iface(struct bridge *br) /* Bridge unixctl user interface functions. */ static void bridge_unixctl_fdb_show(struct unixctl_conn *conn, - const char *args, void *aux UNUSED) + const char *args, void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; const struct bridge *br; @@ -1078,34 +1127,38 @@ bridge_unixctl_fdb_show(struct unixctl_conn *conn, /* Bridge reconfiguration functions. */ static struct bridge * -bridge_create(const char *name) +bridge_create(const struct ovsrec_bridge *br_cfg) { struct bridge *br; int error; - assert(!bridge_lookup(name)); + assert(!bridge_lookup(br_cfg->name)); br = xzalloc(sizeof *br); - error = dpif_create_and_open(name, &br->dpif); + error = dpif_create_and_open(br_cfg->name, br_cfg->datapath_type, + &br->dpif); if (error) { free(br); return NULL; } dpif_flow_flush(br->dpif); - error = ofproto_create(name, &bridge_ofhooks, br, &br->ofproto); + 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", name, strerror(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(name); + br->name = xstrdup(br_cfg->name); + br->cfg = br_cfg; br->ml = mac_learning_create(); br->sent_config_request = false; - eth_addr_random(br->default_ea); + eth_addr_nicira_random(br->default_ea); port_array_init(&br->ifaces); @@ -1175,7 +1228,7 @@ bridge_get_datapathid(const char *name) * stack, including those normally hidden. */ static void bridge_unixctl_dump_flows(struct unixctl_conn *conn, - const char *args, void *aux UNUSED) + const char *args, void *aux OVS_UNUSED) { struct bridge *br; struct ds results; @@ -1254,7 +1307,6 @@ bridge_reconfigure_one(const struct ovsrec_open_vswitch *ovs_cfg, struct svec listeners, old_listeners; struct svec snoops, old_snoops; struct shash_node *node; - uint64_t mgmt_id; size_t i; /* Collect old ports. */ @@ -1290,9 +1342,6 @@ bridge_reconfigure_one(const struct ovsrec_open_vswitch *ovs_cfg, } } - dpid_from_string(ovs_cfg->management_id, &mgmt_id); - ofproto_set_mgmt_id(br->ofproto, mgmt_id); - /* Get rid of deleted ports and add new ports. */ SHASH_FOR_EACH (node, &old_ports) { if (!shash_find(&new_ports, node->name)) { @@ -1386,9 +1435,7 @@ bridge_reconfigure_one(const struct ovsrec_open_vswitch *ovs_cfg, svec_destroy(&old_snoops); #endif -#if 0 mirror_reconfigure(br); -#endif } static void @@ -1426,7 +1473,7 @@ bridge_reconfigure_controller(const struct ovsrec_open_vswitch *ovs_cfg, local_iface = bridge_get_local_iface(br); if (local_iface && c->local_ip && inet_aton(c->local_ip, &ip)) { struct netdev *netdev = local_iface->netdev; - struct in_addr ip, mask, gateway; + struct in_addr mask, gateway; if (!c->local_netmask || !inet_aton(c->local_netmask, &mask)) { mask.s_addr = 0; @@ -1948,7 +1995,7 @@ compose_dsts(const struct bridge *br, const flow_t *flow, uint16_t vlan, return dst - dsts; } -static void UNUSED +static void OVS_UNUSED print_dsts(const struct dst *dsts, size_t n) { for (; n--; dsts++) { @@ -2663,7 +2710,7 @@ bond_send_learning_packets(struct port *port) static void bond_unixctl_list(struct unixctl_conn *conn, - const char *args UNUSED, void *aux UNUSED) + const char *args OVS_UNUSED, void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; const struct bridge *br; @@ -2714,7 +2761,7 @@ bond_find(const char *name) static void bond_unixctl_show(struct unixctl_conn *conn, - const char *args, void *aux UNUSED) + const char *args, void *aux OVS_UNUSED) { struct ds ds = DS_EMPTY_INITIALIZER; const struct port *port; @@ -2780,7 +2827,7 @@ bond_unixctl_show(struct unixctl_conn *conn, static void bond_unixctl_migrate(struct unixctl_conn *conn, const char *args_, - void *aux UNUSED) + void *aux OVS_UNUSED) { char *args = (char *) args_; char *save_ptr = NULL; @@ -2837,7 +2884,7 @@ bond_unixctl_migrate(struct unixctl_conn *conn, const char *args_, static void bond_unixctl_set_active_slave(struct unixctl_conn *conn, const char *args_, - void *aux UNUSED) + void *aux OVS_UNUSED) { char *args = (char *) args_; char *save_ptr = NULL; @@ -2918,21 +2965,21 @@ enable_slave(struct unixctl_conn *conn, const char *args_, bool enable) static void bond_unixctl_enable_slave(struct unixctl_conn *conn, const char *args, - void *aux UNUSED) + void *aux OVS_UNUSED) { enable_slave(conn, args, true); } static void bond_unixctl_disable_slave(struct unixctl_conn *conn, const char *args, - void *aux UNUSED) + void *aux OVS_UNUSED) { enable_slave(conn, args, false); } static void bond_unixctl_hash(struct unixctl_conn *conn, const char *args, - void *aux UNUSED) + void *aux OVS_UNUSED) { uint8_t mac[ETH_ADDR_LEN]; uint8_t hash; @@ -3037,7 +3084,7 @@ port_reconfigure(struct port *port, const struct ovsrec_port *cfg) iface = shash_find_data(&old_ifaces, if_cfg->name); if (!iface) { - iface = iface_create(port, if_cfg); + iface_create(port, if_cfg); } else { iface->cfg = if_cfg; } @@ -3116,18 +3163,17 @@ port_destroy(struct port *port) if (port) { struct bridge *br = port->bridge; struct port *del; + int i; proc_net_compat_update_vlan(port->name, NULL, 0); proc_net_compat_update_bond(port->name, NULL); -#if 0 for (i = 0; i < MAX_MIRRORS; i++) { struct mirror *m = br->mirrors[i]; if (m && m->out_port == port) { mirror_destroy(m); } } -#endif while (port->n_ifaces > 0) { iface_destroy(port->ifaces[port->n_ifaces - 1]); @@ -3476,50 +3522,50 @@ iface_set_mac(struct iface *iface) /* Port mirroring. */ -#if 0 static void -mirror_reconfigure(struct bridge *br UNUSED) +mirror_reconfigure(struct bridge *br) { - struct svec old_mirrors, new_mirrors; - size_t i, n_rspan_vlans; + struct shash old_mirrors, new_mirrors; + struct shash_node *node; unsigned long *rspan_vlans; + int i; - /* Collect old and new mirrors. */ - svec_init(&old_mirrors); - svec_init(&new_mirrors); - cfg_get_subsections(&new_mirrors, "mirror.%s", br->name); + /* Collect old mirrors. */ + shash_init(&old_mirrors); for (i = 0; i < MAX_MIRRORS; i++) { if (br->mirrors[i]) { - svec_add(&old_mirrors, br->mirrors[i]->name); + shash_add(&old_mirrors, br->mirrors[i]->name, br->mirrors[i]); } } - /* Get rid of deleted mirrors and add new mirrors. */ - svec_sort(&old_mirrors); - assert(svec_is_unique(&old_mirrors)); - svec_sort(&new_mirrors); - assert(svec_is_unique(&new_mirrors)); - for (i = 0; i < MAX_MIRRORS; i++) { - struct mirror *m = br->mirrors[i]; - if (m && !svec_contains(&new_mirrors, m->name)) { - mirror_destroy(m); + /* Collect new mirrors. */ + shash_init(&new_mirrors); + for (i = 0; i < br->cfg->n_mirrors; i++) { + struct ovsrec_mirror *cfg = br->cfg->mirrors[i]; + if (!shash_add_once(&new_mirrors, cfg->name, cfg)) { + VLOG_WARN("bridge %s: %s specified twice as mirror", + br->name, cfg->name); } } - for (i = 0; i < new_mirrors.n; i++) { - const char *name = new_mirrors.names[i]; - if (!svec_contains(&old_mirrors, name)) { - mirror_create(br, name); + + /* Get rid of deleted mirrors and add new mirrors. */ + SHASH_FOR_EACH (node, &old_mirrors) { + if (!shash_find(&new_mirrors, node->name)) { + mirror_destroy(node->data); } } - svec_destroy(&old_mirrors); - svec_destroy(&new_mirrors); - - /* Reconfigure all mirrors. */ - for (i = 0; i < MAX_MIRRORS; i++) { - if (br->mirrors[i]) { - mirror_reconfigure_one(br->mirrors[i]); + SHASH_FOR_EACH (node, &new_mirrors) { + struct mirror *mirror = shash_find_data(&old_mirrors, node->name); + if (!mirror) { + mirror = mirror_create(br, node->name); + if (!mirror) { + break; + } } + mirror_reconfigure_one(mirror, node->data); } + shash_destroy(&old_mirrors); + shash_destroy(&new_mirrors); /* Update port reserved status. */ for (i = 0; i < br->n_ports; i++) { @@ -3532,31 +3578,29 @@ mirror_reconfigure(struct bridge *br UNUSED) } } - /* Update learning disabled vlans (for RSPAN). */ + /* Update flooded vlans (for RSPAN). */ rspan_vlans = NULL; - n_rspan_vlans = cfg_count("vlan.%s.disable-learning", br->name); - if (n_rspan_vlans) { + if (br->cfg->n_flood_vlans) { rspan_vlans = bitmap_allocate(4096); - for (i = 0; i < n_rspan_vlans; i++) { - int vlan = cfg_get_vlan(i, "vlan.%s.disable-learning", br->name); - if (vlan >= 0) { + 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 %d\n", + VLOG_INFO("bridge %s: disabling learning on vlan %"PRId64, br->name, vlan); } else { - VLOG_ERR("bridge %s: invalid value '%s' for learning disabled " - "VLAN", br->name, - cfg_get_string(i, "vlan.%s.disable-learning", br->name)); + VLOG_ERR("bridge %s: invalid value %"PRId64 "for flood VLAN", + br->name, vlan); } } } - if (mac_learning_set_disabled_vlans(br->ml, rspan_vlans)) { + if (mac_learning_set_flood_vlans(br->ml, rspan_vlans)) { bridge_flush(br); } } -static void +static struct mirror * mirror_create(struct bridge *br, const char *name) { struct mirror *m; @@ -3566,7 +3610,7 @@ mirror_create(struct bridge *br, const char *name) if (i >= MAX_MIRRORS) { VLOG_WARN("bridge %s: maximum of %d port mirrors reached, " "cannot create %s", br->name, MAX_MIRRORS, name); - return; + return NULL; } if (!br->mirrors[i]) { break; @@ -3580,12 +3624,14 @@ mirror_create(struct bridge *br, const char *name) m->bridge = br; m->idx = i; m->name = xstrdup(name); - svec_init(&m->src_ports); - svec_init(&m->dst_ports); + shash_init(&m->src_ports); + shash_init(&m->dst_ports); m->vlans = NULL; m->n_vlans = 0; m->out_vlan = -1; m->out_port = NULL; + + return m; } static void @@ -3600,8 +3646,8 @@ mirror_destroy(struct mirror *m) br->ports[i]->dst_mirrors &= ~(MIRROR_MASK_C(1) << m->idx); } - svec_destroy(&m->src_ports); - svec_destroy(&m->dst_ports); + shash_destroy(&m->src_ports); + shash_destroy(&m->dst_ports); free(m->vlans); m->bridge->mirrors[m->idx] = NULL; @@ -3612,45 +3658,36 @@ mirror_destroy(struct mirror *m) } static void -prune_ports(struct mirror *m, struct svec *ports) +mirror_collect_ports(struct mirror *m, struct ovsrec_port **ports, int n_ports, + struct shash *names) { - struct svec tmp; size_t i; - svec_sort_unique(ports); - - svec_init(&tmp); - for (i = 0; i < ports->n; i++) { - const char *name = ports->names[i]; + for (i = 0; i < n_ports; i++) { + const char *name = ports[i]->name; if (port_lookup(m->bridge, name)) { - svec_add(&tmp, name); + shash_add_once(names, name, NULL); } else { - VLOG_WARN("mirror.%s.%s: cannot match on nonexistent port %s", - m->bridge->name, m->name, name); + VLOG_WARN("bridge %s: mirror %s cannot match on nonexistent " + "port %s", m->bridge->name, m->name, name); } } - svec_swap(ports, &tmp); - svec_destroy(&tmp); } static size_t -prune_vlans(struct mirror *m, struct svec *vlan_strings, int **vlans) +mirror_collect_vlans(struct mirror *m, const struct ovsrec_mirror *cfg, + int **vlans) { - size_t n_vlans, i; - - /* This isn't perfect: it won't combine "0" and "00", and the textual sort - * order won't give us numeric sort order. But that's good enough for what - * we need right now. */ - svec_sort_unique(vlan_strings); + size_t n_vlans; + size_t i; - *vlans = xmalloc(sizeof *vlans * vlan_strings->n); + *vlans = xmalloc(sizeof **vlans * cfg->n_select_vlan); n_vlans = 0; - for (i = 0; i < vlan_strings->n; i++) { - const char *name = vlan_strings->names[i]; - int vlan; - if (!str_to_int(name, 10, &vlan) || vlan < 0 || vlan > 4095) { - VLOG_WARN("mirror.%s.%s.select.vlan: ignoring invalid VLAN %s", - m->bridge->name, m->name, name); + for (i = 0; i < cfg->n_select_vlan; i++) { + int64_t vlan = cfg->select_vlan[i]; + if (vlan < 0 || vlan > 4095) { + VLOG_WARN("bridge %s: mirror %s selects invalid VLAN %"PRId64, + m->bridge->name, m->name, vlan); } else { (*vlans)[n_vlans++] = vlan; } @@ -3685,13 +3722,10 @@ port_trunks_any_mirrored_vlan(const struct mirror *m, const struct port *p) } static void -mirror_reconfigure_one(struct mirror *m UNUSED) +mirror_reconfigure_one(struct mirror *m, struct ovsrec_mirror *cfg) { - char *pfx = xasprintf("mirror.%s.%s", m->bridge->name, m->name); - struct svec src_ports, dst_ports, ports; - struct svec vlan_strings; + struct shash src_ports, dst_ports; mirror_mask_t mirror_bit; - const char *out_port_name; struct port *out_port; int out_vlan; size_t n_vlans; @@ -3699,74 +3733,71 @@ mirror_reconfigure_one(struct mirror *m UNUSED) size_t i; bool mirror_all_ports; bool any_ports_specified; + bool any_vlans_specified; /* Get output port. */ - out_port_name = cfg_get_key(0, "mirror.%s.%s.output.port", - m->bridge->name, m->name); - if (out_port_name) { - out_port = port_lookup(m->bridge, out_port_name); + if (cfg->output_port) { + out_port = port_lookup(m->bridge, cfg->output_port->name); if (!out_port) { - VLOG_ERR("%s.output.port: bridge %s does not have a port " - "named %s", pfx, m->bridge->name, out_port_name); + VLOG_ERR("bridge %s: mirror %s outputs to port not on bridge", + m->bridge->name, m->name); mirror_destroy(m); - free(pfx); return; } out_vlan = -1; - if (cfg_has("%s.output.vlan", pfx)) { - VLOG_ERR("%s.output.port and %s.output.vlan both specified; " - "ignoring %s.output.vlan", pfx, pfx, pfx); + if (cfg->output_vlan) { + VLOG_ERR("bridge %s: mirror %s specifies both output port and " + "output vlan; ignoring output vlan", + m->bridge->name, m->name); } - } else if (cfg_has("%s.output.vlan", pfx)) { + } else if (cfg->output_vlan) { out_port = NULL; - out_vlan = cfg_get_vlan(0, "%s.output.vlan", pfx); + out_vlan = *cfg->output_vlan; } else { - VLOG_ERR("%s: neither %s.output.port nor %s.output.vlan specified, " - "but exactly one is required; disabling port mirror %s", - pfx, pfx, pfx, pfx); + VLOG_ERR("bridge %s: mirror %s does not specify output; ignoring", + m->bridge->name, m->name); mirror_destroy(m); - free(pfx); return; } /* Get all the ports, and drop duplicates and ports that don't exist. */ - svec_init(&src_ports); - svec_init(&dst_ports); - svec_init(&ports); - cfg_get_all_keys(&src_ports, "%s.select.src-port", pfx); - cfg_get_all_keys(&dst_ports, "%s.select.dst-port", pfx); - cfg_get_all_keys(&ports, "%s.select.port", pfx); - any_ports_specified = src_ports.n || dst_ports.n || ports.n; - svec_append(&src_ports, &ports); - svec_append(&dst_ports, &ports); - svec_destroy(&ports); - prune_ports(m, &src_ports); - prune_ports(m, &dst_ports); - if (any_ports_specified && !src_ports.n && !dst_ports.n) { - VLOG_ERR("%s: none of the specified ports exist; " - "disabling port mirror %s", pfx, pfx); + shash_init(&src_ports); + shash_init(&dst_ports); + mirror_collect_ports(m, cfg->select_src_port, cfg->n_select_src_port, + &src_ports); + mirror_collect_ports(m, cfg->select_dst_port, cfg->n_select_dst_port, + &dst_ports); + any_ports_specified = cfg->n_select_dst_port || cfg->n_select_dst_port; + if (any_ports_specified + && shash_is_empty(&src_ports) && shash_is_empty(&dst_ports)) { + VLOG_ERR("bridge %s: disabling mirror %s since none of the specified " + "selection ports exists", m->bridge->name, m->name); mirror_destroy(m); goto exit; } /* Get all the vlans, and drop duplicate and invalid vlans. */ - svec_init(&vlan_strings); - cfg_get_all_keys(&vlan_strings, "%s.select.vlan", pfx); - n_vlans = prune_vlans(m, &vlan_strings, &vlans); - svec_destroy(&vlan_strings); + n_vlans = mirror_collect_vlans(m, cfg, &vlans); + any_vlans_specified = cfg->n_select_vlan > 0; + if (any_vlans_specified && !n_vlans) { + VLOG_ERR("bridge %s: disabling mirror %s since none of the specified " + "VLANs exists", m->bridge->name, m->name); + mirror_destroy(m); + goto exit; + } /* Update mirror data. */ - if (!svec_equal(&m->src_ports, &src_ports) - || !svec_equal(&m->dst_ports, &dst_ports) + if (!shash_equal_keys(&m->src_ports, &src_ports) + || !shash_equal_keys(&m->dst_ports, &dst_ports) || m->n_vlans != n_vlans || memcmp(m->vlans, vlans, sizeof *vlans * n_vlans) || m->out_port != out_port || m->out_vlan != out_vlan) { bridge_flush(m->bridge); } - svec_swap(&m->src_ports, &src_ports); - svec_swap(&m->dst_ports, &dst_ports); + shash_swap(&m->src_ports, &src_ports); + shash_swap(&m->dst_ports, &dst_ports); free(m->vlans); m->vlans = vlans; m->n_vlans = n_vlans; @@ -3774,7 +3805,7 @@ mirror_reconfigure_one(struct mirror *m UNUSED) m->out_vlan = out_vlan; /* If no selection criteria have been given, mirror for all ports. */ - mirror_all_ports = (!m->src_ports.n) && (!m->dst_ports.n) && (!m->n_vlans); + mirror_all_ports = !any_ports_specified && !any_vlans_specified; /* Update ports. */ mirror_bit = MIRROR_MASK_C(1) << m->idx; @@ -3782,7 +3813,7 @@ mirror_reconfigure_one(struct mirror *m UNUSED) struct port *port = m->bridge->ports[i]; if (mirror_all_ports - || svec_contains(&m->src_ports, port->name) + || shash_find(&m->src_ports, port->name) || (m->n_vlans && (!port->vlan ? port_trunks_any_mirrored_vlan(m, port) @@ -3792,7 +3823,7 @@ mirror_reconfigure_one(struct mirror *m UNUSED) port->src_mirrors &= ~mirror_bit; } - if (mirror_all_ports || svec_contains(&m->dst_ports, port->name)) { + if (mirror_all_ports || shash_find(&m->dst_ports, port->name)) { port->dst_mirrors |= mirror_bit; } else { port->dst_mirrors &= ~mirror_bit; @@ -3801,8 +3832,6 @@ mirror_reconfigure_one(struct mirror *m UNUSED) /* Clean up. */ exit: - svec_destroy(&src_ports); - svec_destroy(&dst_ports); - free(pfx); + shash_destroy(&src_ports); + shash_destroy(&dst_ports); } -#endif