diff --git a/SOURCES/openvswitch-2.16.0.patch b/SOURCES/openvswitch-2.16.0.patch index c82ee65..1241304 100644 --- a/SOURCES/openvswitch-2.16.0.patch +++ b/SOURCES/openvswitch-2.16.0.patch @@ -3035,7 +3035,7 @@ index 9845e8d3fe..e1568e38a0 100644 } diff --git a/lib/odp-util.c b/lib/odp-util.c -index 7729a90608..20d663153b 100644 +index 7729a90608..36e7161714 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -2941,7 +2941,7 @@ odp_nsh_key_from_attr__(const struct nlattr *attr, bool is_mask, @@ -3077,6 +3077,18 @@ index 7729a90608..20d663153b 100644 const struct nlattr *ma = nl_attr_find__(mask, mask_len, OVS_KEY_ATTR_ETHERTYPE); if (ma) { +@@ -7132,11 +7137,6 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], + } + } + } +- } else if (src_flow->nw_proto == IPPROTO_IGMP +- && src_flow->dl_type == htons(ETH_TYPE_IP)) { +- /* OVS userspace parses the IGMP type, code, and group, but its +- * datapaths do not, so there is always missing information. */ +- return ODP_FIT_TOO_LITTLE; + } + if (is_mask && expected_bit != OVS_KEY_ATTR_UNSPEC) { + if ((flow->tp_src || flow->tp_dst) && flow->nw_proto != 0xff) { diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index ecf914eac1..7ea4b6ed56 100644 --- a/lib/ofp-actions.c @@ -5140,7 +5152,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 a426fcfeb6..4c16aa3f99 100644 +index a426fcfeb6..df44c18e7d 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -460,7 +460,7 @@ static void xlate_commit_actions(struct xlate_ctx *ctx); @@ -5242,7 +5254,15 @@ index a426fcfeb6..4c16aa3f99 100644 } /* Determine output bundle. */ -@@ -3272,7 +3296,9 @@ compose_ipfix_action(struct xlate_ctx *ctx, odp_port_t output_odp_port) +@@ -3048,7 +3072,6 @@ xlate_normal(struct xlate_ctx *ctx) + */ + ctx->xout->slow |= SLOW_ACTION; + +- memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src); + if (mcast_snooping_is_membership(flow->tp_src) || + mcast_snooping_is_query(flow->tp_src)) { + if (ctx->xin->allow_side_effects && ctx->xin->packet) { +@@ -3272,7 +3295,9 @@ compose_ipfix_action(struct xlate_ctx *ctx, odp_port_t output_odp_port) struct dpif_ipfix *ipfix = ctx->xbridge->ipfix; odp_port_t tunnel_out_port = ODPP_NONE; @@ -5253,7 +5273,7 @@ index a426fcfeb6..4c16aa3f99 100644 return; } -@@ -3521,6 +3547,9 @@ propagate_tunnel_data_to_flow__(struct flow *dst_flow, +@@ -3521,6 +3546,9 @@ propagate_tunnel_data_to_flow__(struct flow *dst_flow, dst_flow->dl_dst = dmac; dst_flow->dl_src = smac; @@ -5263,7 +5283,7 @@ index a426fcfeb6..4c16aa3f99 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; -@@ -3598,7 +3627,7 @@ propagate_tunnel_data_to_flow(struct xlate_ctx *ctx, struct eth_addr dmac, +@@ -3598,7 +3626,7 @@ propagate_tunnel_data_to_flow(struct xlate_ctx *ctx, struct eth_addr dmac, static int native_tunnel_output(struct xlate_ctx *ctx, const struct xport *xport, const struct flow *flow, odp_port_t tunnel_odp_port, @@ -5272,7 +5292,7 @@ index a426fcfeb6..4c16aa3f99 100644 { struct netdev_tnl_build_header_params tnl_params; struct ovs_action_push_tnl tnl_push_data; -@@ -3728,7 +3757,7 @@ native_tunnel_output(struct xlate_ctx *ctx, const struct xport *xport, +@@ -3728,7 +3756,7 @@ native_tunnel_output(struct xlate_ctx *ctx, const struct xport *xport, entry->tunnel_hdr.hdr_size = tnl_push_data.header_len; entry->tunnel_hdr.operation = ADD; @@ -5281,7 +5301,7 @@ index a426fcfeb6..4c16aa3f99 100644 /* Similar to the stats update in revalidation, the x_cache entries * are populated by the previous translation are used to update the -@@ -3822,7 +3851,7 @@ xlate_flow_is_protected(const struct xlate_ctx *ctx, const struct flow *flow, co +@@ -3822,7 +3850,7 @@ xlate_flow_is_protected(const struct xlate_ctx *ctx, const struct flow *flow, co */ static void patch_port_output(struct xlate_ctx *ctx, const struct xport *in_dev, @@ -5290,7 +5310,7 @@ index a426fcfeb6..4c16aa3f99 100644 { struct flow *flow = &ctx->xin->flow; struct flow old_flow = ctx->xin->flow; -@@ -3864,8 +3893,9 @@ patch_port_output(struct xlate_ctx *ctx, const struct xport *in_dev, +@@ -3864,8 +3892,9 @@ patch_port_output(struct xlate_ctx *ctx, const struct xport *in_dev, if (!process_special(ctx, out_dev) && may_receive(out_dev, ctx)) { if (xport_stp_forward_state(out_dev) && xport_rstp_forward_state(out_dev)) { @@ -5301,7 +5321,7 @@ index a426fcfeb6..4c16aa3f99 100644 if (!ctx->freezing) { xlate_action_set(ctx); } -@@ -3880,7 +3910,7 @@ patch_port_output(struct xlate_ctx *ctx, const struct xport *in_dev, +@@ -3880,7 +3909,7 @@ patch_port_output(struct xlate_ctx *ctx, const struct xport *in_dev, mirror_mask_t old_mirrors2 = ctx->mirrors; xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, true, @@ -5310,7 +5330,7 @@ index a426fcfeb6..4c16aa3f99 100644 ctx->mirrors = old_mirrors2; ctx->base_flow = old_base_flow; ctx->odp_actions->size = old_size; -@@ -4097,7 +4127,21 @@ terminate_native_tunnel(struct xlate_ctx *ctx, struct flow *flow, +@@ -4097,7 +4126,21 @@ terminate_native_tunnel(struct xlate_ctx *ctx, struct flow *flow, (flow->dl_type == htons(ETH_TYPE_ARP) || flow->nw_proto == IPPROTO_ICMPV6) && is_neighbor_reply_correct(ctx, flow)) { @@ -5333,7 +5353,7 @@ index a426fcfeb6..4c16aa3f99 100644 } } -@@ -4107,7 +4151,7 @@ terminate_native_tunnel(struct xlate_ctx *ctx, struct flow *flow, +@@ -4107,7 +4150,7 @@ terminate_native_tunnel(struct xlate_ctx *ctx, struct flow *flow, static void compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, const struct xlate_bond_recirc *xr, bool check_stp, @@ -5342,7 +5362,7 @@ index a426fcfeb6..4c16aa3f99 100644 { const struct xport *xport = get_ofp_port(ctx->xbridge, ofp_port); struct flow_wildcards *wc = ctx->wc; -@@ -4137,6 +4181,10 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, +@@ -4137,6 +4180,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)); @@ -5353,7 +5373,7 @@ index a426fcfeb6..4c16aa3f99 100644 } } -@@ -4144,7 +4192,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, +@@ -4144,7 +4191,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, if (truncate) { xlate_report_error(ctx, "Cannot truncate output to patch port"); } @@ -5362,7 +5382,7 @@ index a426fcfeb6..4c16aa3f99 100644 return; } -@@ -4239,7 +4287,8 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, +@@ -4239,7 +4286,8 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, xr->recirc_id); } else if (is_native_tunnel) { /* Output to native tunnel port. */ @@ -5372,7 +5392,7 @@ index a426fcfeb6..4c16aa3f99 100644 flow->tunnel = flow_tnl; /* Restore tunnel metadata */ } else if (terminate_native_tunnel(ctx, flow, wc, -@@ -6177,11 +6226,32 @@ static void +@@ -6177,11 +6225,32 @@ static void compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc, bool is_last_action) { @@ -5408,7 +5428,7 @@ index a426fcfeb6..4c16aa3f99 100644 /* Ensure that any prior actions are applied before composing the new * conntrack action. */ xlate_commit_actions(ctx); -@@ -6193,11 +6263,6 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc, +@@ -6193,11 +6262,6 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc, do_xlate_actions(ofc->actions, ofpact_ct_get_action_len(ofc), ctx, is_last_action, false); @@ -5420,7 +5440,7 @@ index a426fcfeb6..4c16aa3f99 100644 ct_offset = nl_msg_start_nested(ctx->odp_actions, OVS_ACTION_ATTR_CT); if (ofc->flags & NX_CT_F_COMMIT) { -@@ -6333,6 +6398,7 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, +@@ -6333,6 +6397,7 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, * then ctx->exit would be true. Reset to false so that we can * do flow translation for 'IF_LESS_EQUAL' case. finish_freezing() * would have taken care of Undoing the changes done for freeze. */ @@ -5428,7 +5448,7 @@ index a426fcfeb6..4c16aa3f99 100644 ctx->exit = false; offset_attr = nl_msg_start_nested( -@@ -6357,7 +6423,7 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, +@@ -6357,7 +6422,7 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, ctx->was_mpls = old_was_mpls; ctx->conntracked = old_conntracked; ctx->xin->flow = old_flow; @@ -5437,7 +5457,7 @@ index a426fcfeb6..4c16aa3f99 100644 } static void -@@ -6738,13 +6804,14 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, +@@ -6738,13 +6803,14 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, return; } @@ -5453,7 +5473,7 @@ index a426fcfeb6..4c16aa3f99 100644 if (ctx->error) { break; -@@ -6752,7 +6819,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, +@@ -6752,7 +6818,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, recirc_for_mpls(a, ctx); @@ -5462,7 +5482,7 @@ index a426fcfeb6..4c16aa3f99 100644 /* Check if need to store the remaining actions for later * execution. */ if (ctx->freezing) { -@@ -7149,17 +7216,18 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, +@@ -7149,17 +7215,18 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_CHECK_PKT_LARGER: { @@ -5499,7 +5519,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 cba49a99e1..f926d60142 100644 +index cba49a99e1..13f00e82d2 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); @@ -5585,7 +5605,31 @@ index cba49a99e1..f926d60142 100644 } if (rule) { goto out; /* Match. */ -@@ -5779,15 +5780,7 @@ ofproto_dpif_lookup_by_name(const char *name) +@@ -5556,6 +5557,7 @@ ct_set_zone_timeout_policy(const char *datapath_type, uint16_t zone_id, + ct_timeout_policy_unref(backer, ct_zone->ct_tp); + ct_zone->ct_tp = ct_tp; + ct_tp->ref_count++; ++ backer->need_revalidate = REV_RECONFIGURE; + } + } else { + struct ct_zone *new_ct_zone = ct_zone_alloc(zone_id); +@@ -5563,6 +5565,7 @@ ct_set_zone_timeout_policy(const char *datapath_type, uint16_t zone_id, + cmap_insert(&backer->ct_zones, &new_ct_zone->node, + hash_int(zone_id, 0)); + ct_tp->ref_count++; ++ backer->need_revalidate = REV_RECONFIGURE; + } + } + +@@ -5579,6 +5582,7 @@ ct_del_zone_timeout_policy(const char *datapath_type, uint16_t zone_id) + if (ct_zone) { + ct_timeout_policy_unref(backer, ct_zone->ct_tp); + ct_zone_remove_and_destroy(backer, ct_zone); ++ backer->need_revalidate = REV_RECONFIGURE; + } + } + +@@ -5779,15 +5783,7 @@ ofproto_dpif_lookup_by_name(const char *name) struct ofproto_dpif * ofproto_dpif_lookup_by_uuid(const struct uuid *uuid) { @@ -5602,7 +5646,7 @@ index cba49a99e1..f926d60142 100644 } static void -@@ -6496,6 +6489,7 @@ ofproto_unixctl_dpif_show_dp_features(struct unixctl_conn *conn, +@@ -6496,6 +6492,7 @@ ofproto_unixctl_dpif_show_dp_features(struct unixctl_conn *conn, dpif_show_support(&ofproto->backer->bt_support, &ds); unixctl_command_reply(conn, ds_cstr(&ds)); @@ -6745,10 +6789,10 @@ index a69e37e5c2..48c6df511f 100644 /* On disk data serialization and deserialization. */ diff --git a/ovsdb/raft.c b/ovsdb/raft.c -index 2fb5156519..855404808c 100644 +index 2fb5156519..b70fbed5d4 100644 --- a/ovsdb/raft.c +++ b/ovsdb/raft.c -@@ -74,6 +74,7 @@ enum raft_failure_test { +@@ -74,9 +74,12 @@ enum raft_failure_test { FT_CRASH_BEFORE_SEND_EXEC_REQ, FT_CRASH_AFTER_SEND_EXEC_REQ, FT_CRASH_AFTER_RECV_APPEND_REQ_UPDATE, @@ -6756,7 +6800,12 @@ index 2fb5156519..855404808c 100644 FT_DELAY_ELECTION, FT_DONT_SEND_VOTE_REQUEST, FT_STOP_RAFT_RPC, -@@ -379,12 +380,19 @@ static bool raft_handle_write_error(struct raft *, struct ovsdb_error *); ++ FT_TRANSFER_LEADERSHIP, ++ FT_TRANSFER_LEADERSHIP_AFTER_SEND_APPEND_REQ, + }; + static enum raft_failure_test failure_test; + +@@ -379,12 +382,19 @@ static bool raft_handle_write_error(struct raft *, struct ovsdb_error *); static void raft_run_reconfigure(struct raft *); static void raft_set_leader(struct raft *, const struct uuid *sid); @@ -6776,7 +6825,7 @@ index 2fb5156519..855404808c 100644 static char * raft_make_address_passive(const char *address_) { -@@ -494,11 +502,11 @@ raft_create_cluster(const char *file_name, const char *name, +@@ -494,11 +504,11 @@ raft_create_cluster(const char *file_name, const char *name, .snap_index = index++, .snap = { .term = term, @@ -6789,7 +6838,7 @@ index 2fb5156519..855404808c 100644 shash_add_nocopy(json_object(h.snap.servers), xasprintf(UUID_FMT, UUID_ARGS(&h.sid)), json_string_create(local_address)); -@@ -727,10 +735,10 @@ raft_add_entry(struct raft *raft, +@@ -727,10 +737,10 @@ raft_add_entry(struct raft *raft, uint64_t index = raft->log_end++; struct raft_entry *entry = &raft->entries[index - raft->log_start]; entry->term = term; @@ -6801,7 +6850,7 @@ index 2fb5156519..855404808c 100644 return index; } -@@ -741,13 +749,16 @@ raft_write_entry(struct raft *raft, uint64_t term, struct json *data, +@@ -741,13 +751,16 @@ raft_write_entry(struct raft *raft, uint64_t term, struct json *data, const struct uuid *eid, struct json *servers, uint64_t election_timer) { @@ -6821,7 +6870,7 @@ index 2fb5156519..855404808c 100644 .servers = servers, .election_timer = election_timer, .eid = eid ? *eid : UUID_ZERO, -@@ -1864,6 +1875,8 @@ raft_open_conn(struct raft *raft, const char *address, const struct uuid *sid) +@@ -1864,6 +1877,8 @@ raft_open_conn(struct raft *raft, const char *address, const struct uuid *sid) static void raft_conn_close(struct raft_conn *conn) { @@ -6830,7 +6879,21 @@ index 2fb5156519..855404808c 100644 jsonrpc_session_close(conn->js); ovs_list_remove(&conn->list_node); free(conn->nickname); -@@ -1954,16 +1967,30 @@ raft_run(struct raft *raft) +@@ -1918,6 +1933,13 @@ raft_run(struct raft *raft) + return; + } + ++ if (failure_test == FT_TRANSFER_LEADERSHIP) { ++ /* Using this function as it conveniently implements all we need and ++ * snapshotting is the main test scenario for leadership transfer. */ ++ raft_notify_snapshot_recommended(raft); ++ failure_test = FT_NO_TEST; ++ } ++ + raft_waiters_run(raft); + + if (!raft->listener && time_msec() >= raft->listen_backoff) { +@@ -1954,16 +1976,30 @@ raft_run(struct raft *raft) } /* Close unneeded sessions. */ @@ -6862,7 +6925,23 @@ index 2fb5156519..855404808c 100644 HMAP_FOR_EACH (server, hmap_node, &raft->servers) { raft_open_conn(raft, server->address, &server->sid); } -@@ -2161,7 +2188,7 @@ raft_get_eid(const struct raft *raft, uint64_t index) +@@ -2040,7 +2076,14 @@ raft_run(struct raft *raft) + HMAP_FOR_EACH_SAFE (cmd, next_cmd, hmap_node, &raft->commands) { + if (cmd->timestamp + && now - cmd->timestamp > raft->election_timer * 2) { +- raft_command_complete(raft, cmd, RAFT_CMD_TIMEOUT); ++ if (cmd->index && raft->role != RAFT_LEADER) { ++ /* This server lost leadership and command didn't complete ++ * in time. Likely, it wasn't replicated to the majority ++ * of servers before losing the leadership. */ ++ raft_command_complete(raft, cmd, RAFT_CMD_LOST_LEADERSHIP); ++ } else { ++ raft_command_complete(raft, cmd, RAFT_CMD_TIMEOUT); ++ } + } + } + raft_reset_ping_timer(raft); +@@ -2161,7 +2204,7 @@ raft_get_eid(const struct raft *raft, uint64_t index) { for (; index >= raft->log_start; index--) { const struct raft_entry *e = raft_get_entry(raft, index); @@ -6871,7 +6950,41 @@ index 2fb5156519..855404808c 100644 return &e->eid; } } -@@ -2826,8 +2853,8 @@ raft_truncate(struct raft *raft, uint64_t new_end) +@@ -2232,6 +2275,9 @@ raft_command_initiate(struct raft *raft, + if (failure_test == FT_CRASH_AFTER_SEND_APPEND_REQ) { + ovs_fatal(0, "Raft test: crash after sending append_request."); + } ++ if (failure_test == FT_TRANSFER_LEADERSHIP_AFTER_SEND_APPEND_REQ) { ++ failure_test = FT_TRANSFER_LEADERSHIP; ++ } + raft_reset_ping_timer(raft); + + return cmd; +@@ -2598,7 +2644,13 @@ raft_become_follower(struct raft *raft) + * configuration is already part of the log. Possibly the configuration + * log entry will not be committed, but until we know that we must use the + * new configuration. Our AppendEntries processing will properly update +- * the server configuration later, if necessary. */ ++ * the server configuration later, if necessary. ++ * ++ * Also we do not complete commands here, as they can still be completed ++ * if their log entries have already been replicated to other servers. ++ * If the entries were actually committed according to the new leader, our ++ * AppendEntries processing will complete the corresponding commands. ++ */ + struct raft_server *s; + HMAP_FOR_EACH (s, hmap_node, &raft->add_servers) { + raft_send_add_server_reply__(raft, &s->sid, s->address, false, +@@ -2612,8 +2664,6 @@ raft_become_follower(struct raft *raft) + raft_server_destroy(raft->remove_server); + raft->remove_server = NULL; + } +- +- raft_complete_all_commands(raft, RAFT_CMD_LOST_LEADERSHIP); + } + + static void +@@ -2826,8 +2876,8 @@ raft_truncate(struct raft *raft, uint64_t new_end) return servers_changed; } @@ -6882,7 +6995,7 @@ index 2fb5156519..855404808c 100644 { /* Invariant: log_start - 2 <= last_applied <= commit_index < log_end. */ ovs_assert(raft->log_start <= raft->last_applied + 2); -@@ -2839,32 +2866,20 @@ raft_peek_next_entry(struct raft *raft, struct uuid *eid) +@@ -2839,32 +2889,20 @@ raft_peek_next_entry(struct raft *raft, struct uuid *eid) } if (raft->log_start == raft->last_applied + 2) { @@ -6918,16 +7031,115 @@ index 2fb5156519..855404808c 100644 /* Updates commit index in raft log. If commit index is already up-to-date * it does nothing and return false, otherwise, returns true. */ static bool -@@ -2878,7 +2893,7 @@ raft_update_commit_index(struct raft *raft, uint64_t new_commit_index) - while (raft->commit_index < new_commit_index) { - uint64_t index = ++raft->commit_index; - const struct raft_entry *e = raft_get_entry(raft, index); +@@ -2874,61 +2912,56 @@ raft_update_commit_index(struct raft *raft, uint64_t new_commit_index) + return false; + } + +- if (raft->role == RAFT_LEADER) { +- while (raft->commit_index < new_commit_index) { +- uint64_t index = ++raft->commit_index; +- const struct raft_entry *e = raft_get_entry(raft, index); - if (e->data) { -+ if (raft_entry_has_data(e)) { - struct raft_command *cmd - = raft_find_command_by_eid(raft, &e->eid); - if (cmd) { -@@ -3059,7 +3074,9 @@ raft_handle_append_entries(struct raft *raft, +- struct raft_command *cmd +- = raft_find_command_by_eid(raft, &e->eid); +- if (cmd) { +- if (!cmd->index) { +- VLOG_DBG("Command completed after role change from" +- " follower to leader "UUID_FMT, +- UUID_ARGS(&e->eid)); +- cmd->index = index; +- } +- raft_command_complete(raft, cmd, RAFT_CMD_SUCCESS); ++ while (raft->commit_index < new_commit_index) { ++ uint64_t index = ++raft->commit_index; ++ const struct raft_entry *e = raft_get_entry(raft, index); ++ ++ if (raft_entry_has_data(e)) { ++ struct raft_command *cmd = raft_find_command_by_eid(raft, &e->eid); ++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); ++ ++ if (cmd) { ++ if (!cmd->index && raft->role == RAFT_LEADER) { ++ VLOG_INFO_RL(&rl, ++ "command completed after role change from " ++ "follower to leader (eid: "UUID_FMT", " ++ "commit index: %"PRIu64")", UUID_ARGS(&e->eid), index); ++ } else if (!cmd->index && raft->role != RAFT_LEADER) { ++ /* This can happen when leader fail-over before sending ++ * execute_command_reply. */ ++ VLOG_INFO_RL(&rl, ++ "command completed without reply (eid: "UUID_FMT", " ++ "commit index: %"PRIu64")", UUID_ARGS(&e->eid), index); ++ } else if (cmd->index && raft->role != RAFT_LEADER) { ++ /* This can happen if current server lost leadership after ++ * sending append requests to the majority of servers, but ++ * before receiving majority of append replies. */ ++ VLOG_INFO_RL(&rl, ++ "command completed after role change from " ++ "leader to follower (eid: "UUID_FMT", " ++ "commit index: %"PRIu64")", UUID_ARGS(&e->eid), index); ++ /* Clearing 'sid' to avoid sending cmd execution reply. */ ++ cmd->sid = UUID_ZERO; ++ } else { ++ /* (cmd->index && raft->role == RAFT_LEADER) ++ * Normal command completion on a leader. */ + } +- } +- if (e->election_timer) { +- VLOG_INFO("Election timer changed from %"PRIu64" to %"PRIu64, +- raft->election_timer, e->election_timer); +- raft->election_timer = e->election_timer; +- raft->election_timer_new = 0; +- raft_update_probe_intervals(raft); +- } +- if (e->servers) { +- /* raft_run_reconfigure() can write a new Raft entry, which can +- * reallocate raft->entries, which would invalidate 'e', so +- * this case must be last, after the one for 'e->data'. */ +- raft_run_reconfigure(raft); ++ cmd->index = index; ++ raft_command_complete(raft, cmd, RAFT_CMD_SUCCESS); + } + } +- } else { +- while (raft->commit_index < new_commit_index) { +- uint64_t index = ++raft->commit_index; +- const struct raft_entry *e = raft_get_entry(raft, index); +- if (e->election_timer) { +- VLOG_INFO("Election timer changed from %"PRIu64" to %"PRIu64, +- raft->election_timer, e->election_timer); +- raft->election_timer = e->election_timer; +- raft_update_probe_intervals(raft); +- } ++ if (e->election_timer) { ++ VLOG_INFO("Election timer changed from %"PRIu64" to %"PRIu64, ++ raft->election_timer, e->election_timer); ++ raft->election_timer = e->election_timer; ++ raft->election_timer_new = 0; ++ raft_update_probe_intervals(raft); + } +- /* Check if any pending command can be completed, and complete it. +- * This can happen when leader fail-over before sending +- * execute_command_reply. */ +- const struct uuid *eid = raft_get_eid(raft, new_commit_index); +- struct raft_command *cmd = raft_find_command_by_eid(raft, eid); +- if (cmd) { +- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); +- VLOG_INFO_RL(&rl, +- "Command completed without reply (eid: "UUID_FMT", " +- "commit index: %"PRIu64")", +- UUID_ARGS(eid), new_commit_index); +- cmd->index = new_commit_index; +- raft_command_complete(raft, cmd, RAFT_CMD_SUCCESS); ++ if (e->servers && raft->role == RAFT_LEADER) { ++ /* raft_run_reconfigure() can write a new Raft entry, which can ++ * reallocate raft->entries, which would invalidate 'e', so ++ * this case must be last, after the one for 'e->data'. */ ++ raft_run_reconfigure(raft); + } + } + +@@ -3059,7 +3092,9 @@ raft_handle_append_entries(struct raft *raft, for (; i < n_entries; i++) { const struct raft_entry *e = &entries[i]; error = raft_write_entry(raft, e->term, @@ -6938,7 +7150,7 @@ index 2fb5156519..855404808c 100644 json_nullable_clone(e->servers), e->election_timer); if (error) { -@@ -3314,20 +3331,29 @@ bool +@@ -3314,20 +3349,29 @@ bool raft_has_next_entry(const struct raft *raft_) { struct raft *raft = CONST_CAST(struct raft *, raft_); @@ -6978,7 +7190,7 @@ index 2fb5156519..855404808c 100644 } /* Returns the log index of the last-read snapshot or log entry. */ -@@ -3352,12 +3378,6 @@ raft_find_peer(struct raft *raft, const struct uuid *uuid) +@@ -3352,12 +3396,6 @@ raft_find_peer(struct raft *raft, const struct uuid *uuid) return s && !uuid_equals(&raft->sid, &s->sid) ? s : NULL; } @@ -6991,7 +7203,7 @@ index 2fb5156519..855404808c 100644 /* Figure 3.1: "If there exists an N such that N > commitIndex, a * majority of matchIndex[i] >= N, and log[N].term == currentTerm, set * commitIndex = N (sections 3.5 and 3.6)." */ -@@ -3420,6 +3440,7 @@ raft_send_install_snapshot_request(struct raft *raft, +@@ -3420,6 +3458,7 @@ raft_send_install_snapshot_request(struct raft *raft, const struct raft_server *s, const char *comment) { @@ -6999,7 +7211,7 @@ index 2fb5156519..855404808c 100644 union raft_rpc rpc = { .install_snapshot_request = { .common = { -@@ -3432,7 +3453,7 @@ raft_send_install_snapshot_request(struct raft *raft, +@@ -3432,7 +3471,7 @@ raft_send_install_snapshot_request(struct raft *raft, .last_term = raft->snap.term, .last_servers = raft->snap.servers, .last_eid = raft->snap.eid, @@ -7008,7 +7220,7 @@ index 2fb5156519..855404808c 100644 .election_timer = raft->election_timer, /* use latest value */ } }; -@@ -3980,6 +4001,10 @@ raft_write_snapshot(struct raft *raft, struct ovsdb_log *log, +@@ -3980,6 +4019,10 @@ raft_write_snapshot(struct raft *raft, struct ovsdb_log *log, uint64_t new_log_start, const struct raft_entry *new_snapshot) { @@ -7019,7 +7231,7 @@ index 2fb5156519..855404808c 100644 struct raft_header h = { .sid = raft->sid, .cid = raft->cid, -@@ -3998,12 +4023,13 @@ raft_write_snapshot(struct raft *raft, struct ovsdb_log *log, +@@ -3998,12 +4041,13 @@ raft_write_snapshot(struct raft *raft, struct ovsdb_log *log, /* Write log records. */ for (uint64_t index = new_log_start; index < raft->log_end; index++) { const struct raft_entry *e = &raft->entries[index - raft->log_start]; @@ -7034,7 +7246,7 @@ index 2fb5156519..855404808c 100644 .servers = e->servers, .election_timer = e->election_timer, .eid = e->eid, -@@ -4093,19 +4119,21 @@ raft_handle_install_snapshot_request__( +@@ -4093,19 +4137,21 @@ raft_handle_install_snapshot_request__( /* Case 3: The new snapshot starts past the end of our current log, so * discard all of our current log. */ @@ -7059,7 +7271,7 @@ index 2fb5156519..855404808c 100644 return false; } -@@ -4120,7 +4148,7 @@ raft_handle_install_snapshot_request__( +@@ -4120,7 +4166,7 @@ raft_handle_install_snapshot_request__( } raft_entry_uninit(&raft->snap); @@ -7068,7 +7280,7 @@ index 2fb5156519..855404808c 100644 raft_get_servers_from_log(raft, VLL_INFO); raft_get_election_timer_from_log(raft); -@@ -4132,6 +4160,10 @@ static void +@@ -4132,6 +4178,10 @@ static void raft_handle_install_snapshot_request( struct raft *raft, const struct raft_install_snapshot_request *rq) { @@ -7079,7 +7291,7 @@ index 2fb5156519..855404808c 100644 if (raft_handle_install_snapshot_request__(raft, rq)) { union raft_rpc rpy = { .install_snapshot_reply = { -@@ -4216,7 +4248,7 @@ raft_may_snapshot(const struct raft *raft) +@@ -4216,7 +4266,7 @@ raft_may_snapshot(const struct raft *raft) && !raft->leaving && !raft->left && !raft->failed @@ -7088,7 +7300,7 @@ index 2fb5156519..855404808c 100644 && raft->last_applied >= raft->log_start); } -@@ -4265,11 +4297,12 @@ raft_store_snapshot(struct raft *raft, const struct json *new_snapshot_data) +@@ -4265,11 +4315,12 @@ raft_store_snapshot(struct raft *raft, const struct json *new_snapshot_data) uint64_t new_log_start = raft->last_applied + 1; struct raft_entry new_snapshot = { .term = raft_get_term(raft, new_log_start - 1), @@ -7102,7 +7314,7 @@ index 2fb5156519..855404808c 100644 struct ovsdb_error *error = raft_save_snapshot(raft, new_log_start, &new_snapshot); if (error) { -@@ -4286,6 +4319,9 @@ raft_store_snapshot(struct raft *raft, const struct json *new_snapshot_data) +@@ -4286,6 +4337,9 @@ raft_store_snapshot(struct raft *raft, const struct json *new_snapshot_data) memmove(&raft->entries[0], &raft->entries[new_log_start - raft->log_start], (raft->log_end - new_log_start) * sizeof *raft->entries); raft->log_start = new_log_start; @@ -7112,7 +7324,7 @@ index 2fb5156519..855404808c 100644 return NULL; } -@@ -4926,6 +4962,8 @@ raft_unixctl_failure_test(struct unixctl_conn *conn OVS_UNUSED, +@@ -4926,6 +4980,8 @@ raft_unixctl_failure_test(struct unixctl_conn *conn OVS_UNUSED, failure_test = FT_CRASH_AFTER_SEND_EXEC_REQ; } else if (!strcmp(test, "crash-after-receiving-append-request-update")) { failure_test = FT_CRASH_AFTER_RECV_APPEND_REQ_UPDATE; @@ -7121,6 +7333,18 @@ index 2fb5156519..855404808c 100644 } else if (!strcmp(test, "delay-election")) { failure_test = FT_DELAY_ELECTION; struct raft *raft; +@@ -4938,6 +4994,11 @@ raft_unixctl_failure_test(struct unixctl_conn *conn OVS_UNUSED, + failure_test = FT_DONT_SEND_VOTE_REQUEST; + } else if (!strcmp(test, "stop-raft-rpc")) { + failure_test = FT_STOP_RAFT_RPC; ++ } else if (!strcmp(test, ++ "transfer-leadership-after-sending-append-request")) { ++ failure_test = FT_TRANSFER_LEADERSHIP_AFTER_SEND_APPEND_REQ; ++ } else if (!strcmp(test, "transfer-leadership")) { ++ failure_test = FT_TRANSFER_LEADERSHIP; + } else if (!strcmp(test, "clear")) { + failure_test = FT_NO_TEST; + unixctl_command_reply(conn, "test dismissed"); diff --git a/ovsdb/raft.h b/ovsdb/raft.h index 3545c41c2c..599bc0ae86 100644 --- a/ovsdb/raft.h @@ -8544,6 +8768,81 @@ index 7ef32d13cb..cb0e9df388 100755 print() flows.write(struct.pack('>LH', +diff --git a/tests/mcast-snooping.at b/tests/mcast-snooping.at +index 757cf7186e..fe475e7b38 100644 +--- a/tests/mcast-snooping.at ++++ b/tests/mcast-snooping.at +@@ -216,3 +216,70 @@ AT_CHECK([ovs-appctl mdb/show br0], [0], [dnl + ]) + + AT_CLEANUP ++ ++ ++AT_SETUP([mcast - igmp flood for non-snoop enabled]) ++OVS_VSWITCHD_START([]) ++ ++AT_CHECK([ ++ ovs-vsctl set bridge br0 \ ++ datapath_type=dummy], [0]) ++ ++add_of_ports br0 1 2 ++ ++AT_CHECK([ovs-ofctl add-flow br0 action=normal]) ++ ++ovs-appctl time/stop ++ ++dnl Basic scenario - needs to flood for IGMP followed by unicast ICMP ++dnl in reverse direction ++AT_CHECK([ovs-appctl netdev-dummy/receive p1 \ ++ '0101000c29a0aa55aa550001080046c00028000040000102d3494565eb4ae0000016940400002200f9020000000104000000e00000fb000000000000']) ++AT_CHECK([ovs-appctl netdev-dummy/receive p2 \ ++ 'aa55aa5500010101000c29a008004500001c00010000400164dc0a0101010a0101020800f7ffffffffff']) ++ ++ ++AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl ++ strip_stats | strip_used | strip_recirc | dnl ++ sed -e 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'], ++ [0], [dnl ++recirc_id(),in_port(1),eth(src=aa:55:aa:55:00:01,dst=01:01:00:0c:29:a0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:100,2 ++recirc_id(),in_port(2),eth(src=01:01:00:0c:29:a0,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:1 ++]) ++ ++ovs-appctl time/warp 100000 ++ ++dnl Next we should clear the flows and install a complex case ++AT_CHECK([ovs-ofctl del-flows br0]) ++ ++AT_DATA([flows.txt], [dnl ++table=0, arp actions=NORMAL ++table=0, ip,in_port=1 actions=ct(table=1,zone=64000) ++table=0, in_port=2 actions=output:1 ++table=1, ip,ct_state=+trk+inv actions=drop ++table=1 ip,in_port=1,icmp,ct_state=+trk+new actions=output:2 ++table=1, in_port=1,ip,ct_state=+trk+new actions=controller(userdata=00.de.ad.be.ef.ca.fe.01) ++table=1, in_port=1,ip,ct_state=+trk+est actions=output:2 ++]) ++AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) ++ ++ovs-appctl time/warp 100000 ++ ++dnl Send the IGMP, followed by a unicast ICMP - ensure we won't black hole ++AT_CHECK([ovs-appctl netdev-dummy/receive p1 \ ++ '0101000c29a0aa55aa550001080046c00028000040000102d3494565eb4ae0000016940400002200f9020000000104000000e00000fb000000000000']) ++AT_CHECK([ovs-appctl netdev-dummy/receive p1 \ ++ 'aa55aa550001aa55aa55000208004500001c00010000400164dc0a0101010a0101020800f7ffffffffff']) ++ ++ ++AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl ++ strip_stats | strip_used | strip_recirc | dnl ++ sed 's/pid=[[0-9]]*,// ++ s/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'], ++ [0], [dnl ++ct_state(+new-inv+trk),recirc_id(),in_port(1),eth_type(0x0800),ipv4(proto=1,frag=no), packets:0, bytes:0, used:never, actions:2 ++ct_state(+new-inv+trk),recirc_id(),in_port(1),eth_type(0x0800),ipv4(proto=2,frag=no), packets:0, bytes:0, used:never, actions:userspace(controller(reason=1,dont_send=0,continuation=0,recirc_id=,rule_cookie=0,controller_id=0,max_len=65535)) ++recirc_id(),in_port(1),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:0.0s, actions:ct(zone=64000),recirc() ++]) ++ ++AT_CLEANUP diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index 956a69e1fa..266ed801e6 100644 --- a/tests/ofproto-dpif.at @@ -8889,6 +9188,32 @@ index 956a69e1fa..266ed801e6 100644 OVS_VSWITCHD_STOP AT_CLEANUP +diff --git a/tests/ofproto-macros.at b/tests/ofproto-macros.at +index 736d9809cb..f906b5c3b5 100644 +--- a/tests/ofproto-macros.at ++++ b/tests/ofproto-macros.at +@@ -134,6 +134,21 @@ strip_ufid () { + sed 's/mega_ufid:[[-0-9a-f]]* // + s/ufid:[[-0-9a-f]]* //' + } ++ ++# Strips packets: and bytes: from output ++strip_stats () { ++ sed 's/packets:[[0-9]]*/packets:0/ ++ s/bytes:[[0-9]]*/bytes:0/' ++} ++ ++# Changes all 'recirc(...)' and 'recirc=...' to say 'recirc()' and ++# 'recirc=' respectively. This should make output easier to ++# compare. ++strip_recirc() { ++ sed 's/recirc_id([[x0-9]]*)/recirc_id()/ ++ s/recirc_id=[[x0-9]]*/recirc_id=/ ++ s/recirc([[x0-9]]*)/recirc()/' ++} + m4_divert_pop([PREPARE_TESTS]) + + m4_define([TESTABLE_LOG], [-vPATTERN:ANY:'%c|%p|%m']) diff --git a/tests/ovs-macros.at b/tests/ovs-macros.at index 66545da572..e6c5bc6e94 100644 --- a/tests/ovs-macros.at @@ -8983,7 +9308,7 @@ index 06b671df8c..2d14f1ac26 100644 AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:socket db], [0], [ignore], [ignore]) sed 's/5\.1\.3/5.1.4/' < schema > schema2 diff --git a/tests/ovsdb-cluster.at b/tests/ovsdb-cluster.at -index fc6253cfe9..ee9c7b9379 100644 +index fc6253cfe9..0f7076a052 100644 --- a/tests/ovsdb-cluster.at +++ b/tests/ovsdb-cluster.at @@ -400,6 +400,61 @@ done @@ -9048,7 +9373,11 @@ index fc6253cfe9..ee9c7b9379 100644 OVS_START_SHELL_HELPERS -@@ -416,9 +471,8 @@ ovsdb_cluster_failure_test () { +@@ -413,12 +468,12 @@ ovsdb_cluster_failure_test () { + if test "$crash_node" == "1"; then + new_leader=$5 + fi ++ log_grep=$6 cp $top_srcdir/vswitchd/vswitch.ovsschema schema schema=`ovsdb-tool schema-name schema` @@ -9060,7 +9389,57 @@ index fc6253cfe9..ee9c7b9379 100644 n=3 join_cluster() { -@@ -629,9 +683,8 @@ ovsdb_torture_test () { +@@ -434,7 +489,7 @@ ovsdb|WARN|schema: changed 30 columns in 'Open_vSwitch' database from ephemeral + start_server() { + local i=$1 + printf "\ns$i: starting\n" +- AT_CHECK([ovsdb-server -vjsonrpc -vconsole:off -vsyslog:off --detach --no-chdir --log-file=s$i.log --pidfile=s$i.pid --unixctl=s$i --remote=punix:s$i.ovsdb s$i.db]) ++ AT_CHECK([ovsdb-server -vjsonrpc -vraft -vconsole:off -vsyslog:off --detach --no-chdir --log-file=s$i.log --pidfile=s$i.pid --unixctl=s$i --remote=punix:s$i.ovsdb s$i.db]) + } + connect_server() { + local i=$1 +@@ -460,14 +515,23 @@ ovsdb|WARN|schema: changed 30 columns in 'Open_vSwitch' database from ephemeral + fi + AT_CHECK([ovs-appctl -t "`pwd`"/s$delay_election_node cluster/failure-test delay-election], [0], [ignore]) + fi ++ ++ # Initializing the database separately to avoid extra 'wait' operation ++ # in later transactions. ++ AT_CHECK([ovs-vsctl -v --db="$db" --no-leader-only --no-shuffle-remotes --no-wait init], [0], [ignore], [ignore]) ++ + AT_CHECK([ovs-appctl -t "`pwd`"/s$crash_node cluster/failure-test $crash_command], [0], [ignore]) + AT_CHECK([ovs-vsctl -v --db="$db" --no-leader-only --no-shuffle-remotes --no-wait create QoS type=x], [0], [ignore], [ignore]) + +- # Make sure that the node really crashed. +- AT_CHECK([ls s$crash_node.ovsdb], [2], [ignore], [ignore]) +- # XXX: Client will fail if remotes contains unix socket that doesn't exist (killed). +- if test "$remote_1" = "$crash_node"; then +- db=unix:s$remote_2.ovsdb ++ # Make sure that the node really crashed or has specific log message. ++ if test -z "$log_grep"; then ++ AT_CHECK([ls s$crash_node.ovsdb], [2], [ignore], [ignore]) ++ # XXX: Client will fail if remotes contains unix socket that doesn't exist (killed). ++ if test "$remote_1" = "$crash_node"; then ++ db=unix:s$remote_2.ovsdb ++ fi ++ else ++ OVS_WAIT_UNTIL([grep -q "$log_grep" s${crash_node}.log]) + fi + AT_CHECK([ovs-vsctl --db="$db" --no-leader-only --no-wait --columns=type --bare list QoS], [0], [x + ]) +@@ -563,6 +627,11 @@ AT_KEYWORDS([ovsdb server negative unix cluster pending-txn]) + ovsdb_cluster_failure_test 2 2 3 crash-after-receiving-append-request-update + AT_CLEANUP + ++AT_SETUP([OVSDB cluster - txn on leader, leader transfers leadership after sending appendReq]) ++AT_KEYWORDS([ovsdb server negative unix cluster pending-txn transfer]) ++ovsdb_cluster_failure_test 1 2 1 transfer-leadership-after-sending-append-request -1 "Transferring leadership" ++AT_CLEANUP ++ + + AT_SETUP([OVSDB cluster - competing candidates]) + AT_KEYWORDS([ovsdb server negative unix cluster competing-candidates]) +@@ -629,9 +698,8 @@ ovsdb_torture_test () { local variant=$3 # 'kill' and restart or 'remove' and add cp $top_srcdir/vswitchd/vswitch.ovsschema schema schema=`ovsdb-tool schema-name schema` @@ -9914,7 +10293,7 @@ index 1714273e35..270956d13f 100644 dnl Delete ip address. AT_CHECK([ip addr del 10.0.0.17/24 dev p1-route], [0], [stdout]) diff --git a/tests/system-traffic.at b/tests/system-traffic.at -index f400cfabc9..ea3078e3e4 100644 +index f400cfabc9..c6ff310013 100644 --- a/tests/system-traffic.at +++ b/tests/system-traffic.at @@ -218,6 +218,7 @@ OVS_TRAFFIC_VSWITCHD_STOP @@ -10288,6 +10667,92 @@ index f400cfabc9..ea3078e3e4 100644 echo Request $i NS_CHECK_EXEC([at_ns1], [wget 10.1.1.64 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) done +@@ -6106,6 +6315,85 @@ AT_CHECK([ovs-ofctl dump-flows br0 | grep table=2, | OFPROTO_CLEAR_DURATION_IDLE + OVS_TRAFFIC_VSWITCHD_STOP + AT_CLEANUP + ++AT_BANNER([IGMP]) ++ ++AT_SETUP([IGMP - flood under normal action]) ++ ++OVS_TRAFFIC_VSWITCHD_START() ++ADD_NAMESPACES(at_ns0, at_ns1) ++ ++ADD_VETH(p1, at_ns0, br0, "10.1.1.1/24", "f0:00:00:01:01:01") ++ADD_VETH(p2, at_ns1, br0, "10.1.1.2/24", "f0:00:00:01:01:02") ++ ++AT_CHECK([ovs-ofctl add-flow br0 "actions=NORMAL"]) ++ ++NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 01 00 5e 01 01 03 dnl ++f0 00 00 01 01 01 08 00 46 c0 00 28 00 00 40 00 01 02 d3 49 45 65 eb 4a e0 dnl ++00 00 16 94 04 00 00 22 00 f9 02 00 00 00 01 04 00 00 00 e0 00 00 fb 00 00 dnl ++00 00 00 00 > /dev/null]) ++ ++AT_CHECK([ovs-appctl dpctl/dump-flows --names | grep -e .*ipv4 | sort | dnl ++ strip_stats | strip_used | strip_recirc | dnl ++ sed 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'], ++ [0], [dnl ++recirc_id(),in_port(ovs-p1),eth(src=f0:00:00:01:01:01,dst=01:00:5e:01:01:03),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:br0,ovs-p2 ++]) ++OVS_TRAFFIC_VSWITCHD_STOP ++AT_CLEANUP ++ ++AT_SETUP([IGMP - forward with ICMP]) ++ ++OVS_TRAFFIC_VSWITCHD_START() ++ADD_NAMESPACES(at_ns0, at_ns1) ++ ++ADD_VETH(p1, at_ns0, br0, "10.1.1.1/24", "f0:00:00:01:01:01") ++ADD_VETH(p2, at_ns1, br0, "10.1.1.2/24", "f0:00:00:01:01:02") ++ ++AT_DATA([flows.txt], [dnl ++table=0, arp actions=NORMAL ++table=0, ip,in_port=1 actions=ct(table=1,zone=64000) ++table=0, in_port=2 actions=output:1 ++table=1, ip,ct_state=+trk+inv actions=drop ++table=1 ip,in_port=1,icmp,ct_state=+trk+new actions=output:2 ++table=1, in_port=1,ip,ct_state=+trk+new actions=controller(userdata=00.de.ad.be.ef.ca.fe.01) ++table=1, in_port=1,ip,ct_state=+trk+est actions=output:2 ++]) ++AT_CHECK([ovs-ofctl del-flows br0]) ++AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) ++ ++dnl Send the IGMP, followed by a unicast ICMP - ensure we won't black hole ++ ++NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 f0 00 00 01 01 02 dnl ++f0 00 00 01 01 01 08 00 46 c0 00 28 00 00 40 00 01 02 d3 49 45 65 eb 4a e0 dnl ++00 00 16 94 04 00 00 22 00 f9 02 00 00 00 01 04 00 00 00 e0 00 00 fb 00 00 dnl ++00 00 00 00 > /dev/null]) ++ ++NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 f0 00 00 01 01 02 dnl ++f0 00 00 01 01 01 08 00 45 00 00 1c 00 01 00 00 40 01 64 dc 0a 01 01 01 0a dnl ++01 01 02 08 00 f7 ff ff ff ff ff > /dev/null]) ++ ++sleep 1 ++ ++dnl Prefer the OpenFlow rules, because different datapaths will behave slightly ++dnl differently with respect to the exact dp rules. ++dnl ++dnl This is also why we clear n_bytes / n_packets - some kernels with ipv6 ++dnl enabled will bump some of these counters non-deterministically ++ ++AT_CHECK([ovs-ofctl dump-flows br0 | grep -v NXST | dnl ++ strip_duration | grep -v arp | grep -v n_packets=0 | dnl ++ grep -v 'in_port=2 actions=output:1' | dnl ++ sed 's/n_bytes=[[0-9]]*/n_bytes=0/ ++ s/idle_age=[[0-9]]*/idle_age=0/ ++ s/n_packets=[[1-9]]/n_packets=0/' | sort], [0], [dnl ++ cookie=0x0, table=0, n_packets=0, n_bytes=0, idle_age=0, ip,in_port=1 actions=ct(table=1,zone=64000) ++ cookie=0x0, table=1, n_packets=0, n_bytes=0, idle_age=0, ct_state=+new+trk,icmp,in_port=1 actions=output:2 ++ cookie=0x0, table=1, n_packets=0, n_bytes=0, idle_age=0, ct_state=+new+trk,ip,in_port=1 actions=controller(userdata=00.de.ad.be.ef.ca.fe.01) ++]) ++ ++OVS_TRAFFIC_VSWITCHD_STOP ++AT_CLEANUP ++ + AT_BANNER([802.1ad]) + + AT_SETUP([802.1ad - vlan_limit]) diff --git a/tests/system-tso-macros.at b/tests/system-tso-macros.at index 406334f3e0..1a80047619 100644 --- a/tests/system-tso-macros.at diff --git a/SPECS/openvswitch2.16.spec b/SPECS/openvswitch2.16.spec index 3a5ef72..50275a8 100644 --- a/SPECS/openvswitch2.16.spec +++ b/SPECS/openvswitch2.16.spec @@ -57,7 +57,7 @@ Summary: Open vSwitch Group: System Environment/Daemons daemon/database/utilities URL: http://www.openvswitch.org/ Version: 2.16.0 -Release: 77%{?dist} +Release: 78%{?dist} # Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the # lib/sflow*.[ch] files are SISSL @@ -699,6 +699,14 @@ exit 0 %endif %changelog +* Thu May 26 2022 Ilya Maximets - 2.16.0-78 +- Merging upstream branch-2.16 [RH git: d7d5f09849] + Commit list: + c8c78a76e5 ovsdb: raft: Fix transaction double commit due to lost leadership. (#2046340) + 2809af022a Revert "odp-util: Always report ODP_FIT_TOO_LITTLE for IGMP." + 90e31552be ofproto-dpif: Trigger revalidation if ct tp changes. + + * Wed May 25 2022 Open vSwitch CI - 2.16.0-77 - Merging upstream branch-2.16 [RH git: 3e3d3725d3] Commit list: