#include "shash.h"
#include "socket-util.h"
#include "stream-ssl.h"
+#include "sset.h"
#include "svec.h"
#include "system-stats.h"
#include "timeval.h"
struct uuid uuid; /* UUID of this "mirror" record in database. */
/* Selection criteria. */
- struct shash src_ports; /* Name is port name; data is always NULL. */
- struct shash dst_ports; /* Name is port name; data is always NULL. */
+ struct sset src_ports; /* Source port names. */
+ struct sset dst_ports; /* Destination port names. */
int *vlans;
size_t n_vlans;
#define FLOOD_PORT ((struct port *) 1) /* The 'flood' output port. */
struct port {
struct bridge *bridge;
- size_t port_idx;
+ struct hmap_node hmap_node; /* Element in struct bridge's "ports" hmap. */
+ char *name;
+
int vlan; /* -1=trunk port, else a 12-bit VLAN ID. */
unsigned long *trunks; /* Bitmap of trunked VLANs, if 'vlan' == -1.
* NULL if all VLANs are trunked. */
const struct ovsrec_port *cfg;
- char *name;
/* Monitoring. */
struct netdev_monitor *monitor; /* Tracks carrier. NULL if miimon. */
struct hmap ifaces; /* Contains "struct iface"s. */
/* Bridge ports. */
- struct port **ports;
- size_t n_ports, allocated_ports;
+ struct hmap ports; /* "struct port"s indexed by name. */
struct shash iface_by_name; /* "struct iface"s indexed by name. */
- struct shash port_by_name; /* "struct port"s indexed by name. */
/* Bonding. */
bool has_bonded_ports;
#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;
+
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 uint64_t dpid_from_hash(const void *, size_t nbytes);
static unixctl_cb_func bridge_unixctl_fdb_show;
+static unixctl_cb_func cfm_unixctl_show;
static unixctl_cb_func qos_unixctl_show;
static void bond_init(void);
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_refresh_cfm_stats(struct iface *iface);
+static bool iface_refresh_cfm_stats(struct iface *iface);
static void iface_update_carrier(struct iface *);
static bool iface_get_carrier(const struct iface *);
/* Register unixctl commands. */
unixctl_command_register("fdb/show", bridge_unixctl_fdb_show, NULL);
+ unixctl_command_register("cfm/show", cfm_unixctl_show, NULL);
unixctl_command_register("qos/show", qos_unixctl_show, NULL);
unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows,
NULL);
bridge_configure_once(const struct ovsrec_open_vswitch *cfg)
{
static bool already_configured_once;
- struct svec bridge_names;
- struct svec dpif_names, dpif_types;
+ struct sset bridge_names;
+ struct sset dpif_names, dpif_types;
+ const char *type;
size_t i;
/* Only do this once per ovs-vswitchd run. */
stats_timer = time_msec() + STATS_INTERVAL;
/* Get all the configured bridges' names from 'cfg' into 'bridge_names'. */
- svec_init(&bridge_names);
+ sset_init(&bridge_names);
for (i = 0; i < cfg->n_bridges; i++) {
- svec_add(&bridge_names, cfg->bridges[i]->name);
+ sset_add(&bridge_names, cfg->bridges[i]->name);
}
- svec_sort(&bridge_names);
/* Iterate over all system dpifs and delete any of them that do not appear
* in 'cfg'. */
- svec_init(&dpif_names);
- svec_init(&dpif_types);
+ sset_init(&dpif_names);
+ sset_init(&dpif_types);
dp_enumerate_types(&dpif_types);
- for (i = 0; i < dpif_types.n; i++) {
- size_t j;
+ SSET_FOR_EACH (type, &dpif_types) {
+ const char *name;
- dp_enumerate_names(dpif_types.names[i], &dpif_names);
+ dp_enumerate_names(type, &dpif_names);
/* Delete each dpif whose name is not in 'bridge_names'. */
- for (j = 0; j < dpif_names.n; j++) {
- if (!svec_contains(&bridge_names, dpif_names.names[j])) {
+ SSET_FOR_EACH (name, &dpif_names) {
+ if (!sset_contains(&bridge_names, name)) {
struct dpif *dpif;
int retval;
- retval = dpif_open(dpif_names.names[j], dpif_types.names[i],
- &dpif);
+ retval = dpif_open(name, type, &dpif);
if (!retval) {
dpif_delete(dpif);
dpif_close(dpif);
}
}
}
- svec_destroy(&bridge_names);
- svec_destroy(&dpif_names);
- svec_destroy(&dpif_types);
+ sset_destroy(&bridge_names);
+ sset_destroy(&dpif_names);
+ sset_destroy(&dpif_types);
}
/* Callback for iterate_and_prune_ifaces(). */
void *aux),
void *aux)
{
- size_t i;
+ struct port *port, *next_port;
- for (i = 0; i < br->n_ports; ) {
- struct port *port = br->ports[i];
- struct iface *iface, *next;
+ HMAP_FOR_EACH_SAFE (port, next_port, hmap_node, &br->ports) {
+ struct iface *iface, *next_iface;
- LIST_FOR_EACH_SAFE (iface, next, port_elem, &port->ifaces) {
+ 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 (port->n_ifaces) {
- i++;
- } else {
+ if (!port->n_ifaces) {
VLOG_WARN("%s port has no interfaces, dropping", port->name);
port_destroy(port);
}
{
struct sockaddr_in *managers = NULL;
size_t n_managers = 0;
- struct shash targets;
+ struct sset targets;
size_t i;
/* Collect all of the potential targets from the "targets" columns of the
* rows pointed to by "manager_options", excluding any that are
* out-of-band. */
- shash_init(&targets);
+ sset_init(&targets);
for (i = 0; i < ovs_cfg->n_manager_options; i++) {
struct ovsrec_manager *m = ovs_cfg->manager_options[i];
if (m->connection_mode && !strcmp(m->connection_mode, "out-of-band")) {
- shash_find_and_delete(&targets, m->target);
+ sset_find_and_delete(&targets, m->target);
} else {
- shash_add_once(&targets, m->target, NULL);
+ sset_add(&targets, m->target);
}
}
/* Now extract the targets' IP addresses. */
- if (!shash_is_empty(&targets)) {
- struct shash_node *node;
+ if (!sset_is_empty(&targets)) {
+ const char *target;
- managers = xmalloc(shash_count(&targets) * sizeof *managers);
- SHASH_FOR_EACH (node, &targets) {
- const char *target = node->name;
+ managers = xmalloc(sset_count(&targets) * sizeof *managers);
+ SSET_FOR_EACH (target, &targets) {
struct sockaddr_in *sin = &managers[n_managers];
if ((!strncmp(target, "tcp:", 4)
}
}
}
- shash_destroy(&targets);
+ sset_destroy(&targets);
*managersp = managers;
*n_managersp = n_managers;
"with another vswitch, choose an engine id less "
"than 128", br->name);
}
- if (br->n_ports > 508) {
+ 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);
}
}
- opts.collectors.n = nf_cfg->n_targets;
- opts.collectors.names = nf_cfg->targets;
+ sset_init(&opts.collectors);
+ sset_add_array(&opts.collectors,
+ nf_cfg->targets, nf_cfg->n_targets);
if (ofproto_set_netflow(br->ofproto, &opts)) {
VLOG_ERR("bridge %s: problem setting netflow collectors",
br->name);
}
+ sset_destroy(&opts.collectors);
} else {
ofproto_set_netflow(br->ofproto, NULL);
}
memset(&oso, 0, sizeof oso);
- oso.targets.n = sflow_cfg->n_targets;
- oso.targets.names = sflow_cfg->targets;
+ 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) {
}
ofproto_set_sflow(br->ofproto, &oso);
- /* Do not destroy oso.targets because it is owned by sflow_cfg. */
+ sset_destroy(&oso.targets);
} else {
ofproto_set_sflow(br->ofproto, NULL);
}
bridge_reconfigure_remotes(br, managers, n_managers);
}
LIST_FOR_EACH (br, node, &all_bridges) {
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
+ struct port *port;
+
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
struct iface *iface;
if (port->monitor) {
struct iface **hw_addr_iface)
{
const char *hwaddr;
- size_t i;
+ struct port *port;
int error;
*hw_addr_iface = NULL;
/* Otherwise choose the minimum non-local MAC address among all of the
* interfaces. */
memset(ea, 0xff, ETH_ADDR_LEN);
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
uint8_t iface_ea[ETH_ADDR_LEN];
struct iface *candidate;
struct iface *iface;
}
}
-static void
+/* Writes 'iface''s CFM statistics to the database. Returns true if anything
+ * changed, false otherwise. */
+static bool
iface_refresh_cfm_stats(struct iface *iface)
{
const struct ovsrec_monitor *mon;
const struct cfm *cfm;
+ bool changed = false;
size_t i;
mon = iface->cfg->monitor;
cfm = ofproto_iface_get_cfm(iface->port->bridge->ofproto, iface->dp_ifidx);
if (!cfm || !mon) {
- return;
+ return false;
}
for (i = 0; i < mon->n_remote_mps; i++) {
mp = mon->remote_mps[i];
rmp = cfm_get_remote_mp(cfm, mp->mpid);
- ovsrec_maintenance_point_set_fault(mp, &rmp->fault, 1);
- }
-
- if (hmap_is_empty(&cfm->x_remote_mps)) {
- ovsrec_monitor_set_unexpected_remote_mpids(mon, NULL, 0);
- } else {
- size_t length;
- struct remote_mp *rmp;
- int64_t *x_remote_mps;
-
- length = hmap_count(&cfm->x_remote_mps);
- x_remote_mps = xzalloc(length * sizeof *x_remote_mps);
-
- i = 0;
- HMAP_FOR_EACH (rmp, node, &cfm->x_remote_mps) {
- x_remote_mps[i++] = rmp->mpid;
+ if (mp->n_fault != 1 || mp->fault[0] != rmp->fault) {
+ ovsrec_maintenance_point_set_fault(mp, &rmp->fault, 1);
+ changed = true;
}
-
- ovsrec_monitor_set_unexpected_remote_mpids(mon, x_remote_mps, length);
- free(x_remote_mps);
}
- if (hmap_is_empty(&cfm->x_remote_maids)) {
- ovsrec_monitor_set_unexpected_remote_maids(mon, NULL, 0);
- } else {
- size_t length;
- char **x_remote_maids;
- struct remote_maid *rmaid;
-
- length = hmap_count(&cfm->x_remote_maids);
- x_remote_maids = xzalloc(length * sizeof *x_remote_maids);
-
- i = 0;
- HMAP_FOR_EACH (rmaid, node, &cfm->x_remote_maids) {
- size_t j;
-
- x_remote_maids[i] = xzalloc(CCM_MAID_LEN * 2 + 1);
-
- for (j = 0; j < CCM_MAID_LEN; j++) {
- snprintf(&x_remote_maids[i][j * 2], 3, "%02hhx",
- rmaid->maid[j]);
- }
- i++;
- }
- ovsrec_monitor_set_unexpected_remote_maids(mon, x_remote_maids, length);
-
- for (i = 0; i < length; i++) {
- free(x_remote_maids[i]);
- }
- free(x_remote_maids);
+ if (mon->n_fault != 1 || mon->fault[0] != cfm->fault) {
+ ovsrec_monitor_set_fault(mon, &cfm->fault, 1);
+ changed = true;
}
- ovsrec_monitor_set_fault(mon, &cfm->fault, 1);
+ return changed;
}
static void
txn = ovsdb_idl_txn_create(idl);
LIST_FOR_EACH (br, node, &all_bridges) {
- size_t i;
+ struct port *port;
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
struct iface *iface;
LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
iface_refresh_stats(iface);
- iface_refresh_cfm_stats(iface);
iface_refresh_status(iface);
}
}
stats_timer = time_msec() + STATS_INTERVAL;
}
+
+ if (time_msec() >= cfm_limiter) {
+ struct ovsdb_idl_txn *txn;
+ bool changed = false;
+
+ txn = ovsdb_idl_txn_create(idl);
+ LIST_FOR_EACH (br, node, &all_bridges) {
+ struct port *port;
+
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
+ struct iface *iface;
+
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
+ changed = iface_refresh_cfm_stats(iface) || changed;
+ }
+ }
+ }
+
+ if (changed) {
+ cfm_limiter = time_msec() + CFM_LIMIT_INTERVAL;
+ }
+
+ ovsdb_idl_txn_commit(txn);
+ ovsdb_idl_txn_destroy(txn);
+ }
}
void
struct bridge *br;
LIST_FOR_EACH (br, node, &all_bridges) {
- size_t i;
+ struct port *port;
ofproto_wait(br->ofproto);
- if (ofproto_has_primary_controller(br->ofproto)) {
- continue;
- }
-
mac_learning_wait(br->ml);
-
- for (i = 0; i < br->n_ports; i++) {
- port_wait(br->ports[i]);
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
+ port_wait(port);
}
}
ovsdb_idl_wait(idl);
poll_timer_wait_until(stats_timer);
+
+ if (cfm_limiter > time_msec()) {
+ poll_timer_wait_until(cfm_limiter);
+ }
}
/* Forces 'br' to revalidate all of its flows. This is appropriate when 'br''s
{
COVERAGE_INC(bridge_flush);
br->flush = true;
- mac_learning_flush(br->ml);
}
\f
/* Bridge unixctl user interface functions. */
ds_put_cstr(&ds, " port VLAN MAC Age\n");
LIST_FOR_EACH (e, lru_node, &br->ml->lrus) {
- if (e->port.i < 0 || e->port.i >= br->n_ports) {
- continue;
- }
+ struct port *port = e->port.p;
ds_put_format(&ds, "%5d %4d "ETH_ADDR_FMT" %3d\n",
- port_get_an_iface(br->ports[e->port.i])->dp_ifidx,
+ port_get_an_iface(port)->dp_ifidx,
e->vlan, ETH_ADDR_ARGS(e->mac), mac_entry_age(e));
}
unixctl_command_reply(conn, 200, ds_cstr(&ds));
ds_destroy(&ds);
}
\f
+/* CFM unixctl user interface functions. */
+static void
+cfm_unixctl_show(struct unixctl_conn *conn,
+ const char *args, void *aux OVS_UNUSED)
+{
+ struct ds ds = DS_EMPTY_INITIALIZER;
+ struct iface *iface;
+ const struct cfm *cfm;
+
+ iface = iface_find(args);
+ if (!iface) {
+ unixctl_command_reply(conn, 501, "no such interface");
+ return;
+ }
+
+ cfm = ofproto_iface_get_cfm(iface->port->bridge->ofproto, iface->dp_ifidx);
+
+ if (!cfm) {
+ unixctl_command_reply(conn, 501, "CFM not enabled");
+ return;
+ }
+
+ cfm_dump_ds(cfm, &ds);
+ unixctl_command_reply(conn, 200, ds_cstr(&ds));
+ ds_destroy(&ds);
+}
+\f
/* QoS unixctl user interface functions. */
struct qos_unixctl_show_cbdata {
br->ml = mac_learning_create();
eth_addr_nicira_random(br->default_ea);
+ hmap_init(&br->ports);
hmap_init(&br->ifaces);
-
- shash_init(&br->port_by_name);
shash_init(&br->iface_by_name);
br->flush = false;
bridge_destroy(struct bridge *br)
{
if (br) {
+ struct port *port, *next;
int error;
- while (br->n_ports > 0) {
- port_destroy(br->ports[br->n_ports - 1]);
+ 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));
}
dpif_close(br->dpif);
- ofproto_destroy(br->ofproto);
mac_learning_destroy(br->ml);
hmap_destroy(&br->ifaces);
- shash_destroy(&br->port_by_name);
+ hmap_destroy(&br->ports);
shash_destroy(&br->iface_by_name);
- free(br->ports);
free(br->name);
free(br);
}
static int
bridge_run_one(struct bridge *br)
{
- size_t i;
+ struct port *port;
int error;
error = ofproto_run1(br->ofproto);
mac_learning_run(br->ml, ofproto_get_revalidate_set(br->ofproto));
- for (i = 0; i < br->n_ports; i++) {
- port_run(br->ports[i]);
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
+ port_run(port);
}
error = ofproto_run2(br->ofproto, br->flush);
static void
bridge_reconfigure_one(struct bridge *br)
{
- struct shash old_ports, new_ports;
- struct svec snoops, old_snoops;
- struct shash_node *node;
enum ofproto_fail_mode fail_mode;
+ struct port *port, *next;
+ struct shash_node *node;
+ struct shash new_ports;
size_t i;
- /* Collect old ports. */
- shash_init(&old_ports);
- for (i = 0; i < br->n_ports; i++) {
- shash_add(&old_ports, br->ports[i]->name, br->ports[i]);
- }
-
/* Collect new ports. */
shash_init(&new_ports);
for (i = 0; i < br->cfg->n_ports; i++) {
/* Get rid of deleted ports.
* Get rid of deleted interfaces on ports that still exist. */
- SHASH_FOR_EACH (node, &old_ports) {
- struct port *port = node->data;
+ HMAP_FOR_EACH_SAFE (port, next, hmap_node, &br->ports) {
const struct ovsrec_port *port_cfg;
- port_cfg = shash_find_data(&new_ports, node->name);
+ port_cfg = shash_find_data(&new_ports, port->name);
if (!port_cfg) {
port_destroy(port);
} else {
* Add new interfaces to existing ports.
* Reconfigure existing ports. */
SHASH_FOR_EACH (node, &new_ports) {
- struct port *port = shash_find_data(&old_ports, node->name);
+ struct port *port = port_lookup(br, node->name);
if (!port) {
port = port_create(br, node->name);
}
port_destroy(port);
}
}
- shash_destroy(&old_ports);
shash_destroy(&new_ports);
/* Set the fail-mode */
* controller to another?) */
/* Configure OpenFlow controller connection snooping. */
- svec_init(&snoops);
- svec_add_nocopy(&snoops, xasprintf("punix:%s/%s.snoop",
- ovs_rundir(), br->name));
- svec_init(&old_snoops);
- ofproto_get_snoops(br->ofproto, &old_snoops);
- if (!svec_equal(&snoops, &old_snoops)) {
+ 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);
}
- svec_destroy(&snoops);
- svec_destroy(&old_snoops);
mirror_reconfigure(br);
}
static void
bridge_get_all_ifaces(const struct bridge *br, struct shash *ifaces)
{
- size_t i;
+ struct port *port;
shash_init(ifaces);
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
struct iface *iface;
LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
{
struct dpif_port_dump dump;
struct dpif_port dpif_port;
- size_t i;
+ struct port *port;
/* Reset all interface numbers. */
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
struct iface *iface;
LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
mirror_mask_t mirrors = in_port->src_mirrors;
struct dst dst;
int flow_vlan;
- size_t i;
flow_vlan = vlan_tci_to_vid(flow->vlan_tci);
if (flow_vlan == 0) {
}
if (out_port == FLOOD_PORT) {
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
+ struct port *port;
+
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
if (port != in_port
&& port_is_floodable(port)
&& port_includes_vlan(port, vlan)
dst_set_add(set, &dst);
}
} else {
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
+ struct port *port;
+
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
if (port_includes_vlan(port, m->out_vlan)
&& set_dst(&dst, flow, in_port, port, tags))
{
}
}
- if (mac_entry_is_new(mac) || mac->port.i != in_port->port_idx) {
+ if (mac_entry_is_new(mac) || mac->port.p != in_port) {
/* The log messages here could actually be useful in debugging,
* so keep the rate limit relatively high. */
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
br->name, ETH_ADDR_ARGS(flow->dl_src),
in_port->name, vlan);
- mac->port.i = in_port->port_idx;
+ mac->port.p = in_port;
ofproto_revalidate(br->ofproto, mac_learning_changed(br->ml, mac));
}
}
* reflections on bond slaves. If this is the case, just drop the
* packet now. */
mac = mac_learning_lookup(br->ml, flow->dl_src, vlan, NULL);
- if (mac && mac->port.i != in_port->port_idx &&
+ if (mac && mac->port.p != in_port &&
(!is_gratuitous_arp(flow) || mac_entry_is_grat_arp_locked(mac))) {
return false;
}
/* Determine output port. */
mac = mac_learning_lookup(br->ml, flow->dl_dst, vlan, tags);
- if (mac && mac->port.i >= 0 && mac->port.i < br->n_ports) {
- out_port = br->ports[mac->port.i];
+ if (mac) {
+ out_port = mac->port.p;
} else if (!packet && !eth_addr_is_multicast(flow->dl_dst)) {
/* If we are revalidating but don't have a learning entry then
* eject the flow. Installing a flow that floods packets opens
bridge_account_checkpoint_ofhook_cb(void *br_)
{
struct bridge *br = br_;
+ struct port *port;
long long int now;
- size_t i;
if (!br->has_bonded_ports) {
return;
}
now = time_msec();
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
if (port->n_ifaces > 1 && port->bond_mode != BM_AB
&& now >= port->bond_next_rebalance) {
port->bond_next_rebalance = now + port->bond_rebalance_interval;
struct flow flow;
int retval;
- if (e->port.i == port->port_idx) {
+ if (e->port.p == port) {
continue;
}
ds_put_cstr(&ds, "bridge\tbond\ttype\tslaves\n");
LIST_FOR_EACH (br, node, &all_bridges) {
- size_t i;
+ struct port *port;
- for (i = 0; i < br->n_ports; i++) {
- const struct port *port = br->ports[i];
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
if (port->n_ifaces > 1) {
struct iface *iface;
const struct bridge *br;
LIST_FOR_EACH (br, node, &all_bridges) {
- size_t i;
+ struct port *port;
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
if (!strcmp(port->name, name) && port->n_ifaces > 1) {
return port;
}
memcpy(flow.dl_src, me->mac, ETH_ADDR_LEN);
if (bond_hash_src(me->mac, me->vlan) == hash
- && me->port.i != port->port_idx
+ && me->port.p != port
&& choose_output_iface(port, &flow, me->vlan,
&dp_ifidx, &tags)
&& dp_ifidx == iface->dp_ifidx)
error = netdev_get_etheraddr(iface->netdev, ea);
if (!error) {
struct ofpbuf packet;
+ struct lacp_pdu *packet_pdu;
- ofpbuf_init(&packet, ETH_HEADER_LEN + LACP_PDU_LEN);
- compose_lacp_packet(&packet, ea, pdu);
+ ofpbuf_init(&packet, 0);
+ packet_pdu = eth_compose(&packet, eth_addr_lacp, ea, ETH_TYPE_LACP,
+ sizeof *packet_pdu);
+ memcpy(packet_pdu, pdu, sizeof *packet_pdu);
ofproto_send_packet(iface->port->bridge->ofproto,
iface->dp_ifidx, 0, &packet);
ofpbuf_uninit(&packet);
port = xzalloc(sizeof *port);
port->bridge = br;
- port->port_idx = br->n_ports;
port->vlan = -1;
port->trunks = NULL;
port->name = xstrdup(name);
port->active_iface = NULL;
list_init(&port->ifaces);
- if (br->n_ports >= br->allocated_ports) {
- br->ports = x2nrealloc(br->ports, &br->allocated_ports,
- sizeof *br->ports);
- }
- br->ports[br->n_ports++] = port;
- shash_add_assert(&br->port_by_name, port->name, port);
+ 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);
port_del_ifaces(struct port *port, const struct ovsrec_port *cfg)
{
struct iface *iface, *next;
- struct shash new_ifaces;
+ struct sset new_ifaces;
size_t i;
/* Collect list of new interfaces. */
- shash_init(&new_ifaces);
+ sset_init(&new_ifaces);
for (i = 0; i < cfg->n_interfaces; i++) {
const char *name = cfg->interfaces[i]->name;
- shash_add_once(&new_ifaces, name, NULL);
+ sset_add(&new_ifaces, name);
}
/* Get rid of deleted interfaces. */
LIST_FOR_EACH_SAFE (iface, next, port_elem, &port->ifaces) {
- if (!shash_find(&new_ifaces, iface->name)) {
+ if (!sset_contains(&new_ifaces, iface->name)) {
iface_destroy(iface);
}
}
- shash_destroy(&new_ifaces);
+ sset_destroy(&new_ifaces);
+}
+
+/* Expires all MAC learning entries associated with 'port' and forces ofproto
+ * to revalidate every flow. */
+static void
+port_flush_macs(struct port *port)
+{
+ struct bridge *br = port->bridge;
+ struct mac_learning *ml = br->ml;
+ struct mac_entry *mac, *next_mac;
+
+ bridge_flush(br);
+ LIST_FOR_EACH_SAFE (mac, next_mac, lru_node, &ml->lrus) {
+ if (mac->port.p == port) {
+ mac_learning_expire(ml, mac);
+ }
+ }
}
static void
port_reconfigure(struct port *port, const struct ovsrec_port *cfg)
{
const char *detect_mode;
- struct shash new_ifaces;
+ struct sset new_ifaces;
long long int next_rebalance, miimon_next_update, lacp_priority;
+ bool need_flush = false;
unsigned long *trunks;
int vlan;
size_t i;
}
/* Add new interfaces and update 'cfg' member of existing ones. */
- shash_init(&new_ifaces);
+ 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 (!shash_add_once(&new_ifaces, if_cfg->name, NULL)) {
+ 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);
iface->lacp_priority = lacp_priority;
}
}
- shash_destroy(&new_ifaces);
+ sset_destroy(&new_ifaces);
port->lacp_fast = !strcmp(get_port_other_config(cfg, "lacp-time", "slow"),
"fast");
}
if (port->vlan != vlan) {
port->vlan = vlan;
- bridge_flush(port->bridge);
+ need_flush = true;
}
/* Get trunked VLANs. */
if (trunks == NULL
? port->trunks != NULL
: port->trunks == NULL || !bitmap_equal(trunks, port->trunks, 4096)) {
- bridge_flush(port->bridge);
+ need_flush = true;
}
bitmap_free(port->trunks);
port->trunks = trunks;
+
+ if (need_flush) {
+ port_flush_macs(port);
+ }
}
static void
if (port) {
struct bridge *br = port->bridge;
struct iface *iface, *next;
- struct port *del;
int i;
for (i = 0; i < MAX_MIRRORS; i++) {
iface_destroy(iface);
}
- shash_find_and_delete_assert(&br->port_by_name, port->name);
-
- del = br->ports[port->port_idx] = br->ports[--br->n_ports];
- del->port_idx = port->port_idx;
+ hmap_remove(&br->ports, &port->hmap_node);
VLOG_INFO("destroyed port %s on bridge %s", port->name, br->name);
+ port_flush_macs(port);
+
+ lacp_destroy(port->lacp);
netdev_monitor_destroy(port->monitor);
bitmap_free(port->trunks);
+ free(port->bond_hash);
free(port->name);
free(port);
- bridge_flush(br);
}
}
static struct port *
port_lookup(const struct bridge *br, const char *name)
{
- return shash_find_data(&br->port_by_name, name);
+ struct port *port;
+
+ HMAP_FOR_EACH_WITH_HASH (port, hmap_node, hash_string(name, 0),
+ &br->ports) {
+ if (!strcmp(port->name, name)) {
+ return port;
+ }
+ }
+ return NULL;
}
static struct iface *
struct cfm cfm;
uint16_t *remote_mps;
struct ovsrec_monitor *mon;
- uint8_t ea[ETH_ADDR_LEN], maid[CCM_MAID_LEN];
+ uint8_t maid[CCM_MAID_LEN];
mon = iface->cfg->monitor;
return;
}
- if (netdev_get_etheraddr(iface->netdev, ea)) {
- VLOG_WARN("interface %s: Failed to get ethernet address. "
- "Skipping Monitor.", iface->name);
- return;
- }
-
if (!cfm_generate_maid(mon->md_name, mon->ma_name, maid)) {
VLOG_WARN("interface %s: Failed to generate MAID.", iface->name);
return;
cfm.mpid = mon->mpid;
cfm.interval = mon->interval ? *mon->interval : 1000;
- memcpy(cfm.eth_src, ea, sizeof cfm.eth_src);
memcpy(cfm.maid, maid, sizeof cfm.maid);
remote_mps = xzalloc(mon->n_remote_mps * sizeof *remote_mps);
mirror_reconfigure(struct bridge *br)
{
unsigned long *rspan_vlans;
+ struct port *port;
int i;
/* Get rid of deleted mirrors. */
}
/* Update port reserved status. */
- for (i = 0; i < br->n_ports; i++) {
- br->ports[i]->is_mirror_output_port = false;
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
+ port->is_mirror_output_port = false;
}
for (i = 0; i < MAX_MIRRORS; i++) {
struct mirror *m = br->mirrors[i];
}
if (mac_learning_set_flood_vlans(br->ml, rspan_vlans)) {
bridge_flush(br);
+ mac_learning_flush(br->ml);
}
}
VLOG_INFO("created port mirror %s on bridge %s", cfg->name, br->name);
bridge_flush(br);
+ mac_learning_flush(br->ml);
br->mirrors[i] = m = xzalloc(sizeof *m);
m->bridge = br;
m->idx = i;
m->name = xstrdup(cfg->name);
- shash_init(&m->src_ports);
- shash_init(&m->dst_ports);
+ sset_init(&m->src_ports);
+ sset_init(&m->dst_ports);
m->vlans = NULL;
m->n_vlans = 0;
m->out_vlan = -1;
{
if (m) {
struct bridge *br = m->bridge;
- size_t i;
+ struct port *port;
- for (i = 0; i < br->n_ports; i++) {
- br->ports[i]->src_mirrors &= ~(MIRROR_MASK_C(1) << m->idx);
- br->ports[i]->dst_mirrors &= ~(MIRROR_MASK_C(1) << m->idx);
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
+ port->src_mirrors &= ~(MIRROR_MASK_C(1) << m->idx);
+ port->dst_mirrors &= ~(MIRROR_MASK_C(1) << m->idx);
}
- shash_destroy(&m->src_ports);
- shash_destroy(&m->dst_ports);
+ sset_destroy(&m->src_ports);
+ sset_destroy(&m->dst_ports);
free(m->vlans);
m->bridge->mirrors[m->idx] = NULL;
free(m);
bridge_flush(br);
+ mac_learning_flush(br->ml);
}
}
static void
mirror_collect_ports(struct mirror *m, struct ovsrec_port **ports, int n_ports,
- struct shash *names)
+ struct sset *names)
{
size_t i;
for (i = 0; i < n_ports; i++) {
const char *name = ports[i]->name;
if (port_lookup(m->bridge, name)) {
- shash_add_once(names, name, NULL);
+ sset_add(names, name);
} else {
VLOG_WARN("bridge %s: mirror %s cannot match on nonexistent "
"port %s", m->bridge->name, m->name, name);
static void
mirror_reconfigure_one(struct mirror *m, struct ovsrec_mirror *cfg)
{
- struct shash src_ports, dst_ports;
+ struct sset src_ports, dst_ports;
mirror_mask_t mirror_bit;
struct port *out_port;
+ struct port *port;
int out_vlan;
size_t n_vlans;
int *vlans;
- size_t i;
/* Set name. */
if (strcmp(cfg->name, m->name)) {
return;
}
- shash_init(&src_ports);
- shash_init(&dst_ports);
+ sset_init(&src_ports);
+ sset_init(&dst_ports);
if (cfg->select_all) {
- for (i = 0; i < m->bridge->n_ports; i++) {
- const char *name = m->bridge->ports[i]->name;
- shash_add_once(&src_ports, name, NULL);
- shash_add_once(&dst_ports, name, NULL);
+ HMAP_FOR_EACH (port, hmap_node, &m->bridge->ports) {
+ sset_add(&src_ports, port->name);
+ sset_add(&dst_ports, port->name);
}
vlans = NULL;
n_vlans = 0;
}
/* Update mirror data. */
- if (!shash_equal_keys(&m->src_ports, &src_ports)
- || !shash_equal_keys(&m->dst_ports, &dst_ports)
+ if (!sset_equals(&m->src_ports, &src_ports)
+ || !sset_equals(&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);
+ mac_learning_flush(m->bridge->ml);
}
- shash_swap(&m->src_ports, &src_ports);
- shash_swap(&m->dst_ports, &dst_ports);
+ sset_swap(&m->src_ports, &src_ports);
+ sset_swap(&m->dst_ports, &dst_ports);
free(m->vlans);
m->vlans = vlans;
m->n_vlans = n_vlans;
/* Update ports. */
mirror_bit = MIRROR_MASK_C(1) << m->idx;
- for (i = 0; i < m->bridge->n_ports; i++) {
- struct port *port = m->bridge->ports[i];
-
- if (shash_find(&m->src_ports, port->name)
+ 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)
port->src_mirrors &= ~mirror_bit;
}
- if (shash_find(&m->dst_ports, port->name)) {
+ if (sset_contains(&m->dst_ports, port->name)) {
port->dst_mirrors |= mirror_bit;
} else {
port->dst_mirrors &= ~mirror_bit;
}
/* Clean up. */
- shash_destroy(&src_ports);
- shash_destroy(&dst_ports);
+ sset_destroy(&src_ports);
+ sset_destroy(&dst_ports);
}