/* 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 bool iface_refresh_cfm_stats(struct iface *iface);
static void iface_update_carrier(struct 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 *);
ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_cur_cfg);
ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_statistics);
ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_external_ids);
+ ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_ovs_version);
+ ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_db_version);
+ ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_system_type);
+ ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_system_version);
+ ovsdb_idl_omit_alert(idl, &ovsrec_bridge_col_datapath_id);
ovsdb_idl_omit(idl, &ovsrec_bridge_col_external_ids);
ovsdb_idl_omit(idl, &ovsrec_port_col_external_ids);
ovsdb_idl_omit(idl, &ovsrec_port_col_fake_bridge);
+ ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_admin_state);
+ ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_duplex);
+ ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_link_speed);
+ ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_link_state);
+ ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_mtu);
ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_ofport);
ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_statistics);
+ ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_status);
ovsdb_idl_omit(idl, &ovsrec_interface_col_external_ids);
+ ovsdb_idl_omit_alert(idl, &ovsrec_controller_col_is_connected);
+ ovsdb_idl_omit_alert(idl, &ovsrec_controller_col_role);
+ ovsdb_idl_omit_alert(idl, &ovsrec_controller_col_status);
+ ovsdb_idl_omit(idl, &ovsrec_controller_col_external_ids);
+
+ ovsdb_idl_omit_alert(idl, &ovsrec_maintenance_point_col_fault);
+
+ ovsdb_idl_omit_alert(idl, &ovsrec_monitor_col_fault);
+
+ ovsdb_idl_omit(idl, &ovsrec_qos_col_external_ids);
+
+ ovsdb_idl_omit(idl, &ovsrec_queue_col_external_ids);
+
+ ovsdb_idl_omit(idl, &ovsrec_mirror_col_external_ids);
+
+ ovsdb_idl_omit(idl, &ovsrec_netflow_col_external_ids);
+
+ ovsdb_idl_omit(idl, &ovsrec_sflow_col_external_ids);
+
+ ovsdb_idl_omit(idl, &ovsrec_manager_col_external_ids);
+ ovsdb_idl_omit(idl, &ovsrec_manager_col_inactivity_probe);
+ ovsdb_idl_omit(idl, &ovsrec_manager_col_is_connected);
+ ovsdb_idl_omit(idl, &ovsrec_manager_col_max_backoff);
+ ovsdb_idl_omit(idl, &ovsrec_manager_col_status);
+
+ ovsdb_idl_omit(idl, &ovsrec_ssl_col_external_ids);
+
/* Register unixctl commands. */
unixctl_command_register("fdb/show", bridge_unixctl_fdb_show, NULL);
unixctl_command_register("cfm/show", cfm_unixctl_show, NULL);
/* 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);
- }
+ iface_set_mac(iface);
return true;
}
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;
+
+ bridge_run_one(br);
+
HMAP_FOR_EACH (iface, dp_ifidx_node, &br->ifaces) {
iface_update_cfm(iface);
}
int64_t mtu_64;
int error;
+ if (iface_is_synthetic(iface)) {
+ return;
+ }
+
shash_init(&sh);
if (!netdev_get_status(iface->netdev, &sh)) {
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);
if (br) {
struct port *port, *next;
int error;
+ int i;
HMAP_FOR_EACH_SAFE (port, next, hmap_node, &br->ports) {
port_destroy(port);
}
+ for (i = 0; i < MAX_MIRRORS; i++) {
+ mirror_destroy(br->mirrors[i]);
+ }
list_remove(&br->node);
ofproto_destroy(br->ofproto);
error = dpif_delete(br->dpif);
hmap_destroy(&br->ifaces);
hmap_destroy(&br->ports);
shash_destroy(&br->iface_by_name);
+ free(br->synth_local_iface.type);
free(br->name);
free(br);
}
br->name, name);
}
}
+ if (!shash_find(&new_ports, br->name)) {
+ struct dpif_port dpif_port;
+ char *type;
- /* 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;
+ VLOG_WARN("bridge %s: no port named %s, synthesizing one",
+ br->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);
- }
+ dpif_port_query_by_number(br->dpif, ODPP_LOCAL, &dpif_port);
+ type = xstrdup(dpif_port.type ? dpif_port.type : "internal");
+ dpif_port_destroy(&dpif_port);
+
+ br->synth_local_port.interfaces = &br->synth_local_ifacep;
+ br->synth_local_port.n_interfaces = 1;
+ br->synth_local_port.name = br->name;
+
+ br->synth_local_iface.name = br->name;
+ free(br->synth_local_iface.type);
+ br->synth_local_iface.type = type;
+
+ br->synth_local_ifacep = &br->synth_local_iface;
+
+ shash_add(&new_ports, br->name, &br->synth_local_port);
}
/* Get rid of deleted ports.
return CONTAINER_OF(list_front(&port->ifaces), struct iface, port_elem);
}
+/* 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)) {
struct port *port;
HMAP_FOR_EACH (port, hmap_node, &br->ports) {
{
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) {
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);
}
}
static void
iface_update_qos(struct iface *iface, const struct ovsrec_qos *qos)
{
- if (!qos || qos->type[0] == '\0') {
+ if (!qos || qos->type[0] == '\0' || qos->n_queues < 1) {
netdev_set_qos(iface->netdev, NULL, NULL);
} else {
struct iface_delete_queues_cbdata cbdata;
? netdev_get_carrier(iface->netdev)
: netdev_get_miimon(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_);
+}
\f
/* Port mirroring. */
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);
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)
{
/* 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;