COVERAGE_DEFINE(bridge_reconfigure);
struct dst {
+ struct iface *iface;
uint16_t vlan;
- uint16_t dp_ifidx;
};
struct dst_set {
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);
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);
}
const struct port *in_port, const struct port *out_port,
tag_type *tags)
{
- struct iface *iface;
- uint16_t vlan;
+ dst->vlan = (out_port->vlan >= 0 ? OFP_VLAN_NONE
+ : in_port->vlan >= 0 ? in_port->vlan
+ : flow->vlan_tci == 0 ? OFP_VLAN_NONE
+ : vlan_tci_to_vid(flow->vlan_tci));
- vlan = (out_port->vlan >= 0 ? OFP_VLAN_NONE
- : in_port->vlan >= 0 ? in_port->vlan
- : flow->vlan_tci == 0 ? OFP_VLAN_NONE
- : vlan_tci_to_vid(flow->vlan_tci));
+ dst->iface = (!out_port->bond
+ ? port_get_an_iface(out_port)
+ : bond_choose_output_slave(out_port->bond, flow,
+ dst->vlan, tags));
- iface = (!out_port->bond
- ? port_get_an_iface(out_port)
- : bond_choose_output_slave(out_port->bond, flow, vlan, tags));
- if (iface) {
- dst->vlan = vlan;
- dst->dp_ifidx = iface->dp_ifidx;
- return true;
- } else {
- return false;
- }
-}
-
-static void
-swap_dst(struct dst *p, struct dst *q)
-{
- struct dst tmp = *p;
- *p = *q;
- *q = tmp;
-}
-
-/* Moves all the dsts with vlan == 'vlan' to the front of the 'n_dsts' in
- * 'dsts'. (This may help performance by reducing the number of VLAN changes
- * that we push to the datapath. We could in fact fully sort the array by
- * vlan, but in most cases there are at most two different vlan tags so that's
- * possibly overkill.) */
-static void
-partition_dsts(struct dst_set *set, int vlan)
-{
- struct dst *first = set->dsts;
- struct dst *last = set->dsts + set->n;
-
- while (first != last) {
- /* Invariants:
- * - All dsts < first have vlan == 'vlan'.
- * - All dsts >= last have vlan != 'vlan'.
- * - first < last. */
- while (first->vlan == vlan) {
- if (++first == last) {
- return;
- }
- }
-
- /* Same invariants, plus one additional:
- * - first->vlan != vlan.
- */
- while (last[-1].vlan != vlan) {
- if (--last == first) {
- return;
- }
- }
-
- /* Same invariants, plus one additional:
- * - last[-1].vlan == vlan.*/
- swap_dst(first++, --last);
- }
+ return dst->iface != NULL;
}
static int
size_t i;
for (i = 0; i < set->n; i++) {
if (set->dsts[i].vlan == test->vlan
- && set->dsts[i].dp_ifidx == test->dp_ifidx) {
+ && set->dsts[i].iface == test->iface) {
return true;
}
}
const struct port *in_port, const struct port *out_port,
struct dst_set *set, tag_type *tags, uint16_t *nf_output_iface)
{
- mirror_mask_t mirrors = in_port->src_mirrors;
struct dst dst;
- int flow_vlan;
-
- flow_vlan = vlan_tci_to_vid(flow->vlan_tci);
- if (flow_vlan == 0) {
- flow_vlan = OFP_VLAN_NONE;
- }
if (out_port == FLOOD_PORT) {
struct port *port;
&& port_includes_vlan(port, vlan)
&& !port->is_mirror_output_port
&& set_dst(&dst, flow, in_port, port, tags)) {
- mirrors |= port->dst_mirrors;
dst_set_add(set, &dst);
}
}
*nf_output_iface = NF_OUT_FLOOD;
} else if (out_port && set_dst(&dst, flow, in_port, out_port, tags)) {
dst_set_add(set, &dst);
- *nf_output_iface = dst.dp_ifidx;
- mirrors |= out_port->dst_mirrors;
+ *nf_output_iface = dst.iface->dp_ifidx;
+ }
+}
+
+static void
+compose_mirror_dsts(const struct bridge *br, const struct flow *flow,
+ uint16_t vlan, const struct port *in_port,
+ struct dst_set *set, tag_type *tags)
+{
+ mirror_mask_t mirrors;
+ int flow_vlan;
+ size_t i;
+
+ mirrors = in_port->src_mirrors;
+ for (i = 0; i < set->n; i++) {
+ mirrors |= set->dsts[i].iface->port->dst_mirrors;
+ }
+
+ if (!mirrors) {
+ return;
+ }
+
+ flow_vlan = vlan_tci_to_vid(flow->vlan_tci);
+ if (flow_vlan == 0) {
+ flow_vlan = OFP_VLAN_NONE;
}
while (mirrors) {
struct mirror *m = br->mirrors[mirror_mask_ffs(mirrors) - 1];
if (!m->n_vlans || vlan_is_mirrored(m, vlan)) {
+ struct dst dst;
+
if (m->out_port) {
if (set_dst(&dst, flow, in_port, m->out_port, tags)
&& !dst_is_duplicate(set, &dst)) {
}
mirrors &= mirrors - 1;
}
-
- partition_dsts(set, flow_vlan);
-}
-
-static void OVS_UNUSED
-print_dsts(const struct dst_set *set)
-{
- size_t i;
-
- for (i = 0; i < set->n; i++) {
- const struct dst *dst = &set->dsts[i];
-
- printf(">p%"PRIu16, dst->dp_ifidx);
- if (dst->vlan != OFP_VLAN_NONE) {
- printf("v%"PRIu16, dst->vlan);
- }
- }
}
static void
tag_type *tags, struct ofpbuf *actions,
uint16_t *nf_output_iface)
{
+ uint16_t initial_vlan, cur_vlan;
+ const struct dst *dst;
struct dst_set set;
- uint16_t cur_vlan;
- size_t i;
dst_set_init(&set);
compose_dsts(br, flow, vlan, in_port, out_port, &set, tags,
nf_output_iface);
+ compose_mirror_dsts(br, flow, vlan, in_port, &set, tags);
- cur_vlan = vlan_tci_to_vid(flow->vlan_tci);
- if (cur_vlan == 0) {
- cur_vlan = OFP_VLAN_NONE;
+ /* Output all the packets we can without having to change the VLAN. */
+ initial_vlan = vlan_tci_to_vid(flow->vlan_tci);
+ if (initial_vlan == 0) {
+ initial_vlan = OFP_VLAN_NONE;
}
- for (i = 0; i < set.n; i++) {
- const struct dst *dst = &set.dsts[i];
+ for (dst = set.dsts; dst < &set.dsts[set.n]; dst++) {
+ if (dst->vlan != initial_vlan) {
+ continue;
+ }
+ nl_msg_put_u32(actions, ODP_ACTION_ATTR_OUTPUT, dst->iface->dp_ifidx);
+ }
+
+ /* Then output the rest. */
+ cur_vlan = initial_vlan;
+ for (dst = set.dsts; dst < &set.dsts[set.n]; dst++) {
+ if (dst->vlan == initial_vlan) {
+ continue;
+ }
if (dst->vlan != cur_vlan) {
if (dst->vlan == OFP_VLAN_NONE) {
nl_msg_put_flag(actions, ODP_ACTION_ATTR_STRIP_VLAN);
}
cur_vlan = dst->vlan;
}
- nl_msg_put_u32(actions, ODP_ACTION_ATTR_OUTPUT, dst->dp_ifidx);
+ nl_msg_put_u32(actions, ODP_ACTION_ATTR_OUTPUT, dst->iface->dp_ifidx);
}
+
dst_set_free(&set);
}
}
}
+static uint16_t
+bridge_autopath_ofhook_cb(const struct flow *flow, uint32_t ofp_port,
+ tag_type *tags, void *br_)
+{
+ struct bridge *br = br_;
+ uint16_t odp_port = ofp_port_to_odp_port(ofp_port);
+ struct port *port = port_from_dp_ifidx(br, odp_port);
+ uint16_t ret;
+
+ if (!port) {
+ ret = ODPP_NONE;
+ } else if (list_is_short(&port->ifaces)) {
+ ret = odp_port;
+ } else {
+ struct iface *iface;
+
+ /* Autopath does not support VLAN hashing. */
+ iface = bond_choose_output_slave(port->bond, flow,
+ OFP_VLAN_NONE, tags);
+ ret = iface ? iface->dp_ifidx : ODPP_NONE;
+ }
+
+ return odp_port_to_ofp_port(ret);
+}
+
static struct ofhooks bridge_ofhooks = {
bridge_normal_ofhook_cb,
bridge_special_ofhook_cb,
bridge_account_flow_ofhook_cb,
bridge_account_checkpoint_ofhook_cb,
+ bridge_autopath_ofhook_cb,
};
\f
/* Port functions. */