teamd: add port_master_ifindex_changed for teamd_event_watch_ops

When we add port to new active-backup teams with multi threads. After
the port is set to link up and trigger function obj_input_newlink(),
it's possible that there is no master index in rtnl link info. So the
team slave's master_ifindex is not updated.

On the other hand, the port is up and trigger functions like
- teamd_link_watch_check_link_up()
  - teamd_event_port_link_changed()
    - ab_event_watch_port_link_changed()
      - ab_link_watch_handler()
        - teamd_for_each_tdport()
	  - teamd_get_next_tdport()
	    - teamd_port_present()

Here the teamd_port_present() failed as the port master ifindex is not
update to team ifindex yet. Finally we get nothing and no active port
is set.

Here is the reproducer:

if [ -z $1 ] || [ -z $2 ]; then
	echo "Usage: $0 iface1 iface2"
	exit 1


	local num=$1
	local iface=$2
	teamd -o -n -U -d -t team$num -c '{"runner": {"name": "activebackup"},"link_watch": {"name": "ethtool"}}' -gg
	teamdctl team$num port add $iface

while :; do
	echo "-----------------------------------------------------------"
	let "COUNT++"
	echo "Loop $COUNT"

	teamd -k -t team1
	teamd -k -t team2
	sleep "$WAIT"
	start_team 1 $iface1 &
	start_team 2 $iface2 &
	sleep "$WAIT"

	if teamdctl team1 state | grep -q "active port: $iface1" && \
		teamdctl team2 state | grep -q "active port: $iface2"; then
		echo "Pass"
		echo "FAIL"
		exit 1

Failure as follows:

]# teamdctl teamX state dump
    "runner": {
        "active_port": ""

Currently we only reproduced this with active-backup mode(I could reproduce it
in VM easily, but hard to reproduce it on physical machines).

Fix it by adding a new teamd_event_watch_ops port_master_ifindex_changed for
active-backup mode.

V2: update commit description from Jamie Bainbridge's reply.
v3: update description and reproducer.

Signed-off-by: Hangbin Liu <>
Signed-off-by: Jiri Pirko <>
4 files changed