#include "jsonrpc.h"
#include "lacp.h"
#include "list.h"
+#include "mac-learning.h"
+#include "meta-flow.h"
#include "netdev.h"
#include "ofp-print.h"
#include "ofpbuf.h"
struct netdev *netdev; /* Network device. */
const char *type; /* Usually same as cfg->type. */
const struct ovsrec_interface *cfg;
+ bool need_refresh; /* Refresh iface after create. */
};
struct mirror {
static void bridge_configure_flow_eviction_threshold(struct bridge *);
static void bridge_configure_netflow(struct bridge *);
static void bridge_configure_forward_bpdu(struct bridge *);
+static void bridge_configure_mac_idle_time(struct bridge *);
static void bridge_configure_sflow(struct bridge *, int *sflow_bridge_number);
static void bridge_configure_stp(struct bridge *);
+static void bridge_configure_tables(struct bridge *);
static void bridge_configure_remotes(struct bridge *,
const struct sockaddr_in *managers,
size_t n_managers);
ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_statistics);
ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_status);
ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_fault);
+ ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_fault_status);
ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_remote_mpids);
ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_lacp_current);
ovsdb_idl_omit(idl, &ovsrec_interface_col_external_ids);
lacp_init();
bond_init();
cfm_init();
+ stp_init();
}
void
* has at least one iface, every "struct iface" has a valid ofp_port and
* netdev. */
HMAP_FOR_EACH_SAFE (br, next, node, &all_bridges) {
- if (!br->ofproto && !bridge_add_ofprotos(br)) {
- bridge_destroy(br);
+ if (!br->ofproto) {
+ if (bridge_add_ofprotos(br)) {
+ bridge_del_ofproto_ports(br);
+ } else {
+ bridge_destroy(br);
+ }
}
}
HMAP_FOR_EACH (br, node, &all_bridges) {
bridge_configure_mirrors(br);
bridge_configure_flow_eviction_threshold(br);
bridge_configure_forward_bpdu(br);
+ bridge_configure_mac_idle_time(br);
bridge_configure_remotes(br, managers, n_managers);
bridge_configure_netflow(br);
bridge_configure_sflow(br, &sflow_bridge_number);
bridge_configure_stp(br);
+ bridge_configure_tables(br);
}
free(managers);
}
/* Populate stats columns in new Interface rows. */
- if (iface->netdev && !iface->cfg->mtu) {
+ if (iface->netdev && iface->need_refresh) {
iface_refresh_stats(iface);
iface_refresh_status(iface);
+ iface->need_refresh = false;
}
/* Delete the iface if we failed. */
ofproto_set_forward_bpdu(br->ofproto, forward_bpdu);
}
+/* Set MAC aging time for 'br'. */
+static void
+bridge_configure_mac_idle_time(struct bridge *br)
+{
+ const char *idle_time_str;
+ int idle_time;
+
+ 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);
+ ofproto_set_mac_idle_time(br->ofproto, idle_time);
+}
+
static void
bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
struct iface **hw_addr_iface)
fault = ofproto_port_get_cfm_fault(iface->port->bridge->ofproto,
iface->ofp_port);
if (fault >= 0) {
+ const char *reasons[CFM_FAULT_N_REASONS];
bool fault_bool = fault;
+ size_t i, j;
+
+ j = 0;
+ for (i = 0; i < CFM_FAULT_N_REASONS; i++) {
+ int reason = 1 << i;
+ if (fault & reason) {
+ reasons[j++] = cfm_fault_reason_to_str(reason);
+ }
+ }
+
ovsrec_interface_set_cfm_fault(cfg, &fault_bool, 1);
+ ovsrec_interface_set_cfm_fault_status(cfg, (char **) reasons, j);
} else {
ovsrec_interface_set_cfm_fault(cfg, NULL, 0);
+ ovsrec_interface_set_cfm_fault_status(cfg, NULL, 0);
}
error = ofproto_port_get_cfm_remote_mpids(iface->port->bridge->ofproto,
iface = iface_find(argv[1]);
if (!iface) {
- unixctl_command_reply(conn, 501, "no such interface");
+ unixctl_command_reply_error(conn, "no such interface");
return;
}
if (error) {
ds_put_format(&ds, "failed to dump queues: %s", strerror(error));
}
- unixctl_command_reply(conn, 200, ds_cstr(&ds));
+ unixctl_command_reply(conn, ds_cstr(&ds));
} else {
ds_put_format(&ds, "QoS not configured on %s\n", iface->name);
- unixctl_command_reply(conn, 501, ds_cstr(&ds));
+ unixctl_command_reply_error(conn, ds_cstr(&ds));
}
shash_destroy_free_data(&sh);
br = bridge_lookup(argv[1]);
if (!br) {
- unixctl_command_reply(conn, 501, "Unknown bridge");
+ unixctl_command_reply_error(conn, "Unknown bridge");
return;
}
ds_init(&results);
ofproto_get_all_flows(br->ofproto, &results);
- unixctl_command_reply(conn, 200, ds_cstr(&results));
+ unixctl_command_reply(conn, ds_cstr(&results));
ds_destroy(&results);
}
if (argc > 1) {
br = bridge_lookup(argv[1]);
if (!br) {
- unixctl_command_reply(conn, 501, "Unknown bridge");
+ unixctl_command_reply_error(conn, "Unknown bridge");
return;
}
ofproto_reconnect_controllers(br->ofproto);
ofproto_reconnect_controllers(br->ofproto);
}
}
- unixctl_command_reply(conn, 200, NULL);
+ unixctl_command_reply(conn, NULL);
}
static size_t
oc->band = OFPROTO_OUT_OF_BAND;
oc->rate_limit = 0;
oc->burst_limit = 0;
+ oc->enable_async_msgs = true;
}
/* Converts ovsrec_controller 'c' into an ofproto_controller in 'oc'. */
oc->rate_limit = c->controller_rate_limit ? *c->controller_rate_limit : 0;
oc->burst_limit = (c->controller_burst_limit
? *c->controller_burst_limit : 0);
+ oc->enable_async_msgs = (!c->enable_async_messages
+ || *c->enable_async_messages);
}
/* Configures the IP stack for 'br''s local interface properly according to the
sset_destroy(&snoops);
}
}
+
+static void
+bridge_configure_tables(struct bridge *br)
+{
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+ int n_tables;
+ int i, j;
+
+ n_tables = ofproto_get_n_tables(br->ofproto);
+ j = 0;
+ for (i = 0; i < n_tables; i++) {
+ struct ofproto_table_settings s;
+
+ s.name = NULL;
+ s.max_flows = UINT_MAX;
+ s.groups = NULL;
+ s.n_groups = 0;
+
+ if (j < br->cfg->n_flow_tables && i == br->cfg->key_flow_tables[j]) {
+ struct ovsrec_flow_table *cfg = br->cfg->value_flow_tables[j++];
+
+ s.name = cfg->name;
+ if (cfg->n_flow_limit && *cfg->flow_limit < UINT_MAX) {
+ s.max_flows = *cfg->flow_limit;
+ }
+ if (cfg->overflow_policy
+ && !strcmp(cfg->overflow_policy, "evict")) {
+ size_t k;
+
+ s.groups = xmalloc(cfg->n_groups * sizeof *s.groups);
+ for (k = 0; k < cfg->n_groups; k++) {
+ const char *string = cfg->groups[k];
+ char *msg;
+
+ msg = mf_parse_subfield__(&s.groups[k], &string);
+ if (msg) {
+ VLOG_WARN_RL(&rl, "bridge %s table %d: error parsing "
+ "'groups' (%s)", br->name, i, msg);
+ free(msg);
+ } else if (*string) {
+ VLOG_WARN_RL(&rl, "bridge %s table %d: 'groups' "
+ "element '%s' contains trailing garbage",
+ br->name, i, cfg->groups[k]);
+ } else {
+ s.n_groups++;
+ }
+ }
+ }
+ }
+
+ ofproto_configure_table(br->ofproto, i, &s);
+
+ free(s.groups);
+ }
+ for (; j < br->cfg->n_flow_tables; j++) {
+ VLOG_WARN_RL(&rl, "bridge %s: ignoring configuration for flow table "
+ "%"PRId64" not supported by this datapath", br->name,
+ br->cfg->key_flow_tables[j]);
+ }
+}
\f
/* Port functions. */
s->name = port->name;
system_id = get_port_other_config(port->cfg, "lacp-system-id", NULL);
- if (!system_id
- || sscanf(system_id, ETH_ADDR_SCAN_FMT,
- ETH_ADDR_SCAN_ARGS(s->id)) != ETH_ADDR_SCAN_COUNT) {
+ if (system_id) {
+ if (sscanf(system_id, ETH_ADDR_SCAN_FMT,
+ ETH_ADDR_SCAN_ARGS(s->id)) != ETH_ADDR_SCAN_COUNT) {
+ VLOG_WARN("port %s: LACP system ID (%s) must be an Ethernet"
+ " address.", port->name, system_id);
+ return NULL;
+ }
+ } else {
memcpy(s->id, port->bridge->ea, ETH_ADDR_LEN);
}
size_t i;
s->name = port->name;
- s->balance = BM_SLB;
+ s->balance = BM_AB;
if (port->cfg->bond_mode) {
if (!bond_mode_from_string(&s->balance, port->cfg->bond_mode)) {
VLOG_WARN("port %s: unknown bond_mode %s, defaulting to %s",
} else {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
- /* XXX: Post version 1.4.*, change the default bond_mode to
- * active-backup. Until then, warn that the change is imminent. */
+ /* XXX: Post version 1.5.*, the default bond_mode changed from SLB to
+ * active-backup. At some point we should remove this warning. */
VLOG_WARN_RL(&rl, "port %s: Using the default bond_mode %s. Note that"
- " in future versions, the default bond_mode is expected"
- " to change to active-backup", port->name,
+ " in previous versions, the default bond_mode was"
+ " balance-slb", port->name,
bond_mode_to_string(s->balance));
}
if (s->balance == BM_SLB && port->bridge->cfg->n_flood_vlans) {
s->basis = atoi(get_port_other_config(port->cfg, "bond-hash-basis", "0"));
s->rebalance_interval = atoi(
get_port_other_config(port->cfg, "bond-rebalance-interval", "10000"));
- if (s->rebalance_interval < 1000) {
+ if (s->rebalance_interval && s->rebalance_interval < 1000) {
s->rebalance_interval = 1000;
}
iface->tag = tag_create_random();
iface->netdev = NULL;
iface->cfg = if_cfg;
+ iface->need_refresh = true;
hmap_insert(&br->iface_by_name, &iface->name_node, hash_string(name, 0));
ovsrec_interface_set_link_state(if_cfg, NULL);
ovsrec_interface_set_mtu(if_cfg, NULL, 0);
ovsrec_interface_set_cfm_fault(if_cfg, NULL, 0);
+ ovsrec_interface_set_cfm_fault_status(if_cfg, NULL, 0);
ovsrec_interface_set_cfm_remote_mpids(if_cfg, NULL, 0);
ovsrec_interface_set_lacp_current(if_cfg, NULL, 0);
ovsrec_interface_set_statistics(if_cfg, NULL, NULL, 0);
shash_destroy(&details);
}
if (!queue_zero) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
- VLOG_WARN_RL(&rl, "interface %s: QoS configured without a default "
- "queue (queue 0). Packets not directed to a "
- "correctly configured queue may be dropped.",
- iface->name);
+ shash_init(&details);
+ netdev_set_queue(iface->netdev, 0, &details);
+ shash_destroy(&details);
}
}
"0"));
s.ccm_vlan = atoi(get_interface_other_config(iface->cfg, "cfm_ccm_vlan",
"0"));
+ s.ccm_pcp = atoi(get_interface_other_config(iface->cfg, "cfm_ccm_pcp",
+ "0"));
if (s.interval <= 0) {
s.interval = 1000;
}