X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=inline;f=vswitchd%2Fbridge.c;h=9fcc97098129b026a7a9f240c3872c490b69127f;hb=d02a5f8ea4e1da19ccc4f903026b77649472b236;hp=2c1142b2c8b22c9e79ad0360ce4bc306212acc7a;hpb=edce886c92dc34797a36fd9dd20c530e1799f082;p=openvswitch diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 2c1142b2..9fcc9709 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -66,6 +66,7 @@ struct if_cfg { struct hmap_node hmap_node; /* Node in bridge's if_cfg_todo. */ const struct ovsrec_interface *cfg; /* Interface record. */ const struct ovsrec_port *parent; /* Parent port record. */ + int64_t ofport; /* Requested OpenFlow port number. */ }; /* OpenFlow port slated for removal from ofproto. */ @@ -153,12 +154,6 @@ static unsigned int idl_seqno; #define IFACE_STATS_INTERVAL (5 * 1000) /* In milliseconds. */ static long long int iface_stats_timer = LLONG_MIN; -/* Stores the time after which rate limited statistics may be written to the - * database. Only updated when changes to the database require rate limiting. - */ -#define DB_LIMIT_INTERVAL (1 * 1000) /* In milliseconds. */ -static long long int db_limiter = LLONG_MIN; - /* In some datapaths, creating and destroying OpenFlow ports can be extremely * expensive. This can cause bridge_reconfigure() to take a long time during * which no other work can be done. To deal with this problem, we limit port @@ -267,6 +262,48 @@ static void configure_splinter_port(struct port *); static void add_vlan_splinter_ports(struct bridge *, const unsigned long int *splinter_vlans, struct shash *ports); + +static void +bridge_init_ofproto(const struct ovsrec_open_vswitch *cfg) +{ + struct shash iface_hints; + static bool initialized = false; + int i; + + if (initialized) { + return; + } + + shash_init(&iface_hints); + + for (i = 0; i < cfg->n_bridges; i++) { + const struct ovsrec_bridge *br_cfg = cfg->bridges[i]; + int j; + + for (j = 0; j < br_cfg->n_ports; j++) { + struct ovsrec_port *port_cfg = br_cfg->ports[j]; + int k; + + for (k = 0; k < port_cfg->n_interfaces; k++) { + struct ovsrec_interface *if_cfg = port_cfg->interfaces[k]; + struct iface_hint *iface_hint; + + iface_hint = xmalloc(sizeof *iface_hint); + iface_hint->br_name = br_cfg->name; + iface_hint->br_type = br_cfg->datapath_type; + iface_hint->ofp_port = if_cfg->n_ofport_request ? + *if_cfg->ofport_request : OFPP_NONE; + + shash_add(&iface_hints, if_cfg->name, iface_hint); + } + } + } + + ofproto_init(&iface_hints); + + shash_destroy_free_data(&iface_hints); + initialized = true; +} /* Public functions. */ @@ -280,6 +317,7 @@ bridge_init(const char *remote) idl = ovsdb_idl_create(remote, &ovsrec_idl_class, true); idl_seqno = ovsdb_idl_get_seqno(idl); ovsdb_idl_set_lock(idl, "ovs_vswitchd"); + ovsdb_idl_verify_write_only(idl); ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_cur_cfg); ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_statistics); @@ -311,6 +349,7 @@ bridge_init(const char *remote) 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_health); + ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_remote_opstate); ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_lacp_current); ovsdb_idl_omit(idl, &ovsrec_interface_col_external_ids); @@ -891,7 +930,7 @@ port_configure_stp(const struct ofproto *ofproto, struct port *port, const char *config_str; struct iface *iface; - if (smap_get_bool(&port->cfg->other_config, "stp-enable", false)) { + if (!smap_get_bool(&port->cfg->other_config, "stp-enable", true)) { port_s->enable = false; return; } else { @@ -943,7 +982,7 @@ port_configure_stp(const struct ofproto *ofproto, struct port *port, bitmap_set1(port_num_bitmap, port_idx); port_s->port_num = port_idx; } else { - if (*port_num_counter > STP_MAX_PORTS) { + if (*port_num_counter >= STP_MAX_PORTS) { VLOG_ERR("port %s: too many STP ports, disabling", port->name); port_s->enable = false; return; @@ -957,16 +996,11 @@ port_configure_stp(const struct ofproto *ofproto, struct port *port, port_s->path_cost = strtoul(config_str, NULL, 10); } else { enum netdev_features current; + unsigned int mbps; - if (netdev_get_features(iface->netdev, ¤t, NULL, NULL, NULL)) { - /* Couldn't get speed, so assume 100Mb/s. */ - port_s->path_cost = 19; - } else { - unsigned int mbps; - - mbps = netdev_features_to_bps(current) / 1000000; - port_s->path_cost = stp_convert_speed_to_cost(mbps); - } + netdev_get_features(iface->netdev, ¤t, NULL, NULL, NULL); + mbps = netdev_features_to_bps(current, 100 * 1000 * 1000) / 1000000; + port_s->path_cost = stp_convert_speed_to_cost(mbps); } config_str = smap_get(&port->cfg->other_config, "stp-port-priority"); @@ -1265,7 +1299,7 @@ bridge_refresh_ofp_port(struct bridge *br) } } -/* Opens a network device for 'iface_cfg' and configures it. If '*ofp_portp' +/* Opens a network device for 'if_cfg' and configures it. If '*ofp_portp' * is negative, adds the network device to br->ofproto and stores the OpenFlow * port number in '*ofp_portp'; otherwise leaves br->ofproto and '*ofp_portp' * untouched. @@ -1274,10 +1308,11 @@ bridge_refresh_ofp_port(struct bridge *br) * failure, returns a positive errno value and stores NULL in '*netdevp'. */ static int iface_do_create(const struct bridge *br, - const struct ovsrec_interface *iface_cfg, - const struct ovsrec_port *port_cfg, + const struct if_cfg *if_cfg, int *ofp_portp, struct netdev **netdevp) { + const struct ovsrec_interface *iface_cfg = if_cfg->cfg; + const struct ovsrec_port *port_cfg = if_cfg->parent; struct netdev *netdev; int error; @@ -1295,7 +1330,7 @@ iface_do_create(const struct bridge *br, } if (*ofp_portp < 0) { - uint16_t ofp_port; + uint16_t ofp_port = if_cfg->ofport; error = ofproto_port_add(br->ofproto, netdev, &ofp_port); if (error) { @@ -1339,11 +1374,7 @@ iface_create(struct bridge *br, struct if_cfg *if_cfg, int ofp_port) struct iface *iface; struct port *port; int error; - - /* Get rid of 'if_cfg' itself. We already copied out the interesting - * bits. */ - hmap_remove(&br->if_cfg_todo, &if_cfg->hmap_node); - free(if_cfg); + bool ok = true; /* Do the bits that can fail up front. * @@ -1352,11 +1383,12 @@ iface_create(struct bridge *br, struct if_cfg *if_cfg, int ofp_port) * additions and deletions are cheaper, these calls should be removed. */ bridge_run_fast(); assert(!iface_lookup(br, iface_cfg->name)); - error = iface_do_create(br, iface_cfg, port_cfg, &ofp_port, &netdev); + error = iface_do_create(br, if_cfg, &ofp_port, &netdev); bridge_run_fast(); if (error) { iface_clear_db_record(iface_cfg); - return false; + ok = false; + goto done; } /* Get or create the port structure. */ @@ -1394,7 +1426,9 @@ iface_create(struct bridge *br, struct if_cfg *if_cfg, int ofp_port) error = netdev_open(port->name, "internal", &netdev); if (!error) { - ofproto_port_add(br->ofproto, netdev, NULL); + uint16_t ofp_port = if_cfg->ofport; + + ofproto_port_add(br->ofproto, netdev, &ofp_port); netdev_close(netdev); } else { VLOG_WARN("could not open network device %s (%s)", @@ -1406,7 +1440,11 @@ iface_create(struct bridge *br, struct if_cfg *if_cfg, int ofp_port) } } - return true; +done: + hmap_remove(&br->if_cfg_todo, &if_cfg->hmap_node); + free(if_cfg); + + return ok; } /* Set Flow eviction threshold */ @@ -1421,7 +1459,7 @@ bridge_configure_flow_eviction_threshold(struct bridge *br) if (threshold_str) { threshold = strtoul(threshold_str, NULL, 10); } else { - threshold = OFPROTO_FLOW_EVICTON_THRESHOLD_DEFAULT; + threshold = OFPROTO_FLOW_EVICTION_THRESHOLD_DEFAULT; } ofproto_set_flow_eviction_threshold(br->ofproto, threshold); } @@ -1638,7 +1676,6 @@ iface_refresh_status(struct iface *iface) struct smap smap; enum netdev_features current; - enum netdev_flags flags; int64_t bps; int mtu; int64_t mtu_64; @@ -1658,22 +1695,12 @@ iface_refresh_status(struct iface *iface) smap_destroy(&smap); - error = netdev_get_flags(iface->netdev, &flags); - if (!error) { - ovsrec_interface_set_admin_state(iface->cfg, - flags & NETDEV_UP ? "up" : "down"); - } - else { - ovsrec_interface_set_admin_state(iface->cfg, NULL); - } - error = netdev_get_features(iface->netdev, ¤t, NULL, NULL, NULL); - if (!error) { + bps = !error ? netdev_features_to_bps(current, 0) : 0; + if (bps) { ovsrec_interface_set_duplex(iface->cfg, netdev_features_is_full_duplex(current) ? "full" : "half"); - /* warning: uint64_t -> int64_t conversion */ - bps = netdev_features_to_bps(current); ovsrec_interface_set_link_speed(iface->cfg, &bps, 1); } else { @@ -1691,20 +1718,17 @@ iface_refresh_status(struct iface *iface) } } -/* Writes 'iface''s CFM statistics to the database. */ +/* Writes 'iface''s CFM statistics to the database. 'iface' must not be + * synthetic. */ static void iface_refresh_cfm_stats(struct iface *iface) { const struct ovsrec_interface *cfg = iface->cfg; - int fault, error; + int fault, opup, error; const uint64_t *rmps; size_t n_rmps; int health; - if (iface_is_synthetic(iface)) { - return; - } - fault = ofproto_port_get_cfm_fault(iface->port->bridge->ofproto, iface->ofp_port); if (fault >= 0) { @@ -1727,6 +1751,14 @@ iface_refresh_cfm_stats(struct iface *iface) ovsrec_interface_set_cfm_fault_status(cfg, NULL, 0); } + opup = ofproto_port_get_cfm_opup(iface->port->bridge->ofproto, + iface->ofp_port); + if (opup >= 0) { + ovsrec_interface_set_cfm_remote_opstate(cfg, opup ? "up" : "down"); + } else { + ovsrec_interface_set_cfm_remote_opstate(cfg, NULL); + } + error = ofproto_port_get_cfm_remote_mpids(iface->port->bridge->ofproto, iface->ofp_port, &rmps, &n_rmps); if (error >= 0) { @@ -1968,7 +2000,7 @@ refresh_controller_status(void) } static void -refresh_cfm_stats(void) +refresh_instant_stats(void) { static struct ovsdb_idl_txn *txn = NULL; @@ -1979,8 +2011,47 @@ refresh_cfm_stats(void) HMAP_FOR_EACH (br, node, &all_bridges) { struct iface *iface; + struct port *port; + + br_refresh_stp_status(br); + + HMAP_FOR_EACH (port, hmap_node, &br->ports) { + port_refresh_stp_status(port); + } HMAP_FOR_EACH (iface, name_node, &br->iface_by_name) { + enum netdev_flags flags; + const char *link_state; + int64_t link_resets; + int current, error; + + if (iface_is_synthetic(iface)) { + continue; + } + + current = ofproto_port_is_lacp_current(br->ofproto, + iface->ofp_port); + if (current >= 0) { + bool bl = current; + ovsrec_interface_set_lacp_current(iface->cfg, &bl, 1); + } else { + ovsrec_interface_set_lacp_current(iface->cfg, NULL, 0); + } + + error = netdev_get_flags(iface->netdev, &flags); + if (!error) { + const char *state = flags & NETDEV_UP ? "up" : "down"; + ovsrec_interface_set_admin_state(iface->cfg, state); + } else { + ovsrec_interface_set_admin_state(iface->cfg, NULL); + } + + link_state = netdev_get_carrier(iface->netdev) ? "up" : "down"; + ovsrec_interface_set_link_state(iface->cfg, link_state); + + link_resets = netdev_get_carrier_resets(iface->netdev); + ovsrec_interface_set_link_resets(iface->cfg, &link_resets, 1); + iface_refresh_cfm_stats(iface); } } @@ -2001,8 +2072,17 @@ refresh_cfm_stats(void) void bridge_run_fast(void) { + struct sset types; + const char *type; struct bridge *br; + sset_init(&types); + ofproto_enumerate_types(&types); + SSET_FOR_EACH (type, &types) { + ofproto_type_run_fast(type); + } + sset_destroy(&types); + HMAP_FOR_EACH (br, node, &all_bridges) { ofproto_run_fast(br->ofproto); } @@ -2014,6 +2094,8 @@ bridge_run(void) static const struct ovsrec_open_vswitch null_cfg; const struct ovsrec_open_vswitch *cfg; struct ovsdb_idl_txn *reconf_txn = NULL; + struct sset types; + const char *type; bool vlan_splinters_changed; struct bridge *br; @@ -2041,6 +2123,20 @@ bridge_run(void) } cfg = ovsrec_open_vswitch_first(idl); + /* Initialize the ofproto library. This only needs to run once, but + * it must be done after the configuration is set. If the + * initialization has already occurred, bridge_init_ofproto() + * returns immediately. */ + bridge_init_ofproto(cfg); + + /* Let each datapath type do the work that it needs to do. */ + sset_init(&types); + ofproto_enumerate_types(&types); + SSET_FOR_EACH (type, &types) { + ofproto_type_run(type); + } + sset_destroy(&types); + /* Let each bridge do the work that it needs to do. */ HMAP_FOR_EACH (br, node, &all_bridges) { ofproto_run(br->ofproto); @@ -2137,65 +2233,28 @@ bridge_run(void) } run_system_stats(); - - if (time_msec() >= db_limiter) { - struct ovsdb_idl_txn *txn; - - txn = ovsdb_idl_txn_create(idl); - HMAP_FOR_EACH (br, node, &all_bridges) { - struct iface *iface; - struct port *port; - - br_refresh_stp_status(br); - - HMAP_FOR_EACH (port, hmap_node, &br->ports) { - port_refresh_stp_status(port); - } - - HMAP_FOR_EACH (iface, name_node, &br->iface_by_name) { - const char *link_state; - int64_t link_resets; - int current; - - if (iface_is_synthetic(iface)) { - continue; - } - - current = ofproto_port_is_lacp_current(br->ofproto, - iface->ofp_port); - if (current >= 0) { - bool bl = current; - ovsrec_interface_set_lacp_current(iface->cfg, &bl, 1); - } else { - ovsrec_interface_set_lacp_current(iface->cfg, NULL, 0); - } - - link_state = netdev_get_carrier(iface->netdev) ? "up" : "down"; - ovsrec_interface_set_link_state(iface->cfg, link_state); - - link_resets = netdev_get_carrier_resets(iface->netdev); - ovsrec_interface_set_link_resets(iface->cfg, &link_resets, 1); - } - } - - if (ovsdb_idl_txn_commit(txn) != TXN_UNCHANGED) { - db_limiter = time_msec() + DB_LIMIT_INTERVAL; - } - ovsdb_idl_txn_destroy(txn); - } - - refresh_cfm_stats(); + refresh_instant_stats(); } void bridge_wait(void) { + struct sset types; + const char *type; + ovsdb_idl_wait(idl); if (reconfiguring) { poll_immediate_wake(); } + sset_init(&types); + ofproto_enumerate_types(&types); + SSET_FOR_EACH (type, &types) { + ofproto_type_wait(type); + } + sset_destroy(&types); + if (!hmap_is_empty(&all_bridges)) { struct bridge *br; @@ -2203,10 +2262,6 @@ bridge_wait(void) ofproto_wait(br->ofproto); } poll_timer_wait_until(iface_stats_timer); - - if (db_limiter > time_msec()) { - poll_timer_wait_until(db_limiter); - } } system_stats_wait(); @@ -2472,6 +2527,7 @@ bridge_queue_if_cfg(struct bridge *br, if_cfg->cfg = cfg; if_cfg->parent = parent; + if_cfg->ofport = cfg->n_ofport_request ? *cfg->ofport_request : OFPP_NONE; hmap_insert(&br->if_cfg_todo, &if_cfg->hmap_node, hash_string(if_cfg->cfg->name, 0)); } @@ -2548,7 +2604,12 @@ bridge_add_del_ports(struct bridge *br, if (iface) { iface->cfg = cfg; iface->type = type; - } else if (strcmp(type, "null")) { + } else if (!strcmp(type, "null")) { + VLOG_WARN_ONCE("%s: The null interface type is deprecated and" + " may be removed in February 2013. Please email" + " dev@openvswitch.org with concerns.", + cfg->name); + } else { bridge_queue_if_cfg(br, cfg, port); } } @@ -3078,11 +3139,14 @@ static const char * iface_get_type(const struct ovsrec_interface *iface, const struct ovsrec_bridge *br) { - /* The local port always has type "internal". Other ports take their type - * from the database and default to "system" if none is specified. */ - return (!strcmp(iface->name, br->name) ? "internal" - : iface->type[0] ? iface->type - : "system"); + /* The local port always has type "internal" unless the bridge is of + * type "dummy". Other ports take their type from the database and + * default to "system" if none is specified. */ + if (!strcmp(iface->name, br->name)) { + return !strcmp(br->datapath_type, "dummy") ? "dummy" : "internal"; + } else { + return iface->type[0] ? iface->type : "system"; + } } static void @@ -3328,12 +3392,24 @@ iface_configure_cfm(struct iface *iface) const char *opstate_str; const char *cfm_ccm_vlan; struct cfm_settings s; + struct smap netdev_args; if (!cfg->n_cfm_mpid) { ofproto_port_clear_cfm(iface->port->bridge->ofproto, iface->ofp_port); return; } + s.check_tnl_key = false; + smap_init(&netdev_args); + if (!netdev_get_config(iface->netdev, &netdev_args)) { + const char *key = smap_get(&netdev_args, "key"); + const char *in_key = smap_get(&netdev_args, "in_key"); + + s.check_tnl_key = (key && !strcmp(key, "flow")) + || (in_key && !strcmp(in_key, "flow")); + } + smap_destroy(&netdev_args); + s.mpid = *cfg->cfm_mpid; s.interval = smap_get_int(&iface->cfg->other_config, "cfm_interval", 0); cfm_ccm_vlan = smap_get(&iface->cfg->other_config, "cfm_ccm_vlan");