X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=vswitchd%2Fbridge.c;h=6ce7d2b3346919c9b438530887d37271382e90e2;hb=ac60863f78e412004c5b69f5a64a49bc6f0bc46d;hp=abae7f581c9efd604d6a8055b9f7f76c792004ab;hpb=f9c0c3eccdb8e14dc8fbf572e515dbef1eb7b2ee;p=sliver-openvswitch.git diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index abae7f581..6ce7d2b33 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -18,6 +18,7 @@ #include #include #include +#include "async-append.h" #include "bfd.h" #include "bitmap.h" #include "bond.h" @@ -196,6 +197,7 @@ static size_t bridge_get_controllers(const struct bridge *br, static void bridge_add_del_ports(struct bridge *, const unsigned long int *splinter_vlans); static void bridge_refresh_ofp_port(struct bridge *); +static void bridge_configure_flow_miss_model(const char *opt); static void bridge_configure_datapath_id(struct bridge *); static void bridge_configure_netflow(struct bridge *); static void bridge_configure_forward_bpdu(struct bridge *); @@ -366,6 +368,7 @@ bridge_init(const char *remote) ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_link_state); ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_link_resets); ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_mac_in_use); + ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_ifindex); 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); @@ -373,6 +376,7 @@ bridge_init(const char *remote) 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_cfm_flap_count); ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_health); ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_remote_opstate); ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_bfd_status); @@ -470,10 +474,9 @@ collect_in_band_managers(const struct ovsrec_open_vswitch *ovs_cfg, SSET_FOR_EACH (target, &targets) { struct sockaddr_in *sin = &managers[n_managers]; - if (stream_parse_target_with_default_ports(target, - JSONRPC_TCP_PORT, - JSONRPC_SSL_PORT, - sin)) { + if (stream_parse_target_with_default_port(target, + OVSDB_OLD_PORT, + sin)) { n_managers++; } } @@ -499,6 +502,12 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) smap_get_int(&ovs_cfg->other_config, "flow-eviction-threshold", OFPROTO_FLOW_EVICTION_THRESHOLD_DEFAULT)); + ofproto_set_n_handler_threads( + smap_get_int(&ovs_cfg->other_config, "n-handler-threads", 0)); + + bridge_configure_flow_miss_model(smap_get(&ovs_cfg->other_config, + "force-miss-model")); + /* Destroy "struct bridge"s, "struct port"s, and "struct iface"s according * to 'ovs_cfg' while update the "if_cfg_queue", with only very minimal * configuration otherwise. @@ -539,7 +548,6 @@ bridge_reconfigure_ofp(void) long long int deadline; struct bridge *br; - time_refresh(); deadline = time_msec() + OFP_PORT_ACTION_WINDOW; /* The kernel will reject any attempt to add a given port to a datapath if @@ -558,7 +566,6 @@ bridge_reconfigure_ofp(void) list_remove(&garbage->list_node); free(garbage); - time_refresh(); if (time_msec() >= deadline) { return false; } @@ -571,7 +578,6 @@ bridge_reconfigure_ofp(void) HMAP_FOR_EACH_SAFE (if_cfg, next, hmap_node, &br->if_cfg_todo) { iface_create(br, if_cfg, OFPP_NONE); - time_refresh(); if (time_msec() >= deadline) { return false; } @@ -691,7 +697,7 @@ bridge_update_ofprotos(void) error = ofproto_port_del(br2->ofproto, ofproto_port.ofp_port); if (error) { VLOG_ERR("failed to delete port %s: %s", ofproto_port.name, - strerror(error)); + ovs_strerror(error)); } ofproto_port_destroy(&ofproto_port); } @@ -700,7 +706,7 @@ bridge_update_ofprotos(void) error = ofproto_create(br->name, br->type, &br->ofproto); if (error) { VLOG_ERR("failed to create bridge %s: %s", br->name, - strerror(error)); + ovs_strerror(error)); bridge_destroy(br); } } @@ -804,6 +810,22 @@ port_configure(struct port *port) free(s.lacp_slaves); } +static void +bridge_configure_flow_miss_model(const char *opt) +{ + enum ofproto_flow_miss_model model = OFPROTO_HANDLE_MISS_AUTO; + + if (opt) { + if (strcmp(opt, "with-facets")) { + model = OFPROTO_HANDLE_MISS_WITH_FACETS; + } else if (strcmp(opt, "without-facets")) { + model = OFPROTO_HANDLE_MISS_WITHOUT_FACETS; + } + } + + ofproto_set_flow_miss_model(model); +} + /* Pick local port hardware address and datapath ID for 'br'. */ static void bridge_configure_datapath_id(struct bridge *br) @@ -822,7 +844,7 @@ bridge_configure_datapath_id(struct bridge *br) static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_ERR_RL(&rl, "bridge %s: failed to set bridge " "Ethernet address: %s", - br->name, strerror(error)); + br->name, ovs_strerror(error)); } } memcpy(br->ea, ea, ETH_ADDR_LEN); @@ -962,28 +984,44 @@ bridge_configure_sflow(struct bridge *br, int *sflow_bridge_number) sset_destroy(&oso.targets); } +/* Returns whether a IPFIX row is valid. */ +static bool +ovsrec_ipfix_is_valid(const struct ovsrec_ipfix *ipfix) +{ + return ipfix && ipfix->n_targets > 0; +} + +/* Returns whether a Flow_Sample_Collector_Set row is valid. */ +static bool +ovsrec_fscs_is_valid(const struct ovsrec_flow_sample_collector_set *fscs, + const struct bridge *br) +{ + return ovsrec_ipfix_is_valid(fscs->ipfix) && fscs->bridge == br->cfg; +} + /* Set IPFIX configuration on 'br'. */ static void bridge_configure_ipfix(struct bridge *br) { const struct ovsrec_ipfix *be_cfg = br->cfg->ipfix; + bool valid_be_cfg = ovsrec_ipfix_is_valid(be_cfg); const struct ovsrec_flow_sample_collector_set *fe_cfg; struct ofproto_ipfix_bridge_exporter_options be_opts; struct ofproto_ipfix_flow_exporter_options *fe_opts = NULL; size_t n_fe_opts = 0; OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH(fe_cfg, idl) { - if (fe_cfg->bridge == br->cfg) { + if (ovsrec_fscs_is_valid(fe_cfg, br)) { n_fe_opts++; } } - if (!be_cfg && n_fe_opts == 0) { + if (!valid_be_cfg && n_fe_opts == 0) { ofproto_set_ipfix(br->ofproto, NULL, NULL, 0); return; } - if (be_cfg) { + if (valid_be_cfg) { memset(&be_opts, 0, sizeof be_opts); sset_init(&be_opts.targets); @@ -1000,6 +1038,12 @@ bridge_configure_ipfix(struct bridge *br) if (be_cfg->obs_point_id) { be_opts.obs_point_id = *be_cfg->obs_point_id; } + if (be_cfg->cache_active_timeout) { + be_opts.cache_active_timeout = *be_cfg->cache_active_timeout; + } + if (be_cfg->cache_max_flows) { + be_opts.cache_max_flows = *be_cfg->cache_max_flows; + } } if (n_fe_opts > 0) { @@ -1007,20 +1051,24 @@ bridge_configure_ipfix(struct bridge *br) fe_opts = xcalloc(n_fe_opts, sizeof *fe_opts); opts = fe_opts; OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH(fe_cfg, idl) { - if (fe_cfg->bridge == br->cfg) { + if (ovsrec_fscs_is_valid(fe_cfg, br)) { opts->collector_set_id = fe_cfg->id; sset_init(&opts->targets); sset_add_array(&opts->targets, fe_cfg->ipfix->targets, fe_cfg->ipfix->n_targets); + opts->cache_active_timeout = fe_cfg->ipfix->cache_active_timeout + ? *fe_cfg->ipfix->cache_active_timeout : 0; + opts->cache_max_flows = fe_cfg->ipfix->cache_max_flows + ? *fe_cfg->ipfix->cache_max_flows : 0; opts++; } } } - ofproto_set_ipfix(br->ofproto, be_cfg ? &be_opts : NULL, fe_opts, + ofproto_set_ipfix(br->ofproto, valid_be_cfg ? &be_opts : NULL, fe_opts, n_fe_opts); - if (be_cfg) { + if (valid_be_cfg) { sset_destroy(&be_opts.targets); } @@ -1300,7 +1348,7 @@ iface_set_netdev_config(const struct ovsrec_interface *iface_cfg, error = netdev_set_config(netdev, &iface_cfg->options); if (error) { VLOG_WARN("could not configure network device %s (%s)", - iface_cfg->name, strerror(error)); + iface_cfg->name, ovs_strerror(error)); } return error; } @@ -1441,7 +1489,7 @@ iface_do_create(const struct bridge *br, iface_get_type(iface_cfg, br->cfg), &netdev); if (error) { VLOG_WARN("could not open network device %s (%s)", - iface_cfg->name, strerror(error)); + iface_cfg->name, ovs_strerror(error)); goto error; } @@ -1555,7 +1603,7 @@ iface_create(struct bridge *br, struct if_cfg *if_cfg, ofp_port_t ofp_port) netdev_close(netdev); } else { VLOG_WARN("could not open network device %s (%s)", - port->name, strerror(error)); + port->name, ovs_strerror(error)); } } else { /* Already exists, nothing to do. */ @@ -1790,6 +1838,7 @@ iface_refresh_status(struct iface *iface) int mtu; int64_t mtu_64; uint8_t mac[ETH_ADDR_LEN]; + int64_t ifindex64; int error; if (iface_is_synthetic(iface)) { @@ -1835,6 +1884,14 @@ iface_refresh_status(struct iface *iface) } else { ovsrec_interface_set_mac_in_use(iface->cfg, NULL); } + + /* The netdev may return a negative number (such as -EOPNOTSUPP) + * if there is no valid ifindex number. */ + ifindex64 = netdev_get_ifindex(iface->netdev); + if (ifindex64 < 0) { + ifindex64 = 0; + } + ovsrec_interface_set_ifindex(iface->cfg, &ifindex64, 1); } /* Writes 'iface''s CFM statistics to the database. 'iface' must not be @@ -1850,11 +1907,13 @@ iface_refresh_cfm_stats(struct iface *iface) ovsrec_interface_set_cfm_fault(cfg, NULL, 0); ovsrec_interface_set_cfm_fault_status(cfg, NULL, 0); ovsrec_interface_set_cfm_remote_opstate(cfg, NULL); + ovsrec_interface_set_cfm_flap_count(cfg, NULL, 0); ovsrec_interface_set_cfm_health(cfg, NULL, 0); ovsrec_interface_set_cfm_remote_mpids(cfg, NULL, 0); } else { const char *reasons[CFM_FAULT_N_REASONS]; int64_t cfm_health = status.health; + int64_t cfm_flap_count = status.flap_count; bool faulted = status.faults != 0; size_t i, j; @@ -1869,6 +1928,8 @@ iface_refresh_cfm_stats(struct iface *iface) } ovsrec_interface_set_cfm_fault_status(cfg, (char **) reasons, j); + ovsrec_interface_set_cfm_flap_count(cfg, &cfm_flap_count, 1); + if (status.remote_opstate >= 0) { const char *remote_opstate = status.remote_opstate ? "up" : "down"; ovsrec_interface_set_cfm_remote_opstate(cfg, remote_opstate); @@ -1884,6 +1945,8 @@ iface_refresh_cfm_stats(struct iface *iface) } else { ovsrec_interface_set_cfm_health(cfg, NULL, 0); } + + free(status.rmps); } } @@ -2216,11 +2279,10 @@ instant_stats_run(void) iface_refresh_cfm_stats(iface); smap_init(&smap); - if (!ofproto_port_get_bfd_status(br->ofproto, iface->ofp_port, - &smap)) { - ovsrec_interface_set_bfd_status(iface->cfg, &smap); - smap_destroy(&smap); - } + ofproto_port_get_bfd_status(br->ofproto, iface->ofp_port, + &smap); + ovsrec_interface_set_bfd_status(iface->cfg, &smap); + smap_destroy(&smap); } } } @@ -2414,6 +2476,8 @@ bridge_run(void) * process that forked us to exit successfully. */ daemonize_complete(); + vlog_enable_async(); + VLOG_INFO_ONCE("%s (Open vSwitch) %s", program_name, VERSION); } } @@ -2509,13 +2573,11 @@ struct qos_unixctl_show_cbdata { }; static void -qos_unixctl_show_cb(unsigned int queue_id, - const struct smap *details, - void *aux) +qos_unixctl_show_queue(unsigned int queue_id, + const struct smap *details, + struct iface *iface, + struct ds *ds) { - struct qos_unixctl_show_cbdata *data = aux; - struct ds *ds = data->ds; - struct iface *iface = data->iface; struct netdev_queue_stats stats; struct smap_node *node; int error; @@ -2546,7 +2608,7 @@ qos_unixctl_show_cb(unsigned int queue_id, } } else { ds_put_format(ds, "\tFailed to get statistics for queue %u: %s", - queue_id, strerror(error)); + queue_id, ovs_strerror(error)); } } @@ -2559,8 +2621,6 @@ qos_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED, struct iface *iface; const char *type; struct smap_node *node; - struct qos_unixctl_show_cbdata data; - int error; iface = iface_find(argv[1]); if (!iface) { @@ -2571,19 +2631,22 @@ qos_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED, netdev_get_qos(iface->netdev, &type, &smap); if (*type != '\0') { + struct netdev_queue_dump dump; + struct smap details; + unsigned int queue_id; + ds_put_format(&ds, "QoS: %s %s\n", iface->name, type); SMAP_FOR_EACH (node, &smap) { ds_put_format(&ds, "%s: %s\n", node->key, node->value); } - data.ds = &ds; - data.iface = iface; - error = netdev_dump_queues(iface->netdev, qos_unixctl_show_cb, &data); - - if (error) { - ds_put_format(&ds, "failed to dump queues: %s", strerror(error)); + smap_init(&details); + NETDEV_QUEUE_FOR_EACH (&queue_id, &details, &dump, iface->netdev) { + qos_unixctl_show_queue(queue_id, &details, iface, &ds); } + smap_destroy(&details); + unixctl_command_reply(conn, ds_cstr(&ds)); } else { ds_put_format(&ds, "QoS not configured on %s\n", iface->name); @@ -3255,8 +3318,8 @@ port_configure_lacp(struct port *port, struct lacp_settings *s) system_id = smap_get(&port->cfg->other_config, "lacp-system-id"); if (system_id) { - if (sscanf(system_id, ETH_ADDR_SCAN_FMT, - ETH_ADDR_SCAN_ARGS(s->id)) != ETH_ADDR_SCAN_COUNT) { + if (!ovs_scan(system_id, ETH_ADDR_SCAN_FMT, + ETH_ADDR_SCAN_ARGS(s->id))) { VLOG_WARN("port %s: LACP system ID (%s) must be an Ethernet" " address.", port->name, system_id); return NULL; @@ -3279,6 +3342,10 @@ port_configure_lacp(struct port *port, struct lacp_settings *s) lacp_time = smap_get(&port->cfg->other_config, "lacp-time"); s->fast = lacp_time && !strcasecmp(lacp_time, "fast"); + + s->fallback_ab_cfg = smap_get_bool(&port->cfg->other_config, + "lacp-fallback-ab", false); + return s; } @@ -3367,6 +3434,9 @@ port_configure_bond(struct port *port, struct bond_settings *s) s->fake_iface = port->cfg->bond_fake_iface; + s->lacp_fallback_ab_cfg = smap_get_bool(&port->cfg->other_config, + "lacp-fallback-ab", false); + LIST_FOR_EACH (iface, port_elem, &port->ifaces) { netdev_set_miimon_interval(iface->netdev, miimon_interval); } @@ -3514,7 +3584,7 @@ iface_set_mac(struct iface *iface) int error = netdev_set_etheraddr(iface->netdev, ea); if (error) { VLOG_ERR("interface %s: setting MAC failed (%s)", - iface->name, strerror(error)); + iface->name, ovs_strerror(error)); } } } @@ -3552,14 +3622,10 @@ iface_clear_db_record(const struct ovsrec_interface *if_cfg) 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); + ovsrec_interface_set_ifindex(if_cfg, NULL, 0); } } -struct iface_delete_queues_cbdata { - struct netdev *netdev; - const struct ovsdb_datum *queues; -}; - static bool queue_ids_include(const struct ovsdb_datum *queues, int64_t target) { @@ -3569,17 +3635,6 @@ queue_ids_include(const struct ovsdb_datum *queues, int64_t target) return ovsdb_datum_find_key(queues, &atom, OVSDB_TYPE_INTEGER) != UINT_MAX; } -static void -iface_delete_queues(unsigned int queue_id, - const struct smap *details OVS_UNUSED, void *cbdata_) -{ - struct iface_delete_queues_cbdata *cbdata = cbdata_; - - if (!queue_ids_include(cbdata->queues, queue_id)) { - netdev_delete_queue(cbdata->netdev, queue_id); - } -} - static void iface_configure_qos(struct iface *iface, const struct ovsrec_qos *qos) { @@ -3590,7 +3645,10 @@ iface_configure_qos(struct iface *iface, const struct ovsrec_qos *qos) if (!qos || qos->type[0] == '\0' || qos->n_queues < 1) { netdev_set_qos(iface->netdev, NULL, NULL); } else { - struct iface_delete_queues_cbdata cbdata; + const struct ovsdb_datum *queues; + struct netdev_queue_dump dump; + unsigned int queue_id; + struct smap details; bool queue_zero; size_t i; @@ -3598,10 +3656,15 @@ iface_configure_qos(struct iface *iface, const struct ovsrec_qos *qos) netdev_set_qos(iface->netdev, qos->type, &qos->other_config); /* Deconfigure queues that were deleted. */ - cbdata.netdev = iface->netdev; - cbdata.queues = ovsrec_qos_get_queues(qos, OVSDB_TYPE_INTEGER, - OVSDB_TYPE_UUID); - netdev_dump_queues(iface->netdev, iface_delete_queues, &cbdata); + queues = ovsrec_qos_get_queues(qos, OVSDB_TYPE_INTEGER, + OVSDB_TYPE_UUID); + smap_init(&details); + NETDEV_QUEUE_FOR_EACH (&queue_id, &details, &dump, iface->netdev) { + if (!queue_ids_include(queues, queue_id)) { + netdev_delete_queue(iface->netdev, queue_id); + } + } + smap_destroy(&details); /* Configure queues for 'iface'. */ queue_zero = false; @@ -4055,10 +4118,10 @@ collect_splinter_vlans(const struct ovsrec_open_vswitch *ovs_cfg) if (!netdev_open(vlan_dev->name, "system", &netdev)) { if (!netdev_get_in4(netdev, NULL, NULL) || !netdev_get_in6(netdev, NULL)) { - vlandev_del(vlan_dev->name); - } else { /* It has an IP address configured, so we don't own * it. Don't delete it. */ + } else { + vlandev_del(vlan_dev->name); } netdev_close(netdev); }