diff --git a/SOURCES/openvswitch-3.4.0.patch b/SOURCES/openvswitch-3.4.0.patch index fb91663..ff62b55 100644 --- a/SOURCES/openvswitch-3.4.0.patch +++ b/SOURCES/openvswitch-3.4.0.patch @@ -1,3 +1,16 @@ +diff --git a/.ci/linux-prepare.sh b/.ci/linux-prepare.sh +index 2a191b57fb..5f8a1db6af 100755 +--- a/.ci/linux-prepare.sh ++++ b/.ci/linux-prepare.sh +@@ -23,7 +23,7 @@ cd .. + # https://github.com/pypa/pip/issues/10655 + pip3 install --disable-pip-version-check --user wheel + pip3 install --disable-pip-version-check --user \ +- flake8 netaddr pyparsing sarif-tools sphinx setuptools ++ flake8 netaddr pyparsing sarif-tools==2.0.0 sphinx setuptools + + # Install python test dependencies + pip3 install -r python/test_requirements.txt diff --git a/Documentation/ref/ovs-appctl.8.rst b/Documentation/ref/ovs-appctl.8.rst index 7054cf559e..e7c8b96d49 100644 --- a/Documentation/ref/ovs-appctl.8.rst @@ -198,6 +211,21 @@ index 7054cf559e..e7c8b96d49 100644 of ``kern``, ``user``, ``mail``, ``daemon``, ``auth``, ``syslog``, ``lpr``, ``news``, ``uucp``, ``clock``, ``ftp``, ``ntp``, ``audit``, ``alert``, ``clock2``, ``local0``, ``local1``, ``local2``, +diff --git a/lib/mcast-snooping.c b/lib/mcast-snooping.c +index dc5164b41c..bf25e6f20a 100644 +--- a/lib/mcast-snooping.c ++++ b/lib/mcast-snooping.c +@@ -432,7 +432,9 @@ mcast_snooping_add_group(struct mcast_snooping *ms, + uint32_t hash = mcast_table_hash(ms, addr, vlan); + + if (hmap_count(&ms->table) >= ms->max_entries) { +- group_get_lru(ms, &grp); ++ if (!group_get_lru(ms, &grp)) { ++ return false; ++ } + mcast_snooping_flush_group(ms, grp); + } + diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c index 16c56608d8..529d64fe1d 100644 --- a/lib/netdev-native-tnl.c @@ -211,3 +239,344 @@ index 16c56608d8..529d64fe1d 100644 } else if (IP_VER(ip->ip_ihl_ver) == 6) { dp_packet_hwol_set_tx_ipv6(packet); } +diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c +index ba720474b6..d92df28d19 100644 +--- a/lib/ovsdb-idl.c ++++ b/lib/ovsdb-idl.c +@@ -3783,6 +3783,8 @@ ovsdb_idl_txn_delete(const struct ovsdb_idl_row *row_) + ovsdb_idl_remove_from_indexes(row_); + if (!row->old_datum) { + ovsdb_idl_row_unparse(row); ++ ovsdb_idl_destroy_all_map_op_lists(row); ++ ovsdb_idl_destroy_all_set_op_lists(row); + ovsdb_idl_row_clear_new(row); + ovs_assert(!row->prereqs); + hmap_remove(&row->table->rows, &row->hmap_node); +diff --git a/lib/vconn.c b/lib/vconn.c +index e9603432d2..4b1c262eaa 100644 +--- a/lib/vconn.c ++++ b/lib/vconn.c +@@ -1017,6 +1017,8 @@ recv_flow_stats_reply(struct vconn *vconn, ovs_be32 send_xid, + VLOG_WARN_RL(&rl, "received bad reply: %s", + ofp_to_string(reply->data, reply->size, + NULL, NULL, 1)); ++ ofpbuf_delete(reply); ++ *replyp = NULL; + return EPROTO; + } + } +@@ -1031,9 +1033,9 @@ recv_flow_stats_reply(struct vconn *vconn, ovs_be32 send_xid, + case EOF: + more = ofpmp_more(reply->header); + ofpbuf_delete(reply); ++ *replyp = NULL; + reply = NULL; + if (!more) { +- *replyp = NULL; + return EOF; + } + break; +@@ -1041,6 +1043,8 @@ recv_flow_stats_reply(struct vconn *vconn, ovs_be32 send_xid, + default: + VLOG_WARN_RL(&rl, "parse error in reply (%s)", + ofperr_to_string(retval)); ++ ofpbuf_delete(reply); ++ *replyp = NULL; + return EPROTO; + } + } +diff --git a/ofproto/bond.c b/ofproto/bond.c +index c31869a4c7..0858de3746 100644 +--- a/ofproto/bond.c ++++ b/ofproto/bond.c +@@ -246,7 +246,7 @@ bond_create(const struct bond_settings *s, struct ofproto_dpif *ofproto) + ovs_refcount_init(&bond->ref_cnt); + hmap_init(&bond->pr_rule_ops); + +- bond->active_member_mac = eth_addr_zero; ++ bond->active_member_mac = s->active_member_mac; + bond->active_member_changed = false; + bond->primary = NULL; + +diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c +index 4d39bc5a71..e7d4c2b2c3 100644 +--- a/ofproto/ofproto-dpif-upcall.c ++++ b/ofproto/ofproto-dpif-upcall.c +@@ -57,6 +57,7 @@ COVERAGE_DEFINE(dumped_inconsistent_flow); + COVERAGE_DEFINE(dumped_new_flow); + COVERAGE_DEFINE(handler_duplicate_upcall); + COVERAGE_DEFINE(revalidate_missed_dp_flow); ++COVERAGE_DEFINE(revalidate_missing_dp_flow); + COVERAGE_DEFINE(ukey_dp_change); + COVERAGE_DEFINE(ukey_invalid_stat_reset); + COVERAGE_DEFINE(ukey_replace_contention); +@@ -284,6 +285,7 @@ enum flow_del_reason { + FDR_TOO_EXPENSIVE, /* Too expensive to revalidate. */ + FDR_UPDATE_FAIL, /* Datapath update failed. */ + FDR_XLATION_ERROR, /* Flow translation error. */ ++ FDR_FLOW_MISSING_DP, /* Flow is missing from the datapath. */ + }; + + /* 'udpif_key's are responsible for tracking the little bit of state udpif +@@ -318,6 +320,7 @@ struct udpif_key { + uint64_t dump_seq OVS_GUARDED; /* Tracks udpif->dump_seq. */ + uint64_t reval_seq OVS_GUARDED; /* Tracks udpif->reval_seq. */ + enum ukey_state state OVS_GUARDED; /* Tracks ukey lifetime. */ ++ uint32_t missed_dumps OVS_GUARDED; /* Missed consecutive dumps. */ + + /* 'state' debug information. */ + unsigned int state_thread OVS_GUARDED; /* Thread that transitions. */ +@@ -3040,6 +3043,21 @@ revalidator_sweep__(struct revalidator *revalidator, bool purge) + result = revalidate_ukey(udpif, ukey, &stats, &odp_actions, + reval_seq, &recircs, &del_reason); + } ++ ++ if (ukey->dump_seq != dump_seq) { ++ ukey->missed_dumps++; ++ if (ukey->missed_dumps >= 4) { ++ /* If the flow was not dumped for 4 revalidator rounds, ++ * we can assume the datapath flow no longer exists ++ * and the ukey should be deleted. */ ++ COVERAGE_INC(revalidate_missing_dp_flow); ++ del_reason = FDR_FLOW_MISSING_DP; ++ result = UKEY_DELETE; ++ } ++ } else { ++ ukey->missed_dumps = 0; ++ } ++ + if (result != UKEY_KEEP) { + /* Clears 'recircs' if filled by revalidate_ukey(). */ + reval_op_init(&ops[n_ops++], result, udpif, ukey, &recircs, +diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at +index 42fb66de68..12cb7f7a6a 100644 +--- a/tests/ofproto-dpif.at ++++ b/tests/ofproto-dpif.at +@@ -757,6 +757,73 @@ Datapath actions: drop + OVS_VSWITCHD_STOP() + AT_CLEANUP + ++AT_SETUP([ofproto-dpif - active bond member survives restart]) ++dnl Create bond0 with members p1, p2 and p3. Initially, set p2 as active. ++dnl Restart ovs-vswitchd. Check that p2 is still active. ++OVS_VSWITCHD_START( ++ [add-bond br0 bond0 p1 p2 p3 bond_mode=active-backup -- \ ++ set interface p1 type=dummy ofport_request=1 -- \ ++ set interface p2 type=dummy ofport_request=2 -- \ ++ set interface p3 type=dummy ofport_request=3 --]) ++AT_CHECK([ovs-appctl bond/set-active-member bond0 p2], [0], [ignore]) ++OVS_WAIT_UNTIL_EQUAL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC], [dnl ++---- bond0 ---- ++bond_mode: active-backup ++bond may use recirculation: no, ++bond-hash-basis: 0 ++lb_output action: disabled, bond-id: -1 ++updelay: 0 ms ++downdelay: 0 ms ++lacp_status: off ++lacp_fallback_ab: false ++active-backup primary: ++ ++ ++member p1: enabled ++ may_enable: true ++ ++member p2: enabled ++ active member ++ may_enable: true ++ ++member p3: enabled ++ may_enable: true ++]) ++ ++dnl Restart ovs-vswitchd with an empty ovs-vswitchd log file. ++OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) ++mv ovs-vswitchd.log ovs-vswitchd_1.log ++AT_CHECK([ovs-vswitchd --enable-dummy --disable-system --disable-system-route --detach \ ++ --no-chdir --pidfile --log-file -vfile:rconn:dbg -vvconn -vofproto_dpif -vunixctl], ++ [0], [], [stderr]) ++ ++OVS_WAIT_UNTIL_EQUAL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC], [dnl ++---- bond0 ---- ++bond_mode: active-backup ++bond may use recirculation: no, ++bond-hash-basis: 0 ++lb_output action: disabled, bond-id: -1 ++updelay: 0 ms ++downdelay: 0 ms ++lacp_status: off ++lacp_fallback_ab: false ++active-backup primary: ++ ++ ++member p1: enabled ++ may_enable: true ++ ++member p2: enabled ++ active member ++ may_enable: true ++ ++member p3: enabled ++ may_enable: true ++]) ++ ++OVS_VSWITCHD_STOP ++AT_CLEANUP ++ + AT_SETUP([ofproto-dpif - bond - allow duplicated frames]) + dnl Receiving of duplicated multicast frames should be allowed with 'all_members_active'. + OVS_VSWITCHD_START([dnl +@@ -12661,3 +12728,48 @@ AT_CHECK([ovs-appctl revalidator/resume]) + + OVS_VSWITCHD_STOP + AT_CLEANUP ++ ++AT_SETUP([ofproto-dpif - Cleanup missing datapath flows]) ++ ++OVS_VSWITCHD_START ++add_of_ports br0 1 2 ++ ++m4_define([ICMP_PKT], [m4_join([,], ++ [eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),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)])]) ++ ++AT_CHECK([ovs-ofctl del-flows br0]) ++AT_CHECK([ovs-ofctl add-flow br0 'actions=normal' ]) ++ ++AT_CHECK([ovs-appctl netdev-dummy/receive p1 'ICMP_PKT']) ++ ++AT_CHECK([ovs-appctl dpctl/dump-flows --names | strip_used | strip_stats | dnl ++ strip_duration | strip_dp_hash | sort], [0], [dnl ++flow-dump from the main thread: ++recirc_id(0),in_port(p1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:br0,p2 ++]) ++ ++dnl Make sure the ukey exists. ++AT_CHECK([ovs-appctl upcall/show | grep '(keys' | awk '{print $3}' | \ ++ grep -q '1)'], [0]) ++ ++dnl Delete all datapath flows, and make sure they are gone. ++AT_CHECK([ovs-appctl dpctl/del-flows]) ++AT_CHECK([ovs-appctl dpctl/dump-flows --names ], [0], []) ++ ++dnl Move forward in time and make sure we have at least 4 * 500ms. ++AT_CHECK([ovs-appctl time/warp 3000 300], [0], [ignore]) ++ ++dnl Make sure no more ukeys exists. ++AT_CHECK([ovs-appctl upcall/show | grep '(keys' | awk '{print $3}' | \ ++ grep -qv '0)'], [1]) ++ ++dnl Verify coverage counter was hit. ++AT_CHECK([ovs-appctl coverage/read-counter revalidate_missing_dp_flow], [0], ++ [dnl ++1 ++]) ++ ++OVS_VSWITCHD_STOP(["/failed to flow_del (No such file or directory)/d"]) ++AT_CLEANUP +diff --git a/tests/ovsdb-idl.at b/tests/ovsdb-idl.at +index 9070ea051a..74ccaccdd2 100644 +--- a/tests/ovsdb-idl.at ++++ b/tests/ovsdb-idl.at +@@ -1881,7 +1881,10 @@ OVSDB_CHECK_IDL_PARTIAL_UPDATE_MAP_COLUMN([map, simple2 idl-partial-update-map-c + 007: name=String2 smap=[[key2 : value2]] imap=[[3 : myids2]] + 008: After trying to delete a deleted element + 009: name=String2 smap=[[key2 : value2]] imap=[[3 : myids2]] +-010: End test ++010: After Create element, update smap and Delete element ++011: name=String2 smap=[[key2 : value2]] imap=[[3 : myids2]] ++012: After update smap and Delete element ++014: End test + ]]) + + OVSDB_CHECK_IDL_PY([partial-map idl], +@@ -1944,7 +1947,9 @@ OVSDB_CHECK_IDL_PARTIAL_UPDATE_SET_COLUMN([set, simple3 idl-partial-update-set-c + 009: table simple3: name=String2 uset=[<0>,<1>,<4>] uref=[] uuid=<2> + 010: After add to other table + set of strong ref + 011: table simple3: name=String2 uset=[<0>,<1>,<4>] uref=[<5>] uuid=<2> +-012: End test ++012: After Create element, update set and Delete element ++013: table simple3: name=String2 uset=[<0>,<1>,<4>] uref=[<5>] uuid=<2> ++014: End test + ]]) + + OVSDB_CHECK_IDL_PY([partial-set idl], +diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c +index 41c1525f45..710341b655 100644 +--- a/tests/test-ovsdb.c ++++ b/tests/test-ovsdb.c +@@ -3020,6 +3020,29 @@ do_idl_partial_update_map_column(struct ovs_cmdl_context *ctx) + printf("%03d: After trying to delete a deleted element\n", step++); + dump_simple2(idl, myRow, step++); + ++ myTxn = ovsdb_idl_txn_create(idl); ++ myRow = idltest_simple2_insert(myTxn); ++ idltest_simple2_update_smap_setkey(myRow, "key3", "myList3"); ++ idltest_simple2_set_name(myRow, "String2"); ++ idltest_simple2_delete(myRow); ++ ovsdb_idl_txn_commit_block(myTxn); ++ ovsdb_idl_txn_destroy(myTxn); ++ ovsdb_idl_get_initial_snapshot(idl); ++ printf("%03d: After Create element, update smap and Delete element\n", ++ step++); ++ dump_simple2(idl, myRow, step++); ++ ++ myTxn = ovsdb_idl_txn_create(idl); ++ myRow = idltest_simple2_first(idl); ++ idltest_simple2_update_smap_setkey(myRow, "key4", "myList4"); ++ idltest_simple2_set_name(myRow, "String3"); ++ idltest_simple2_delete(myRow); ++ ovsdb_idl_txn_commit_block(myTxn); ++ ovsdb_idl_txn_destroy(myTxn); ++ ovsdb_idl_get_initial_snapshot(idl); ++ printf("%03d: After update smap and Delete element\n", step++); ++ dump_simple2(idl, myRow, step++); ++ + ovsdb_idl_destroy(idl); + printf("%03d: End test\n", step); + } +@@ -3118,6 +3141,21 @@ do_idl_partial_update_set_column(struct ovs_cmdl_context *ctx) + ovsdb_idl_get_initial_snapshot(idl); + printf("%03d: After add to other table + set of strong ref\n", step++); + dump_simple3(idl, myRow, step++); ++ ++ /* create row, insert key, delete row */ ++ myTxn = ovsdb_idl_txn_create(idl); ++ myRow = idltest_simple3_insert(myTxn); ++ uuid_from_string(&uuid_to_add, "12345678-dd3f-4616-ab6a-83a490bb0991"); ++ idltest_simple3_update_uset_addvalue(myRow, uuid_to_add); ++ idltest_simple3_set_name(myRow, "String2"); ++ idltest_simple3_delete(myRow); ++ ovsdb_idl_txn_commit_block(myTxn); ++ ovsdb_idl_txn_destroy(myTxn); ++ ovsdb_idl_get_initial_snapshot(idl); ++ printf("%03d: After Create element, update set and Delete element\n", ++ step++); ++ dump_simple3(idl, myRow, step++); ++ + ovsdb_idl_destroy(idl); + printf("%03d: End test\n", step); + } +diff --git a/utilities/usdt-scripts/flow_reval_monitor.py b/utilities/usdt-scripts/flow_reval_monitor.py +index 28479a5650..80c9c98bdb 100755 +--- a/utilities/usdt-scripts/flow_reval_monitor.py ++++ b/utilities/usdt-scripts/flow_reval_monitor.py +@@ -255,6 +255,7 @@ FdrReasons = IntEnum( + "FDR_TOO_EXPENSIVE", + "FDR_UPDATE_FAIL", + "FDR_XLATION_ERROR", ++ "FDR_FLOW_MISSING_DP" + ], + start=0, + ) +@@ -270,7 +271,8 @@ FdrReasonStrings = { + FdrReasons.FDR_PURGE: "User requested flow deletion", + FdrReasons.FDR_TOO_EXPENSIVE: "Too expensive to revalidate", + FdrReasons.FDR_UPDATE_FAIL: "Datapath update failed", +- FdrReasons.FDR_XLATION_ERROR: "Flow translation error" ++ FdrReasons.FDR_XLATION_ERROR: "Flow translation error", ++ FdrReasons.FDR_FLOW_MISSING_DP: "Flow is missing from the datapath" + } + + diff --git a/SPECS/openvswitch3.4.spec b/SPECS/openvswitch3.4.spec index e3ebae5..0994104 100644 --- a/SPECS/openvswitch3.4.spec +++ b/SPECS/openvswitch3.4.spec @@ -57,7 +57,7 @@ Summary: Open vSwitch Group: System Environment/Daemons daemon/database/utilities URL: http://www.openvswitch.org/ Version: 3.4.0 -Release: 3%{?dist} +Release: 4%{?dist} # Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the # lib/sflow*.[ch] files are SISSL @@ -770,6 +770,17 @@ exit 0 %endif %changelog +* Mon Sep 16 2024 Open vSwitch CI - 3.4.0-4 +- Merging upstream branch-3.4 [RH git: 743a772569] + Commit list: + 76ba41b5c2 vconn: Always properly free flow stats reply. + fa840997f5 mcast-snooping: Properly check group_get_lru return code. + 64cb905077 ovsdb-idl: Fix IDL memory leak. + 9e9433ec5b ofproto/bond: Preserve active bond member over restarts. + 05b7520826 ofproto-dpif-upcall: Avoid stale ukeys leaks. + a91553ef0e ci: Use previous sarif-tools release due to issue in latest release. + + * Thu Aug 29 2024 Open vSwitch CI - 3.4.0-3 - Merging upstream branch-3.4 [RH git: 7e8c8356c9] Commit list: