#include "xenserver.h"
#include "vlog.h"
#include "sflow_api.h"
+#include "vlan-bitmap.h"
VLOG_DEFINE_THIS_MODULE(bridge);
/* 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 void iface_update_cfm(struct iface *);
static bool iface_refresh_cfm_stats(struct iface *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 *);
sset_destroy(&dpif_types);
}
-/* Callback for iterate_and_prune_ifaces(). */
-static bool
-check_iface(struct bridge *br, struct iface *iface, void *aux OVS_UNUSED)
-{
- if (!iface->netdev) {
- /* We already reported a related error, don't bother duplicating it. */
- return false;
- }
-
- if (iface->dp_ifidx < 0) {
- VLOG_ERR("%s interface not in %s, dropping",
- iface->name, dpif_name(br->dpif));
- return false;
- }
-
- VLOG_DBG("%s has interface %s on port %d", dpif_name(br->dpif),
- iface->name, iface->dp_ifidx);
- return true;
-}
-
-/* Callback for iterate_and_prune_ifaces(). */
-static bool
-set_iface_properties(struct bridge *br OVS_UNUSED, struct iface *iface,
- void *aux OVS_UNUSED)
-{
- /* Set policing attributes. */
- netdev_set_policing(iface->netdev,
- iface->cfg->ingress_policing_rate,
- iface->cfg->ingress_policing_burst);
-
- /* Set MAC address of internal interfaces other than the local
- * interface. */
- iface_set_mac(iface);
-
- return true;
-}
-
-/* Calls 'cb' for each interfaces in 'br', passing along the 'aux' argument.
- * Deletes from 'br' all the interfaces for which 'cb' returns false, and then
- * deletes from 'br' any ports that no longer have any interfaces. */
-static void
-iterate_and_prune_ifaces(struct bridge *br,
- bool (*cb)(struct bridge *, struct iface *,
- void *aux),
- void *aux)
-{
- struct port *port, *next_port;
-
- HMAP_FOR_EACH_SAFE (port, next_port, hmap_node, &br->ports) {
- struct iface *iface, *next_iface;
-
- 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 (list_is_empty(&port->ifaces)) {
- VLOG_WARN("%s port has no interfaces, dropping", port->name);
- port_destroy(port);
- }
- }
-}
-
/* Looks at the list of managers in 'ovs_cfg' and extracts their remote IP
* addresses and ports into '*managersp' and '*n_managersp'. The caller is
* responsible for freeing '*managersp' (with free()).
&& strcmp(dpif_port.name, br->name)) {
int retval = dpif_port_del(br->dpif, dpif_port.port_no);
if (retval) {
- VLOG_WARN("failed to remove %s interface from %s: %s",
- dpif_port.name, dpif_name(br->dpif),
- strerror(retval));
+ VLOG_WARN("bridge %s: failed to remove %s interface (%s)",
+ br->name, dpif_port.name, strerror(retval));
}
}
}
dpif_port = NULL;
}
if (iface) {
+ if (iface->port->bond) {
+ /* The bond has a pointer to the netdev, so remove it
+ * from the bond before closing the netdev. The slave
+ * will get added back to the bond later, after a new
+ * netdev is available. */
+ bond_slave_unregister(iface->port->bond, iface);
+ }
netdev_close(iface->netdev);
iface->netdev = NULL;
}
if (error) {
netdev_close(netdev);
if (error == EFBIG) {
- VLOG_ERR("ran out of valid port numbers on %s",
- dpif_name(br->dpif));
+ VLOG_ERR("bridge %s: out of valid port numbers",
+ br->name);
break;
} else {
- VLOG_WARN("failed to add %s interface to %s: %s",
- if_name, dpif_name(br->dpif),
- strerror(error));
+ VLOG_WARN("bridge %s: failed to add %s interface "
+ "(%s)",
+ br->name, if_name, strerror(error));
continue;
}
}
uint8_t ea[ETH_ADDR_LEN];
uint64_t dpid;
struct iface *local_iface;
+ struct port *port, *next_port;
struct iface *hw_addr_iface;
char *dpid_string;
/* Delete interfaces that cannot be opened.
*
- * From this point forward we are guaranteed that every "struct iface"
- * has nonnull 'netdev' and correct 'dp_ifidx'. */
- iterate_and_prune_ifaces(br, check_iface, NULL);
+ * Following this loop, every remaining "struct iface" has nonnull
+ * 'netdev' and correct 'dp_ifidx'. */
+ HMAP_FOR_EACH_SAFE (port, next_port, hmap_node, &br->ports) {
+ struct iface *iface, *next_iface;
+
+ LIST_FOR_EACH_SAFE (iface, next_iface, port_elem, &port->ifaces) {
+ if (iface->netdev && iface->dp_ifidx >= 0) {
+ VLOG_DBG("bridge %s: interface %s is on port %d",
+ br->name, iface->name, iface->dp_ifidx);
+ } else {
+ if (iface->netdev) {
+ VLOG_ERR("bridge %s: missing %s interface, dropping",
+ br->name, iface->name);
+ } else {
+ /* We already reported a related error, don't bother
+ * duplicating it. */
+ }
+
+ iface_set_ofport(iface->cfg, -1);
+ iface_destroy(iface);
+ }
+ }
+
+ if (list_is_empty(&port->ifaces)) {
+ VLOG_WARN("%s port has no interfaces, dropping", port->name);
+ port_destroy(port);
+ }
+ }
/* Pick local port hardware address, datapath ID. */
bridge_pick_local_hw_addr(br, ea, &hw_addr_iface);
LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
iface_update_qos(iface, port->cfg->qos);
+ netdev_set_policing(iface->netdev,
+ iface->cfg->ingress_policing_rate,
+ iface->cfg->ingress_policing_burst);
+ iface_set_mac(iface);
}
}
}
- LIST_FOR_EACH (br, node, &all_bridges) {
- iterate_and_prune_ifaces(br, set_iface_properties, NULL);
- }
/* Some reconfiguration operations require the bridge to have been run at
* least once. */
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);
list_push_back(&all_bridges, &br->node);
- VLOG_INFO("created bridge %s on %s", br->name, dpif_name(br->dpif));
+ VLOG_INFO("bridge %s: created", br->name);
return br;
}
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);
if (error && error != ENOENT) {
- VLOG_ERR("failed to delete %s: %s",
- dpif_name(br->dpif), strerror(error));
+ VLOG_ERR("bridge %s: failed to destroy (%s)",
+ br->name, strerror(error));
}
dpif_close(br->dpif);
mac_learning_destroy(br->ml);
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.
|| !strcmp(br->cfg->fail_mode, "standalone")
? OFPROTO_FAIL_STANDALONE
: OFPROTO_FAIL_SECURE;
- if (ofproto_get_fail_mode(br->ofproto) != fail_mode
- && !ofproto_has_primary_controller(br->ofproto)) {
- ofproto_flush_flows(br->ofproto);
- }
ofproto_set_fail_mode(br->ofproto, fail_mode);
- /* 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?) */
-
/* Configure OpenFlow controller connection snooping. */
if (!ofproto_has_snoops(br->ofproto)) {
struct sset snoops;
struct ovsrec_controller **controllers;
size_t n_controllers;
- bool had_primary;
struct ofproto_controller *ocs;
size_t n_ocs;
} else {
ofproto_set_extra_in_band_remotes(br->ofproto, managers, n_managers);
}
- had_primary = ofproto_has_primary_controller(br->ofproto);
n_controllers = bridge_get_controllers(br, &controllers);
/* Prevent remote ovsdb-server users from accessing arbitrary Unix
* domain sockets and overwriting arbitrary local files. */
- VLOG_ERR_RL(&rl, "%s: not adding Unix domain socket controller "
- "\"%s\" due to possibility for remote exploit",
- dpif_name(br->dpif), c->target);
+ VLOG_ERR_RL(&rl, "bridge %s: not adding Unix domain socket "
+ "controller \"%s\" due to possibility for remote "
+ "exploit", br->name, c->target);
continue;
}
ofproto_set_controllers(br->ofproto, ocs, n_ocs);
free(ocs[0].target); /* From bridge_ofproto_controller_for_mgmt(). */
free(ocs);
-
- if (had_primary != ofproto_has_primary_controller(br->ofproto)) {
- ofproto_flush_flows(br->ofproto);
- }
-
- /* 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
- && ofproto_get_fail_mode(br->ofproto) == OFPROTO_FAIL_STANDALONE) {
- union ofp_action action;
- struct cls_rule rule;
-
- memset(&action, 0, sizeof action);
- action.type = htons(OFPAT_OUTPUT);
- action.output.len = htons(sizeof action);
- action.output.port = htons(OFPP_NORMAL);
- cls_rule_init_catchall(&rule, 0);
- ofproto_add_flow(br->ofproto, &rule, &action, 1);
- }
}
static void
struct iface *iface = iface_lookup(br, dpif_port.name);
if (iface) {
if (iface->dp_ifidx >= 0) {
- VLOG_WARN("%s reported interface %s twice",
- dpif_name(br->dpif), dpif_port.name);
+ VLOG_WARN("bridge %s: interface %s reported twice",
+ br->name, dpif_port.name);
} else if (iface_from_dp_ifidx(br, dpif_port.port_no)) {
- VLOG_WARN("%s reported interface %"PRIu16" twice",
- dpif_name(br->dpif), dpif_port.port_no);
+ VLOG_WARN("bridge %s: interface %"PRIu16" reported twice",
+ br->name, dpif_port.port_no);
} else {
iface->dp_ifidx = dpif_port.port_no;
hmap_insert(&br->ifaces, &iface->dp_ifidx_node,
static bool
port_trunks_vlan(const struct port *port, uint16_t vlan)
{
- return (port->vlan < 0
- && (!port->trunks || bitmap_is_set(port->trunks, vlan)));
+ return (port->vlan < 0 || vlan_bitmap_contains(port->trunks, vlan));
}
static bool
/* Get trunked VLANs. */
trunks = NULL;
if (vlan < 0 && cfg->n_trunks) {
- size_t n_errors;
-
- trunks = bitmap_allocate(4096);
- n_errors = 0;
- for (i = 0; i < cfg->n_trunks; i++) {
- int trunk = cfg->trunks[i];
- if (trunk >= 0) {
- bitmap_set1(trunks, trunk);
- } else {
- n_errors++;
- }
- }
- if (n_errors) {
- VLOG_ERR("port %s: invalid values for %zu trunk VLANs",
- port->name, cfg->n_trunks);
- }
- if (n_errors == cfg->n_trunks) {
+ trunks = vlan_bitmap_from_array(cfg->trunks, cfg->n_trunks);
+ if (!trunks) {
VLOG_ERR("port %s: no valid trunks, trunking all VLANs",
port->name);
- bitmap_free(trunks);
- trunks = NULL;
}
} else if (vlan >= 0 && cfg->n_trunks) {
VLOG_ERR("port %s: ignoring trunks in favor of implicit vlan",
port->name);
}
- if (trunks == NULL
- ? port->trunks != NULL
- : port->trunks == NULL || !bitmap_equal(trunks, port->trunks, 4096)) {
+ if (!vlan_bitmap_equal(trunks, port->trunks)) {
need_flush = true;
}
bitmap_free(port->trunks);
iface_reconfigure_lacp(struct iface *iface)
{
struct lacp_slave_settings s;
- int priority;
+ int priority, portid;
+
+ portid = atoi(get_interface_other_config(iface->cfg, "lacp-port-id", "0"));
+ priority = atoi(get_interface_other_config(iface->cfg,
+ "lacp-port-priority", "0"));
+
+ if (portid <= 0 || portid > UINT16_MAX) {
+ portid = iface->dp_ifidx;
+ }
+
+ if (priority <= 0 || priority > UINT16_MAX) {
+ priority = UINT16_MAX;
+ }
s.name = iface->name;
- s.id = iface->dp_ifidx;
- priority = atoi(get_interface_other_config(
- iface->cfg, "lacp-port-priority", "0"));
- s.priority = (priority >= 0 && priority <= UINT16_MAX
- ? priority : UINT16_MAX);
+ s.id = portid;
+ s.priority = priority;
lacp_slave_register(iface->port->lacp, iface, &s);
}
{
static struct lacp_settings s;
struct iface *iface;
+ uint8_t sysid[ETH_ADDR_LEN];
+ const char *sysid_str;
+ const char *lacp_time;
+ long long int custom_time;
int priority;
if (!enable_lacp(port, &s.active)) {
return;
}
+ sysid_str = get_port_other_config(port->cfg, "lacp-system-id", NULL);
+ if (sysid_str && eth_addr_from_string(sysid_str, sysid)) {
+ memcpy(s.id, sysid, ETH_ADDR_LEN);
+ } else {
+ memcpy(s.id, port->bridge->ea, ETH_ADDR_LEN);
+ }
+
s.name = port->name;
- memcpy(s.id, port->bridge->ea, ETH_ADDR_LEN);
/* Prefer bondable links if unspecified. */
priority = atoi(get_port_other_config(port->cfg, "lacp-system-priority",
? priority
: UINT16_MAX - !list_is_short(&port->ifaces));
- s.fast = !strcmp(get_port_other_config(port->cfg, "lacp-time", "slow"),
- "fast");
+ s.strict = !strcmp(get_port_other_config(port->cfg, "lacp-strict",
+ "false"),
+ "true");
+
+ lacp_time = get_port_other_config(port->cfg, "lacp-time", "slow");
+ custom_time = atoi(lacp_time);
+ if (!strcmp(lacp_time, "fast")) {
+ s.lacp_time = LACP_TIME_FAST;
+ } else if (!strcmp(lacp_time, "slow")) {
+ s.lacp_time = LACP_TIME_SLOW;
+ } else if (custom_time > 0) {
+ s.lacp_time = LACP_TIME_CUSTOM;
+ s.custom_time = custom_time;
+ } else {
+ s.lacp_time = LACP_TIME_SLOW;
+ }
if (!port->lacp) {
port->lacp = lacp_create();
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);
}
}
/* XXX */
return netdev_get_carrier(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. */
/* Update flooded vlans (for RSPAN). */
rspan_vlans = NULL;
if (br->cfg->n_flood_vlans) {
- rspan_vlans = bitmap_allocate(4096);
-
- 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 %"PRId64,
- br->name, vlan);
- } else {
- VLOG_ERR("bridge %s: invalid value %"PRId64 "for flood VLAN",
- br->name, vlan);
- }
- }
+ rspan_vlans = vlan_bitmap_from_array(br->cfg->flood_vlans,
+ br->cfg->n_flood_vlans);
}
if (mac_learning_set_flood_vlans(br->ml, rspan_vlans)) {
bridge_flush(br);
mac_learning_flush(br->ml);
}
+ free(rspan_vlans);
}
static void