* [PATCH net v4 0/2] net: openvswitch: fix a feature leak on a failed change
@ 2026-11-15 16:31 Minxi Hou
2026-11-15 16:31 ` [PATCH net v4 1/2] net: openvswitch: do not record user features when the change fails Minxi Hou
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Minxi Hou @ 2026-11-15 16:31 UTC (permalink / raw)
To: netdev
Cc: Aaron Conole, Eelco Chaudron, Ilya Maximets, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Shuah Khan,
linux-kselftest, Minxi Hou
The datapath records the user features before it applies the change, so
a request that fails leaves it claiming a bit whose reference count was
never taken. The first patch records the features last. The second adds a
selftest that drives the failing request and reads back what the datapath
reports.
v4:
- Rebased onto current main.
- The skip message is one printf again. Splitting it made shellcheck
report SC2182 and dropped a word and the newline from the output.
- The new tests say why they failed on stdout. info() writes debug.log
and a failing run deletes that file, so CI showed a FAIL with no reason.
- A datapath that cannot be read is reported as that instead of as a
feature mismatch.
- The outdated add-dp request is checked instead of discarded.
- The errno numbers come from python rather than from a literal, and a
lookup that cannot answer says so rather than comparing against an
empty string.
v3: https://lore.kernel.org/netdev/20261110174651.972936-1-houminxi@gmail.com/
- Cover the recirc bit as well as the dispatch bit.
v2: https://lore.kernel.org/netdev/20261108123424.2825403-1-houminxi@gmail.com/
- Name the two paths that leaked a reference and fix both.
v1: https://lore.kernel.org/netdev/20261107113403.797779-1-houminxi@gmail.com/
Neither leak has a test of its own. The reference count behind the bit is
not visible from user space, so the tests read back the features a
datapath reports: the reset drops them to zero where a test can see it,
and a datapath freed after a failed creation leaves no state to check.
One thing this series leaves alone: ovs_add_dp() returns the status of the
last command in its body rather than of the add, so the `|| return 1` that
follows its calls cannot fail. That predates this series and every OVS
test shares it. The two tests here do not depend on it.
Signed-off-by: Minxi Hou <houminxi@gmail.com>
Minxi Hou (2):
net: openvswitch: do not record user features when the change fails
selftests/net/openvswitch: check that a failed set keeps the features
net/openvswitch/datapath.c | 34 ++--
net/openvswitch/datapath.h | 5 +-
.../testing/selftests/net/openvswitch/config | 3 +
.../selftests/net/openvswitch/openvswitch.sh | 173 ++++++++++++++++++
.../selftests/net/openvswitch/ovs-dpctl.py | 61 ++++++
5 files changed, 262 insertions(+), 14 deletions(-)
base-commit: 6964ff21c5d8b75649211a52dbfd92753e605649
--
2.56.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH net v4 1/2] net: openvswitch: do not record user features when the change fails
2026-11-15 16:31 [PATCH net v4 0/2] net: openvswitch: fix a feature leak on a failed change Minxi Hou
@ 2026-11-15 16:31 ` Minxi Hou
2026-11-15 16:31 ` [PATCH net v4 2/2] selftests/net/openvswitch: check that a failed set keeps the features Minxi Hou
2026-11-15 20:12 ` [PATCH net v4 0/2] net: openvswitch: fix a feature leak on a failed change netdev-bot+sinfo
2 siblings, 0 replies; 4+ messages in thread
From: Minxi Hou @ 2026-11-15 16:31 UTC (permalink / raw)
To: netdev
Cc: Aaron Conole, Eelco Chaudron, Ilya Maximets, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Shuah Khan,
linux-kselftest, Minxi Hou, stable
ovs_dp_change() stores the new features in dp->user_features before it
updates the per-cpu upcall port IDs, and that update fails when the
per-cpu-pids attribute is empty or its length is not a multiple of four.
The request returns -EINVAL with the new features already recorded, while
the code that enables or disables the tc skb extension key never ran.
The datapath then claims TC_RECIRC_SHARING without holding the reference
the bit stands for. A later request that clears the bit drops a
reference that was never taken, and a datapath destroyed with the bit
clear never drops the one it did take. The key is shared with the other
users of recirc sharing, so the count can reach zero while one of them
still reads it, and a disable on a count of zero warns from
static_key_dec_not_one(), which panics a host that runs with
panic_on_warn.
The request only needs CAP_NET_ADMIN, which a user namespace that owns a
network namespace provides. datapath_policy has no entry for
OVS_DP_ATTR_PER_CPU_PIDS and the operation skips strict validation, so an
empty attribute reaches the check that fails.
Record the features last, in one setter that also takes and drops the
reference, and use it from every place that changes or clears the bit.
Two of those places leaked a reference: a datapath that fails after
ovs_dp_change() enabled the key was freed without a disable, and
ovs_dp_reset_user_features() cleared the bit without one. The reset runs
when an outdated user space instance sends OVS_DP_CMD_NEW for a name that
already exists, and after it the datapath's packets no longer share the tc
skb extension.
Fixes: 35d39fecbc24 ("net/sched: Enable tc skb ext allocation on chain miss only when needed")
Cc: stable@vger.kernel.org
Signed-off-by: Minxi Hou <houminxi@gmail.com>
---
net/openvswitch/datapath.c | 34 +++++++++++++++++++++-------------
net/openvswitch/datapath.h | 5 ++++-
2 files changed, 25 insertions(+), 14 deletions(-)
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index b2a0b09fd4a5..8fcb9f2c8ece 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -1704,6 +1704,20 @@ static struct datapath *lookup_datapath(struct net *net,
return dp ? dp : ERR_PTR(-ENODEV);
}
+/* Called with ovs_mutex. */
+static void ovs_dp_set_user_features(struct datapath *dp, u32 features)
+{
+ bool was = dp->user_features & OVS_DP_F_TC_RECIRC_SHARING;
+ bool now = features & OVS_DP_F_TC_RECIRC_SHARING;
+
+ if (now && !was)
+ tc_skb_ext_tc_enable();
+ else if (!now && was)
+ tc_skb_ext_tc_disable();
+
+ dp->user_features = features;
+}
+
static void ovs_dp_reset_user_features(struct sk_buff *skb,
struct genl_info *info)
{
@@ -1716,7 +1730,7 @@ static void ovs_dp_reset_user_features(struct sk_buff *skb,
pr_warn("%s: Dropping previously announced user features\n",
ovs_dp_name(dp));
- dp->user_features = 0;
+ ovs_dp_set_user_features(dp, 0);
}
static int ovs_dp_set_upcall_portids(struct datapath *dp,
@@ -1773,7 +1787,7 @@ u32 ovs_dp_get_upcall_portid(const struct datapath *dp, uint32_t cpu_id)
static int ovs_dp_change(struct datapath *dp, struct nlattr *a[])
{
- u32 user_features = 0, old_features = dp->user_features;
+ u32 user_features = 0;
int err;
if (a[OVS_DP_ATTR_USER_FEATURES]) {
@@ -1801,9 +1815,7 @@ static int ovs_dp_change(struct datapath *dp, struct nlattr *a[])
return err;
}
- dp->user_features = user_features;
-
- if (dp->user_features & OVS_DP_F_DISPATCH_UPCALL_PER_CPU &&
+ if (user_features & OVS_DP_F_DISPATCH_UPCALL_PER_CPU &&
a[OVS_DP_ATTR_PER_CPU_PIDS]) {
/* Upcall Netlink Port IDs have been updated */
err = ovs_dp_set_upcall_portids(dp,
@@ -1812,12 +1824,7 @@ static int ovs_dp_change(struct datapath *dp, struct nlattr *a[])
return err;
}
- if ((dp->user_features & OVS_DP_F_TC_RECIRC_SHARING) &&
- !(old_features & OVS_DP_F_TC_RECIRC_SHARING))
- tc_skb_ext_tc_enable();
- else if (!(dp->user_features & OVS_DP_F_TC_RECIRC_SHARING) &&
- (old_features & OVS_DP_F_TC_RECIRC_SHARING))
- tc_skb_ext_tc_disable();
+ ovs_dp_set_user_features(dp, user_features);
return 0;
}
@@ -1939,6 +1946,8 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
err_destroy_portids:
kfree(rcu_dereference_raw(dp->upcall_portids));
err_unlock_and_destroy_meters:
+ /* The datapath is freed here and never reaches __dp_destroy(). */
+ ovs_dp_set_user_features(dp, 0);
ovs_unlock();
ovs_meters_exit(dp);
err_destroy_ports:
@@ -1961,8 +1970,7 @@ static void __dp_destroy(struct datapath *dp)
struct flow_table *table = &dp->table;
int i;
- if (dp->user_features & OVS_DP_F_TC_RECIRC_SHARING)
- tc_skb_ext_tc_disable();
+ ovs_dp_set_user_features(dp, 0);
for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
struct vport *vport;
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
index 7a7afaeceee5..e94b77261b95 100644
--- a/net/openvswitch/datapath.h
+++ b/net/openvswitch/datapath.h
@@ -76,7 +76,10 @@ struct dp_nlsk_pids {
* ovs_mutex and RCU.
* @stats_percpu: Per-CPU datapath statistics.
* @net: Reference to net namespace.
- * @user_features: Bitmap of enabled %OVS_DP_F_* features.
+ * @user_features: Bitmap of enabled %OVS_DP_F_* features. A datapath
+ * that has %OVS_DP_F_TC_RECIRC_SHARING set holds one reference to the tc
+ * skb extension, so this field is written last, through
+ * ovs_dp_set_user_features(), with ovs_mutex held.
* @max_headroom: The maximum headroom of all vports in this datapath; it will
* be used by all the internal vports in this dp.
* @meter_tbl: Meter table.
--
2.56.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH net v4 2/2] selftests/net/openvswitch: check that a failed set keeps the features
2026-11-15 16:31 [PATCH net v4 0/2] net: openvswitch: fix a feature leak on a failed change Minxi Hou
2026-11-15 16:31 ` [PATCH net v4 1/2] net: openvswitch: do not record user features when the change fails Minxi Hou
@ 2026-11-15 16:31 ` Minxi Hou
2026-11-15 20:12 ` [PATCH net v4 0/2] net: openvswitch: fix a feature leak on a failed change netdev-bot+sinfo
2 siblings, 0 replies; 4+ messages in thread
From: Minxi Hou @ 2026-11-15 16:31 UTC (permalink / raw)
To: netdev
Cc: Aaron Conole, Eelco Chaudron, Ilya Maximets, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Shuah Khan,
linux-kselftest, Minxi Hou
Add a set-dp command to ovs-dpctl for the kernel's datapath SET command,
and two tests that use it.
The first test clears the features of a fresh datapath, sets the dispatch
bit with a valid pid list, and clears them again. It then sends a set that
would set that bit with an empty per-cpu-pids. The request has to fail
with EINVAL, and the datapath has to keep reporting the features it had,
which a kernel that records them before the change reads as 0x8 instead of
0x0. A second request sends OVS_DP_CMD_NEW for that name from an outdated
client, which makes the kernel drop the features, and a further set has
to work.
The second test covers the recirc bit. It sets that bit on a fresh datapath
and sends a set that would set the dispatch bit with an empty per-cpu-pids.
The rejected request has to leave the recirc bit in place. A kernel that
records the features first reads 0x8 there instead of 0x4. A datapath
holds that bit only when the tc skb extension is compiled in, so the test
prints the reason and skips when the kernel answers EOPNOTSUPP, and any
other failure of that request fails the test. CONFIG_NET_TC_SKB_EXT
depends on CONFIG_NET_CLS_ACT and both sit under CONFIG_NET_SCHED, so the
selftest config fragment selects all three.
The reference count itself is not visible from user space, so the steps
that use an outdated client only show that those paths run and that a
datapath keeps working across them.
set-dp sends the features it is given. When --features is left out it
sends the features the datapath reports, and it refuses to send the
request when the datapath reports none. A pid list that is not a list of
numbers is reported as such, and empty entries are dropped.
Signed-off-by: Minxi Hou <houminxi@gmail.com>
---
.../testing/selftests/net/openvswitch/config | 3 +
.../selftests/net/openvswitch/openvswitch.sh | 173 ++++++++++++++++++
.../selftests/net/openvswitch/ovs-dpctl.py | 61 ++++++
3 files changed, 237 insertions(+)
diff --git a/tools/testing/selftests/net/openvswitch/config b/tools/testing/selftests/net/openvswitch/config
index 15685d242813..38fa1477b7cd 100644
--- a/tools/testing/selftests/net/openvswitch/config
+++ b/tools/testing/selftests/net/openvswitch/config
@@ -2,10 +2,13 @@ CONFIG_GENEVE=m
CONFIG_INET_DIAG=y
CONFIG_IP_SCTP=y
CONFIG_IPV6=y
+CONFIG_NET_CLS_ACT=y
CONFIG_NETFILTER=y
CONFIG_NETFILTER_ADVANCED=y
CONFIG_NET_IPGRE=m
CONFIG_NET_IPGRE_DEMUX=m
+CONFIG_NET_SCHED=y
+CONFIG_NET_TC_SKB_EXT=y
CONFIG_NF_CONNTRACK=m
CONFIG_NF_CONNTRACK_OVS=y
CONFIG_NF_CT_PROTO_SCTP=y
diff --git a/tools/testing/selftests/net/openvswitch/openvswitch.sh b/tools/testing/selftests/net/openvswitch/openvswitch.sh
index 21444657a040..559c25d51099 100755
--- a/tools/testing/selftests/net/openvswitch/openvswitch.sh
+++ b/tools/testing/selftests/net/openvswitch/openvswitch.sh
@@ -24,6 +24,8 @@ tests="
nat_connect_v4 ip4-nat-xon: Basic ipv4 tcp connection via NAT
nat_related_v4 ip4-nat-related: ICMP related matches work with SNAT
netlink_checks ovsnl: validate netlink attrs and settings
+ dp_features ovsdp: failed set keeps bits
+ dp_features_recirc ovsdp: recirc bit survives
upcall_interfaces ovs: test the upcall interfaces
tunnel_metadata ovs: test extraction of tunnel metadata
drop_reason drop: test drop reasons are emitted
@@ -44,6 +46,11 @@ info() {
[ $VERBOSE = 0 ] || echo $*
}
+# ovs_sbx sends everything a command prints to debug.log, and a failing run
+# deletes that file. Keep a handle on the real stdout so a failure reason
+# still reaches the CI log.
+exec 9>&1
+
ovs_wait() {
info "waiting $WAIT_TIMEOUT s for: $@"
@@ -1409,6 +1416,172 @@ test_netlink_checks () {
return 0
}
+ovs_dp_features_set() {
+ python3 $ovs_base/ovs-dpctl.py set-dp "$@"
+}
+
+ovs_dp_features_check() {
+ local out
+
+ # A show that fails and a datapath that reports other features are
+ # different faults, so they return different statuses. ovs-dpctl prints
+ # the value with %X, so convert before comparing.
+ out=$(python3 $ovs_base/ovs-dpctl.py show "$1") || {
+ printf '# could not read the datapath %s\n' "$1" >&9
+ return 2
+ }
+ printf '%s\n' "$out" |
+ grep -q "features: 0x$(printf '%X' "$2")\$"
+}
+
+# info() writes debug.log, and a failing run deletes that file, so a FAIL
+# would reach CI with no reason. Say it on stdout instead.
+ovs_fail() {
+ printf '# %s\n' "$*" >&9
+ return 1
+}
+
+ovs_dp_features_expect() {
+ ovs_dp_features_check "$1" "$2"
+ case $? in
+ 0) return 0 ;;
+ # The check itself reported that it could not read the datapath.
+ 2) return 1 ;;
+ esac
+ ovs_fail "$3"
+}
+
+# EOPNOTSUPP is not in the base errno list and its number differs by
+# architecture, so ask python instead of hard-coding one.
+ovs_errno() {
+ local n
+
+ n=$(python3 -c "import errno; print(errno.$1)" 2>/dev/null)
+ if [ -z "$n" ]; then
+ printf '# could not read errno.%s from python\n' "$1" >&9
+ return 1
+ fi
+ printf '%s\n' "$n"
+}
+
+# dp_features test
+# - a set with the dispatch bit and pids is accepted and reported back
+# - a set with an empty per-cpu-pids is rejected with EINVAL and leaves
+# the features as they were
+# - an outdated new request drops the features, and sets work afterwards
+test_dp_features() {
+ local t="test_dp_features"
+ local dp="dpfeat0"
+
+ sbx_add "$t" || return $?
+ ovs_add_dp "$t" "$dp" || return 1
+
+ info "clear the datapath features"
+ ovs_sbx "$t" ovs_dp_features_set "$dp" --features 0 || return 1
+ ovs_sbx "$t" ovs_dp_features_expect "$dp" 0 \
+ "features were not cleared" || return 1
+
+ # 8 is OVS_DP_F_DISPATCH_UPCALL_PER_CPU, the bit that makes the
+ # kernel read per-cpu-pids.
+ info "a set with the dispatch bit and pids is accepted"
+ ovs_sbx "$t" ovs_dp_features_set "$dp" --features 8 \
+ --per-cpu-pids 1,2 || return 1
+ ovs_sbx "$t" ovs_dp_features_expect "$dp" 8 \
+ "the accepted set was not applied" || return 1
+
+ ovs_sbx "$t" ovs_dp_features_set "$dp" --features 0 || return 1
+
+ # ovs-dpctl sends the empty list as an attribute with no payload,
+ # which is what the kernel rejects.
+ info "a set with an empty per-cpu-pids is rejected"
+ einval=$(ovs_errno EINVAL) || return 1
+ ovs_sbx "$t" ovs_dp_features_set "$dp" --features 8 \
+ --per-cpu-pids "" &> /dev/null
+ rc=$?
+ [ $rc -eq "$einval" ] || {
+ ovs_fail "the empty per-cpu-pids set failed with $rc"
+ return 1
+ }
+
+ info "the rejected set keeps the features it had"
+ ovs_sbx "$t" ovs_dp_features_expect "$dp" 0 \
+ "the rejected set was recorded" || return 1
+
+ # An outdated client that asks for an existing datapath again makes
+ # the kernel drop its features. The datapath keeps working.
+ info "an outdated new request drops the features"
+ ovs_sbx "$t" ovs_dp_features_set "$dp" --features 8 || return 1
+ ovs_sbx "$t" python3 $ovs_base/ovs-dpctl.py add-dp "$dp" -V 1:0 || {
+ ovs_fail "the outdated add request did not run"
+ return 1
+ }
+ ovs_sbx "$t" ovs_dp_features_expect "$dp" 0 \
+ "the outdated new request did not drop the features" || return 1
+ ovs_sbx "$t" ovs_dp_features_set "$dp" --features 8 || {
+ ovs_fail "the datapath stopped accepting sets"
+ return 1
+ }
+ ovs_sbx "$t" ovs_dp_features_expect "$dp" 8 \
+ "the reset datapath took no features" || return 1
+
+ return 0
+}
+
+# dp_features_recirc test
+# - a datapath that holds the recirc bit keeps it across a rejected set
+# - an outdated new request drops the features
+# - the bit needs CONFIG_NET_TC_SKB_EXT, so the test skips without it
+test_dp_features_recirc() {
+ local t="test_dp_features_recirc"
+ local dp="dpfeat1"
+
+ sbx_add "$t" || return $?
+ ovs_add_dp "$t" "$dp" || return 1
+
+ ovs_sbx "$t" ovs_dp_features_set "$dp" --features 0 || return 1
+
+ # 4 is OVS_DP_F_TC_RECIRC_SHARING. The kernel takes the bit only when
+ # the tc skb extension is compiled in.
+ ovs_sbx "$t" ovs_dp_features_set "$dp" --features 4 &> /dev/null
+ rc=$?
+ if [ $rc -ne 0 ]; then
+ eopnotsupp=$(ovs_errno EOPNOTSUPP) || return 1
+ if [ $rc -eq "$eopnotsupp" ]; then
+ # info() only writes debug.log, which CI does not keep.
+ printf "# tc skb extension is not compiled in,"
+ printf " skipping recirc\n"
+ ovs_exit_sig
+ return $ksft_skip
+ fi
+ info "the recirc set failed with $rc"
+ return 1
+ fi
+ ovs_sbx "$t" ovs_dp_features_expect "$dp" 4 \
+ "the accepted recirc set was not applied" || return 1
+
+ info "the rejected set keeps the recirc bit"
+ einval=$(ovs_errno EINVAL) || return 1
+ ovs_sbx "$t" ovs_dp_features_set "$dp" --features 8 \
+ --per-cpu-pids "" &> /dev/null
+ rc=$?
+ [ $rc -eq "$einval" ] || {
+ ovs_fail "the rejected set failed with $rc"
+ return 1
+ }
+ ovs_sbx "$t" ovs_dp_features_expect "$dp" 4 \
+ "the rejected set dropped the recirc bit" || return 1
+
+ info "an outdated new request drops the features"
+ ovs_sbx "$t" python3 $ovs_base/ovs-dpctl.py add-dp "$dp" -V 1:0 || {
+ ovs_fail "the outdated add request did not run"
+ return 1
+ }
+ ovs_sbx "$t" ovs_dp_features_expect "$dp" 0 \
+ "the outdated new request did not drop the features" || return 1
+
+ return 0
+}
+
test_upcall_interfaces() {
sbx_add "test_upcall_interfaces" || return 1
diff --git a/tools/testing/selftests/net/openvswitch/ovs-dpctl.py b/tools/testing/selftests/net/openvswitch/ovs-dpctl.py
index 1615843c225e..ee3b69a6fe19 100644
--- a/tools/testing/selftests/net/openvswitch/ovs-dpctl.py
+++ b/tools/testing/selftests/net/openvswitch/ovs-dpctl.py
@@ -2301,6 +2301,25 @@ class OvsDatapath(GenericNetlinkSocket):
return reply
+ def set(self, dpname, ifindex=0, features=None, per_cpu_pids=None):
+ """ Send OVS_DP_CMD_SET for a datapath. """
+ msg = OvsDatapath.dp_cmd_msg()
+ msg["cmd"] = OVS_DP_CMD_SET
+ msg["version"] = OVS_DATAPATH_VERSION
+ msg["reserved"] = 0
+ msg["dpifindex"] = ifindex
+ msg["attrs"].append(["OVS_DP_ATTR_NAME", dpname])
+ if features is not None:
+ msg["attrs"].append(["OVS_DP_ATTR_USER_FEATURES", features])
+ if per_cpu_pids is not None:
+ msg["attrs"].append(["OVS_DP_ATTR_PER_CPU_PIDS", per_cpu_pids])
+
+ reply = self.nlm_request(
+ msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
+ )
+
+ return reply[0]
+
def create(
self, dpname, shouldUpcall=False, versionStr=None, p=OvsPacket()
):
@@ -2961,6 +2980,23 @@ def main(argv):
deldpcmd = subparsers.add_parser("del-dp")
deldpcmd.add_argument("deldp", help="Datapath Name")
+ setdpcmd = subparsers.add_parser("set-dp")
+ setdpcmd.add_argument("setdp", help="Datapath Name")
+ setdpcmd.add_argument(
+ "-f",
+ "--features",
+ type=lambda x: int(x, 0),
+ default=None,
+ help="Datapath user features, defaults to the current value",
+ )
+ setdpcmd.add_argument(
+ "-p",
+ "--per-cpu-pids",
+ type=str,
+ default=None,
+ help="Comma separated upcall pids, an empty string sends none",
+ )
+
addifcmd = subparsers.add_parser("add-if")
addifcmd.add_argument("dpname", help="Datapath Name")
addifcmd.add_argument("addif", help="Interface name for adding")
@@ -3057,6 +3093,31 @@ def main(argv):
ovspk.upcall_handler(ovsflow)
elif hasattr(args, "deldp"):
ovsdp.destroy(args.deldp)
+ elif hasattr(args, "setdp"):
+ rep = ovsdp.info(args.setdp, 0)
+ if rep is None:
+ print(f"DP '{args.setdp}' not found.")
+ return 1
+ pids = None
+ if args.per_cpu_pids is not None:
+ try:
+ pids = [int(x) for x in args.per_cpu_pids.split(",")
+ if x != ""]
+ except ValueError:
+ print(f"invalid per-cpu-pids: {args.per_cpu_pids}")
+ return 1
+ features = args.features
+ if features is None:
+ features = rep.get_attr("OVS_DP_ATTR_USER_FEATURES")
+ if features is None:
+ print(f"DP '{args.setdp}' does not report its features")
+ return 1
+ try:
+ ovsdp.set(args.setdp, rep["dpifindex"], features, pids)
+ except NetlinkError as ne:
+ print(f"set failed: {ne.args[1]}")
+ return ne.code
+ print(f"DP '{args.setdp}' updated")
elif hasattr(args, "addif"):
rep = ovsdp.info(args.dpname, 0)
if rep is None:
--
2.56.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH net v4 0/2] net: openvswitch: fix a feature leak on a failed change
2026-11-15 16:31 [PATCH net v4 0/2] net: openvswitch: fix a feature leak on a failed change Minxi Hou
2026-11-15 16:31 ` [PATCH net v4 1/2] net: openvswitch: do not record user features when the change fails Minxi Hou
2026-11-15 16:31 ` [PATCH net v4 2/2] selftests/net/openvswitch: check that a failed set keeps the features Minxi Hou
@ 2026-11-15 20:12 ` netdev-bot+sinfo
2 siblings, 0 replies; 4+ messages in thread
From: netdev-bot+sinfo @ 2026-11-15 20:12 UTC (permalink / raw)
To: Minxi Hou
Cc: netdev, Aaron Conole, Eelco Chaudron, Ilya Maximets, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Shuah Khan,
linux-kselftest
Hi!
This is an automated message. This series looks like a fix, but its
commit messages seem to be missing some information:
- How the issue was discovered, e.g. hit in production, hit during
development, syzbot report, manual code inspection, LLM or static
analysis tool scan.
Please do not repost the series just to address the above. Instead,
reply to this email with the missing information, so that reviewers
can take it into account.
*IMPORTANT*: If you do repost (for other reasons) - please include
the relevant info in the cover letter or commit messages.
--
The evaluation is done by an LLM so it may be wrong, if you think
that is the case please reply and explain.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-11-15 20:12 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-15 16:31 [PATCH net v4 0/2] net: openvswitch: fix a feature leak on a failed change Minxi Hou
2026-11-15 16:31 ` [PATCH net v4 1/2] net: openvswitch: do not record user features when the change fails Minxi Hou
2026-11-15 16:31 ` [PATCH net v4 2/2] selftests/net/openvswitch: check that a failed set keeps the features Minxi Hou
2026-11-15 20:12 ` [PATCH net v4 0/2] net: openvswitch: fix a feature leak on a failed change netdev-bot+sinfo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox