diff --git a/SOURCES/openvswitch-2.17.0.patch b/SOURCES/openvswitch-2.17.0.patch index fc7cc38..caa6ae8 100644 --- a/SOURCES/openvswitch-2.17.0.patch +++ b/SOURCES/openvswitch-2.17.0.patch @@ -61128,9 +61128,18 @@ index 57f94df544..53b47073ad 100644 * netdev, flow state (offloaded/kernel path), flow_pps_rate. */ diff --git a/ofproto/ofproto-dpif-xlate-cache.c b/ofproto/ofproto-dpif-xlate-cache.c -index dcc91cb380..9224ee2e6d 100644 +index dcc91cb380..2e1fcb3a6f 100644 --- a/ofproto/ofproto-dpif-xlate-cache.c +++ b/ofproto/ofproto-dpif-xlate-cache.c +@@ -125,7 +125,7 @@ xlate_push_stats_entry(struct xc_entry *entry, + case XC_LEARN: { + enum ofperr error; + error = ofproto_flow_mod_learn(entry->learn.ofm, true, +- entry->learn.limit, NULL); ++ entry->learn.limit, NULL, stats->used); + if (error) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "xcache LEARN action execution failed."); @@ -209,6 +209,7 @@ xlate_cache_clear_entry(struct xc_entry *entry) { switch (entry->type) { @@ -61164,7 +61173,7 @@ index 114aff8ea3..0fc6d2ea60 100644 enum xc_type type; union { diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c -index 578cbfe581..2b1611c912 100644 +index 578cbfe581..c0d1cfa94b 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -66,6 +66,7 @@ @@ -61328,7 +61337,7 @@ index 578cbfe581..2b1611c912 100644 free(xbundle->name); free(xbundle); } -@@ -1515,7 +1598,7 @@ xlate_lookup_ofproto_(const struct dpif_backer *backer, +@@ -1515,13 +1598,14 @@ xlate_lookup_ofproto_(const struct dpif_backer *backer, if (OVS_UNLIKELY(!recirc_id_node)) { if (errorp) { *errorp = xasprintf("no recirculation data for recirc_id " @@ -61337,7 +61346,43 @@ index 578cbfe581..2b1611c912 100644 } return NULL; } -@@ -1556,8 +1639,8 @@ xlate_lookup_ofproto_(const struct dpif_backer *backer, + + ofp_port_t in_port = recirc_id_node->state.metadata.in_port; +- if (in_port != OFPP_NONE && in_port != OFPP_CONTROLLER) { ++ if (in_port != OFPP_NONE && in_port != OFPP_CONTROLLER && ++ !uuid_is_zero(&recirc_id_node->state.xport_uuid)) { + struct uuid xport_uuid = recirc_id_node->state.xport_uuid; + xport = xport_lookup_by_uuid(xcfg, &xport_uuid); + if (xport && xport->xbridge && xport->xbridge->ofproto) { +@@ -1532,11 +1616,19 @@ xlate_lookup_ofproto_(const struct dpif_backer *backer, + * that the packet originated from the controller via an OpenFlow + * "packet-out". The right thing to do is to find just the + * ofproto. There is no xport, which is OK. ++ * Also a zeroed xport_uuid with a valid in_port, means that ++ * the packet originated from OFPP_CONTROLLER passed ++ * through a patch port. + * + * OFPP_NONE can also indicate that a bond caused recirculation. */ + struct uuid uuid = recirc_id_node->state.ofproto_uuid; + const struct xbridge *bridge = xbridge_lookup_by_uuid(xcfg, &uuid); ++ + if (bridge && bridge->ofproto) { ++ if (in_port != OFPP_CONTROLLER && in_port != OFPP_NONE && ++ !get_ofp_port(bridge, in_port)) { ++ goto xport_lookup; ++ } + if (errorp) { + *errorp = NULL; + } +@@ -1549,6 +1641,7 @@ xlate_lookup_ofproto_(const struct dpif_backer *backer, + } + } + ++xport_lookup: + xport = xport_lookup(xcfg, tnl_port_should_receive(flow) + ? tnl_port_receive(flow) + : odp_port_to_ofport(backer, flow->in_port.odp_port)); +@@ -1556,8 +1649,8 @@ xlate_lookup_ofproto_(const struct dpif_backer *backer, if (errorp) { *errorp = (tnl_port_should_receive(flow) ? xstrdup("no OpenFlow tunnel port for this packet") @@ -61348,7 +61393,7 @@ index 578cbfe581..2b1611c912 100644 } return NULL; } -@@ -1639,7 +1722,7 @@ xbridge_lookup(struct xlate_cfg *xcfg, const struct ofproto_dpif *ofproto) +@@ -1639,7 +1732,7 @@ xbridge_lookup(struct xlate_cfg *xcfg, const struct ofproto_dpif *ofproto) xbridges = &xcfg->xbridges; @@ -61357,7 +61402,7 @@ index 578cbfe581..2b1611c912 100644 xbridges) { if (xbridge->ofproto == ofproto) { return xbridge; -@@ -1661,6 +1744,23 @@ xbridge_lookup_by_uuid(struct xlate_cfg *xcfg, const struct uuid *uuid) +@@ -1661,6 +1754,23 @@ xbridge_lookup_by_uuid(struct xlate_cfg *xcfg, const struct uuid *uuid) return NULL; } @@ -61381,7 +61426,7 @@ index 578cbfe581..2b1611c912 100644 static struct xbundle * xbundle_lookup(struct xlate_cfg *xcfg, const struct ofbundle *ofbundle) { -@@ -1894,8 +1994,8 @@ group_is_alive(const struct xlate_ctx *ctx, uint32_t group_id, int depth) +@@ -1894,8 +2004,8 @@ group_is_alive(const struct xlate_ctx *ctx, uint32_t group_id, int depth) #define MAX_LIVENESS_RECURSION 128 /* Arbitrary limit */ static bool @@ -61392,7 +61437,7 @@ index 578cbfe581..2b1611c912 100644 { if (depth >= MAX_LIVENESS_RECURSION) { xlate_report_error(ctx, "bucket chaining exceeded %d links", -@@ -1903,6 +2003,12 @@ bucket_is_alive(const struct xlate_ctx *ctx, +@@ -1903,6 +2013,12 @@ bucket_is_alive(const struct xlate_ctx *ctx, return false; } @@ -61405,7 +61450,7 @@ index 578cbfe581..2b1611c912 100644 return (!ofputil_bucket_has_liveness(bucket) || (bucket->watch_port != OFPP_ANY && bucket->watch_port != OFPP_CONTROLLER -@@ -1943,7 +2049,7 @@ group_first_live_bucket(const struct xlate_ctx *ctx, +@@ -1943,7 +2059,7 @@ group_first_live_bucket(const struct xlate_ctx *ctx, { struct ofputil_bucket *bucket; LIST_FOR_EACH (bucket, list_node, &group->up.buckets) { @@ -61414,7 +61459,7 @@ index 578cbfe581..2b1611c912 100644 return bucket; } xlate_report_bucket_not_live(ctx, bucket); -@@ -1962,7 +2068,7 @@ group_best_live_bucket(const struct xlate_ctx *ctx, +@@ -1962,7 +2078,7 @@ group_best_live_bucket(const struct xlate_ctx *ctx, struct ofputil_bucket *bucket; LIST_FOR_EACH (bucket, list_node, &group->up.buckets) { @@ -61423,7 +61468,7 @@ index 578cbfe581..2b1611c912 100644 uint32_t score = (hash_int(bucket->bucket_id, basis) & 0xffff) * bucket->weight; if (score >= best_score) { -@@ -2125,9 +2231,14 @@ mirror_packet(struct xlate_ctx *ctx, struct xbundle *xbundle, +@@ -2125,9 +2241,14 @@ mirror_packet(struct xlate_ctx *ctx, struct xbundle *xbundle, int snaplen; /* Get the details of the mirror represented by the rightmost 1-bit. */ @@ -61441,7 +61486,7 @@ index 578cbfe581..2b1611c912 100644 /* If this mirror selects on the basis of VLAN, and it does not select -@@ -2444,9 +2555,18 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle, +@@ -2444,9 +2565,18 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle, /* In case recirculation is not actually in use, 'xr.recirc_id' * will be set to '0', since a valid 'recirc_id' can * not be zero. */ @@ -61463,7 +61508,7 @@ index 578cbfe581..2b1611c912 100644 if (xr.recirc_id) { /* Use recirculation instead of output. */ use_recirc = true; -@@ -3015,7 +3135,7 @@ xlate_normal(struct xlate_ctx *ctx) +@@ -3015,7 +3145,7 @@ xlate_normal(struct xlate_ctx *ctx) bool is_grat_arp = is_gratuitous_arp(flow, wc); if (ctx->xin->allow_side_effects && flow->packet_type == htonl(PT_ETH) @@ -61472,7 +61517,7 @@ index 578cbfe581..2b1611c912 100644 ) { update_learning_table(ctx, in_xbundle, flow->dl_src, vlan, is_grat_arp); -@@ -3024,12 +3144,14 @@ xlate_normal(struct xlate_ctx *ctx) +@@ -3024,12 +3154,14 @@ xlate_normal(struct xlate_ctx *ctx) struct xc_entry *entry; /* Save just enough info to update mac learning table later. */ @@ -61493,7 +61538,7 @@ index 578cbfe581..2b1611c912 100644 } /* Determine output bundle. */ -@@ -3048,7 +3170,6 @@ xlate_normal(struct xlate_ctx *ctx) +@@ -3048,7 +3180,6 @@ xlate_normal(struct xlate_ctx *ctx) */ ctx->xout->slow |= SLOW_ACTION; @@ -61501,7 +61546,7 @@ index 578cbfe581..2b1611c912 100644 if (mcast_snooping_is_membership(flow->tp_src) || mcast_snooping_is_query(flow->tp_src)) { if (ctx->xin->allow_side_effects && ctx->xin->packet) { -@@ -3523,6 +3644,9 @@ propagate_tunnel_data_to_flow__(struct flow *dst_flow, +@@ -3523,6 +3654,9 @@ propagate_tunnel_data_to_flow__(struct flow *dst_flow, dst_flow->dl_dst = dmac; dst_flow->dl_src = smac; @@ -61511,7 +61556,7 @@ index 578cbfe581..2b1611c912 100644 dst_flow->packet_type = htonl(PT_ETH); dst_flow->nw_dst = src_flow->tunnel.ip_dst; dst_flow->nw_src = src_flow->tunnel.ip_src; -@@ -3654,14 +3778,27 @@ native_tunnel_output(struct xlate_ctx *ctx, const struct xport *xport, +@@ -3654,14 +3788,27 @@ native_tunnel_output(struct xlate_ctx *ctx, const struct xport *xport, err = tnl_neigh_lookup(out_dev->xbridge->name, &d_ip6, &dmac); if (err) { @@ -61541,7 +61586,7 @@ index 578cbfe581..2b1611c912 100644 } return err; } -@@ -3827,20 +3964,17 @@ static void +@@ -3827,20 +3974,17 @@ static void patch_port_output(struct xlate_ctx *ctx, const struct xport *in_dev, struct xport *out_dev, bool is_last_action) { @@ -61569,7 +61614,7 @@ index 578cbfe581..2b1611c912 100644 flow->in_port.ofp_port = out_dev->ofp_port; flow->metadata = htonll(0); memset(&flow->tunnel, 0, sizeof flow->tunnel); -@@ -3879,14 +4013,15 @@ patch_port_output(struct xlate_ctx *ctx, const struct xport *in_dev, +@@ -3879,14 +4023,15 @@ patch_port_output(struct xlate_ctx *ctx, const struct xport *in_dev, } else { /* Forwarding is disabled by STP and RSTP. Let OFPP_NORMAL and * the learning action look at the packet, then drop it. */ @@ -61587,7 +61632,7 @@ index 578cbfe581..2b1611c912 100644 ctx->odp_actions->size = old_size; /* Undo changes that may have been done for freezing. */ -@@ -3898,18 +4033,15 @@ patch_port_output(struct xlate_ctx *ctx, const struct xport *in_dev, +@@ -3898,18 +4043,15 @@ patch_port_output(struct xlate_ctx *ctx, const struct xport *in_dev, if (independent_mirrors) { ctx->mirrors = old_mirrors; } @@ -61610,7 +61655,7 @@ index 578cbfe581..2b1611c912 100644 /* The out bridge popping MPLS should have no effect on the original * bridge. */ -@@ -4099,6 +4231,16 @@ xport_has_ip(const struct xport *xport) +@@ -4099,6 +4241,16 @@ xport_has_ip(const struct xport *xport) return n_in6 ? true : false; } @@ -61627,7 +61672,7 @@ index 578cbfe581..2b1611c912 100644 static bool terminate_native_tunnel(struct xlate_ctx *ctx, const struct xport *xport, struct flow *flow, struct flow_wildcards *wc, -@@ -4119,9 +4261,7 @@ terminate_native_tunnel(struct xlate_ctx *ctx, const struct xport *xport, +@@ -4119,9 +4271,7 @@ terminate_native_tunnel(struct xlate_ctx *ctx, const struct xport *xport, /* If no tunnel port was found and it's about an ARP or ICMPv6 packet, * do tunnel neighbor snooping. */ if (*tnl_port == ODPP_NONE && @@ -61638,7 +61683,7 @@ index 578cbfe581..2b1611c912 100644 tnl_neigh_snoop(flow, wc, ctx->xbridge->name, ctx->xin->allow_side_effects); } else if (*tnl_port != ODPP_NONE && -@@ -4151,7 +4291,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, +@@ -4151,7 +4301,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, const struct xport *xport = get_ofp_port(ctx->xbridge, ofp_port); struct flow_wildcards *wc = ctx->wc; struct flow *flow = &ctx->xin->flow; @@ -61647,7 +61692,7 @@ index 578cbfe581..2b1611c912 100644 union flow_vlan_hdr flow_vlans[FLOW_MAX_VLAN_HEADERS]; uint8_t flow_nw_tos; odp_port_t out_port, odp_port, odp_tnl_port; -@@ -4165,7 +4305,6 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, +@@ -4165,7 +4315,6 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, /* If 'struct flow' gets additional metadata, we'll need to zero it out * before traversing a patch port. */ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 42); @@ -61655,7 +61700,7 @@ index 578cbfe581..2b1611c912 100644 if (!check_output_prerequisites(ctx, xport, flow, check_stp)) { return; -@@ -4176,6 +4315,10 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, +@@ -4176,6 +4325,10 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, if (xport->pt_mode == NETDEV_PT_LEGACY_L3) { flow->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE, ntohs(flow->dl_type)); @@ -61666,7 +61711,7 @@ index 578cbfe581..2b1611c912 100644 } } -@@ -4205,7 +4348,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, +@@ -4205,7 +4358,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, * the Logical (tunnel) Port are not visible for any further * matches, while explicit set actions on tunnel metadata are. */ @@ -61675,7 +61720,7 @@ index 578cbfe581..2b1611c912 100644 odp_port = tnl_port_send(xport->ofport, flow, ctx->wc); if (odp_port == ODPP_NONE) { xlate_report(ctx, OFT_WARN, "Tunneling decided against output"); -@@ -4236,7 +4379,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, +@@ -4236,7 +4389,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, tnl_type = tnl_port_get_type(xport->ofport); commit_odp_tunnel_action(flow, &ctx->base_flow, ctx->odp_actions, tnl_type); @@ -61684,7 +61729,7 @@ index 578cbfe581..2b1611c912 100644 } } else { odp_port = xport->odp_port; -@@ -4280,7 +4423,8 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, +@@ -4280,7 +4433,8 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, /* Output to native tunnel port. */ native_tunnel_output(ctx, xport, flow, odp_port, truncate, is_last_action); @@ -61694,7 +61739,7 @@ index 578cbfe581..2b1611c912 100644 } else if (terminate_native_tunnel(ctx, xport, flow, wc, &odp_tnl_port)) { -@@ -4323,7 +4467,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, +@@ -4323,7 +4477,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, xport->xbundle)); } @@ -61703,7 +61748,7 @@ index 578cbfe581..2b1611c912 100644 /* Restore flow */ memcpy(flow->vlans, flow_vlans, sizeof flow->vlans); flow->nw_tos = flow_nw_tos; -@@ -4331,6 +4475,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, +@@ -4331,6 +4485,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, flow->dl_src = flow_dl_src; flow->packet_type = flow_packet_type; flow->dl_type = flow_dl_type; @@ -61711,7 +61756,7 @@ index 578cbfe581..2b1611c912 100644 } static void -@@ -4678,7 +4823,7 @@ pick_dp_hash_select_group(struct xlate_ctx *ctx, struct group_dpif *group) +@@ -4678,7 +4833,7 @@ pick_dp_hash_select_group(struct xlate_ctx *ctx, struct group_dpif *group) for (int i = 0; i <= hash_mask; i++) { struct ofputil_bucket *b = group->hash_map[(dp_hash + i) & hash_mask]; @@ -61720,7 +61765,7 @@ index 578cbfe581..2b1611c912 100644 return b; } } -@@ -5120,6 +5265,7 @@ compose_dec_ttl(struct xlate_ctx *ctx, struct ofpact_cnt_ids *ids) +@@ -5120,6 +5275,7 @@ compose_dec_ttl(struct xlate_ctx *ctx, struct ofpact_cnt_ids *ids) } ctx->wc->masks.nw_ttl = 0xff; @@ -61728,15 +61773,15 @@ index 578cbfe581..2b1611c912 100644 if (flow->nw_ttl > 1) { flow->nw_ttl--; return false; -@@ -5308,15 +5454,15 @@ xlate_output_reg_action(struct xlate_ctx *ctx, +@@ -5308,15 +5464,15 @@ xlate_output_reg_action(struct xlate_ctx *ctx, { uint64_t port = mf_get_subfield(&or->src, &ctx->xin->flow); if (port <= UINT16_MAX) { - xlate_report(ctx, OFT_DETAIL, "output port is %"PRIu64, port); +- +- union mf_subvalue value; + union mf_subvalue *value = xmalloc(sizeof *value); -- union mf_subvalue value; -- - memset(&value, 0xff, sizeof value); - mf_write_subfield_flow(&or->src, &value, &ctx->wc->masks); + xlate_report(ctx, OFT_DETAIL, "output port is %"PRIu64, port); @@ -61749,7 +61794,25 @@ index 578cbfe581..2b1611c912 100644 } else { xlate_report(ctx, OFT_WARN, "output port %"PRIu64" is out of range", port); -@@ -5622,7 +5768,8 @@ xlate_sample_action(struct xlate_ctx *ctx, +@@ -5525,8 +5681,16 @@ xlate_learn_action(struct xlate_ctx *ctx, const struct ofpact_learn *learn) + if (!error) { + bool success = true; + if (ctx->xin->allow_side_effects) { ++ long long int last_used; ++ ++ if (ctx->xin->resubmit_stats) { ++ last_used = ctx->xin->resubmit_stats->used; ++ } else { ++ last_used = time_msec(); ++ } + error = ofproto_flow_mod_learn(ofm, ctx->xin->xcache != NULL, +- learn->limit, &success); ++ learn->limit, &success, ++ last_used); + } else if (learn->limit) { + if (!ofm->temp_rule + || ofm->temp_rule->state != RULE_INSERTED) { +@@ -5622,7 +5786,8 @@ xlate_sample_action(struct xlate_ctx *ctx, /* Scale the probability from 16-bit to 32-bit while representing * the same percentage. */ @@ -61759,7 +61822,7 @@ index 578cbfe581..2b1611c912 100644 /* If ofp_port in flow sample action is equel to ofp_port, * this sample action is a input port action. */ -@@ -5656,13 +5803,15 @@ xlate_sample_action(struct xlate_ctx *ctx, +@@ -5656,13 +5821,15 @@ xlate_sample_action(struct xlate_ctx *ctx, struct flow *flow = &ctx->xin->flow; tnl_port_send(xport->ofport, flow, ctx->wc); if (!ovs_native_tunneling_is_on(ctx->xbridge->ofproto)) { @@ -61777,7 +61840,7 @@ index 578cbfe581..2b1611c912 100644 } } else { xlate_report_error(ctx, -@@ -5772,21 +5921,12 @@ clone_xlate_actions(const struct ofpact *actions, size_t actions_len, +@@ -5772,21 +5939,12 @@ clone_xlate_actions(const struct ofpact *actions, size_t actions_len, struct xlate_ctx *ctx, bool is_last_action, bool group_bucket_action OVS_UNUSED) { @@ -61802,7 +61865,7 @@ index 578cbfe581..2b1611c912 100644 do_xlate_actions(actions, actions_len, ctx, is_last_action, false); if (!ctx->freezing) { xlate_action_set(ctx); -@@ -5801,7 +5941,8 @@ clone_xlate_actions(const struct ofpact *actions, size_t actions_len, +@@ -5801,7 +5959,8 @@ clone_xlate_actions(const struct ofpact *actions, size_t actions_len, * avoid emitting those actions twice. Once inside * the clone, another time for the action after clone. */ xlate_commit_actions(ctx); @@ -61812,7 +61875,7 @@ index 578cbfe581..2b1611c912 100644 bool old_was_mpls = ctx->was_mpls; bool old_conntracked = ctx->conntracked; -@@ -5858,14 +5999,10 @@ dp_clone_done: +@@ -5858,14 +6017,10 @@ dp_clone_done: ctx->was_mpls = old_was_mpls; /* Restore the 'base_flow' for the next action. */ @@ -61829,7 +61892,7 @@ index 578cbfe581..2b1611c912 100644 } static void -@@ -6241,8 +6378,8 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc, +@@ -6241,8 +6396,8 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc, { uint16_t zone; if (ofc->zone_src.field) { @@ -61840,7 +61903,7 @@ index 578cbfe581..2b1611c912 100644 zone = mf_get_subfield(&ofc->zone_src, &ctx->xin->flow); if (ctx->xin->frozen_state) { -@@ -6252,12 +6389,13 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc, +@@ -6252,12 +6407,13 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc, * which will invalidate the megaflow with old the recirc_id. */ if (!mf_is_frozen_metadata(ofc->zone_src.field)) { @@ -61856,7 +61919,7 @@ index 578cbfe581..2b1611c912 100644 } else { zone = ofc->zone_imm; } -@@ -6347,16 +6485,16 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, +@@ -6347,16 +6503,16 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, const struct ofpact *remaining_acts, size_t remaining_acts_len) { @@ -61877,7 +61940,7 @@ index 578cbfe581..2b1611c912 100644 &ctx->xin->flow); /* If datapath doesn't support check_pkt_len action, then set the * SLOW_ACTION flag. If we don't set SLOW_ACTION, we -@@ -6366,22 +6504,17 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, +@@ -6366,22 +6522,17 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, * the packet length. This results in wrong actions being applied. */ ctx->xout->slow |= SLOW_ACTION; @@ -61905,7 +61968,7 @@ index 578cbfe581..2b1611c912 100644 bool old_was_mpls = ctx->was_mpls; bool old_conntracked = ctx->conntracked; -@@ -6391,8 +6524,8 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, +@@ -6391,8 +6542,8 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, check_pkt_larger->pkt_len); size_t offset_attr = nl_msg_start_nested( ctx->odp_actions, OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER); @@ -61916,7 +61979,7 @@ index 578cbfe581..2b1611c912 100644 do_xlate_actions(remaining_acts, remaining_acts_len, ctx, true, false); if (!ctx->freezing) { xlate_action_set(ctx); -@@ -6402,10 +6535,10 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, +@@ -6402,10 +6553,10 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, } nl_msg_end_nested(ctx->odp_actions, offset_attr); @@ -61929,7 +61992,7 @@ index 578cbfe581..2b1611c912 100644 /* If the flow translation for the IF_GREATER case requires freezing, * then ctx->exit would be true. Reset to false so that we can -@@ -6416,8 +6549,8 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, +@@ -6416,8 +6567,8 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, offset_attr = nl_msg_start_nested( ctx->odp_actions, OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL); @@ -61940,7 +62003,7 @@ index 578cbfe581..2b1611c912 100644 do_xlate_actions(remaining_acts, remaining_acts_len, ctx, true, false); if (!ctx->freezing) { xlate_action_set(ctx); -@@ -6428,15 +6561,12 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, +@@ -6428,15 +6579,12 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, nl_msg_end_nested(ctx->odp_actions, offset_attr); nl_msg_end_nested(ctx->odp_actions, offset); @@ -61959,7 +62022,7 @@ index 578cbfe581..2b1611c912 100644 } static void -@@ -6887,6 +7017,107 @@ xlate_ofpact_unroll_xlate(struct xlate_ctx *ctx, +@@ -6887,6 +7035,107 @@ xlate_ofpact_unroll_xlate(struct xlate_ctx *ctx, "cookie=%#"PRIx64, a->rule_table_id, a->rule_cookie); } @@ -62067,7 +62130,7 @@ index 578cbfe581..2b1611c912 100644 static void do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, struct xlate_ctx *ctx, bool is_last_action, -@@ -6928,6 +7159,8 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, +@@ -6928,6 +7177,8 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; } @@ -62076,7 +62139,7 @@ index 578cbfe581..2b1611c912 100644 if (OVS_UNLIKELY(ctx->xin->trace)) { struct ds s = DS_EMPTY_INITIALIZER; struct ofpact_format_params fp = { .s = &s }; -@@ -7027,6 +7260,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, +@@ -7027,6 +7278,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, case OFPACT_SET_IPV4_SRC: if (flow->dl_type == htons(ETH_TYPE_IP)) { memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src); @@ -62084,7 +62147,7 @@ index 578cbfe581..2b1611c912 100644 flow->nw_src = ofpact_get_SET_IPV4_SRC(a)->ipv4; } break; -@@ -7034,12 +7268,14 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, +@@ -7034,12 +7286,14 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, case OFPACT_SET_IPV4_DST: if (flow->dl_type == htons(ETH_TYPE_IP)) { memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst); @@ -62099,7 +62162,7 @@ index 578cbfe581..2b1611c912 100644 wc->masks.nw_tos |= IP_DSCP_MASK; flow->nw_tos &= ~IP_DSCP_MASK; flow->nw_tos |= ofpact_get_SET_IP_DSCP(a)->dscp; -@@ -7048,6 +7284,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, +@@ -7048,6 +7302,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, case OFPACT_SET_IP_ECN: if (is_ip_any(flow)) { @@ -62107,7 +62170,7 @@ index 578cbfe581..2b1611c912 100644 wc->masks.nw_tos |= IP_ECN_MASK; flow->nw_tos &= ~IP_ECN_MASK; flow->nw_tos |= ofpact_get_SET_IP_ECN(a)->ecn; -@@ -7056,6 +7293,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, +@@ -7056,6 +7311,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, case OFPACT_SET_IP_TTL: if (is_ip_any(flow)) { @@ -62115,7 +62178,7 @@ index 578cbfe581..2b1611c912 100644 wc->masks.nw_ttl = 0xff; flow->nw_ttl = ofpact_get_SET_IP_TTL(a)->ttl; } -@@ -7123,6 +7361,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, +@@ -7123,6 +7379,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, /* Set the field only if the packet actually has it. */ if (mf_are_prereqs_ok(mf, flow, wc)) { @@ -62123,7 +62186,7 @@ index 578cbfe581..2b1611c912 100644 mf_mask_field_masked(mf, ofpact_set_field_mask(set_field), wc); mf_set_flow_value_masked(mf, set_field->value, ofpact_set_field_mask(set_field), -@@ -7179,6 +7418,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, +@@ -7179,6 +7436,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, case OFPACT_DEC_TTL: wc->masks.nw_ttl = 0xff; @@ -62131,7 +62194,7 @@ index 578cbfe581..2b1611c912 100644 if (compose_dec_ttl(ctx, ofpact_get_DEC_TTL(a))) { return; } -@@ -7609,6 +7849,43 @@ xlate_wc_finish(struct xlate_ctx *ctx) +@@ -7609,6 +7867,43 @@ xlate_wc_finish(struct xlate_ctx *ctx) ctx->wc->masks.vlans[i].tci = 0; } } @@ -62175,7 +62238,7 @@ index 578cbfe581..2b1611c912 100644 } /* Translates the flow, actions, or rule in 'xin' into datapath actions in -@@ -7784,6 +8061,12 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) +@@ -7784,6 +8079,12 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) goto exit; } @@ -62188,7 +62251,7 @@ index 578cbfe581..2b1611c912 100644 /* Tunnel metadata in udpif format must be normalized before translation. */ if (flow->tunnel.flags & FLOW_TNL_F_UDPIF) { const struct tun_table *tun_tab = ofproto_get_tun_tab( -@@ -8030,6 +8313,10 @@ exit: +@@ -8030,6 +8331,10 @@ exit: if (xin->odp_actions) { ofpbuf_clear(xin->odp_actions); } @@ -62212,7 +62275,7 @@ index 851088d794..2ba90e999c 100644 void xlate_bundle_set(struct ofproto_dpif *, struct ofbundle *, const char *name, enum port_vlan_mode, diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c -index 8143dd965f..bd235ce2b8 100644 +index 8143dd965f..06f6d00b39 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -215,10 +215,6 @@ struct shash all_dpif_backers = SHASH_INITIALIZER(&all_dpif_backers); @@ -62544,6 +62607,15 @@ index 8143dd965f..bd235ce2b8 100644 } if (rule) { goto out; /* Match. */ +@@ -4879,7 +4880,7 @@ packet_xlate(struct ofproto *ofproto_, struct ofproto_packet_out *opo) + if (entry->type == XC_LEARN) { + struct ofproto_flow_mod *ofm = entry->learn.ofm; + +- error = ofproto_flow_mod_learn_refresh(ofm); ++ error = ofproto_flow_mod_learn_refresh(ofm, time_msec()); + if (error) { + goto error_out; + } @@ -5550,9 +5551,9 @@ ct_zone_timeout_policy_sweep(struct dpif_backer *backer) { if (!ovs_list_is_empty(&backer->ct_tp_kill_list) @@ -62598,7 +62670,7 @@ index 8143dd965f..bd235ce2b8 100644 static void diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h -index 14b909973d..e64ca5b805 100644 +index 14b909973d..4cdae27bc1 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -143,6 +143,8 @@ struct ofproto { @@ -62622,8 +62694,22 @@ index 14b909973d..e64ca5b805 100644 /* Number of upcall handler and revalidator threads. Only affects the * ofproto-dpif implementation. */ extern uint32_t n_handlers, n_revalidators; +@@ -2015,9 +2022,11 @@ enum ofperr ofproto_flow_mod_init_for_learn(struct ofproto *, + struct ofproto_flow_mod *) + OVS_EXCLUDED(ofproto_mutex); + enum ofperr ofproto_flow_mod_learn(struct ofproto_flow_mod *, bool keep_ref, +- unsigned limit, bool *below_limit) ++ unsigned limit, bool *below_limit, ++ long long int last_used) + OVS_EXCLUDED(ofproto_mutex); +-enum ofperr ofproto_flow_mod_learn_refresh(struct ofproto_flow_mod *ofm); ++enum ofperr ofproto_flow_mod_learn_refresh(struct ofproto_flow_mod *ofm, ++ long long int last_used); + enum ofperr ofproto_flow_mod_learn_start(struct ofproto_flow_mod *ofm) + OVS_REQUIRES(ofproto_mutex); + void ofproto_flow_mod_learn_revert(struct ofproto_flow_mod *ofm) diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c -index 56aeac7209..8569ce94cb 100644 +index 56aeac7209..609627d99e 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -310,6 +310,7 @@ unsigned ofproto_flow_limit = OFPROTO_FLOW_LIMIT_DEFAULT; @@ -62801,7 +62887,120 @@ index 56aeac7209..8569ce94cb 100644 VLOG_WARN_RL(&rl, "%s: failed to allocate a rule.", ofproto->name); return OFPERR_OFPFMFC_UNKNOWN; } -@@ -6797,9 +6862,9 @@ static void +@@ -5377,7 +5442,8 @@ ofproto_flow_mod_init_for_learn(struct ofproto *ofproto, + } + + enum ofperr +-ofproto_flow_mod_learn_refresh(struct ofproto_flow_mod *ofm) ++ofproto_flow_mod_learn_refresh(struct ofproto_flow_mod *ofm, ++ long long int last_used) + { + enum ofperr error = 0; + +@@ -5398,9 +5464,37 @@ ofproto_flow_mod_learn_refresh(struct ofproto_flow_mod *ofm) + * this function is executed the rule will be reinstated. */ + if (rule->state == RULE_REMOVED) { + struct cls_rule cr; ++ struct oftable *table = &rule->ofproto->tables[rule->table_id]; ++ ovs_version_t tables_version = rule->ofproto->tables_version; ++ ++ if (!cls_rule_visible_in_version(&rule->cr, tables_version)) { ++ const struct cls_rule *curr_cls_rule; ++ ++ /* Only check for matching classifier rules and their modified ++ * time, instead of also checking all rule metadata, with the goal ++ * of suppressing a learn action update that would replace a more ++ * recent rule in the classifier. */ ++ curr_cls_rule = classifier_find_rule_exactly(&table->cls, ++ &rule->cr, ++ tables_version); ++ if (curr_cls_rule) { ++ struct rule *curr_rule = rule_from_cls_rule(curr_cls_rule); ++ long long int curr_last_used; ++ ++ ovs_mutex_lock(&curr_rule->mutex); ++ curr_last_used = curr_rule->modified; ++ ovs_mutex_unlock(&curr_rule->mutex); ++ ++ if (curr_last_used > last_used) { ++ /* In the case of a newer visible rule, don't recreate the ++ * current rule. */ ++ return 0; ++ } ++ } ++ } + +- cls_rule_clone(&cr, &rule->cr); + ovs_mutex_lock(&rule->mutex); ++ cls_rule_clone(&cr, &rule->cr); + error = ofproto_rule_create(rule->ofproto, &cr, rule->table_id, + rule->flow_cookie, + rule->idle_timeout, +@@ -5411,6 +5505,7 @@ ofproto_flow_mod_learn_refresh(struct ofproto_flow_mod *ofm) + rule->match_tlv_bitmap, + rule->ofpacts_tlv_bitmap, + &ofm->temp_rule); ++ ofm->temp_rule->modified = last_used; + ovs_mutex_unlock(&rule->mutex); + if (!error) { + ofproto_rule_unref(rule); /* Release old reference. */ +@@ -5418,7 +5513,7 @@ ofproto_flow_mod_learn_refresh(struct ofproto_flow_mod *ofm) + } else { + /* Refresh the existing rule. */ + ovs_mutex_lock(&rule->mutex); +- rule->modified = time_msec(); ++ rule->modified = last_used; + ovs_mutex_unlock(&rule->mutex); + } + return error; +@@ -5470,10 +5565,16 @@ ofproto_flow_mod_learn_finish(struct ofproto_flow_mod *ofm, + + /* Refresh 'ofm->temp_rule', for which the caller holds a reference, if already + * in the classifier, insert it otherwise. If the rule has already been +- * removed from the classifier, a new rule is created using 'ofm->temp_rule' as +- * a template and the reference to the old 'ofm->temp_rule' is freed. If +- * 'keep_ref' is true, then a reference to the current rule is held, otherwise +- * it is released and 'ofm->temp_rule' is set to NULL. ++ * removed from the classifier and replaced by another rule, the 'last_used' ++ * parameter is used to determine whether the newer rule is replaced or kept. ++ * If 'last_used' is greater than the last modified time of an identical rule ++ * in the classifier, then a new rule is created using 'ofm->temp_rule' as a ++ * template and the reference to the old 'ofm->temp_rule' is freed. If the ++ * rule has been removed but another identical rule doesn't exist in the ++ * classifier, then it will be recreated. If the rule hasn't been removed ++ * from the classifier, then 'last_used' is used to update the rules modified ++ * time. If 'keep_ref' is true, then a reference to the current rule is held, ++ * otherwise it is released and 'ofm->temp_rule' is set to NULL. + * + * If 'limit' != 0, insertion will fail if there are more than 'limit' rules + * in the same table with the same cookie. If insertion succeeds, +@@ -5484,10 +5585,11 @@ ofproto_flow_mod_learn_finish(struct ofproto_flow_mod *ofm, + * during the call. */ + enum ofperr + ofproto_flow_mod_learn(struct ofproto_flow_mod *ofm, bool keep_ref, +- unsigned limit, bool *below_limitp) ++ unsigned limit, bool *below_limitp, ++ long long int last_used) + OVS_EXCLUDED(ofproto_mutex) + { +- enum ofperr error = ofproto_flow_mod_learn_refresh(ofm); ++ enum ofperr error = ofproto_flow_mod_learn_refresh(ofm, last_used); + struct rule *rule = ofm->temp_rule; + bool below_limit = true; + +@@ -5520,6 +5622,11 @@ ofproto_flow_mod_learn(struct ofproto_flow_mod *ofm, bool keep_ref, + + error = ofproto_flow_mod_learn_start(ofm); + if (!error) { ++ /* ofproto_flow_mod_learn_start may have overwritten ++ * modified with current time. */ ++ ovs_mutex_lock(&ofm->temp_rule->mutex); ++ ofm->temp_rule->modified = last_used; ++ ovs_mutex_unlock(&ofm->temp_rule->mutex); + error = ofproto_flow_mod_learn_finish(ofm, NULL); + } + } else { +@@ -6797,9 +6904,9 @@ static void meter_delete_all(struct ofproto *ofproto) OVS_REQUIRES(ofproto_mutex) { @@ -62813,7 +63012,7 @@ index 56aeac7209..8569ce94cb 100644 hmap_remove(&ofproto->meters, &meter->node); meter_destroy(ofproto, meter); } -@@ -7339,8 +7404,13 @@ init_group(struct ofproto *ofproto, const struct ofputil_group_mod *gm, +@@ -7339,8 +7446,13 @@ init_group(struct ofproto *ofproto, const struct ofputil_group_mod *gm, return OFPERR_OFPGMFC_BAD_TYPE; } @@ -62827,7 +63026,7 @@ index 56aeac7209..8569ce94cb 100644 VLOG_WARN_RL(&rl, "%s: failed to allocate group", ofproto->name); return OFPERR_OFPGMFC_OUT_OF_GROUPS; } -@@ -7377,6 +7447,7 @@ init_group(struct ofproto *ofproto, const struct ofputil_group_mod *gm, +@@ -7377,6 +7489,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)); @@ -62835,7 +63034,7 @@ index 56aeac7209..8569ce94cb 100644 ofproto->ofproto_class->group_dealloc(*ofgroup); } return error; -@@ -8902,7 +8973,7 @@ eviction_group_hash_rule(struct rule *rule) +@@ -8902,7 +9015,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; @@ -62844,7 +63043,7 @@ index 56aeac7209..8569ce94cb 100644 sf++) { if (mf_are_prereqs_ok(sf->field, &flow, NULL)) { -@@ -9138,8 +9209,8 @@ oftable_configure_eviction(struct oftable *table, unsigned int eviction, +@@ -9138,8 +9251,8 @@ oftable_configure_eviction(struct oftable *table, unsigned int eviction, /* Destroy existing eviction groups, then destroy and recreate data * structures to recover memory. */ @@ -65306,7 +65505,7 @@ index ef7bb4b8ee..c36a140a8e 100644 -#endif } diff --git a/python/ovs/db/idl.py b/python/ovs/db/idl.py -index 4ecdcaa197..08846b0d51 100644 +index 4ecdcaa197..1aa0c33d13 100644 --- a/python/ovs/db/idl.py +++ b/python/ovs/db/idl.py @@ -85,9 +85,9 @@ class Monitor(enum.IntEnum): @@ -65425,7 +65624,15 @@ index 4ecdcaa197..08846b0d51 100644 def restart_fsm(self): # Resync data DB table conditions to avoid missing updated due to -@@ -482,7 +517,7 @@ class Idl(object): +@@ -459,6 +494,7 @@ class Idl(object): + if not msg.result[0]: + self.__clear() + self.__parse_update(msg.result[2], OVSDB_UPDATE3) ++ self.last_id = msg.result[1] + elif self.state == self.IDL_S_DATA_MONITOR_COND_REQUESTED: + self.__clear() + self.__parse_update(msg.result, OVSDB_UPDATE2) +@@ -482,7 +518,7 @@ class Idl(object): sh.register_table(self._server_db_table) schema = sh.get_idl_schema() self._server_db = schema @@ -65434,7 +65641,7 @@ index 4ecdcaa197..08846b0d51 100644 self.__send_server_monitor_request() except error.Error as e: vlog.err("%s: error receiving server schema: %s" -@@ -588,10 +623,10 @@ class Idl(object): +@@ -588,10 +624,10 @@ class Idl(object): for table in self.tables.values(): # Always use the most recent conditions set by the IDL client when # requesting monitor_cond_change @@ -65448,7 +65655,7 @@ index 4ecdcaa197..08846b0d51 100644 if not change_requests: return -@@ -627,19 +662,20 @@ class Idl(object): +@@ -627,19 +663,20 @@ class Idl(object): cond = [False] # Compare the new condition to the last known condition @@ -65474,7 +65681,7 @@ index 4ecdcaa197..08846b0d51 100644 def wait(self, poller): """Arranges for poller.block() to wake up when self.run() has something -@@ -811,8 +847,8 @@ class Idl(object): +@@ -811,8 +848,8 @@ class Idl(object): columns.append(column) monitor_request = {"columns": columns} if method in ("monitor_cond", "monitor_cond_since") and ( @@ -65485,7 +65692,7 @@ index 4ecdcaa197..08846b0d51 100644 monitor_requests[table.name] = [monitor_request] args = [self._db.name, str(self.uuid), monitor_requests] -@@ -1148,13 +1184,6 @@ class Idl(object): +@@ -1148,13 +1185,6 @@ class Idl(object): return True @@ -65499,7 +65706,7 @@ index 4ecdcaa197..08846b0d51 100644 def _row_to_uuid(value): if isinstance(value, Row): return value.uuid -@@ -1266,7 +1295,19 @@ class Row(object): +@@ -1266,7 +1296,19 @@ class Row(object): return "{table}({data})".format( table=self._table.name, data=", ".join("{col}={val}".format(col=c, val=getattr(self, c)) @@ -65520,7 +65727,7 @@ index 4ecdcaa197..08846b0d51 100644 def __getattr__(self, column_name): assert self._changes is not None -@@ -1309,7 +1350,7 @@ class Row(object): +@@ -1309,7 +1351,7 @@ class Row(object): datum = data.Datum.from_python(column.type, dlist, _row_to_uuid) elif column.type.is_map(): @@ -65529,7 +65736,7 @@ index 4ecdcaa197..08846b0d51 100644 if inserts is not None: dmap.update(inserts) if removes is not None: -@@ -1326,7 +1367,7 @@ class Row(object): +@@ -1326,7 +1368,7 @@ class Row(object): else: datum = inserts @@ -65538,7 +65745,7 @@ index 4ecdcaa197..08846b0d51 100644 def __setattr__(self, column_name, value): assert self._changes is not None -@@ -1410,7 +1451,7 @@ class Row(object): +@@ -1410,7 +1452,7 @@ class Row(object): if value: try: old_value = data.Datum.to_python(self._data[column_name], @@ -66644,7 +66851,7 @@ index f3e19cd83b..1d3af98dab 100644 ovs-appctl netdev-dummy/receive p1 'in_port(1),packet_type(ns=0,id=0),eth(src=3a:6d:d2:09:9c:ab,dst=1e:2c:e9:2a:66:9e),ipv4(src=192.168.10.10,dst=192.168.10.30,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' ], [0], [ignore]) diff --git a/tests/learn.at b/tests/learn.at -index 5f1d6df9de..d127fed348 100644 +index 5f1d6df9de..d0bcc83633 100644 --- a/tests/learn.at +++ b/tests/learn.at @@ -6,7 +6,7 @@ actions=learn() @@ -66665,6 +66872,70 @@ index 5f1d6df9de..d127fed348 100644 OFPT_FLOW_MOD (xid=0x6): ADD actions=learn(table=1,idle_timeout=10,hard_timeout=20,fin_idle_timeout=5,fin_hard_timeout=10,priority=10,cookie=0xfedcba9876543210,in_port=99,NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_IN_PORT[]->NXM_NX_REG1[16..31]) OFPT_FLOW_MOD (xid=0x7): ADD actions=learn(table=1,limit=4096) OFPT_FLOW_MOD (xid=0x8): ADD actions=learn(table=1,limit=4096,result_dst=NXM_NX_REG0[0]) +@@ -836,3 +836,63 @@ AT_CHECK([ovs-vsctl add-br br1 -- set b br1 datapath_type=dummy]) + + OVS_VSWITCHD_STOP + AT_CLEANUP ++ ++AT_SETUP([learning action - flapping learn rule]) ++OVS_VSWITCHD_START ++add_of_ports br0 1 2 3 ++ ++AT_CHECK([ovs-appctl time/stop], [0], [ignore]) ++AT_CHECK([[ovs-ofctl add-flow br0 'table=0,priority=2,in_port=1,actions=resubmit(,2)']]) ++AT_CHECK([[ovs-ofctl add-flow br0 'table=0,priority=2,in_port=2,actions=resubmit(,2)']]) ++AT_CHECK([[ovs-ofctl add-flow br0 'table=2,actions=learn(table=0,hard_timeout=3,priority=1,cookie=0x123,NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],output:OXM_OF_IN_PORT[]),output:3']]) ++ ++packet="eth(src=50:54:00:00:00:06,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)" ++ ++dnl Run this test a few times in a loop to reduce the likelyhood that it passes by chance. ++for i in 1 2 3; do ++ AT_CHECK([ovs-appctl revalidator/pause], [0]) ++ AT_CHECK([ovs-appctl netdev-dummy/receive p2 $packet], [0]) ++ AT_CHECK([ovs-appctl time/warp 75], [0], [ignore]) ++ AT_CHECK([ovs-appctl netdev-dummy/receive p1 $packet], [0]) ++ AT_CHECK([ovs-appctl time/warp 75], [0], [ignore]) ++ AT_CHECK([ovs-appctl netdev-dummy/receive p2 $packet], [0]) ++ AT_CHECK([ovs-appctl time/warp 75], [0], [ignore]) ++ AT_CHECK([ovs-appctl netdev-dummy/receive p1 $packet], [0]) ++ AT_CHECK([ovs-appctl time/warp 75], [0], [ignore]) ++ ++ AT_CHECK([ovs-appctl revalidator/resume], [0]) ++ AT_CHECK([ovs-appctl revalidator/wait], [0]) ++ ++ AT_CHECK([ovs-ofctl --no-stats dump-flows br0 | ofctl_strip | sort | grep 0x123], [0], [dnl ++ cookie=0x123, hard_timeout=3, priority=1,dl_dst=50:54:00:00:00:06 actions=output:1 ++ table=2, actions=learn(table=0,hard_timeout=3,priority=1,cookie=0x123,NXM_OF_ETH_DST[[]]=NXM_OF_ETH_SRC[[]],output:OXM_OF_IN_PORT[[]]),output:3 ++]) ++ ++ AT_CHECK([ovs-appctl revalidator/pause], [0]) ++ AT_CHECK([ovs-appctl netdev-dummy/receive p1 $packet], [0]) ++ AT_CHECK([ovs-appctl time/warp 75], [0], [ignore]) ++ AT_CHECK([ovs-appctl netdev-dummy/receive p2 $packet], [0]) ++ AT_CHECK([ovs-appctl time/warp 75], [0], [ignore]) ++ AT_CHECK([ovs-appctl netdev-dummy/receive p1 $packet], [0]) ++ AT_CHECK([ovs-appctl time/warp 75], [0], [ignore]) ++ AT_CHECK([ovs-appctl netdev-dummy/receive p2 $packet], [0]) ++ AT_CHECK([ovs-appctl time/warp 75], [0], [ignore]) ++ ++ AT_CHECK([ovs-appctl revalidator/resume], [0]) ++ AT_CHECK([ovs-appctl revalidator/wait], [0]) ++ ++ AT_CHECK([ovs-ofctl --no-stats dump-flows br0 | ofctl_strip | sort | grep 0x123], [0], [dnl ++ cookie=0x123, hard_timeout=3, priority=1,dl_dst=50:54:00:00:00:06 actions=output:2 ++ table=2, actions=learn(table=0,hard_timeout=3,priority=1,cookie=0x123,NXM_OF_ETH_DST[[]]=NXM_OF_ETH_SRC[[]],output:OXM_OF_IN_PORT[[]]),output:3 ++]) ++done ++ ++dnl Wait and check for learned rule eviction due to hard timeout. ++AT_CHECK([ovs-appctl time/warp 3200], [0], [ignore]) ++ ++AT_CHECK([ovs-ofctl --no-stats dump-flows br0 | ofctl_strip | grep 0x123], [0], [dnl ++ table=2, actions=learn(table=0,hard_timeout=3,priority=1,cookie=0x123,NXM_OF_ETH_DST[[]]=NXM_OF_ETH_SRC[[]],output:OXM_OF_IN_PORT[[]]),output:3 ++]) ++ ++OVS_VSWITCHD_STOP ++AT_CLEANUP diff --git a/tests/learning-switch.at b/tests/learning-switch.at new file mode 100644 index 0000000000..ac2fc1b801 @@ -67014,7 +67285,7 @@ index 2c7e163bd6..7be6628c34 100644 AT_CLEANUP diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at -index 7c2edeb9d4..fc125eac32 100644 +index 7c2edeb9d4..16c8af67ed 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -29,6 +29,58 @@ AT_CHECK([ovs-appctl revalidator/wait]) @@ -68319,7 +68590,7 @@ index 7c2edeb9d4..fc125eac32 100644 ]) OVS_VSWITCHD_STOP -@@ -5573,7 +5691,36 @@ check_flows () { +@@ -5573,7 +5691,70 @@ check_flows () { echo "n_packets=$n" test "$n" = 1 } @@ -68354,10 +68625,44 @@ index 7c2edeb9d4..fc125eac32 100644 + test "$n" = 2 +} +OVS_WAIT_UNTIL([check_flows], [ovs-ofctl dump-flows br0]) ++ ++OVS_VSWITCHD_STOP ++AT_CLEANUP ++ ++dnl Checks for regression against a bug in which OVS dropped packets ++dnl originating from a controller passing through a patch port. ++AT_SETUP([ofproto-dpif - packet-out recirculation OFPP_CONTROLLER and patch port]) ++OVS_VSWITCHD_START( ++ [add-port br0 patch-br1 -- \ ++ set interface patch-br1 type=patch options:peer=patch-br0 -- \ ++ add-br br1 -- set bridge br1 datapath-type=dummy fail-mode=secure -- \ ++ add-port br1 patch-br0 -- set interface patch-br0 type=patch options:peer=patch-br1 ++]) ++ ++add_of_ports --pcap br1 1 ++ ++AT_DATA([flows-br0.txt], [dnl ++table=0 icmp actions=output:patch-br1 ++]) ++AT_CHECK([ovs-ofctl add-flows br0 flows-br0.txt]) ++ ++AT_DATA([flows-br1.txt], [dnl ++table=0, icmp actions=ct(table=1,zone=1) ++table=1, ct_state=+trk, icmp actions=p1 ++]) ++AT_CHECK([ovs-ofctl add-flows br1 flows-br1.txt]) ++ ++packet=50540000000750540000000508004500005c000000008001b94dc0a80001c0a80002080013fc00000000000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f ++AT_CHECK([ovs-ofctl packet-out br0 "in_port=CONTROLLER packet=$packet actions=table"]) ++ ++OVS_WAIT_UNTIL_EQUAL([ovs-ofctl dump-flows -m br1 | grep "ct_state" | ofctl_strip], [dnl ++ table=1, n_packets=1, n_bytes=106, ct_state=+trk,icmp actions=output:2]) ++ ++OVS_WAIT_UNTIL([ovs-pcap p1-tx.pcap | grep -q "$packet"]) OVS_VSWITCHD_STOP AT_CLEANUP -@@ -6202,6 +6349,20 @@ AT_CHECK([tail -2 stderr], [0], [dnl +@@ -6202,6 +6383,20 @@ AT_CHECK([tail -2 stderr], [0], [dnl ovs-appctl: ovs-vswitchd: server returned an error ]) @@ -68378,7 +68683,7 @@ index 7c2edeb9d4..fc125eac32 100644 OVS_VSWITCHD_STOP AT_CLEANUP -@@ -7004,6 +7165,29 @@ AT_CHECK([ovs-appctl coverage/read-counter mac_learning_static_none_move], [0], +@@ -7004,6 +7199,29 @@ AT_CHECK([ovs-appctl coverage/read-counter mac_learning_static_none_move], [0], OVS_VSWITCHD_STOP AT_CLEANUP @@ -68408,7 +68713,7 @@ index 7c2edeb9d4..fc125eac32 100644 AT_SETUP([ofproto-dpif - basic truncate action]) OVS_VSWITCHD_START add_of_ports br0 1 2 3 4 5 -@@ -7031,7 +7215,7 @@ dnl An 170 byte packet +@@ -7031,7 +7249,7 @@ dnl An 170 byte packet AT_CHECK([ovs-appctl netdev-dummy/receive p1 '000c29c8a0a4005056c0000808004500009cb4a6000040019003c0a8da01c0a8da640800cb5fa762000556f431ad0009388e08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f']) AT_CHECK([ovs-ofctl parse-pcap p1.pcap], [0], [dnl @@ -68417,7 +68722,7 @@ index 7c2edeb9d4..fc125eac32 100644 ]) AT_CHECK([ovs-appctl revalidator/purge], [0]) -@@ -7600,13 +7784,28 @@ dnl configure bridge IPFIX and ensure that sample action generation works at the +@@ -7600,13 +7818,28 @@ dnl configure bridge IPFIX and ensure that sample action generation works at the dnl datapath level. AT_SETUP([ofproto-dpif - Bridge IPFIX sanity check]) OVS_VSWITCHD_START @@ -68447,7 +68752,7 @@ index 7c2edeb9d4..fc125eac32 100644 dnl Send some packets that should be sampled. for i in `seq 1 3`; do AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800)']) -@@ -8666,7 +8865,7 @@ recirc_id(0),in_port(100),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(src=192.1 +@@ -8666,7 +8899,7 @@ recirc_id(0),in_port(100),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(src=192.1 ]) AT_CHECK([grep -e '|ofproto_dpif_xlate|WARN|' ovs-vswitchd.log | sed "s/^.*|WARN|//"], [0], [dnl @@ -68456,7 +68761,7 @@ index 7c2edeb9d4..fc125eac32 100644 ]) OVS_VSWITCHD_STOP(["/stack underflow/d"]) -@@ -8717,6 +8916,40 @@ AT_CHECK([tail -1 stdout], [0], +@@ -8717,6 +8950,40 @@ AT_CHECK([tail -1 stdout], [0], OVS_VSWITCHD_STOP AT_CLEANUP @@ -68497,7 +68802,7 @@ index 7c2edeb9d4..fc125eac32 100644 dnl ---------------------------------------------------------------------- AT_BANNER([ofproto-dpif -- megaflows]) -@@ -9855,7 +10088,7 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl]) +@@ -9855,7 +10122,7 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=86 in_port=1 (via no_match) data_len=86 (unbuffered) @@ -68506,7 +68811,7 @@ index 7c2edeb9d4..fc125eac32 100644 ]) OVS_VSWITCHD_STOP -@@ -9906,7 +10139,7 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl]) +@@ -9906,7 +10173,7 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=86 in_port=1 (via action) data_len=86 (unbuffered) @@ -68515,7 +68820,7 @@ index 7c2edeb9d4..fc125eac32 100644 ]) OVS_VSWITCHD_STOP -@@ -10166,10 +10399,10 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) +@@ -10166,10 +10433,10 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) dnl Check this output. We only see the latter two packets, not the first. AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): table_id=6 cookie=0x0 total_len=106 reg0=0x1,reg1=0x4d2,reg2=0x1,reg3=0x1,reg4=0x1,in_port=1 (via action) data_len=106 (unbuffered) @@ -68528,7 +68833,7 @@ index 7c2edeb9d4..fc125eac32 100644 ]) AT_CHECK([ovs-ofctl monitor br0 65534 invalid_ttl -P nxt_packet_in --detach --no-chdir --pidfile 2> ofctl_monitor.log]) -@@ -10187,10 +10420,10 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) +@@ -10187,10 +10454,10 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) dnl Check this output. We should see both packets AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): table_id=6 cookie=0x0 total_len=106 reg0=0x1,reg1=0x4d2,reg2=0x1,reg3=0x1,reg4=0x1,in_port=1 (via action) data_len=106 (unbuffered) @@ -68541,7 +68846,7 @@ index 7c2edeb9d4..fc125eac32 100644 ]) OVS_VSWITCHD_STOP -@@ -10239,10 +10472,10 @@ dnl Note that the first packet doesn't have the ct_state bits set. This +@@ -10239,10 +10506,10 @@ dnl Note that the first packet doesn't have the ct_state bits set. This dnl happens because the ct_state field is available only after recirc. AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=106 in_port=1 (via action) data_len=106 (unbuffered) @@ -68554,7 +68859,7 @@ index 7c2edeb9d4..fc125eac32 100644 ]) AT_CHECK([ovs-ofctl monitor br0 65534 invalid_ttl -P nxt_packet_in --detach --no-chdir --pidfile 2> ofctl_monitor.log]) -@@ -10261,10 +10494,10 @@ dnl Note that the first packet doesn't have the ct_state bits set. This +@@ -10261,10 +10528,10 @@ dnl Note that the first packet doesn't have the ct_state bits set. This dnl happens because the ct_state field is available only after recirc. AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=106 in_port=1 (via action) data_len=106 (unbuffered) @@ -68567,7 +68872,7 @@ index 7c2edeb9d4..fc125eac32 100644 ]) dnl -@@ -10320,9 +10553,9 @@ dnl Note that the first packet doesn't have the ct_state bits set. This +@@ -10320,9 +10587,9 @@ dnl Note that the first packet doesn't have the ct_state bits set. This dnl happens because the ct_state field is available only after recirc. AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=126 in_port=1 (via action) data_len=126 (unbuffered) @@ -68579,7 +68884,7 @@ index 7c2edeb9d4..fc125eac32 100644 ]) OVS_VSWITCHD_STOP -@@ -10433,7 +10666,7 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) +@@ -10433,7 +10700,7 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) dnl Check this output. Only one reply must be there AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=106 ct_state=est|rpl|trk,ct_nw_src=10.1.1.1,ct_nw_dst=10.1.1.2,ct_nw_proto=17,ct_tp_src=1,ct_tp_dst=2,ip,in_port=2 (via action) data_len=106 (unbuffered) @@ -68588,7 +68893,7 @@ index 7c2edeb9d4..fc125eac32 100644 dnl OFPT_ECHO_REQUEST (xid=0x0): 0 bytes of payload ]) -@@ -10467,7 +10700,7 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) +@@ -10467,7 +10734,7 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=86 ct_state=inv|trk,ipv6,in_port=2 (via action) data_len=86 (unbuffered) @@ -68597,7 +68902,7 @@ index 7c2edeb9d4..fc125eac32 100644 ]) OVS_VSWITCHD_STOP -@@ -10523,16 +10756,16 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) +@@ -10523,16 +10790,16 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) dnl Check this output. We only see the latter two packets (for each zone), not the first. AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=106 in_port=1 (via action) data_len=106 (unbuffered) @@ -68618,7 +68923,7 @@ index 7c2edeb9d4..fc125eac32 100644 ]) OVS_VSWITCHD_STOP -@@ -10579,10 +10812,10 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) +@@ -10579,10 +10846,10 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) dnl Check this output. We only see the latter two packets, not the first. AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=106 in_port=1 (via action) data_len=106 (unbuffered) @@ -68631,7 +68936,7 @@ index 7c2edeb9d4..fc125eac32 100644 ]) OVS_VSWITCHD_STOP -@@ -10629,10 +10862,10 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) +@@ -10629,10 +10896,10 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) dnl Check this output. We only see the first and the last packet AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=47 ct_state=new|trk,ct_nw_src=172.16.0.1,ct_nw_dst=172.16.0.2,ct_nw_proto=17,ct_tp_src=41614,ct_tp_dst=5555,ip,in_port=1 (via action) data_len=47 (unbuffered) @@ -68644,7 +68949,7 @@ index 7c2edeb9d4..fc125eac32 100644 ]) OVS_VSWITCHD_STOP -@@ -10681,19 +10914,19 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) +@@ -10681,19 +10948,19 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) dnl Check this output. AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=106 in_port=1 (via action) data_len=106 (unbuffered) @@ -68669,7 +68974,7 @@ index 7c2edeb9d4..fc125eac32 100644 ]) OVS_VSWITCHD_STOP -@@ -10738,10 +10971,10 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) +@@ -10738,10 +11005,10 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) dnl Check this output. AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=106 ct_state=est|rpl|trk,ct_label=0x1,ct_nw_src=10.1.1.1,ct_nw_dst=10.1.1.2,ct_nw_proto=17,ct_tp_src=1,ct_tp_dst=2,ip,in_port=2 (via action) data_len=106 (unbuffered) @@ -68682,7 +68987,7 @@ index 7c2edeb9d4..fc125eac32 100644 ]) OVS_VSWITCHD_STOP -@@ -11152,16 +11385,16 @@ dnl Note that the first packet doesn't have the ct_state bits set. This +@@ -11152,16 +11419,16 @@ dnl Note that the first packet doesn't have the ct_state bits set. This dnl happens because the ct_state field is available only after recirc. AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=106 in_port=1 (via action) data_len=106 (unbuffered) @@ -68703,7 +69008,7 @@ index 7c2edeb9d4..fc125eac32 100644 ]) dnl The next test verifies that ct_clear at the datapath only gets executed -@@ -11235,13 +11468,13 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) +@@ -11235,13 +11502,13 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) dnl Check this output. AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=106 ct_state=est|rpl|trk,ct_nw_src=10.1.2.100,ct_nw_dst=10.1.2.200,ct_nw_proto=17,ct_tp_src=6,ct_tp_dst=6,ip,in_port=2 (via action) data_len=106 (unbuffered) @@ -68720,7 +69025,7 @@ index 7c2edeb9d4..fc125eac32 100644 ]) OVS_VSWITCHD_STOP -@@ -11504,7 +11737,7 @@ ovs-ofctl dump-flows br0 +@@ -11504,7 +11771,7 @@ ovs-ofctl dump-flows br0 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.10.10.2,dst=10.10.10.1,proto=1,tos=1,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout]) AT_CHECK([tail -3 stdout], [0], [dnl @@ -69459,7 +69764,7 @@ index e72bf06069..fd1c7a2395 100644 [{"count":1},{"details":"cannot delete b row <0> because of 2 remaining reference(s)","error":"referential integrity violation"}] [{"count":1}] diff --git a/tests/ovsdb-idl.at b/tests/ovsdb-idl.at -index 62e2b63832..092d9f81a2 100644 +index 62e2b63832..bacb7f161a 100644 --- a/tests/ovsdb-idl.at +++ b/tests/ovsdb-idl.at @@ -561,9 +561,9 @@ OVSDB_CHECK_IDL([simple idl, conditional, false condition], @@ -69695,7 +70000,60 @@ index 62e2b63832..092d9f81a2 100644 003: table simple3: name=row0_s3 uset=[] uref=[] uuid=<1> 004: {"error":null,"result":[{"uuid":["uuid","<2>"]}]} 005: table simple3: name=row0_s3 uset=[] uref=[] uuid=<1> -@@ -2341,11 +2378,11 @@ OVSDB_CHECK_CLUSTER_IDL([simple idl, monitor_cond_since, cluster disconnect], +@@ -2230,6 +2267,23 @@ CHECK_STREAM_OPEN_BLOCK([Python3], [$PYTHON3 $srcdir/test-stream.py], + CHECK_STREAM_OPEN_BLOCK([Python3], [$PYTHON3 $srcdir/test-stream.py], + [tcp6], [[[::1]]]) + ++dnl OVSDB_CLUSTER_CHECK_MONITOR_COND_SINCE_TXN_IDS(LOG) ++dnl ++dnl Looks up transaction IDs in the log of OVSDB client application. ++dnl All-zero UUID should not be sent within a monitor request more than once, ++dnl unless some database requests were lost (not replied). ++m4_define([OVSDB_CLUSTER_CHECK_MONITOR_COND_SINCE_TXN_IDS], ++[ ++ requests=$(grep -c 'send request' $1) ++ replies=$(grep -c 'received reply' $1) ++ ++ if test "$requests" -eq "$replies"; then ++ AT_CHECK([grep 'monitor_cond_since' $1 \ ++ | grep -c "00000000-0000-0000-0000-000000000000" | tr -d '\n'], ++ [0], [1]) ++ fi ++]) ++ + # same as OVSDB_CHECK_IDL but uses Python IDL implementation with tcp + # with multiple remotes to assert the idl connects to the leader of the Raft cluster + m4_define([OVSDB_CHECK_IDL_LEADER_ONLY_PY], +@@ -2245,10 +2299,11 @@ m4_define([OVSDB_CHECK_IDL_LEADER_ONLY_PY], + pids=$(cat s2.pid s3.pid s1.pid | tr '\n' ',') + echo $pids + AT_CHECK([$PYTHON3 $srcdir/test-ovsdb.py -t30 idl-cluster $srcdir/idltest.ovsschema $remotes $pids $3], +- [0], [stdout], [ignore]) ++ [0], [stdout], [stderr]) + remote=$(ovsdb_cluster_leader $remotes "idltest") + leader=$(echo $remote | cut -d'|' -f 1) + AT_CHECK([grep -F -- "${leader}" stdout], [0], [ignore]) ++ OVSDB_CLUSTER_CHECK_MONITOR_COND_SINCE_TXN_IDS([stderr]) + AT_CLEANUP]) + + OVSDB_CHECK_IDL_LEADER_ONLY_PY([Check Python IDL connects to leader], 3, ['remote']) +@@ -2291,6 +2346,7 @@ m4_define([OVSDB_CHECK_CLUSTER_IDL_C], + AT_CHECK([sort stdout | uuidfilt]m4_if([$7],,, [[| $7]]), + [0], [$5]) + m4_ifval([$8], [AT_CHECK([grep '$8' stderr], [1])], [], []) ++ OVSDB_CLUSTER_CHECK_MONITOR_COND_SINCE_TXN_IDS([stderr]) + AT_CLEANUP]) + + # Same as OVSDB_CHECK_CLUSTER_IDL_C but uses the Python IDL implementation. +@@ -2311,6 +2367,7 @@ m4_define([OVSDB_CHECK_CLUSTER_IDL_PY], + AT_CHECK([sort stdout | uuidfilt]m4_if([$7],,, [[| $7]]), + [0], [$5]) + m4_if([$8], [AT_CHECK([grep '$8' stderr], [1])], [], []) ++ OVSDB_CLUSTER_CHECK_MONITOR_COND_SINCE_TXN_IDS([stderr]) + AT_CLEANUP]) + + m4_define([OVSDB_CHECK_CLUSTER_IDL], +@@ -2341,11 +2398,11 @@ OVSDB_CHECK_CLUSTER_IDL([simple idl, monitor_cond_since, cluster disconnect], "table": "simple", "where": [["i", "==", 1]], "row": {"r": 2.0 }}]']], @@ -69710,7 +70068,7 @@ index 62e2b63832..092d9f81a2 100644 005: reconnect 006: table simple 007: {"error":null,"result":[{"count":1}]} -@@ -2437,3 +2474,92 @@ unix:socket2 remote has col id in table simple7 +@@ -2437,3 +2494,92 @@ unix:socket2 remote has col id in table simple7 OVSDB_SERVER_SHUTDOWN AT_CLEANUP diff --git a/SPECS/openvswitch2.17.spec b/SPECS/openvswitch2.17.spec index 324396f..870875e 100644 --- a/SPECS/openvswitch2.17.spec +++ b/SPECS/openvswitch2.17.spec @@ -63,7 +63,7 @@ Summary: Open vSwitch Group: System Environment/Daemons daemon/database/utilities URL: http://www.openvswitch.org/ Version: 2.17.0 -Release: 121%{?dist} +Release: 124%{?dist} # Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the # lib/sflow*.[ch] files are SISSL @@ -749,6 +749,24 @@ exit 0 %endif %changelog +* Mon Sep 18 2023 Open vSwitch CI - 2.17.0-124 +- Merging upstream branch-2.17 [RH git: 3993da3fa4] + Commit list: + 3c39cfe031 python: idl: Fix last-id update from a monitor reply. + + +* Wed Sep 06 2023 Open vSwitch CI - 2.17.0-123 +- Merging upstream branch-2.17 [RH git: aeefcc3167] + Commit list: + a6207b2bce ofproto-dpif-xlate: Fix recirculation with patch port and controller. (#2170920) + + +* Wed Sep 06 2023 Open vSwitch CI - 2.17.0-122 +- Merging upstream branch-2.17 [RH git: ca3687e513] + Commit list: + a141b62c2f ofproto-dpif-xlate: Don't reinstall removed XC_LEARN rule. (#2213892) + + * Wed Aug 30 2023 Open vSwitch CI - 2.17.0-121 - Merging upstream branch-2.17 [RH git: f9dc5dbd23] Commit list: