diff --git a/SOURCES/openvswitch-2.17.0.patch b/SOURCES/openvswitch-2.17.0.patch index 4a6c88b..d98f087 100644 --- a/SOURCES/openvswitch-2.17.0.patch +++ b/SOURCES/openvswitch-2.17.0.patch @@ -59040,7 +59040,7 @@ index 78a54c715d..109940ad2a 100644 oftrace_node_destroy(node); } diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c -index 57f94df544..308876d38c 100644 +index 57f94df544..53b47073ad 100644 --- a/ofproto/ofproto-dpif-upcall.c +++ b/ofproto/ofproto-dpif-upcall.c @@ -47,17 +47,20 @@ @@ -59130,7 +59130,46 @@ index 57f94df544..308876d38c 100644 ovsrcu_postpone(ukey_delete__, old_ukey); transition_ukey(old_ukey, UKEY_DELETED); transition_ukey(new_ukey, UKEY_VISIBLE); -@@ -2321,6 +2346,13 @@ revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey, +@@ -2074,10 +2099,12 @@ ukey_delete(struct umap *umap, struct udpif_key *ukey) + } + + static bool +-should_revalidate(const struct udpif *udpif, uint64_t packets, +- long long int used) ++should_revalidate(const struct udpif *udpif, const struct udpif_key *ukey, ++ uint64_t packets) ++ OVS_REQUIRES(ukey->mutex) + { + long long int metric, now, duration; ++ long long int used = ukey->stats.used; + + if (!used) { + /* Always revalidate the first time a flow is dumped. */ +@@ -2104,8 +2131,12 @@ should_revalidate(const struct udpif *udpif, uint64_t packets, + duration = now - used; + metric = duration / packets; + +- if (metric < 1000 / ofproto_min_revalidate_pps) { +- /* The flow is receiving more than min-revalidate-pps, so keep it. */ ++ if (metric < 1000 / ofproto_min_revalidate_pps || ++ (ukey->offloaded && duration < ofproto_offloaded_stats_delay)) { ++ /* The flow is receiving more than min-revalidate-pps, so keep it. ++ * Or it's a hardware offloaded flow that might take up to X seconds ++ * to update its statistics. Until we are sure the statistics had a ++ * chance to be updated, also keep it. */ + return true; + } + return false; +@@ -2303,7 +2334,7 @@ static enum reval_result + revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey, + const struct dpif_flow_stats *stats, + struct ofpbuf *odp_actions, uint64_t reval_seq, +- struct recirc_refs *recircs, bool offloaded) ++ struct recirc_refs *recircs) + OVS_REQUIRES(ukey->mutex) + { + bool need_revalidate = ukey->reval_seq != reval_seq; +@@ -2321,8 +2352,15 @@ revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey, ? stats->n_bytes - ukey->stats.n_bytes : 0); @@ -59142,9 +59181,21 @@ index 57f94df544..308876d38c 100644 + } + if (need_revalidate) { - if (should_revalidate(udpif, push.n_packets, ukey->stats.used)) { +- if (should_revalidate(udpif, push.n_packets, ukey->stats.used)) { ++ if (should_revalidate(udpif, ukey, push.n_packets)) { if (!ukey->xcache) { -@@ -2434,6 +2466,15 @@ push_dp_ops(struct udpif *udpif, struct ukey_op *ops, size_t n_ops) + ukey->xcache = xlate_cache_new(); + } else { +@@ -2338,7 +2376,7 @@ revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey, + + /* Stats for deleted flows will be attributed upon flow deletion. Skip. */ + if (result != UKEY_DELETE) { +- xlate_push_stats(ukey->xcache, &push, offloaded); ++ xlate_push_stats(ukey->xcache, &push, ukey->offloaded); + ukey->stats = *stats; + ukey->reval_seq = reval_seq; + } +@@ -2434,6 +2472,15 @@ push_dp_ops(struct udpif *udpif, struct ukey_op *ops, size_t n_ops) push->tcp_flags = stats->tcp_flags | op->ukey->stats.tcp_flags; push->n_packets = stats->n_packets - op->ukey->stats.n_packets; push->n_bytes = stats->n_bytes - op->ukey->stats.n_bytes; @@ -59160,7 +59211,7 @@ index 57f94df544..308876d38c 100644 ovs_mutex_unlock(&op->ukey->mutex); } else { push = stats; -@@ -2738,6 +2779,22 @@ revalidate(struct revalidator *revalidator) +@@ -2738,6 +2785,22 @@ revalidate(struct revalidator *revalidator) continue; } @@ -59183,16 +59234,29 @@ index 57f94df544..308876d38c 100644 already_dumped = ukey->dump_seq == dump_seq; if (already_dumped) { /* The flow has already been handled during this flow dump -@@ -2853,7 +2910,7 @@ revalidator_sweep__(struct revalidator *revalidator, bool purge) +@@ -2769,8 +2832,7 @@ revalidate(struct revalidator *revalidator) + result = UKEY_DELETE; + } else { + result = revalidate_ukey(udpif, ukey, &stats, &odp_actions, +- reval_seq, &recircs, +- f->attrs.offloaded); ++ reval_seq, &recircs); + } + ukey->dump_seq = dump_seq; + +@@ -2853,9 +2915,9 @@ revalidator_sweep__(struct revalidator *revalidator, bool purge) } else { struct dpif_flow_stats stats; COVERAGE_INC(revalidate_missed_dp_flow); - memset(&stats, 0, sizeof stats); + memcpy(&stats, &ukey->stats, sizeof stats); result = revalidate_ukey(udpif, ukey, &stats, &odp_actions, - reval_seq, &recircs, false); +- reval_seq, &recircs, false); ++ reval_seq, &recircs); } -@@ -3099,6 +3156,31 @@ upcall_unixctl_purge(struct unixctl_conn *conn, int argc OVS_UNUSED, + if (result != UKEY_KEEP) { + /* Clears 'recircs' if filled by revalidate_ukey(). */ +@@ -3099,6 +3161,31 @@ upcall_unixctl_purge(struct unixctl_conn *conn, int argc OVS_UNUSED, unixctl_command_reply(conn, ""); } @@ -60015,7 +60079,7 @@ index 8143dd965f..b3e575bcd0 100644 static void diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h -index 14b909973d..47e96e62e1 100644 +index 14b909973d..e64ca5b805 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -143,6 +143,8 @@ struct ofproto { @@ -60027,11 +60091,31 @@ index 14b909973d..47e96e62e1 100644 }; void ofproto_init_tables(struct ofproto *, int n_tables); +@@ -536,6 +538,11 @@ extern unsigned ofproto_max_revalidator; + * duration exceeds half of max-revalidator config variable. */ + extern unsigned ofproto_min_revalidate_pps; + ++/* Worst case delay (in ms) it might take before statistics of offloaded flows ++ * are updated. Offloaded flows younger than this delay will always be ++ * revalidated regardless of ofproto_min_revalidate_pps. */ ++extern unsigned ofproto_offloaded_stats_delay; ++ + /* Number of upcall handler and revalidator threads. Only affects the + * ofproto-dpif implementation. */ + extern uint32_t n_handlers, n_revalidators; diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c -index 56aeac7209..933f7de2dc 100644 +index 56aeac7209..8569ce94cb 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c -@@ -549,6 +549,7 @@ ofproto_create(const char *datapath_name, const char *datapath_type, +@@ -310,6 +310,7 @@ unsigned ofproto_flow_limit = OFPROTO_FLOW_LIMIT_DEFAULT; + unsigned ofproto_max_idle = OFPROTO_MAX_IDLE_DEFAULT; + unsigned ofproto_max_revalidator = OFPROTO_MAX_REVALIDATOR_DEFAULT; + unsigned ofproto_min_revalidate_pps = OFPROTO_MIN_REVALIDATE_PPS_DEFAULT; ++unsigned ofproto_offloaded_stats_delay = OFPROTO_OFFLOADED_STATS_DELAY; + + uint32_t n_handlers, n_revalidators; + +@@ -549,6 +550,7 @@ ofproto_create(const char *datapath_name, const char *datapath_type, ovs_mutex_init(&ofproto->vl_mff_map.mutex); cmap_init(&ofproto->vl_mff_map.cmap); @@ -60039,7 +60123,23 @@ index 56aeac7209..933f7de2dc 100644 error = ofproto->ofproto_class->construct(ofproto); if (error) { -@@ -1695,9 +1696,33 @@ ofproto_destroy__(struct ofproto *ofproto) +@@ -725,6 +727,15 @@ ofproto_set_min_revalidate_pps(unsigned min_revalidate_pps) + ofproto_min_revalidate_pps = min_revalidate_pps ? min_revalidate_pps : 1; + } + ++/* Set worst case delay (in ms) it might take before statistics of offloaded ++ * flows are updated. Offloaded flows younger than this delay will always be ++ * revalidated regardless of ofproto_min_revalidate_pps. */ ++void ++ofproto_set_offloaded_stats_delay(unsigned offloaded_stats_delay) ++{ ++ ofproto_offloaded_stats_delay = offloaded_stats_delay; ++} ++ + /* If forward_bpdu is true, the NORMAL action will forward frames with + * reserved (e.g. STP) destination Ethernet addresses. if forward_bpdu is false, + * the NORMAL action will drop these frames. */ +@@ -1695,9 +1706,33 @@ ofproto_destroy__(struct ofproto *ofproto) ofproto->ofproto_class->dealloc(ofproto); } @@ -60076,7 +60176,7 @@ index 56aeac7209..933f7de2dc 100644 static void ofproto_destroy_defer__(struct ofproto *ofproto) OVS_EXCLUDED(ofproto_mutex) -@@ -1705,11 +1730,31 @@ ofproto_destroy_defer__(struct ofproto *ofproto) +@@ -1705,11 +1740,31 @@ ofproto_destroy_defer__(struct ofproto *ofproto) ovsrcu_postpone(ofproto_destroy__, ofproto); } @@ -60109,7 +60209,7 @@ index 56aeac7209..933f7de2dc 100644 struct ofport_usage *usage; if (!p) { -@@ -1717,7 +1762,7 @@ ofproto_destroy(struct ofproto *p, bool del) +@@ -1717,7 +1772,7 @@ ofproto_destroy(struct ofproto *p, bool del) } ofproto_flush__(p, del); @@ -60118,7 +60218,7 @@ index 56aeac7209..933f7de2dc 100644 ofport_destroy(ofport, del); } -@@ -1736,8 +1781,7 @@ ofproto_destroy(struct ofproto *p, bool del) +@@ -1736,8 +1791,7 @@ ofproto_destroy(struct ofproto *p, bool del) p->connmgr = NULL; ovs_mutex_unlock(&ofproto_mutex); @@ -60128,7 +60228,7 @@ index 56aeac7209..933f7de2dc 100644 } /* Destroys the datapath with the respective 'name' and 'type'. With the Linux -@@ -2782,7 +2826,7 @@ init_ports(struct ofproto *p) +@@ -2782,7 +2836,7 @@ init_ports(struct ofproto *p) { struct ofproto_port_dump dump; struct ofproto_port ofproto_port; @@ -60137,7 +60237,7 @@ index 56aeac7209..933f7de2dc 100644 OFPROTO_PORT_FOR_EACH (&ofproto_port, &dump, p) { const char *name = ofproto_port.name; -@@ -2813,7 +2857,7 @@ init_ports(struct ofproto *p) +@@ -2813,7 +2867,7 @@ init_ports(struct ofproto *p) } } @@ -60146,7 +60246,7 @@ index 56aeac7209..933f7de2dc 100644 struct iface_hint *iface_hint = node->data; if (!strcmp(iface_hint->br_name, p->name)) { -@@ -2929,6 +2973,9 @@ ofproto_rule_destroy__(struct rule *rule) +@@ -2929,6 +2983,9 @@ ofproto_rule_destroy__(struct rule *rule) cls_rule_destroy(CONST_CAST(struct cls_rule *, &rule->cr)); rule_actions_destroy(rule_get_actions(rule)); ovs_mutex_destroy(&rule->mutex); @@ -60156,7 +60256,7 @@ index 56aeac7209..933f7de2dc 100644 rule->ofproto->ofproto_class->rule_dealloc(rule); } -@@ -3069,6 +3116,9 @@ group_destroy_cb(struct ofgroup *group) +@@ -3069,6 +3126,9 @@ group_destroy_cb(struct ofgroup *group) &group->props)); ofputil_bucket_list_destroy(CONST_CAST(struct ovs_list *, &group->buckets)); @@ -60166,7 +60266,7 @@ index 56aeac7209..933f7de2dc 100644 group->ofproto->ofproto_class->group_dealloc(group); } -@@ -5271,10 +5321,15 @@ ofproto_rule_create(struct ofproto *ofproto, struct cls_rule *cr, +@@ -5271,10 +5331,15 @@ ofproto_rule_create(struct ofproto *ofproto, struct cls_rule *cr, struct rule *rule; enum ofperr error; @@ -60182,7 +60282,7 @@ index 56aeac7209..933f7de2dc 100644 VLOG_WARN_RL(&rl, "%s: failed to allocate a rule.", ofproto->name); return OFPERR_OFPFMFC_UNKNOWN; } -@@ -6797,9 +6852,9 @@ static void +@@ -6797,9 +6862,9 @@ static void meter_delete_all(struct ofproto *ofproto) OVS_REQUIRES(ofproto_mutex) { @@ -60194,7 +60294,7 @@ index 56aeac7209..933f7de2dc 100644 hmap_remove(&ofproto->meters, &meter->node); meter_destroy(ofproto, meter); } -@@ -7339,8 +7394,13 @@ init_group(struct ofproto *ofproto, const struct ofputil_group_mod *gm, +@@ -7339,8 +7404,13 @@ init_group(struct ofproto *ofproto, const struct ofputil_group_mod *gm, return OFPERR_OFPGMFC_BAD_TYPE; } @@ -60208,7 +60308,7 @@ index 56aeac7209..933f7de2dc 100644 VLOG_WARN_RL(&rl, "%s: failed to allocate group", ofproto->name); return OFPERR_OFPGMFC_OUT_OF_GROUPS; } -@@ -7377,6 +7437,7 @@ init_group(struct ofproto *ofproto, const struct ofputil_group_mod *gm, +@@ -7377,6 +7447,7 @@ init_group(struct ofproto *ofproto, const struct ofputil_group_mod *gm, &(*ofgroup)->props)); ofputil_bucket_list_destroy(CONST_CAST(struct ovs_list *, &(*ofgroup)->buckets)); @@ -60216,7 +60316,7 @@ index 56aeac7209..933f7de2dc 100644 ofproto->ofproto_class->group_dealloc(*ofgroup); } return error; -@@ -8902,7 +8963,7 @@ eviction_group_hash_rule(struct rule *rule) +@@ -8902,7 +8973,7 @@ eviction_group_hash_rule(struct rule *rule) hash = table->eviction_group_id_basis; miniflow_expand(rule->cr.match.flow, &flow); for (sf = table->eviction_fields; @@ -60225,7 +60325,7 @@ index 56aeac7209..933f7de2dc 100644 sf++) { if (mf_are_prereqs_ok(sf->field, &flow, NULL)) { -@@ -9138,8 +9199,8 @@ oftable_configure_eviction(struct oftable *table, unsigned int eviction, +@@ -9138,8 +9209,8 @@ oftable_configure_eviction(struct oftable *table, unsigned int eviction, /* Destroy existing eviction groups, then destroy and recreate data * structures to recover memory. */ @@ -60237,10 +60337,26 @@ index 56aeac7209..933f7de2dc 100644 } hmap_destroy(&table->eviction_groups_by_id); diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h -index b0262da2df..4e15167ab7 100644 +index b0262da2df..fa7973ac72 100644 --- a/ofproto/ofproto.h +++ b/ofproto/ofproto.h -@@ -563,6 +563,10 @@ int ofproto_port_get_cfm_status(const struct ofproto *, +@@ -311,6 +311,7 @@ int ofproto_port_dump_done(struct ofproto_port_dump *); + #define OFPROTO_MAX_IDLE_DEFAULT 10000 /* ms */ + #define OFPROTO_MAX_REVALIDATOR_DEFAULT 500 /* ms */ + #define OFPROTO_MIN_REVALIDATE_PPS_DEFAULT 5 ++#define OFPROTO_OFFLOADED_STATS_DELAY 2000 /* ms */ + + const char *ofproto_port_open_type(const struct ofproto *, + const char *port_type); +@@ -340,6 +341,7 @@ void ofproto_set_flow_limit(unsigned limit); + void ofproto_set_max_idle(unsigned max_idle); + void ofproto_set_max_revalidator(unsigned max_revalidator); + void ofproto_set_min_revalidate_pps(unsigned min_revalidate_pps); ++void ofproto_set_offloaded_stats_delay(unsigned offloaded_stats_delay); + void ofproto_set_forward_bpdu(struct ofproto *, bool forward_bpdu); + void ofproto_set_mac_table_config(struct ofproto *, unsigned idle_time, + size_t max_entries); +@@ -563,6 +565,10 @@ int ofproto_port_get_cfm_status(const struct ofproto *, enum ofputil_table_miss ofproto_table_get_miss_config(const struct ofproto *, uint8_t table_id); @@ -70157,7 +70273,7 @@ index 37cc72d401..1032089fc2 100644 if (fscset->bridge == br->br_cfg) { ovsrec_flow_sample_collector_set_delete(fscset); diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c -index 5223aa8970..793bad1243 100644 +index 5223aa8970..81f073b1cf 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -543,13 +543,13 @@ bridge_exit(bool delete_datapath) @@ -70234,7 +70350,17 @@ index 5223aa8970..793bad1243 100644 int sflow_bridge_number; size_t n_managers; -@@ -875,7 +875,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) +@@ -832,6 +832,9 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) + ofproto_set_min_revalidate_pps( + smap_get_uint(&ovs_cfg->other_config, "min-revalidate-pps", + OFPROTO_MIN_REVALIDATE_PPS_DEFAULT)); ++ ofproto_set_offloaded_stats_delay( ++ smap_get_uint(&ovs_cfg->other_config, "offloaded-stats-delay", ++ OFPROTO_OFFLOADED_STATS_DELAY)); + ofproto_set_vlan_limit(smap_get_int(&ovs_cfg->other_config, "vlan-limit", + LEGACY_MAX_VLAN_HEADERS)); + ofproto_set_bundle_idle_timeout(smap_get_uint(&ovs_cfg->other_config, +@@ -875,7 +878,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) * - Create ofprotos that are missing. * * - Add ports that are missing. */ @@ -70243,7 +70369,7 @@ index 5223aa8970..793bad1243 100644 if (!br->ofproto) { int error; -@@ -1020,7 +1020,7 @@ bridge_delete_or_reconfigure_ports(struct bridge *br) +@@ -1020,7 +1023,7 @@ bridge_delete_or_reconfigure_ports(struct bridge *br) struct ofproto_port_dump dump; struct sset ofproto_ports; @@ -70252,7 +70378,7 @@ index 5223aa8970..793bad1243 100644 /* List of "ofp_port"s to delete. We make a list instead of deleting them * right away because ofproto implementations aren't necessarily able to -@@ -1132,10 +1132,10 @@ bridge_delete_or_reconfigure_ports(struct bridge *br) +@@ -1132,10 +1135,10 @@ bridge_delete_or_reconfigure_ports(struct bridge *br) * device destroyed via "tunctl -d", a physical Ethernet device * whose module was just unloaded via "rmmod", or a virtual NIC for a * VM whose VM was just terminated. */ @@ -70266,7 +70392,7 @@ index 5223aa8970..793bad1243 100644 if (!sset_contains(&ofproto_ports, iface->name)) { iface_destroy__(iface); } -@@ -1967,7 +1967,7 @@ port_is_bond_fake_iface(const struct port *port) +@@ -1967,7 +1970,7 @@ port_is_bond_fake_iface(const struct port *port) static void add_del_bridges(const struct ovsrec_open_vswitch *cfg) { @@ -70275,7 +70401,7 @@ index 5223aa8970..793bad1243 100644 struct shash_node *node; struct shash new_br; size_t i; -@@ -1993,7 +1993,7 @@ add_del_bridges(const struct ovsrec_open_vswitch *cfg) +@@ -1993,7 +1996,7 @@ add_del_bridges(const struct ovsrec_open_vswitch *cfg) /* Get rid of deleted bridges or those whose types have changed. * Update 'cfg' of bridges that still exist. */ @@ -70284,7 +70410,7 @@ index 5223aa8970..793bad1243 100644 br->cfg = shash_find_data(&new_br, br->name); if (!br->cfg || strcmp(br->type, ofproto_normalize_type( br->cfg->datapath_type))) { -@@ -2660,6 +2660,7 @@ iface_refresh_stats(struct iface *iface) +@@ -2660,6 +2663,7 @@ iface_refresh_stats(struct iface *iface) IFACE_STAT(tx_512_to_1023_packets, "tx_512_to_1023_packets") \ IFACE_STAT(tx_1024_to_1522_packets, "tx_1024_to_1522_packets") \ IFACE_STAT(tx_1523_to_max_packets, "tx_1523_to_max_packets") \ @@ -70292,7 +70418,7 @@ index 5223aa8970..793bad1243 100644 IFACE_STAT(tx_multicast_packets, "tx_multicast_packets") \ IFACE_STAT(rx_broadcast_packets, "rx_broadcast_packets") \ IFACE_STAT(tx_broadcast_packets, "tx_broadcast_packets") \ -@@ -3266,13 +3267,13 @@ bridge_run(void) +@@ -3266,13 +3270,13 @@ bridge_run(void) if (ovsdb_idl_is_lock_contended(idl)) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); @@ -70308,7 +70434,7 @@ index 5223aa8970..793bad1243 100644 bridge_destroy(br, false); } /* Since we will not be running system_stats_run() in this process -@@ -3594,13 +3595,13 @@ static void +@@ -3594,13 +3598,13 @@ static void bridge_destroy(struct bridge *br, bool del) { if (br) { @@ -70326,7 +70452,7 @@ index 5223aa8970..793bad1243 100644 mirror_destroy(mirror); } -@@ -3746,11 +3747,11 @@ static void +@@ -3746,11 +3750,11 @@ static void bridge_del_ports(struct bridge *br, const struct shash *wanted_ports) { struct shash_node *port_node; @@ -70340,7 +70466,7 @@ index 5223aa8970..793bad1243 100644 port->cfg = shash_find_data(wanted_ports, port->name); if (!port->cfg) { port_destroy(port); -@@ -4211,7 +4212,7 @@ bridge_configure_aa(struct bridge *br) +@@ -4211,7 +4215,7 @@ bridge_configure_aa(struct bridge *br) const struct ovsdb_datum *mc; struct ovsrec_autoattach *auto_attach = br->cfg->auto_attach; struct aa_settings aa_s; @@ -70349,7 +70475,7 @@ index 5223aa8970..793bad1243 100644 size_t i; if (!auto_attach) { -@@ -4227,7 +4228,7 @@ bridge_configure_aa(struct bridge *br) +@@ -4227,7 +4231,7 @@ bridge_configure_aa(struct bridge *br) mc = ovsrec_autoattach_get_mappings(auto_attach, OVSDB_TYPE_INTEGER, OVSDB_TYPE_INTEGER); @@ -70358,7 +70484,7 @@ index 5223aa8970..793bad1243 100644 union ovsdb_atom atom; atom.integer = m->isid; -@@ -4341,12 +4342,12 @@ static void +@@ -4341,12 +4345,12 @@ static void bridge_aa_refresh_queued(struct bridge *br) { struct ovs_list *list = xmalloc(sizeof *list); @@ -70373,7 +70499,7 @@ index 5223aa8970..793bad1243 100644 struct port *port; VLOG_INFO("ifname=%s, vlan=%u, oper=%u", node->port_name, node->vlan, -@@ -4387,7 +4388,7 @@ port_create(struct bridge *br, const struct ovsrec_port *cfg) +@@ -4387,7 +4391,7 @@ port_create(struct bridge *br, const struct ovsrec_port *cfg) static void port_del_ifaces(struct port *port) { @@ -70382,7 +70508,7 @@ index 5223aa8970..793bad1243 100644 struct sset new_ifaces; size_t i; -@@ -4398,7 +4399,7 @@ port_del_ifaces(struct port *port) +@@ -4398,7 +4402,7 @@ port_del_ifaces(struct port *port) } /* Get rid of deleted interfaces. */ @@ -70391,7 +70517,7 @@ index 5223aa8970..793bad1243 100644 if (!sset_contains(&new_ifaces, iface->name)) { iface_destroy(iface); } -@@ -4412,13 +4413,13 @@ port_destroy(struct port *port) +@@ -4412,13 +4416,13 @@ port_destroy(struct port *port) { if (port) { struct bridge *br = port->bridge; @@ -70407,7 +70533,7 @@ index 5223aa8970..793bad1243 100644 iface_destroy__(iface); } -@@ -5013,12 +5014,12 @@ bridge_configure_mirrors(struct bridge *br) +@@ -5013,12 +5017,12 @@ bridge_configure_mirrors(struct bridge *br) { const struct ovsdb_datum *mc; unsigned long *flood_vlans; @@ -70423,10 +70549,30 @@ index 5223aa8970..793bad1243 100644 atom.uuid = m->uuid; diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml -index 0c66326171..87d8f3e67a 100644 +index 0c66326171..0c8534f142 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml -@@ -2312,7 +2312,7 @@ +@@ -222,6 +222,19 @@ +
+ + ++++ Set worst case delay (in ms) it might take before statistics of ++ offloaded flows are updated. Offloaded flows younger than this ++ delay will always be revalidated regardless of ++ . ++
++++ The default is 2000. ++
+++@@ -2312,7 +2325,7 @@ lowest port-id is elected as the root.