From fca6b902a1fe7ff8e96e10ed987bcb340e51f871 Mon Sep 17 00:00:00 2001 From: Ying Xie Date: Mon, 1 Apr 2019 16:51:30 -0700 Subject: [PATCH] [teamd] prevent re-entrance of port priv change handler (#2723) When adding a lag member dynamically after system boots up, teamd port priv change handler could re-entrant itself and causing adding operation to fail. While handling PORT_CHANGE event, teamd_per_port.c port priv change handler was called, it will then call runner_lacp to add port to lag, the later causes IFINFO_CHANGE to be notified and calls the priv change handler again, this re-entrance would cause runner_lacp port_added to be called again and messes up with the previous adding sequence. Then fails the lag member adding operation. Prevent per port priv change handler re-entrance solves the problem. Signed-off-by: Ying Xie --- ...nt-private-change-handler-reentrance.patch | 90 +++++++++++++++++++ src/libteam/series | 1 + 2 files changed, 91 insertions(+) create mode 100644 src/libteam/0009-teamd-prevent-private-change-handler-reentrance.patch diff --git a/src/libteam/0009-teamd-prevent-private-change-handler-reentrance.patch b/src/libteam/0009-teamd-prevent-private-change-handler-reentrance.patch new file mode 100644 index 000000000000..dad10a4c1ae9 --- /dev/null +++ b/src/libteam/0009-teamd-prevent-private-change-handler-reentrance.patch @@ -0,0 +1,90 @@ +From fb00b070482dc587eec7b4e34acec094be1af00d Mon Sep 17 00:00:00 2001 +From: Ying Xie +Date: Fri, 29 Mar 2019 20:54:49 +0000 +Subject: [PATCH 10/11] [teamd] prevent private change handler reentrance + +While handling PORT_CHANGE, teamd could casue an INTERFACE_CHANGE in the +same context. Which will interfere with the PORT_CHANGE handling and +causing it to fail. + +Lock is not needed because the re-entrance happened in the same thread +context. + +This issue was noticed while dynamically adding a port into a lag. + +Signed-off-by: Ying Xie +--- + teamd/teamd.c | 2 ++ + teamd/teamd.h | 2 ++ + teamd/teamd_per_port.c | 13 +++++++++++-- + 3 files changed, 15 insertions(+), 2 deletions(-) + +diff --git a/teamd/teamd.c b/teamd/teamd.c +index e28aa7d..140b98b 100644 +--- a/teamd/teamd.c ++++ b/teamd/teamd.c +@@ -1255,6 +1255,8 @@ static int teamd_init(struct teamd_context *ctx) + { + int err; + ++ ctx->reentrant = false; ++ + ctx->th = team_alloc(); + if (!ctx->th) { + teamd_log_err("Team alloc failed."); +diff --git a/teamd/teamd.h b/teamd/teamd.h +index 622c365..7cd3266 100644 +--- a/teamd/teamd.h ++++ b/teamd/teamd.h +@@ -160,6 +160,8 @@ struct teamd_context { + int pipe_r; + int pipe_w; + } workq; ++ ++ bool reentrant; + }; + + struct teamd_port { +diff --git a/teamd/teamd_per_port.c b/teamd/teamd_per_port.c +index 137da57..8b4a457 100644 +--- a/teamd/teamd_per_port.c ++++ b/teamd/teamd_per_port.c +@@ -250,6 +250,10 @@ static int port_priv_change_handler_func(struct team_handle *th, void *priv, + struct port_obj *port_obj; + int err; + ++ if (ctx->reentrant) { ++ return 0; ++ } ++ ctx->reentrant = true; + team_for_each_port(port, th) { + uint32_t ifindex = team_get_port_ifindex(port); + +@@ -258,17 +262,22 @@ static int port_priv_change_handler_func(struct team_handle *th, void *priv, + if (team_is_port_removed(port)) + continue; + err = port_obj_create(ctx, &port_obj, ifindex, port); +- if (err) ++ if (err) { ++ ctx->reentrant = false; + return err; ++ } + } + if (team_is_port_changed(port)) { + err = teamd_event_port_changed(ctx, _port(port_obj)); +- if (err) ++ if (err) { ++ ctx->reentrant = false; + return err; ++ } + } + if (team_is_port_removed(port)) + port_obj_remove(ctx, port_obj); + } ++ ctx->reentrant = false; + return 0; + } + +-- +2.7.4 + diff --git a/src/libteam/series b/src/libteam/series index 51b43ca14885..a6c4893d021a 100644 --- a/src/libteam/series +++ b/src/libteam/series @@ -6,3 +6,4 @@ 0006-Fix-ifinfo_link_with_port-race-condition-with-newlink.patch 0007-Skip-setting-the-same-hwaddr-to-lag-port-to-avoid-di.patch 0008-teamd-register-change-handler-for-TEAM_IFINFO_CHANGE.patch +0009-teamd-prevent-private-change-handler-reentrance.patch