-/* Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks
+/* Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
static void bridge_reconfigure_remotes(struct bridge *,
const struct sockaddr_in *managers,
size_t n_managers);
+static void bridge_reconfigure_remotes_late(struct bridge *);
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 *);
HMAP_FOR_EACH (iface, dp_ifidx_node, &br->ifaces) {
iface_update_cfm(iface);
}
+ bridge_reconfigure_remotes_late(br);
}
free(managers);
ovsrec_interface_set_statistics(iface->cfg, keys, values, n);
}
+static bool
+enable_system_stats(const struct ovsrec_open_vswitch *cfg)
+{
+ const char *enable;
+
+ /* Use other-config:enable-system-stats by preference. */
+ enable = get_ovsrec_key_value(&cfg->header_,
+ &ovsrec_open_vswitch_col_other_config,
+ "enable-statistics");
+ if (enable) {
+ return !strcmp(enable, "true");
+ }
+
+ /* Disable by default. */
+ return false;
+}
+
static void
refresh_system_stats(const struct ovsrec_open_vswitch *cfg)
{
struct shash stats;
shash_init(&stats);
- get_system_stats(&stats);
+ if (enable_system_stats(cfg)) {
+ get_system_stats(&stats);
+ }
ovsdb_datum_from_shash(&datum, &stats);
ovsdb_idl_txn_write(&cfg->header_, &ovsrec_open_vswitch_col_statistics,
}
ds_put_format(&ds, "%5d %4d "ETH_ADDR_FMT" %3d\n",
br->ports[e->port]->ifaces[0]->dp_ifidx,
- e->vlan, ETH_ADDR_ARGS(e->mac), mac_entry_age(e));
+ e->vlan, ETH_ADDR_ARGS(e->mac),
+ mac_entry_age(br->ml, e));
}
unixctl_command_reply(conn, 200, ds_cstr(&ds));
ds_destroy(&ds);
br->name = xstrdup(br_cfg->name);
br->cfg = br_cfg;
- br->ml = mac_learning_create();
+ br->ml = mac_learning_create(MAC_ENTRY_DEFAULT_IDLE_TIME);
eth_addr_nicira_random(br->default_ea);
hmap_init(&br->ifaces);
struct svec snoops, old_snoops;
struct shash_node *node;
enum ofproto_fail_mode fail_mode;
+ const char *idle_time_str;
+ int idle_time;
size_t i;
/* Collect old ports. */
}
ofproto_set_fail_mode(br->ofproto, fail_mode);
+ /* Set the MAC learning aging timeout. */
+ idle_time_str = bridge_get_other_config(br->cfg, "mac-aging-time");
+ idle_time = (idle_time_str && atoi(idle_time_str)
+ ? atoi(idle_time_str)
+ : MAC_ENTRY_DEFAULT_IDLE_TIME);
+ mac_learning_set_idle_time(br->ml, idle_time);
+
/* 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?) */
oc->max_backoff = 0;
oc->probe_interval = 60;
oc->band = OFPROTO_OUT_OF_BAND;
- oc->accept_re = NULL;
- oc->update_resolv_conf = false;
oc->rate_limit = 0;
oc->burst_limit = 0;
}
oc->probe_interval = c->inactivity_probe ? *c->inactivity_probe / 1000 : 5;
oc->band = (!c->connection_mode || !strcmp(c->connection_mode, "in-band")
? OFPROTO_IN_BAND : OFPROTO_OUT_OF_BAND);
- oc->accept_re = c->discover_accept_regex;
- oc->update_resolv_conf = c->discover_update_resolv_conf;
oc->rate_limit = c->controller_rate_limit ? *c->controller_rate_limit : 0;
oc->burst_limit = (c->controller_burst_limit
? *c->controller_burst_limit : 0);
struct iface *local_iface;
struct in_addr ip;
- /* Controller discovery does its own TCP/IP configuration later. */
- if (strcmp(c->target, "discover")) {
- return;
- }
-
/* If there's no local interface or no IP address, give up. */
local_iface = bridge_get_local_iface(br);
if (!local_iface || !c->local_ip || !inet_aton(c->local_ip, &ip)) {
if (had_primary != ofproto_has_primary_controller(br->ofproto)) {
ofproto_flush_flows(br->ofproto);
}
+}
+/* Does configuration of remotes that must happen after all of the ports and
+ * interfaces are fully configured, that is, when flow translation can be
+ * expected to succeed. (This is because ofproto_add_flow() immediately
+ * re-translates any existing facets for the rule that it replaces, if any.)
+ * In particular, it must be called after port_update_bonding(), to ensure that
+ * 'bond_hash' is non-NULL for bonded ports. */
+static void
+bridge_reconfigure_remotes_late(struct bridge *br)
+{
/* 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
+ if (!bridge_get_controllers(br, NULL)
&& ofproto_get_fail_mode(br->ofproto) == OFPROTO_FAIL_STANDALONE) {
union ofp_action action;
struct cls_rule rule;
return true;
}
+/* Returns true if a packet with Ethernet destination MAC 'dst' may be mirrored
+ * to a VLAN. In general most packets may be mirrored but we want to drop
+ * protocols that may confuse switches. */
+static bool
+eth_dst_may_rspan(const uint8_t dst[ETH_ADDR_LEN])
+{
+ /* If you change this function's behavior, please update corresponding
+ * documentation in vswitch.xml at the same time. */
+ if (dst[0] != 0x01) {
+ /* All the currently banned MACs happen to start with 01 currently, so
+ * this is a quick way to eliminate most of the good ones. */
+ } else {
+ if (eth_addr_is_reserved(dst)) {
+ /* Drop STP, IEEE pause frames, and other reserved protocols
+ * (01-80-c2-00-00-0x). */
+ return false;
+ }
+
+ if (dst[0] == 0x01 && dst[1] == 0x00 && dst[2] == 0x0c) {
+ /* Cisco OUI. */
+ if ((dst[3] & 0xfe) == 0xcc &&
+ (dst[4] & 0xfe) == 0xcc &&
+ (dst[5] & 0xfe) == 0xcc) {
+ /* Drop the following protocols plus others following the same
+ pattern:
+
+ CDP, VTP, DTP, PAgP (01-00-0c-cc-cc-cc)
+ Spanning Tree PVSTP+ (01-00-0c-cc-cc-cd)
+ STP Uplink Fast (01-00-0c-cd-cd-cd) */
+ return false;
+ }
+
+ if (!(dst[3] | dst[4] | dst[5])) {
+ /* Drop Inter Switch Link packets (01-00-0c-00-00-00). */
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
static void
compose_dsts(const struct bridge *br, const struct flow *flow, uint16_t vlan,
const struct port *in_port, const struct port *out_port,
&& !dst_is_duplicate(set, &dst)) {
dst_set_add(set, &dst);
}
- } else {
+ } else if (eth_dst_may_rspan(flow->dl_dst)) {
for (i = 0; i < br->n_ports; i++) {
struct port *port = br->ports[i];
if (port_includes_vlan(port, m->out_vlan)
* to the exception is if we locked the learning table to avoid
* reflections on bond slaves. If this is the case, just drop the
* packet now. */
- src_idx = mac_learning_lookup(br->ml, flow->dl_src, vlan,
- &is_grat_arp_locked);
- if (src_idx != -1 && src_idx != in_port->port_idx &&
- (!is_gratuitous_arp(flow) || is_grat_arp_locked)) {
+ if (in_port->bond_mode != BM_AB) {
+ src_idx = mac_learning_lookup(br->ml, flow->dl_src, vlan,
+ &is_grat_arp_locked);
+ if (src_idx != -1 && src_idx != in_port->port_idx &&
+ (!is_gratuitous_arp(flow) || is_grat_arp_locked)) {
return false;
+ }
+ }
+ }
+
+ /* Drop all packets which arrive on backup slaves. This is similar to how
+ * Linux bonding handles active-backup bonds. */
+ if (in_port->bond_mode == BM_AB) {
+
+ *tags |= in_port->active_iface;
+ if (in_port->active_iface != in_iface->port_ifidx) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+
+ VLOG_WARN_RL(&rl, "active-backup bond received packet on backup"
+ " interface (%s) destined for " ETH_ADDR_FMT,
+ in_iface->name, ETH_ADDR_ARGS(flow->dl_dst));
+ return false ;
}
}
netdev_monitor_destroy(port->monitor);
free(port->ifaces);
bitmap_free(port->trunks);
+ free(port->bond_hash);
free(port->name);
free(port);
bridge_flush(br);