From 2a692e0e726f574a2bd92ed0a99403bb7aa2c3ae Mon Sep 17 00:00:00 2001
From: Mingming Cao <mmc@linux.vnet.ibm.com>
Date: Wed, 16 Feb 2022 00:31:23 -0800
Subject: [PATCH 4/6] Support wicked HNV using new wicked functions for bonding

first: Add wicked support hnv command functions

second: fixed offline remove HNV

Added scanhcn_wicked() to be able to reconfigure HNV at the end of scan.
When lpar has been shut down, and an old HNV can be removed, the virtual
device can be added to a new HNV,  the configration
changes then. This requires to reconfigure all bonds.

Third, udev renaming racing with hcncfg and wicked ifup, here we improved
wicked cfghcn function by always waiting for udev events complete before
search for device to get the device-ready device names

Last: post LPM migration the new sr_iov should be set as primary, it
currently calling
wicked ifup after the ifcfg file modified to make the sr_iov as primary device.
However the kernel is not noticed, we added a workaround here to directly
update via sysfs

Signed-off-by: Marius Tomaschewski <mt@suse.com>
Signed-off-by: Mingming Cao <mmc@linux.vnet.ibm.com>
---
 scripts/hcnmgr | 234 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 233 insertions(+), 1 deletion(-)

diff --git a/scripts/hcnmgr b/scripts/hcnmgr
index 1551724..c617960 100644
--- a/scripts/hcnmgr
+++ b/scripts/hcnmgr
@@ -359,11 +359,68 @@ do_config_vdevice_nm() {
 	return $E_SUCCESS
 }
 
+# function do_config_vdevice_wicked
+#	configure or create HCN (active-backup bonding)
+#	add device as bonding slave
+#
+#	On enter, the vdevice name, mode, hcnid and drcindex are set
+#
+do_config_vdevice_wicked() {
+	hcnlog DEBUG "do_config_vdevice: enter"
+
+	BONDNAME=bond$HCNID
+	BOND_PATH=$BOND_BASEPATH/$BONDNAME/bonding
+
+	hcnlog DEBUG "Check if there is bond $BONDNAME with hcn id $HCNID"
+
+	if ! suse_ifcfg_is_bond_master "$BONDNAME"; then
+		hcnlog INFO "create bonding for $BONDNAME with bond.options $BONDOPTIONS "
+		# Note: wicked needs spaces in BONDING_MODULE_OPTS as comma is
+		#       used/reserved to separate multiple arp_ip_targets, thus
+		#	this could result in invalid options...:
+		suse_ifcfg_bond_create "$BONDNAME" "" "${BONDOPTIONS//,/ }"
+	fi
+
+	# Add device to the bond
+	hcnlog INFO "suse_ifcfg_bond_add_slave $BONDNAME $DEVNAME"
+	if ! suse_ifcfg_bond_add_slave "$BONDNAME" "$DEVNAME"; then
+		hcnlog DEBUG "enslave $DEVNAME failed"
+		return $E_ENODEV
+	fi
+
+	# if the device is primary, adjust it in the config
+	if [[ $MODE == "primary" ]]; then
+		hcnlog INFO "Change bonding primary slave to $DEVNAME"
+		suse_ifcfg_bond_set_primary "$BONDNAME" "$DEVNAME"
+	fi
+
+	# Prepare configuration while hcn-init.service run, but do not try
+	# to apply when the wicked.service aka network.service is active.
+	# The network.service start at boot (or next one) will apply it.
+	if systemctl is-active -q wicked.service ; then
+		# Apply the config changes to wicked
+		hcnlog DEBUG "Bring up the $BONDNAME interface"
+		wicked ifup "$BONDNAME"
+
+		# workaround: make sure the primary gets applied
+		# so kernel reselect it as primary
+		if [[ $MODE == "primary" ]]; then
+			echo "$DEVNAME" > "$BOND_PATH/primary"
+		fi
+	fi
+
+	hcnlog DEBUG "do_config_vdevice: exit"
+	return $E_SUCCESS
+}
+
 do_config_vdevice() {
 	case $SERVICE in
 		NetworkManager.service)
 			do_config_vdevice_nm
 			;;
+		wicked.service)
+			do_config_vdevice_wicked
+			;;
 	esac
 }
 
@@ -401,7 +458,29 @@ cfghcn_nm() {
 	return $E_SUCCESS
 }
 
+#
+# function cfghcn_wicked
+#	Given device DRC_INDEX, configure or create HCN (active-backup bonding)
+#	add device as bonding slave
+#
+# $1 DRC_INDEX of the hybrid network device
+#
+cfghcn_wicked() {
 
+	hcnlog DEBUG "cfghcn wicked: enter $1"
+
+	hcnlog DEBUG "cfg_hcn wicked: wait for udev events complete, udevadm settle"
+	udevadm settle
+	search_dev "$1"
+
+	hcnlog DEBUG "cfg_hcn: calling do_confi_vdevice to enslave $DEVNAME to HNV"
+	do_config_vdevice
+
+	hcnlog DEBUG "cfghcn wicked: exit"
+	return $E_SUCCESS
+}
+
+#
 # function cfghcn
 #	Given device DRC_INDEX, configure or create HCN (active-backup bonding)
 #	add device as bonding slave
@@ -415,6 +494,9 @@ cfghcn() {
 		NetworkManager.service)
 			cfghcn_nm $1
 			;;
+		wicked.service)
+			cfghcn_wicked $1
+			;;
 	esac
 
 	hcnlog DEBUG "cfghcn: exit"
@@ -427,6 +509,13 @@ rmhcn_nm() {
 		nmcli con delete "$connection"
 	done
 }
+
+rmhcn_wicked() {
+	hcnlog INFO "Delete bonding $BONDNAME"
+	wicked ifdown "$BONDNAME"
+	suse_ifcfg_bond_delete "$BONDNAME"
+}
+
 #
 # function rmhcn
 #	Given HCNID, remove HCN
@@ -449,6 +538,9 @@ rmhcn() {
 		NetworkManager.service)
 			rmhcn_nm
 			;;
+		wicked.service)
+			rmhcn_wicked
+			;;
 	esac
 	hcnlog DEBUG "rmhcn: exit"
 	return $E_SUCCESS
@@ -463,6 +555,15 @@ qrydev_nm() {
 		return $E_SUCCESS
 	fi
 }
+qrydev_wicked() {
+	if ! wicked ifstatus $DEVNAME |grep link |grep up; then
+		hcnlog DEBUG "network connection $BONDNAME-$DEVNAME is inactive or nonexist"
+		hcnlog DEBUG "HCNID $HCNID devname $DEVNAME mode $MODE physloc $PHYSLOC DEVPATH $DEVPATH"
+		hcnlog DEBUG "qryhcn: exit"
+		# In this case, tell HMC to do rmdev and okay to migrate
+		return $E_SUCCESS
+	fi
+}
 #
 #function qrydev
 #	Called by HMC right before migration, to see if it is safe to
@@ -494,6 +595,9 @@ qrydev() {
 		NetworkManager.service)
 			qrydev_nm
 			;;
+		wicked.service)
+			qrydev_wicked
+			;;
 	esac
 
 	hcnlog DEBUG "check if there is bond for this $HCNID"
@@ -533,9 +637,16 @@ show_hcnstatus() {
 			nmcli connection show >>$LOG_FILE
 			nmcli device status >>$LOG_FILE
 			;;
+		wicked.service)
+			if systemctl is-active -q "$SERVICE" ; then
+				wicked ifstatus all >>$LOG_FILE
+			else
+				hcnlog DEBUG "network service $SERVICE is currently inactive"
+			fi
+			;;
 	esac
 
-	ip addr show >>$LOG_FILE
+	ip -d addr show >>$LOG_FILE
 }
 
 #
@@ -554,6 +665,16 @@ rmdev_nm() {
 		nmcli con delete "$BONDNAME-$DEVNAME"
 	fi
 }
+
+rmdev_wicked() {
+	hcnlog DEBUG "rmdev_wicked: enter"
+	suse_ifcfg_bond_del_slave "$BONDNAME" "$DEVNAME"
+	wicked ifdown "$DEVNAME"
+	wicked ifup "$BONDNAME"
+	hcnlog DEBUG "rmdev_wicked: exit"
+	return $E_SUCCESS
+}
+
 #
 #function rmdev
 #	this is called at pre-migration time, remove sr-iov from HCN
@@ -576,6 +697,9 @@ rmdev() {
 		NetworkManager.service)
 			rmdev_nm
 			;;
+		wicked.service)
+			rmdev_wicked
+			;;
 	esac
 
 	hcnlog DEBUG "rmdev: exit"
@@ -701,14 +825,122 @@ scanhcn_nm() {
 		done
 		;;
 	esac
+
 	hcnlog DEBUG "scanhcn: scan for hybrid virtual network finished"
 }
 
+#
+# function scanhcn_wicked
+#
+#	This function will scan the device-tree to find new SR-IOV vfs and virtual devices
+#	that has configured as migratable sr-iov device or as backup vdevice during LPAR
+#	is inactive (or during manual 'hcnmgr -s' call).
+#
+scanhcn_wicked() {
+	local hcnids=()
+	local -A hcn_devs hcn_primary
+	local file dev
+
+	hcnlog DEBUG "scanhcn: on boot scan for hybrid virtual network starts"
+
+	hcnlog DEBUG "search sr_iov device with ibm,hcn-id propterty......"
+	# Look at pci ethernet devices for SR_IOV VFs with ibm,hcn-id propterty
+	# join or Create bond for this hcnid if not exist, add SR-IOVs as primary
+	# slave for this bond accosiated with hcnid, if not already to
+	for pci_dev in "$DT_PATH"/pci*; do
+		[ -d "$pci_dev" ] || continue
+		for dev in "$pci_dev"/ethernet*; do
+			[ -d "$dev" ] || continue
+			if [ -e "$dev"/ibm,hcn-id ] && get_dev_hcn "$dev"; then
+				hcnlog DEBUG "scanhcn found $MODE sr-iov device $DEVNAME with hcnid  $HCNID"
+				# Collect what we have found
+				hcnids=($(suse_wlist_uniq ${hcnids[*]} $HCNID))
+				hcn_devs[$HCNID]=$(suse_wlist_uniq ${hcn_devs[$HCNID]} $DEVNAME)
+				[ "X$MODE" = "Xprimary" ] && hcn_primary[$HCNID]="$DEVNAME"
+			fi
+		done
+	done
+
+	hcnlog DEBUG "search ibmveth device with ibm,hcn-id propterty......"
+	# Look at every vNIC device with ibm,hcn-id propterty
+	# join or create bond for this hcnid if not exist, add vnic device as
+	# slave for this bond accosiated with hcnid, if not already to
+	for dev in "$DT_PATH"/vdevice/l-lan*; do
+		[ -d "$dev" ] || continue
+		if [ -e "$dev"/ibm,hcn-id ] && get_dev_hcn "$dev"; then
+			hcnlog DEBUG "scanhcn found $MODE veth device $DEVNAME with hcnid $HCNID"
+			# Collect what we have found
+			hcnids=($(suse_wlist_uniq ${hcnids[*]} $HCNID))
+			hcn_devs[$HCNID]=$(suse_wlist_uniq ${hcn_devs[$HCNID]} $DEVNAME)
+			[ "X$MODE" = "Xprimary" ] && hcn_primary[$HCNID]="$DEVNAME"
+		fi
+	done
+
+	hcnlog DEBUG "search vnic device with ibm,hcn-id propterty......"
+	# Look at every vNIC device with ibm,hcn-id propterty
+	# join or create bond for this hcnid if not exist, add vnic device as
+	# slave for this bond accosiated with hcnid, if not already to
+	for dev in "$DT_PATH"/vdevice/vnic*; do
+		[ -d "$dev" ] || continue
+		if [ -e "$dev"/ibm,hcn-id ] && get_dev_hcn "$dev"; then
+			hcnlog DEBUG "scanhcn found $MODE vnic device $DEVNAME with hcnid $HCNID"
+			# Collect what we have found
+			hcnids=($(suse_wlist_uniq ${hcnids[*]} $HCNID))
+			hcn_devs[$HCNID]=$(suse_wlist_uniq ${hcn_devs[$HCNID]} $DEVNAME)
+			[ "X$MODE" = "Xprimary" ] && hcn_primary[$HCNID]="$DEVNAME"
+		fi
+	done
+
+	# TODO: when the LPAR has been shut down and the configuration changes then,
+	#	e.g. from: bond$HCNID_old { eth0, eth1 }
+	#	     into: bond$HCNID_new { eth0, eth2 }
+	#	                            ^^^^
+	#     	there is still a config for bond$HCNID_old that we need to remove
+	#	at LPAR boot _before_ we can setup bond$HCNID_new as the new bond
+	#	is (re)using one slave device of the old bond..
+	#	This requires to know which bond is managed via HCN and we may need
+	#	to mark or remember the hcn managed bonds...
+
+	# (Re)configure all bonds
+	for id in "${hcnids[@]}" ; do
+		local bond="bond$id"
+		local primary="${hcn_primary[$id]}"
+		local devices="${hcn_devs[$id]}"
+
+		hcnlog INFO "scanhcn configure HCN $bond with devices '$devices'"
+		if suse_ifcfg_bond_modify "$bond" "$devices" ; then
+			hcnlog INFO "scanhcn configured bond '$bond' config with devices '$devices'"
+		else
+			hcnlog INFO "scanhcn failed to configure bond '$bond' with devices '$devices'"
+			continue
+		fi
+		if suse_ifcfg_bond_set_primary "$bond" "$primary" ; then
+			hcnlog INFO "scanhcn adjusted bond '$bond' config primary to '$primary'"
+		else
+			hcnlog INFO "scanhcn failed to adjust bond '$bond' config primary to '$primary'"
+		fi
+
+		if systemctl is-active -q wicked.service ; then
+			hcnlog INFO "scanhcn reloading HCN bonding: $bond"
+			wicked ifreload "$bond"
+		else
+			hcnlog INFO "scanhcn omits HCN bondings reload due to inactive network"
+			# at boot, hcn-init.service adjusts the configuration and
+			# the wicked.service starting after sets up the bondings.
+		fi
+	done
+
+	hcnlog DEBUG "scanhcn: scan for hybrid virtual network finished"
+	return $E_SUCCESS
+}
 scanhcn() {
 	case $SERVICE in
 		NetworkManager.service)
 			scanhcn_nm
 			;;
+		wicked.service)
+			scanhcn_wicked
+			;;
 	esac
 }
 
-- 
2.34.1

